trekoon 0.2.1 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,47 +19,58 @@ pick the right command with the fewest reads and mutations.
19
19
  - Preview replace before `--apply`.
20
20
  - Prefer `--ids` over `--all` for bulk updates.
21
21
  - Never edit `.trekoon/trekoon.db` directly.
22
+ - Treat `.trekoon` as shared repo-scoped operational state in git worktrees.
23
+ - Keep `.trekoon` gitignored; do not commit the SQLite DB as a recovery fix.
22
24
  - Never run `trekoon wipe --yes --toon` unless the user explicitly asks for it.
23
25
 
24
26
  ## Default agent loop
25
27
 
26
- Run this loop each session:
28
+ The primary loop is: **session → work → task done → repeat**.
27
29
 
28
- 1. Check sync baseline:
30
+ ### 1. Orient with a single call
29
31
 
30
- ```bash
31
- trekoon --toon sync status
32
- ```
32
+ ```bash
33
+ trekoon --toon session
34
+ ```
35
+
36
+ `session` replaces the old five-call bootstrap sequence
37
+ (init + sync status + task next + dep list + task show) with a single DB open.
38
+ It returns diagnostics, sync status, the full next-task tree with subtasks, blocker
39
+ list, and readiness counts in one envelope.
33
40
 
34
- If this returns `missing_branch_db` on a fresh branch or worktree, continue
35
- with local task selection and treat sync as unavailable for now.
41
+ Fail fast if the envelope reports `recoveryRequired`, a storage mismatch, or any
42
+ bootstrap error. In linked worktrees, `sharedStorageRoot` may differ from
43
+ `worktreeRoot`; that is expected because the repo shares one DB across checkouts.
36
44
 
37
- 2. Pick the next item deterministically:
45
+ ### 2. Claim work explicitly
46
+
47
+ ```bash
48
+ trekoon --toon task update <task-id> --status in_progress
49
+ ```
38
50
 
39
- ```bash
40
- trekoon --toon task next
41
- trekoon --toon task ready --limit 5
42
- ```
51
+ ### 3. Finish or report a block
43
52
 
44
- 3. Inspect dependencies or downstream impact when needed:
53
+ ```bash
54
+ trekoon --toon task done <task-id>
55
+ trekoon --toon task update <task-id> --append "Blocked by <reason>" --status blocked
56
+ ```
45
57
 
46
- ```bash
47
- trekoon --toon dep list <task-id>
48
- trekoon --toon dep reverse <task-or-subtask-id>
49
- ```
58
+ `task done` replaces the old three-call transition sequence
59
+ (mark done + get next + load deps + show task) with a single call that marks the
60
+ task done and returns the next ready candidate with its full tree and blockers.
50
61
 
51
- 4. Claim work explicitly:
62
+ Append a completion note before calling `task done` when useful:
52
63
 
53
- ```bash
54
- trekoon --toon task update <task-id> --status in_progress
55
- ```
64
+ ```bash
65
+ trekoon --toon task update <task-id> --append "Completed implementation and checks"
66
+ trekoon --toon task done <task-id>
67
+ ```
56
68
 
57
- 5. Finish or report a block with appended context:
69
+ ### 4. Repeat
58
70
 
59
- ```bash
60
- trekoon --toon task update <task-id> --append "Completed implementation and checks" --status done
61
- trekoon --toon task update <task-id> --append "Blocked by <reason>" --status blocked
62
- ```
71
+ Run `session` again at the start of each new session. After `task done`, the
72
+ returned next-task envelope is sufficient to continue; a fresh `session` call is
73
+ not required mid-loop unless you need updated diagnostics or sync status.
63
74
 
64
75
  Recommended statuses for consistent workflows: `todo`, `in_progress`, `done`.
65
76
 
@@ -69,7 +80,8 @@ Use the narrowest command that answers the question.
69
80
 
70
81
  | Need | Preferred command |
71
82
  |---|---|
72
- | Next task | `trekoon --toon task next` |
83
+ | Session startup (diagnostics + sync + next task) | `trekoon --toon session` |
84
+ | Next task only | `trekoon --toon task next` |
73
85
  | A few ready options | `trekoon --toon task ready --limit 5` |
