trekoon 0.2.0 → 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.
- package/.agents/skills/trekoon/SKILL.md +232 -297
- package/README.md +288 -16
- package/package.json +1 -1
- package/src/commands/arg-parser.ts +116 -0
- package/src/commands/dep.ts +197 -25
- package/src/commands/epic.ts +490 -28
- package/src/commands/error-utils.ts +111 -0
- package/src/commands/events.ts +23 -3
- package/src/commands/help.ts +83 -17
- package/src/commands/init.ts +115 -9
- package/src/commands/migrate.ts +11 -4
- package/src/commands/quickstart.ts +76 -30
- package/src/commands/session.ts +223 -0
- package/src/commands/skills.ts +100 -63
- package/src/commands/subtask.ts +224 -26
- package/src/commands/sync.ts +64 -17
- package/src/commands/task-readiness.ts +147 -0
- package/src/commands/task.ts +277 -168
- package/src/commands/wipe.ts +15 -5
- package/src/domain/mutation-service.ts +152 -0
- package/src/domain/tracker-domain.ts +503 -0
- package/src/domain/types.ts +80 -0
- package/src/runtime/cli-shell.ts +83 -5
- package/src/storage/database.ts +86 -0
- package/src/storage/migrations.ts +48 -0
- package/src/storage/path.ts +70 -21
- package/src/storage/schema.ts +9 -2
- package/src/storage/worktree-recovery.ts +376 -0
- package/src/sync/branch-db.ts +87 -35
- package/src/sync/git-context.ts +7 -2
- package/src/sync/service.ts +131 -95
- package/src/sync/types.ts +2 -0
package/src/commands/events.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { hasFlag, parseArgs, parseStrictPositiveInt, readMissingOptionValue, readOption } from "./arg-parser";
|
|
2
|
+
import { safeErrorMessage, sqliteBusyFailure } from "./error-utils";
|
|
2
3
|
|
|
3
4
|
import { failResult, okResult } from "../io/output";
|
|
4
5
|
import { type CliContext, type CliResult } from "../runtime/command-types";
|
|
5
|
-
import { openTrekoonDatabase } from "../storage/database";
|
|
6
|
+
import { openTrekoonDatabase, type TrekoonDatabase } from "../storage/database";
|
|
6
7
|
import { DEFAULT_EVENT_RETENTION_DAYS, pruneEvents } from "../storage/events-retention";
|
|
7
8
|
|
|
8
9
|
const EVENTS_USAGE = "Usage: trekoon events prune [--dry-run] [--archive] [--retention-days <n>]";
|
|
@@ -62,9 +63,10 @@ export async function runEvents(context: CliContext): Promise<CliResult> {
|
|
|
62
63
|
const retentionDays: number = parsedRetentionDays ?? DEFAULT_EVENT_RETENTION_DAYS;
|
|
63
64
|
const dryRun: boolean = hasFlag(parsed.flags, "dry-run");
|
|
64
65
|
const archive: boolean = hasFlag(parsed.flags, "archive");
|
|
65
|
-
|
|
66
|
+
let storage: TrekoonDatabase | undefined;
|
|
66
67
|
|
|
67
68
|
try {
|
|
69
|
+
storage = openTrekoonDatabase(context.cwd);
|
|
68
70
|
const summary = pruneEvents(storage.db, {
|
|
69
71
|
retentionDays,
|
|
70
72
|
dryRun,
|
|
@@ -82,7 +84,25 @@ export async function runEvents(context: CliContext): Promise<CliResult> {
|
|
|
82
84
|
].join("\n"),
|
|
83
85
|
data: summary,
|
|
84
86
|
});
|
|
87
|
+
} catch (error: unknown) {
|
|
88
|
+
const busyFailure = sqliteBusyFailure("events.prune", error);
|
|
89
|
+
if (busyFailure !== null) {
|
|
90
|
+
return busyFailure;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const message = safeErrorMessage(error, "Unknown events prune failure.");
|
|
94
|
+
return failResult({
|
|
95
|
+
command: "events.prune",
|
|
96
|
+
human: message,
|
|
97
|
+
data: {
|
|
98
|
+
reason: "events_failed",
|
|
99
|
+
},
|
|
100
|
+
error: {
|
|
101
|
+
code: "events_failed",
|
|
102
|
+
message,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
85
105
|
} finally {
|
|
86
|
-
storage
|
|
106
|
+
storage?.close();
|
|
87
107
|
}
|
|
88
108
|
}
|
package/src/commands/help.ts
CHANGED
|
@@ -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
|
|
22
|
-
" quickstart Show
|
|
23
|
-
" wipe Remove
|
|
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
|
|
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
|
|
52
|
+
" Show shared-storage bootstrap, diagnostics, and the canonical AI loop.",
|
|
50
53
|
"",
|
|
51
54
|
"Flow:",
|
|
52
|
-
" 1) trekoon --toon
|
|
53
|
-
" 2) trekoon --toon
|
|
54
|
-
" 3)
|
|
55
|
-
" 4) trekoon --toon
|
|
56
|
-
" 5) trekoon --toon task
|
|
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,17 +69,35 @@ const WIPE_HELP = [
|
|
|
64
69
|
"Usage: trekoon wipe --yes [--json|--toon]",
|
|
65
70
|
"",
|
|
66
71
|
"Purpose:",
|
|
67
|
-
" Remove
|
|
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
|
|
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",
|
|
74
84
|
].join("\n");
|
|
75
85
|
|
|
76
86
|
const EPIC_HELP = [
|
|
77
|
-
"Usage: trekoon epic <create|list|show|search|replace|update|delete> [options]",
|
|
87
|
+
"Usage: trekoon epic <create|expand|list|show|search|replace|update|delete> [options]",
|
|
88
|
+
"",
|
|
89
|
+
"Create behavior:",
|
|
90
|
+
" trekoon epic create --title \"...\" --description \"...\" [--status <status>]",
|
|
91
|
+
" trekoon epic create --title \"...\" --description \"...\" [--task <spec>] [--subtask <spec>] [--dep <spec>]",
|
|
92
|
+
" Preferred one-shot flow when the full tree is known up front.",
|
|
93
|
+
" Uses the same compact spec grammar as epic expand and returns mappings/counts.",
|
|
94
|
+
"",
|
|
95
|
+
"Expand behavior:",
|
|
96
|
+
" trekoon epic expand <epic-id> [--task <spec>] [--subtask <spec>] [--dep <spec>]",
|
|
97
|
+
" --task <temp-key>|<title>|<description>|<status>",
|
|
98
|
+
` --subtask <parent-ref>|<temp-key>|<title>|<description>|<status> (use ${"@"}<temp-key> for newly declared parents)`,
|
|
99
|
+
` --dep <source-ref>|<depends-on-ref> (refs can be ids or ${"@"}<temp-key>)`,
|
|
100
|
+
" Escapes inside compact specs: \\| for |, \\\\ for \\, \\n, \\r, \\t",
|
|
78
101
|
"",
|
|
79
102
|
"List behavior:",
|
|
80
103
|
" Defaults:",
|
|
@@ -115,7 +138,14 @@ const EPIC_HELP = [
|
|
|
115
138
|
].join("\n");
|
|
116
139
|
|
|
117
140
|
const TASK_HELP = [
|
|
118
|
-
"Usage: trekoon task <create|list|show|ready|next|search|replace|update|delete> [options]",
|
|
141
|
+
"Usage: trekoon task <create|create-many|list|show|ready|next|search|replace|update|delete> [options]",
|
|
142
|
+
"",
|
|
143
|
+
"Create-many behavior:",
|
|
144
|
+
" trekoon task create-many --epic <epic-id> --task <spec> [--task <spec> ...]",
|
|
145
|
+
" --task <temp-key>|<title>|<description>|<status>",
|
|
146
|
+
" Rejects unexpected positional arguments and empty required fields.",
|
|
147
|
+
" Repeated --task flags are applied in the order provided.",
|
|
148
|
+
" Escapes inside compact specs: \\| for |, \\\\ for \\, \\n, \\r, \\t",
|
|
119
149
|
"",
|
|
120
150
|
"List behavior:",
|
|
121
151
|
" Defaults:",
|
|
@@ -165,7 +195,15 @@ const TASK_HELP = [
|
|
|
165
195
|
].join("\n");
|
|
166
196
|
|
|
167
197
|
const SUBTASK_HELP = [
|
|
168
|
-
"Usage: trekoon subtask <create|list|search|replace|update|delete> [options]",
|
|
198
|
+
"Usage: trekoon subtask <create|create-many|list|search|replace|update|delete> [options]",
|
|
199
|
+
"",
|
|
200
|
+
"Create-many behavior:",
|
|
201
|
+
" trekoon subtask create-many [<task-id>] [--task <task-id>] --subtask <spec> [--subtask <spec> ...]",
|
|
202
|
+
" --subtask <temp-key>|<title>|<description>|<status>",
|
|
203
|
+
" Positional <task-id> and --task may be combined only when equal.",
|
|
204
|
+
" Rejects extra positional arguments and empty required fields.",
|
|
205
|
+
" Repeated --subtask flags are applied in the order provided.",
|
|
206
|
+
" Escapes inside compact specs: \\| for |, \\\\ for \\, \\n, \\r, \\t",
|
|
169
207
|
"",
|
|
170
208
|
"List behavior:",
|
|
171
209
|
" Defaults:",
|
|
@@ -197,11 +235,15 @@ const SUBTASK_HELP = [
|
|
|
197
235
|
].join("\n");
|
|
198
236
|
|
|
199
237
|
const DEP_HELP = [
|
|
200
|
-
"Usage: trekoon dep <add|remove|list|reverse> [options]",
|
|
238
|
+
"Usage: trekoon dep <add|add-many|remove|list|reverse> [options]",
|
|
201
239
|
"",
|
|
202
240
|
"Subcommands:",
|
|
203
241
|
" add <source-id> <depends-on-id>",
|
|
204
242
|
" Create dependency edge: source depends on depends-on.",
|
|
243
|
+
" add-many --dep <source-ref>|<depends-on-ref> [--dep <spec> ...]",
|
|
244
|
+
" Create validated dependency edges from compact specs in order.",
|
|
245
|
+
" Standalone add-many resolves persisted ids only; @<temp-key>",
|
|
246
|
+
" refs are reserved for higher-level compact batch workflows.",
|
|
205
247
|
" remove <source-id> <depends-on-id>",
|
|
206
248
|
" Remove one dependency edge if it exists.",
|
|
207
249
|
" list <source-id>",
|
|
@@ -280,6 +322,28 @@ const SYNC_HELP = [
|
|
|
280
322
|
" trekoon sync resolve <conflict-id> --use ours",
|
|
281
323
|
].join("\n");
|
|
282
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
|
+
|
|
283
347
|
const SKILLS_HELP = [
|
|
284
348
|
"Usage:",
|
|
285
349
|
" trekoon skills install [--link --editor opencode|claude|pi] [--to <path>] [--allow-outside-repo]",
|
|
@@ -299,7 +363,8 @@ const SKILLS_HELP = [
|
|
|
299
363
|
"",
|
|
300
364
|
"Update behavior:",
|
|
301
365
|
" - Refreshes canonical SKILL file in the install path above.",
|
|
302
|
-
" -
|
|
366
|
+
" - Auto-creates or refreshes editor symlinks when editor config dir exists.",
|
|
367
|
+
" - Skips editors with no config dir or conflicting paths.",
|
|
303
368
|
"",
|
|
304
369
|
"Examples:",
|
|
305
370
|
" trekoon skills install",
|
|
@@ -312,6 +377,7 @@ const SKILLS_HELP = [
|
|
|
312
377
|
const COMMAND_HELP: Record<string, string> = {
|
|
313
378
|
init: INIT_HELP,
|
|
314
379
|
quickstart: QUICKSTART_HELP,
|
|
380
|
+
session: SESSION_HELP,
|
|
315
381
|
wipe: WIPE_HELP,
|
|
316
382
|
epic: EPIC_HELP,
|
|
317
383
|
task: TASK_HELP,
|
package/src/commands/init.ts
CHANGED
|
@@ -1,24 +1,130 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { unexpectedFailureResult } from "./error-utils";
|
|
2
|
+
|
|
3
|
+
import { DomainError } from "../domain/types";
|
|
4
|
+
import { failResult, okResult } from "../io/output";
|
|
2
5
|
import { type CliContext, type CliResult } from "../runtime/command-types";
|
|
3
|
-
import { openTrekoonDatabase } from "../storage/database";
|
|
6
|
+
import { openTrekoonDatabase, type TrekoonDatabase } from "../storage/database";
|
|
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
|
+
}
|
|
4
76
|
|
|
5
77
|
export async function runInit(context: CliContext): Promise<CliResult> {
|
|
6
|
-
|
|
78
|
+
let database: TrekoonDatabase | undefined;
|
|
7
79
|
|
|
8
80
|
try {
|
|
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
|
+
|
|
9
93
|
return okResult({
|
|
10
94
|
command: "init",
|
|
11
|
-
human:
|
|
12
|
-
"Trekoon initialized.",
|
|
13
|
-
`Storage directory: ${database.paths.storageDir}`,
|
|
14
|
-
`Database file: ${database.paths.databaseFile}`,
|
|
15
|
-
].join("\n"),
|
|
95
|
+
human: humanLines.join("\n"),
|
|
16
96
|
data: {
|
|
97
|
+
invocationCwd: diagnostics.invocationCwd,
|
|
98
|
+
storageMode: diagnostics.storageMode,
|
|
99
|
+
repoCommonDir: diagnostics.repoCommonDir,
|
|
100
|
+
worktreeRoot: diagnostics.worktreeRoot,
|
|
101
|
+
sharedStorageRoot: diagnostics.sharedStorageRoot,
|
|
17
102
|
storageDir: database.paths.storageDir,
|
|
18
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,
|
|
19
113
|
},
|
|
20
114
|
});
|
|
115
|
+
} catch (error: unknown) {
|
|
116
|
+
if (error instanceof DomainError) {
|
|
117
|
+
const recoveryFailure = recoveryFailureResult(error);
|
|
118
|
+
if (recoveryFailure !== null) {
|
|
119
|
+
return recoveryFailure;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return unexpectedFailureResult(error, {
|
|
124
|
+
command: "init",
|
|
125
|
+
human: "Unexpected init command failure",
|
|
126
|
+
});
|
|
21
127
|
} finally {
|
|
22
|
-
database
|
|
128
|
+
database?.close();
|
|
23
129
|
}
|
|
24
130
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { parseArgs, readMissingOptionValue, readOption } from "./arg-parser";
|
|
2
|
+
import { safeErrorMessage, sqliteBusyFailure } from "./error-utils";
|
|
2
3
|
|
|
3
4
|
import { failResult, okResult } from "../io/output";
|
|
4
5
|
import { type CliContext, type CliResult } from "../runtime/command-types";
|
|
5
|
-
import { openTrekoonDatabase } from "../storage/database";
|
|
6
|
+
import { openTrekoonDatabase, type TrekoonDatabase } from "../storage/database";
|
|
6
7
|
import { describeMigrations, rollbackDatabase } from "../storage/migrations";
|
|
7
8
|
|
|
8
9
|
const MIGRATE_USAGE = "Usage: trekoon migrate <status|rollback> [--to-version <n>]";
|
|
@@ -54,9 +55,10 @@ export async function runMigrate(context: CliContext): Promise<CliResult> {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
let storage: TrekoonDatabase | undefined;
|
|
58
59
|
|
|
59
60
|
try {
|
|
61
|
+
storage = openTrekoonDatabase(context.cwd, { autoMigrate: false });
|
|
60
62
|
if (subcommand === "status") {
|
|
61
63
|
const status = describeMigrations(storage.db);
|
|
62
64
|
|
|
@@ -104,7 +106,12 @@ export async function runMigrate(context: CliContext): Promise<CliResult> {
|
|
|
104
106
|
|
|
105
107
|
return usage(`Unknown migrate subcommand '${subcommand}'.`);
|
|
106
108
|
} catch (error: unknown) {
|
|
107
|
-
const
|
|
109
|
+
const busyFailure = sqliteBusyFailure("migrate", error);
|
|
110
|
+
if (busyFailure !== null) {
|
|
111
|
+
return busyFailure;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const message = safeErrorMessage(error, "Unknown migration failure.");
|
|
108
115
|
|
|
109
116
|
return failResult({
|
|
110
117
|
command: "migrate",
|
|
@@ -118,6 +125,6 @@ export async function runMigrate(context: CliContext): Promise<CliResult> {
|
|
|
118
125
|
},
|
|
119
126
|
});
|
|
120
127
|
} finally {
|
|
121
|
-
storage
|
|
128
|
+
storage?.close();
|
|
122
129
|
}
|
|
123
130
|
}
|
|
@@ -7,28 +7,42 @@ const QUICKSTART_TEXT = [
|
|
|
7
7
|
"This quickstart is aligned with .agents/skills/trekoon/SKILL.md.",
|
|
8
8
|
"For agents: always use --toon for every command.",
|
|
9
9
|
"",
|
|
10
|
-
"1)
|
|
11
|
-
"-
|
|
12
|
-
"-
|
|
10
|
+
"1) Shared storage model",
|
|
11
|
+
"- In git repos and worktrees, Trekoon resolves one repo-scoped .trekoon directory.",
|
|
12
|
+
"- Every worktree for the same repo points at the same .trekoon/trekoon.db file.",
|
|
13
|
+
"- Keep .trekoon gitignored: the SQLite DB is live operational state, not source.",
|
|
14
|
+
"- Committing the DB is the wrong fix for setup drift because it snapshots machine-local state.",
|
|
13
15
|
"",
|
|
14
|
-
"2)
|
|
15
|
-
"-
|
|
16
|
-
"-
|
|
17
|
-
"-
|
|
18
|
-
"-
|
|
19
|
-
"-
|
|
20
|
-
"-
|
|
16
|
+
"2) Bootstrap and agent startup (primary)",
|
|
17
|
+
"- Single call: trekoon --toon session",
|
|
18
|
+
"- Replaces: init + sync status + task next + dep list + task show in one call.",
|
|
19
|
+
"- Returns diagnostics, next ready task, its dependencies, and full task payload.",
|
|
20
|
+
"- If diagnostics show recoveryRequired or a tracked/ignored mismatch, stop and repair setup.",
|
|
21
|
+
"- Do not continue after storage mismatch, ambiguous recovery, or broken bootstrap warnings.",
|
|
22
|
+
"- In worktrees, confirm meta.storageRootDiagnostics.sharedStorageRoot matches the repo root.",
|
|
23
|
+
"",
|
|
24
|
+
"2a) Bootstrap (manual/legacy — use session instead)",
|
|
25
|
+
"- 1. Initialize or verify shared storage: trekoon --toon init",
|
|
26
|
+
"- 2. Read machine diagnostics: trekoon --toon sync status",
|
|
27
|
+
"- 3. Select next task: trekoon --toon task next",
|
|
28
|
+
"- 4. Check dependencies: trekoon --toon dep list <task-id>",
|
|
29
|
+
"- 5. Show full task: trekoon --toon task show <task-id> --all",
|
|
21
30
|
"",
|
|
22
31
|
"3) AI execution loop (deterministic, dependency-aware)",
|
|
23
|
-
"- 1.
|
|
24
|
-
"- 2.
|
|
25
|
-
"- 3.
|
|
26
|
-
"-
|
|
27
|
-
"-
|
|
28
|
-
"-
|
|
29
|
-
"
|
|
32
|
+
"- 1. Start or resume session: trekoon --toon session",
|
|
33
|
+
"- 2. Claim work: trekoon --toon task update <task-id> --status in_progress",
|
|
34
|
+
"- 3. Complete with context: trekoon --toon task done <task-id> --append \"Completed implementation\"",
|
|
35
|
+
" - Replaces: update status done + task next + dep list + task show in one call.",
|
|
36
|
+
" - Returns next ready task, its dependencies, and full task payload.",
|
|
37
|
+
"- 4. Or report block: trekoon --toon task update <task-id> --append \"Blocked by <reason>\" --status blocked",
|
|
38
|
+
"",
|
|
39
|
+
"4) Worktree diagnostics and recovery",
|
|
40
|
+
"- Read machine fields when available: storageMode, repoCommonDir, worktreeRoot, sharedStorageRoot, databaseFile.",
|
|
41
|
+
"- sharedStorageRoot differs from worktreeRoot in linked worktrees; that is expected and should be visible.",
|
|
42
|
+
"- If recoveryRequired is true, run trekoon --toon init and follow the reported recovery action before more commands.",
|
|
43
|
+
"- If tracked and ignored storage disagree, delete the bad fix in Git and re-bootstrap local storage instead.",
|
|
30
44
|
"",
|
|
31
|
-
"
|
|
45
|
+
"5) Power-user command patterns (aligned with skill)",
|
|
32
46
|
"- Inspect full epic tree: trekoon --toon epic show <epic-id> --all",
|
|
33
47
|
"- Inspect full task payload: trekoon --toon task show <task-id> --all",
|
|
34
48
|
"- Check direct dependencies before starting: trekoon --toon dep list <task-id>",
|
|
@@ -37,7 +51,7 @@ const QUICKSTART_TEXT = [
|
|
|
37
51
|
"- Paginate deterministically: trekoon --toon task list --cursor <n>",
|
|
38
52
|
"- Bulk append/status update: trekoon --toon task update --ids id1,id2 --append \"...\" --status in_progress",
|
|
39
53
|
"",
|
|
40
|
-
"
|
|
54
|
+
"6) Task details and description",
|
|
41
55
|
"- Human list and show views default to table format.",
|
|
42
56
|
"- Alternate list view: add --view compact.",
|
|
43
57
|
"- task/epic/subtask list defaults: open work only (in_progress/in-progress, todo), max 10.",
|
|
@@ -53,14 +67,21 @@ const QUICKSTART_TEXT = [
|
|
|
53
67
|
"- Full task payload (including description): trekoon --toon task show <task-id> --all",
|
|
54
68
|
"- Optional integration format: trekoon --json task show <task-id> --all",
|
|
55
69
|
"",
|
|
56
|
-
"
|
|
70
|
+
"7) Pre-merge sync flow",
|
|
57
71
|
"- Run: trekoon --toon sync status",
|
|
58
72
|
"- Pull upstream tracker events: trekoon --toon sync pull --from main",
|
|
59
73
|
"- Resolve conflicts if needed: trekoon --toon sync resolve <id> --use ours",
|
|
60
74
|
"- Run sync status again before opening or merging a PR.",
|
|
61
75
|
"",
|
|
62
|
-
"
|
|
76
|
+
"8) Shared-storage wipe warning",
|
|
77
|
+
"- trekoon wipe --yes removes the shared repo-scoped .trekoon directory for every worktree in the repo.",
|
|
78
|
+
"- Treat wipe as destructive recovery, not routine cleanup.",
|
|
79
|
+
"- Never use wipe as a substitute for sync, bootstrap, or gitignore fixes.",
|
|
80
|
+
"",
|
|
81
|
+
"9) Machine output examples",
|
|
63
82
|
"- trekoon --toon quickstart",
|
|
83
|
+
"- trekoon --toon session",
|
|
84
|
+
"- trekoon --toon task done <task-id> --append \"Completed implementation\"",
|
|
64
85
|
"- trekoon --toon task show <task-id> --all",
|
|
65
86
|
"- trekoon --toon epic show <epic-id> --all",
|
|
66
87
|
"- trekoon --toon sync status",
|
|
@@ -77,17 +98,24 @@ export async function runQuickstart(_: CliContext): Promise<CliResult> {
|
|
|
77
98
|
localModel: {
|
|
78
99
|
storageDir: ".trekoon",
|
|
79
100
|
databaseFile: ".trekoon/trekoon.db",
|
|
101
|
+
storageScope: "repo-shared-across-worktrees",
|
|
102
|
+
gitPolicy: "gitignored-operational-state",
|
|
80
103
|
mergeBehavior: "manual-sync",
|
|
81
104
|
},
|
|
82
105
|
alignedSkill: ".agents/skills/trekoon/SKILL.md",
|
|
83
106
|
requiresToonForAgents: true,
|
|
84
|
-
|
|
107
|
+
bootstrapChecklist: [
|
|
108
|
+
"trekoon --toon session",
|
|
109
|
+
"Replaces: init + sync status + task next + dep list + task show in one call",
|
|
110
|
+
"Fail fast on recoveryRequired or tracked/ignored mismatch diagnostics",
|
|
111
|
+
"Confirm meta.storageRootDiagnostics.sharedStorageRoot matches the repo root",
|
|
112
|
+
],
|
|
113
|
+
bootstrapLegacy: [
|
|
85
114
|
"trekoon --toon init",
|
|
86
115
|
"trekoon --toon sync status",
|
|
87
|
-
"trekoon --toon
|
|
88
|
-
"trekoon --toon
|
|
89
|
-
"trekoon --toon task
|
|
90
|
-
"trekoon --toon dep reverse <task-or-subtask-id>",
|
|
116
|
+
"trekoon --toon task next",
|
|
117
|
+
"trekoon --toon dep list <task-id>",
|
|
118
|
+
"trekoon --toon task show <task-id> --all",
|
|
91
119
|
],
|
|
92
120
|
preMergeFlow: [
|
|
93
121
|
"trekoon --toon sync status",
|
|
@@ -96,11 +124,22 @@ export async function runQuickstart(_: CliContext): Promise<CliResult> {
|
|
|
96
124
|
"trekoon --toon sync status",
|
|
97
125
|
],
|
|
98
126
|
executionLoop: [
|
|
99
|
-
"trekoon --toon
|
|
100
|
-
"trekoon --toon task ready --limit 5",
|
|
101
|
-
"trekoon --toon task next",
|
|
102
|
-
"trekoon --toon dep reverse <task-or-subtask-id>",
|
|
127
|
+
"trekoon --toon session",
|
|
103
128
|
"trekoon --toon task update <task-id> --status in_progress",
|
|
129
|
+
"trekoon --toon task done <task-id> --append \"Completed implementation\"",
|
|
130
|
+
],
|
|
131
|
+
diagnostics: [
|
|
132
|
+
"storageMode",
|
|
133
|
+
"repoCommonDir",
|
|
134
|
+
"worktreeRoot",
|
|
135
|
+
"sharedStorageRoot",
|
|
136
|
+
"databaseFile",
|
|
137
|
+
"recoveryRequired",
|
|
138
|
+
],
|
|
139
|
+
recoveryGuidance: [
|
|
140
|
+
"Run trekoon --toon init to bootstrap or re-bootstrap shared storage",
|
|
141
|
+
"Stop when diagnostics report tracked/ignored mismatch or ambiguous recovery",
|
|
142
|
+
"Do not commit .trekoon/trekoon.db; remove the tracked DB and keep .trekoon ignored",
|
|
104
143
|
],
|
|
105
144
|
powerUserCommands: [
|
|
106
145
|
"trekoon --toon epic show <epic-id> --all",
|
|
@@ -113,6 +152,8 @@ export async function runQuickstart(_: CliContext): Promise<CliResult> {
|
|
|
113
152
|
],
|
|
114
153
|
machineExamples: [
|
|
115
154
|
"trekoon --toon quickstart",
|
|
155
|
+
"trekoon --toon session",
|
|
156
|
+
"trekoon --toon task done <task-id> --append \"Completed implementation\"",
|
|
116
157
|
"trekoon --toon task show <task-id> --all",
|
|
117
158
|
"trekoon --toon epic show <epic-id> --all",
|
|
118
159
|
"trekoon --toon sync status",
|
|
@@ -120,6 +161,11 @@ export async function runQuickstart(_: CliContext): Promise<CliResult> {
|
|
|
120
161
|
"trekoon --toon task next",
|
|
121
162
|
"trekoon --toon dep reverse <task-or-subtask-id>",
|
|
122
163
|
],
|
|
164
|
+
wipeWarning: {
|
|
165
|
+
command: "trekoon wipe --yes",
|
|
166
|
+
scope: "repo-wide shared storage",
|
|
167
|
+
destructive: true,
|
|
168
|
+
},
|
|
123
169
|
},
|
|
124
170
|
});
|
|
125
171
|
}
|