alamion_obsidian-jira-sync/AGENTS.md
Alamoin 0786db1535
Feats
- `Super Simple Time Tracker` plugin format support
- Support of multiple Jira connections.
- `AGENTS.md` file from Obidian plugin template and filled with info about project
- Updated eslint configs to `eslint.config.js` format + linted all the code; added prettier with according config
- localization validator improvement; multiple localization fixes
- many minor fixes
2026-04-29 17:41:24 +03:00

265 lines
10 KiB
Markdown

# Obsidian Jira Sync - Community plugin for Obsidian
## Project overview
- **Plugin ID**: `jira-sync`
- **Name**: Jira Issue Manager
- **Target**: Obsidian Community Plugin (TypeScript → bundled JavaScript)
- **Entry point**: `main.ts` compiled to `main.js` and loaded by Obsidian
- **Required release artifacts**: `main.js`, `manifest.json`, and optional `styles.css`
- **Min App Version**: 1.10.1
- **Author**: Alamion
- **Mobile compatible**: Yes (`isDesktopOnly: false`)
## Environment & tooling
- Node.js: use current LTS (Node 18+ recommended)
- **Package manager: yarn** (required - `package.json` defines yarn scripts)
- **Bundler: esbuild** (required - `esbuild.config.mjs` and build scripts depend on it)
- Types: `obsidian` type definitions
### Install
```bash
yarn install
```
### Dev (watch)
```bash
yarn run dev
```
### Production build
```bash
yarn run build
```
### Localization
```bash
yarn run validate_locale_once # Validate YAML source files
yarn run compile_locale_once # Compile YAML to JSON
```
## Linting
All three commands must pass without errors:
1. `yarn run format` - No Prettier errors
2. `yarn run lint:fix` - No ESLint errors
3. `yarn run build` - No TypeScript/build errors
4. `yarn run validate_locale_once` - No localization errors
## File & folder conventions
- **Source lives in `src/`**. Keep `main.ts` small and focused on plugin lifecycle.
- **Do not commit build artifacts**: Never commit `node_modules/`, `main.js`, or other generated files.
- Generated output should be placed at the plugin root. Release artifacts must end up at the top level of the plugin folder in the vault.
### Directory structure (`src/`)
| Directory | Purpose | Key Files |
| ------------------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `commands/` | User commands | `getIssue.ts`, `createIssue.ts`, `updateIssue.ts`, `updateStatus.ts`, `addWorkLogBatch.ts`, `addWorkLogManually.ts`, `batchFetchIssues.ts` |
| `api/` | Jira REST API | `base.ts` (core HTTP), `auth.ts`, `issues.ts`, `projects.ts`, `self.ts` |
| `settings/` | Settings tab & components | `default.ts` (defaults), `JiraSettingTab.ts`, `components/*` |
| `modals/` | UI dialogs | `IssueSearchModal.ts`, `JQLSearchModal.ts`, `IssueWorkLogModal.ts`, `ProjectModal.ts`, `IssueTypeModal.ts`, `IssueStatusModal.ts` |
| `file_operations/` | File read/write | `getIssue.ts`, `createUpdateIssue.ts`, `commonPrepareData.ts` |
| `tools/` | Utilities | `debugLogging.ts`, `cacheUtils.ts`, `filesUtils.ts`, `convertFunctionString.ts`, `sanitizers.ts`, `asyncLimiter.ts` |
| `postprocessing/` | Live Preview/Reading | `livePreview.ts`, `reading.ts` |
| `default/` | Defaults | `defaultTemplate.ts`, `defaultIssue.ts`, `obsidianJiraFieldsMapping.ts` |
| `interfaces/` | TypeScript types | `settingsTypes.ts`, `index.ts` |
| `localization/` | i18n | `translator.ts`, `compiled/*.json`, `source/*.yaml` |
## Packages used
| Package | Purpose | Usage |
| -------------- | ----------------- | ------------------------------------------------------ |
| `obsidian` | Obsidian API | Core plugin, `requestUrl`, `TFile`, `Plugin` etc. |
| `esbuild` | Bundler | `esbuild.config.mjs` - bundles all deps into `main.js` |
| `typescript` | Type safety | TypeScript 4.7.4 |
| `fs-extra` | File operations | `src/tools/filesUtils.ts` |
| `yaml` | YAML parsing | Settings validation, field mapping config |
| `highlight.js` | Code highlighting | `src/tools/markdownHtml.ts` |
| `chokidar` | File watching | Localization compiler watch mode |
## Logging
- Location: `src/tools/debugLogging.ts:1-19`
- **IMPORTANT BUG**: Uses `process.env.NODE_ENV` which is always `undefined` in Obsidian (no Node.js runtime) - logging is **always on** in both dev and production
- Exports: `debugLog`, `debugWarn`, `debugError`
- Used in: `src/api/base.ts` for API request/response logging
- Prefix format: `[DEBUG]`, `[DEBUG WARNING]`, `[DEBUG ERROR]`
```typescript
import { debugLog, debugWarn, debugError } from './tools/debugLogging';
debugLog('Request:', { url, method });
debugWarn('Missing field:', fieldName);
debugError('Failed to fetch:', error);
```
## Cache system
- Maps Jira issue keys to local file paths
- In-memory cache: `issueKeyToFilePathCache` (Map in plugin instance)
- Persisted in settings: `settings.issueKeyToFilePathCache`
- Vault event listeners for maintenance (`main.ts:105-130`):
- `rename`: updates cache when file is moved
- `delete`: removes from cache when file is deleted
## Localization (i18n)
- Source files: `src/localization/source/{lang}/*.yaml`
- Compiled to: `src/localization/compiled/{lang}.json`
- Auto-detects locale from `window.localStorage.getItem('language')`
- Falls back to `en` if not found
- Build-time compilation: `src/localization/compiler.js`
## Pre-commit hooks
- Uses husky (`.husky/pre-commit`)
- Current check: `node check-version.js`
- `version-bump.mjs` - syncs version from `package.json` to `manifest.json` and `versions.json`
```bash
# Runs on every commit:
node check-version.js
```
- **Note**: Future pre-commit upgrades may include linting and type checking
## Manifest rules
- Must include:
- `id` (stable - never change after release)
- `name`
- `version` (Semantic Versioning x.y.z)
- `minAppVersion`
- `description`
- `isDesktopOnly` (boolean)
- Keep `minAppVersion` accurate when using newer APIs
## Testing
- Manual install for testing: copy `main.js`, `manifest.json`, `styles.css` to:
```
<Vault>/.obsidian/plugins/<plugin-id>/
```
- Reload Obsidian and enable in **Settings → Community plugins**
## Commands & settings
- Commands added via `this.addCommand(...)` in `src/commands/`
- Settings persisted with `this.loadData()` / `this.saveData()`
- Use stable command IDs - avoid renaming after release
- All commands wrapped in `register*Command` functions
## Versioning & releases
- Bump version in `manifest.json` (SemVer) and update `versions.json`
- Run `yarn version` to auto-bump via `version-bump.mjs`
- Create GitHub release with tag matching `manifest.json` version (no leading `v`)
- Attach: `manifest.json`, `main.js`, `styles.css` (if present)
## Security, privacy, and compliance
- Default to local/offline operation. Only make network requests when essential.
- No hidden telemetry.
- Never execute remote code, fetch and eval scripts.
- Minimize scope: read/write only what's necessary inside the vault.
- Use `register*` helpers for all listeners to ensure proper cleanup on unload.
## Performance
- Keep startup light - defer heavy work until needed
- Batch disk access, avoid excessive vault scans
- Debounce/throttle operations in response to file system events
## Coding conventions
- TypeScript with `"strict": true` preferred
- Keep `main.ts` minimal - delegate feature logic to separate modules
- Split large files (~200-300+ lines) into smaller focused modules
- Bundle everything into `main.js` (no unbundled runtime deps)
- Prefer `async/await` over promise chains
- Handle errors gracefully
- **Do not add comments unless explicitly requested**
## Agent do/don't
**Do**
- Add commands with stable IDs (don't rename after release)
- Provide defaults and validation in settings
- Write idempotent code paths
- Use `this.register*` helpers for cleanup
**Don't**
- Introduce network calls without user-facing reason and documentation
- Ship features requiring cloud services without opt-in
- Store or transmit vault contents unless essential
## Common tasks
### Add a command
```typescript
export function registerMyCommand(plugin: JiraPlugin): void {
plugin.addCommand({
id: 'my-command',
name: t('name'),
checkCallback: (checking: boolean) => {
const valid = validateSettings(plugin);
if (!checking && valid) doSomething(plugin);
return valid;
},
});
}
```
### Make API request
```typescript
import { baseRequest } from './api/base';
const issue = await baseRequest(plugin, 'GET', `/issue/${issueKey}`);
```
### Persist settings
```typescript
await this.saveData(this.settings);
```
### Register listeners safely
```typescript
this.registerEvent(
this.app.workspace.on('file-open', (f) => {
/* ... */
}),
);
this.registerDomEvent(window, 'resize', () => {
/* ... */
});
this.registerInterval(
window.setInterval(() => {
/* ... */
}, 1000),
);
```
## Troubleshooting
- Plugin doesn't load: ensure `main.js` and `manifest.json` at top level of plugin folder
- Build issues: run `yarn run dev` or `yarn run build` to compile
- Commands not appearing: verify `addCommand` runs after `onload` and IDs are unique
- Settings not persisting: ensure `loadData`/`saveData` are awaited
## References
- Obsidian plugin docs: https://docs.obsidian.md
- Plugin guidelines: https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines
- Style guide: https://help.obsidian.md/style-guide