74
86
  | Direct blockers for one task | `trekoon --toon dep list <task-id>` |
75
87
  | What this item unblocks | `trekoon --toon dep reverse <task-or-subtask-id>` |
@@ -97,6 +109,28 @@ creates unless only one record is needed.
97
109
  | Multiple dependency edges across existing IDs | `trekoon --toon dep add-many --dep ...` |
98
110
  | One record only | `epic create`, `task create`, or `subtask create` |
99
111
 
112
+ ### Compact spec escaping rules
113
+
114
+ Compact specs (pipe-delimited `--task`, `--subtask`, `--dep` values) use `\` as
115
+ the escape character. Only these sequences are valid:
116
+
117
+ | Sequence | Produces |
118
+ |---|---|
119
+ | `\|` | literal `|` (not a field separator) |
120
+ | `\\` | literal `\` |
121
+ | `\n` | newline |
122
+ | `\r` | carriage return |
123
+ | `\t` | tab |
124
+
125
+ Any other `\X` combination (e.g., `\!`, `\=`, `\$`) is rejected with
126
+ `Invalid escape sequence`. To avoid accidental escapes:
127
+
128
+ - Do not use `!=` or similar operators in description text; rephrase instead
129
+ (e.g., "null does not equal sourceBranch" instead of "null !== sourceBranch").
130
+ - If a literal backslash is needed, double it: `\\`.
131
+ - When using shell line continuations (`\` at end of line), ensure the next
132
+ line's first character is not one that forms an invalid escape with `\`.
133
+
100
134
  ### Critical temp-key rule
101
135
 
102
136
  - Use plain temp keys when declaring records in compact specs, for example
@@ -229,20 +263,35 @@ Guardrails:
229
263
 
230
264
  ## Setup and fallback
231
265
 
232
- If Trekoon is unavailable or state is missing:
266
+ If Trekoon is unavailable or storage diagnostics require repair:
233
267
 
234
268
  ```bash
235
269
  trekoon --toon init
270
+ trekoon --toon sync status
236
271
  trekoon --toon quickstart
237
- trekoon --help --toon
272
+ trekoon --toon help sync
238
273
  ```
239
274
 
240
- Use `quickstart` for the canonical execution loop. Use `--help --toon` when you
241
- need exact syntax.
275
+ Rules:
276
+
277
+ - Re-bootstrap first, then re-read diagnostics.
278
+ - Stop if `recoveryRequired` stays true or diagnostics report storage mismatch.
279
+ - Do not continue with task selection after missing shared storage or broken
280
+ bootstrap.
281
+ - Do not commit `.trekoon/trekoon.db`; remove the tracked DB and keep
282
+ `.trekoon` ignored instead.
283
+
284
+ Use `quickstart` for the canonical execution loop. Use help when you need exact
285
+ syntax.
242
286
 
243
287
  ## Sync reminders
244
288
 
245
- - Run `trekoon --toon sync status` at session start and before PR or merge.
289
+ Same-branch sync is a no-op: `sync pull --from main` while on `main` produces
290
+ zero conflicts and simply advances the cursor. `sync status` returns `behind=0`
291
+ on the source branch. No action is needed.
292
+
293
+ Cross-branch sync matters before merging a feature branch back:
294
+
246
295
  - Before merge, pull tracker events from the base branch:
247
296
 
248
297
  ```bash
@@ -257,5 +306,18 @@ need exact syntax.
257
306
  trekoon --toon sync resolve <conflict-id> --use ours
258
307
  ```
259
308
 
309
+ ## Worktree diagnostics and destructive scope
310
+
311
+ - Inspect machine-readable storage fields when debugging worktrees:
312
+ `storageMode`, `repoCommonDir`, `worktreeRoot`, `sharedStorageRoot`, and
313
+ `databaseFile`.
314
+ - `sharedStorageRoot` is the repo-scoped source of truth for `.trekoon` in git
315
+ worktrees.
316
+ - If `trekoon wipe --yes --toon` is explicitly requested, warn that it deletes
317
+ shared storage for the entire repository and every linked worktree.
318
+ - Wipe is destructive recovery only; it is never the right fix for a tracked DB
319
+ or gitignore mistake.
320
+
260
321
  Trekoon stores local state in `.trekoon/trekoon.db`. In git repos and
261
- worktrees, storage resolves from the repository root.
322
+ worktrees, storage resolves from the shared repository root rather than each
323
+ worktree independently.
package/README.md CHANGED
@@ -40,7 +40,7 @@ npm i -g trekoon
40
40
 
41
41
  1. Make issue tracking fast enough for daily terminal use.
42
42
  2. Make issue data deterministic and machine-readable for AI automation.
43
- 3. Keep branch/worktree-aware state so parallel execution can be coordinated safely.
43
+ 3. Keep one repo-scoped state store that every worktree can coordinate through safely.
44
44
  4. Stay minimal in code size while preserving robustness and clear boundaries.
45
45
 
46
46
  ## Command surface
@@ -49,7 +49,8 @@ npm i -g trekoon
49
49
  - `trekoon help [command]`
50
50
  - `trekoon quickstart`
51
51
  - `trekoon epic <create|expand|list|show|search|replace|update|delete>`
52
- - `trekoon task <create|create-many|list|show|ready|next|search|replace|update|delete>`
52
+ - `trekoon session`
53
+ - `trekoon task <create|create-many|list|show|ready|next|done|search|replace|update|delete>`
53
54
  - `trekoon subtask <create|create-many|list|search|replace|update|delete>`
54
55
  - `trekoon dep <add|add-many|remove|list|reverse>`
55
56
  - `trekoon events prune [--dry-run] [--archive] [--retention-days <n>]`
@@ -117,15 +118,23 @@ trekoon epic update --ids <epic-1>,<epic-2> --status done
117
118
 
118
119
  ## Quickstart
119
120
 
120
- Trekoon is local-first: in git repos/worktrees, Trekoon resolves state to one
121
- canonical repository root (`git rev-parse --show-toplevel`) so nested
122
- invocations share the same `.trekoon/trekoon.db`.
121
+ Trekoon is local-first, but in git repos and worktrees it is **repo-shared**:
122
+ every worktree for the same repository resolves to one shared `.trekoon`
123
+ directory and one shared `.trekoon/trekoon.db`.
124
+
125
+ - `worktreeRoot` identifies the current checkout.
126
+ - `sharedStorageRoot` identifies the repository root that owns `.trekoon`.
127
+ - `databaseFile` points at the shared SQLite database.
128
+ - `.trekoon` stays gitignored on purpose because the DB is operational state,
129
+ not source code.
130
+ - Committing `.trekoon/trekoon.db` is the wrong fix for drift because it bakes
131
+ machine-local state and stale snapshots into Git.
123
132
 
124
133
  Outside git repos, Trekoon falls back to the invocation cwd.
125
134
 
126
135
  When machine output is enabled (`--json`/`--toon`) and a command resolves
127
136
  storage from a non-canonical cwd, Trekoon emits
128
- `meta.storageRootDiagnostics` to make the divergence explicit for automation.
137
+ `meta.storageRootDiagnostics` so automation can verify the storage contract.
129
138
 
130
139
  ### 1) Initialize
131
140
 
@@ -134,6 +143,15 @@ trekoon init
134
143
  trekoon --version
135
144
  ```
136
145
 
146
+ Bootstrap expectations:
147
+
148
+ - Run `trekoon --toon init` once per repository to create or re-bootstrap the
149
+ shared storage root.
150
+ - Run `trekoon --toon sync status` before agent work to inspect diagnostics.
151
+ - If diagnostics report `recoveryRequired`, a tracked/ignored mismatch, or an
152
+ ambiguous recovery path, stop and repair setup before continuing.
153
+ - Do **not** continue with task selection after broken bootstrap warnings.
154
+
137
155
  ### 2) Create epic → task → subtask
138
156
 
139
157
  ```bash
@@ -366,23 +384,52 @@ When to choose which command:
366
384
 
367
385
  ### 4) AI execution loop for agents
368
386
 
369
- Run this loop each session to pick next work deterministically:
387
+ The primary loop is: **session work task done → repeat**.
388
+
389
+ Orient with a single call that returns diagnostics, sync status, next ready
390
+ task with subtasks, blocker list, and readiness counts:
391
+
392
+ ```bash
393
+ trekoon --toon session
394
+ ```
395
+
396
+ Claim work, then finish or report a block:
370
397
 
371
398
  ```bash
372
- trekoon --toon sync status
373
- trekoon --toon task ready --limit 5
374
- trekoon --toon task next
375
- trekoon --toon dep reverse <task-or-subtask-id>
376
399
  trekoon --toon task update <task-id> --status in_progress
400
+ trekoon --toon task done <task-id>
401
+ trekoon --toon task update <task-id> --append "Blocked by <reason>" --status blocked
377
402
  ```
378
403
 
379
- When done or blocked, append context and update final status:
404
+ `task done` marks the task done and returns the next ready task with
405
+ dependencies inline, replacing the old multi-step transition.
406
+
407
+ Fail-fast rules:
408
+
409
+ - Treat `meta.storageRootDiagnostics` as the source of truth for worktree
410
+ storage.
411
+ - In linked worktrees, `sharedStorageRoot` may differ from `worktreeRoot`; that
412
+ is expected.
413
+ - If `recoveryRequired` is `true`, stop and follow the reported bootstrap or
414
+ recovery action.
415
+ - Do not fall back to a separate per-worktree DB or continue after missing
416
+ shared storage.
417
+
418
+ <details>
419
+ <summary>Legacy manual bootstrap (use <code>session</code> instead)</summary>
380
420
 
381
421
  ```bash
422
+ trekoon --toon init
423
+ trekoon --toon sync status
424
+ trekoon --toon task ready --limit 5
425
+ trekoon --toon task next
426
+ trekoon --toon dep reverse <task-or-subtask-id>
427
+ trekoon --toon task update <task-id> --status in_progress
382
428
  trekoon --toon task update <task-id> --append "Completed implementation and checks" --status done
383
- trekoon --toon task update <task-id> --append "Blocked by <reason>" --status blocked
384
429
  ```
385
430
 
431
+ </details>
432
+
386
433
  ### 5) Use TOON output for agent workflows
387
434
 
388
435
  ```bash
@@ -501,6 +548,19 @@ react deterministically:
501
548
  - `diagnostics.conflictEvents`
502
549
  - `diagnostics.errorHints`
503
550
 
551
+ Worktree diagnostics and recovery:
552
+
553
+ - Inspect `storageMode`, `repoCommonDir`, `worktreeRoot`, `sharedStorageRoot`,
554
+ and `databaseFile` in machine output when debugging worktree behavior.
555
+ - If a worktree resolves shared storage outside its checkout, that is expected
556
+ for linked worktrees and should not be “fixed” by committing `.trekoon`.
557
+ - If Git contains a tracked `.trekoon/trekoon.db`, remove it from Git history or
558
+ the index as appropriate, keep `.trekoon` ignored, and re-run
559
+ `trekoon --toon init`.
560
+ - Use `trekoon wipe --yes` only for explicit destructive recovery; it deletes
561
+ the shared storage root for the entire repository, not just the current
562
+ worktree.
563
+
504
564
  Compatibility mode for legacy sync command IDs:
505
565
 
506
566
  ```bash
@@ -590,6 +650,7 @@ Trekoon does not mutate global editor config directories.
590
650
  - [ ] done tasks/subtasks are marked completed
591
651
  - [ ] dependency graph has no stale blockers
592
652
  - [ ] final AI check: `trekoon --toon epic show <epic-id>`
653
+ - [ ] no one tried to commit `.trekoon/trekoon.db` as a worktree fix
593
654
 
594
655
  ## Machine-contract recipes (--toon)
595
656
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trekoon",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "description": "AI-first local issue tracker CLI.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -18,15 +18,16 @@ const ROOT_HELP = [
18
18
  "",
19
19
  "Commands:",
20
20
  " help Show root or command help",
21
- " init Initialize .trekoon storage and local DB",
22
- " quickstart Show AI execution loop + task detail workflow",
23
- " wipe Remove local Trekoon state (requires --yes)",
21
+ " init Initialize repo-shared .trekoon storage and DB",
22
+ " quickstart Show shared-storage bootstrap + AI execution loop",
23
+ " wipe Remove repo-shared Trekoon state (requires --yes)",
24
24
  " epic Epic lifecycle commands",
25
25
  " task Task lifecycle commands",
26
26
  " subtask Subtask lifecycle commands",
27
27
  " dep Dependency graph commands",
28
28
  " events Event retention and cleanup commands",
29
29
  " migrate Migration status and rollback commands",
30
+ " session One-call agent orientation (diagnostics + sync + next task)",
30
31
  " sync Cross-branch sync commands",
31
32
  " skills Project-local skill install/update/link",
32
33
  ].join("\n");
@@ -35,7 +36,9 @@ const INIT_HELP = [
35
36
  "Usage: trekoon init [--json|--toon]",
36
37
  "",
37
38
  "Purpose:",
38
- " Initialize local Trekoon storage (.trekoon) and database.",
39
+ " Initialize repo-scoped Trekoon storage (.trekoon) and database.",
40
+ " In git worktrees, every worktree shares the same repository DB.",
41
+ " Keep .trekoon gitignored; committing the SQLite DB is not a recovery path.",
39
42
  "",
40
43
  "Examples:",
41
44
  " trekoon init",
@@ -46,14 +49,16 @@ const QUICKSTART_HELP = [
46
49
  "Usage: trekoon quickstart [--json|--toon]",
47
50
  "",
48
51
  "Purpose:",
49
- " Show the canonical Trekoon AI execution loop and task-detail workflow.",
52
+ " Show shared-storage bootstrap, diagnostics, and the canonical AI loop.",
50
53
  "",
51
54
  "Flow:",
52
- " 1) trekoon --toon sync status",
53
- " 2) trekoon --toon task ready --limit 5",
54
- " 3) trekoon --toon task next",
55
- " 4) trekoon --toon dep reverse <task-or-subtask-id>",
56
- " 5) trekoon --toon task update <task-id> --status in_progress",
55
+ " 1) trekoon --toon init",
56
+ " 2) trekoon --toon sync status",
57
+ " 3) Fail fast on recoveryRequired or tracked/ignored mismatch diagnostics",
58
+ " 4) trekoon --toon task ready --limit 5",
59
+ " 5) trekoon --toon task next",
60
+ " 6) trekoon --toon dep reverse <task-or-subtask-id>",
61
+ " 7) trekoon --toon task update <task-id> --status in_progress",
57
62
  "",
58
63
  "Examples:",
59
64
  " trekoon quickstart",
@@ -64,10 +69,15 @@ const WIPE_HELP = [
64
69
  "Usage: trekoon wipe --yes [--json|--toon]",
65
70
  "",
66
71
  "Purpose:",
67
- " Remove local Trekoon state for the current repository.",
72
+ " Remove the repository's shared Trekoon storage directory.",
73
+ " In git worktrees this erases the same .trekoon state for every linked worktree.",
68
74
  "",
69
75
  "Options:",
70
- " --yes Required safety confirmation.",
76
+ " --yes Required confirmation for destructive repo-wide removal.",
77
+ "",
78
+ "Recovery guidance:",
79
+ " Use wipe only for explicit destructive recovery.",
80
+ " Do not use wipe to fix gitignore mistakes or to replace bootstrap diagnostics.",
71
81
  "",
72
82
  "Examples:",
73
83
  " trekoon wipe --yes",
@@ -312,6 +322,28 @@ const SYNC_HELP = [
312
322
  " trekoon sync resolve <conflict-id> --use ours",
313
323
  ].join("\n");
314
324
 
325
+ const SESSION_HELP = [
326
+ "Usage: trekoon session [--json|--toon]",
327
+ "",
328
+ "Purpose:",
329
+ " One-call agent orientation. Opens DB once and returns:",
330
+ " - diagnostics: storageMode, recoveryRequired, recoveryStatus",
331
+ " - sync: ahead/behind counts and pendingConflicts vs main",
332
+ " - next: full task tree with subtasks for the top ready candidate (null if none)",
333
+ " - nextDeps: blocker list with statuses for the next task (empty if none)",
334
+ " - readiness: readyCount and blockedCount across all open tasks",
335
+ "",
336
+ "Output modes:",
337
+ " human Multi-section summary (default in TTY)",
338
+ " toon Compact pipe-encoded envelope",
339
+ " json Full structured JSON envelope",
340
+ "",
341
+ "Examples:",
342
+ " trekoon session",
343
+ " trekoon --toon session",
344
+ " trekoon --json session",
345
+ ].join("\n");
346
+
315
347
  const SKILLS_HELP = [
316
348
  "Usage:",
317
349
  " trekoon skills install [--link --editor opencode|claude|pi] [--to <path>] [--allow-outside-repo]",
@@ -331,7 +363,8 @@ const SKILLS_HELP = [
331
363
  "",
332
364
  "Update behavior:",
333
365
  " - Refreshes canonical SKILL file in the install path above.",
334
- " - Reports default link states for opencode/claude/pi.",
366
+ " - Auto-creates or refreshes editor symlinks when editor config dir exists.",
367
+ " - Skips editors with no config dir or conflicting paths.",
335
368
  "",
336
369
  "Examples:",
337
370
  " trekoon skills install",
@@ -344,6 +377,7 @@ const SKILLS_HELP = [
344
377
  const COMMAND_HELP: Record<string, string> = {
345
378
  init: INIT_HELP,
346
379
  quickstart: QUICKSTART_HELP,
380
+ session: SESSION_HELP,
347
381
  wipe: WIPE_HELP,
348
382
  epic: EPIC_HELP,
349
383
  task: TASK_HELP,
@@ -1,27 +1,125 @@
1
1
  import { unexpectedFailureResult } from "./error-utils";
2
2
 
3
- import { okResult } from "../io/output";
3
+ import { DomainError } from "../domain/types";
4
+ import { failResult, okResult } from "../io/output";
4
5
  import { type CliContext, type CliResult } from "../runtime/command-types";
5
6
  import { openTrekoonDatabase, type TrekoonDatabase } from "../storage/database";
6
7
 
8
+ function buildRecoverySummary(database: TrekoonDatabase): string[] {
9
+ const diagnostics = database.diagnostics;
10
+ const lines: string[] = [];
11
+
12
+ if (diagnostics.recoveryStatus === "no_legacy_state") {
13
+ lines.push("Recovery status: no legacy worktree-local state detected.");
14
+ return lines;
15
+ }
16
+
17
+ if (diagnostics.recoveryStatus === "safe_auto_migrate") {
18
+ if (diagnostics.autoMigratedLegacyState) {
19
+ lines.push("Recovery status: safe auto-migrate completed.");
20
+ lines.push(`Imported from: ${diagnostics.importedFromLegacyDatabase}`);
21
+ lines.push(`Backups created: ${diagnostics.backupFiles.join(", ")}`);
22
+ } else {
23
+ lines.push("Recovery status: legacy worktree-local state detected.");
24
+ lines.push("Shared storage already exists; no import was required.");
25
+ }
26
+
27
+ lines.push(`Operator action: ${diagnostics.operatorAction}`);
28
+ return lines;
29
+ }
30
+
31
+ lines.push(`Recovery status: ${diagnostics.recoveryStatus}`);
32
+ lines.push(`Operator action: ${diagnostics.operatorAction}`);
33
+ return lines;
34
+ }
35
+
36
+ function recoveryFailureResult(error: DomainError): CliResult | null {
37
+ if (error.code !== "ambiguous_legacy_state" && error.code !== "tracked_ignored_mismatch") {
38
+ return null;
39
+ }
40
+
41
+ const details = error.details ?? {};
42
+ const status = typeof details.status === "string" ? details.status : error.code;
43
+ const operatorAction = typeof details.operatorAction === "string" ? details.operatorAction : error.message;
44
+ const legacyDatabaseFiles = Array.isArray(details.legacyDatabaseFiles) ? details.legacyDatabaseFiles : [];
45
+ const trackedStorageFiles = Array.isArray(details.trackedStorageFiles) ? details.trackedStorageFiles : [];
46
+ const humanLines: string[] = [
47
+ "Trekoon init requires operator action.",
48
+ `Recovery status: ${status}`,
49
+ error.message,
50
+ `Operator action: ${operatorAction}`,
51
+ ];
52
+
53
+ if (legacyDatabaseFiles.length > 0) {
54
+ humanLines.push(`Legacy databases: ${legacyDatabaseFiles.join(", ")}`);
55
+ }
56
+
57
+ if (trackedStorageFiles.length > 0) {
58
+ humanLines.push(`Tracked storage files: ${trackedStorageFiles.join(", ")}`);
59
+ }
60
+
61
+ return failResult({
62
+ command: "init",
63
+ human: humanLines.join("\n"),
64
+ data: {
65
+ status,
66
+ legacyDatabaseFiles,
67
+ trackedStorageFiles,
68
+ operatorAction,
69
+ },
70
+ error: {
71
+ code: error.code,
72
+ message: error.message,
73
+ },
74
+ });
75
+ }
76
+
7
77
  export async function runInit(context: CliContext): Promise<CliResult> {
8
78
  let database: TrekoonDatabase | undefined;
9
79
 
10
80
  try {
11
81
  database = openTrekoonDatabase(context.cwd);
82
+ const diagnostics = database.diagnostics;
83
+ const humanLines: string[] = [
84
+ "Trekoon initialized.",
85
+ `Storage mode: ${diagnostics.storageMode}`,
86
+ `Worktree root: ${diagnostics.worktreeRoot}`,
87
+ `Shared storage root: ${diagnostics.sharedStorageRoot}`,
88
+ `Storage directory: ${database.paths.storageDir}`,
89
+ `Database file: ${database.paths.databaseFile}`,
90
+ ...buildRecoverySummary(database),
91
+ ];
92
+
12
93
  return okResult({
13
94
  command: "init",
14
- human: [
15
- "Trekoon initialized.",
16
- `Storage directory: ${database.paths.storageDir}`,
17
- `Database file: ${database.paths.databaseFile}`,
18
- ].join("\n"),
95
+ human: humanLines.join("\n"),
19
96
  data: {
97
+ invocationCwd: diagnostics.invocationCwd,
98
+ storageMode: diagnostics.storageMode,
99
+ repoCommonDir: diagnostics.repoCommonDir,
100
+ worktreeRoot: diagnostics.worktreeRoot,
101
+ sharedStorageRoot: diagnostics.sharedStorageRoot,
20
102
  storageDir: database.paths.storageDir,
21
103
  databaseFile: database.paths.databaseFile,
104
+ legacyStateDetected: diagnostics.legacyStateDetected,
105
+ recoveryRequired: diagnostics.recoveryRequired,
106
+ recoveryStatus: diagnostics.recoveryStatus,
107
+ legacyDatabaseFiles: diagnostics.legacyDatabaseFiles,
108
+ backupFiles: diagnostics.backupFiles,
109
+ trackedStorageFiles: diagnostics.trackedStorageFiles,
110
+ autoMigratedLegacyState: diagnostics.autoMigratedLegacyState,
111
+ importedFromLegacyDatabase: diagnostics.importedFromLegacyDatabase,
112
+ operatorAction: diagnostics.operatorAction,
22
113
  },
23
114
  });
24
115
  } catch (error: unknown) {
116
+ if (error instanceof DomainError) {
117
+ const recoveryFailure = recoveryFailureResult(error);
118
+ if (recoveryFailure !== null) {
119
+ return recoveryFailure;
120
+ }
121
+ }
122
+
25
123
  return unexpectedFailureResult(error, {
26
124
  command: "init",
27
125
  human: "Unexpected init command failure",