trekoon 0.1.7 → 0.1.9
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 +81 -15
- package/README.md +181 -21
- package/package.json +1 -1
- package/src/commands/arg-parser.ts +95 -0
- package/src/commands/dep.ts +20 -1
- package/src/commands/epic.ts +141 -7
- package/src/commands/help.ts +266 -17
- package/src/commands/quickstart.ts +88 -24
- package/src/commands/subtask.ts +98 -6
- package/src/commands/sync.ts +130 -52
- package/src/commands/task.ts +369 -7
- package/src/domain/tracker-domain.ts +113 -7
- package/src/domain/types.ts +7 -0
- package/src/index.ts +1 -1
- package/src/io/output.ts +98 -5
- package/src/runtime/cli-shell.ts +160 -24
- package/src/runtime/command-types.ts +18 -0
- package/src/runtime/version.ts +20 -0
- package/src/storage/path.ts +58 -1
package/src/commands/epic.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasFlag,
|
|
3
|
+
parseArgs,
|
|
4
|
+
parseStrictNonNegativeInt,
|
|
5
|
+
parseStrictPositiveInt,
|
|
6
|
+
readEnumOption,
|
|
7
|
+
readMissingOptionValue,
|
|
8
|
+
readOption,
|
|
9
|
+
} from "./arg-parser";
|
|
2
10
|
|
|
3
11
|
import { MutationService } from "../domain/mutation-service";
|
|
4
12
|
import { TrackerDomain } from "../domain/tracker-domain";
|
|
@@ -41,21 +49,58 @@ function getStatusPriority(status: string): number {
|
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
function sortByStatusPriority(epics: readonly EpicRecord[]): EpicRecord[] {
|
|
44
|
-
return [...epics].sort((left, right) =>
|
|
52
|
+
return [...epics].sort((left, right) => {
|
|
53
|
+
const byStatus = getStatusPriority(left.status) - getStatusPriority(right.status);
|
|
54
|
+
if (byStatus !== 0) {
|
|
55
|
+
return byStatus;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const byCreatedAt = left.createdAt - right.createdAt;
|
|
59
|
+
if (byCreatedAt !== 0) {
|
|
60
|
+
return byCreatedAt;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return left.id.localeCompare(right.id);
|
|
64
|
+
});
|
|
45
65
|
}
|
|
46
66
|
|
|
47
|
-
|
|
48
|
-
|
|
67
|
+
interface PaginationMeta {
|
|
68
|
+
readonly hasMore: boolean;
|
|
69
|
+
readonly nextCursor: string | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function filterSortAndLimitEpics(epics: readonly EpicRecord[], options: {
|
|
73
|
+
includeAll: boolean;
|
|
74
|
+
statuses: readonly string[] | undefined;
|
|
75
|
+
limit: number | undefined;
|
|
76
|
+
cursor: number;
|
|
77
|
+
}): { epics: EpicRecord[]; pagination: PaginationMeta } {
|
|
78
|
+
const { includeAll, statuses, limit, cursor } = options;
|
|
49
79
|
const selectedStatuses = includeAll ? undefined : (statuses ?? DEFAULT_OPEN_STATUSES);
|
|
50
80
|
const selectedEpics = selectedStatuses === undefined ? [...epics] : epics.filter((epic) => selectedStatuses.includes(epic.status));
|
|
51
81
|
const sortedEpics = sortByStatusPriority(selectedEpics);
|
|
52
82
|
|
|
53
83
|
if (includeAll) {
|
|
54
|
-
return
|
|
84
|
+
return {
|
|
85
|
+
epics: sortedEpics,
|
|
86
|
+
pagination: {
|
|
87
|
+
hasMore: false,
|
|
88
|
+
nextCursor: null,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
55
91
|
}
|
|
56
92
|
|
|
57
93
|
const effectiveLimit = limit ?? DEFAULT_LIST_LIMIT;
|
|
58
|
-
|
|
94
|
+
const pagedEpics = sortedEpics.slice(cursor, cursor + effectiveLimit);
|
|
95
|
+
const nextIndex = cursor + pagedEpics.length;
|
|
96
|
+
const hasMore = nextIndex < sortedEpics.length;
|
|
97
|
+
return {
|
|
98
|
+
epics: pagedEpics,
|
|
99
|
+
pagination: {
|
|
100
|
+
hasMore,
|
|
101
|
+
nextCursor: hasMore ? `${nextIndex}` : null,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
59
104
|
}
|
|
60
105
|
|
|
61
106
|
function invalidEpicListInput(human: string, message: string, data: Record<string, unknown>): CliResult {
|
|
@@ -266,6 +311,7 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
266
311
|
const missingListOption =
|
|
267
312
|
readMissingOptionValue(parsed.missingOptionValues, "status", "s") ??
|
|
268
313
|
readMissingOptionValue(parsed.missingOptionValues, "limit", "l") ??
|
|
314
|
+
readMissingOptionValue(parsed.missingOptionValues, "cursor") ??
|
|
269
315
|
readMissingOptionValue(parsed.missingOptionValues, "view");
|
|
270
316
|
if (missingListOption !== undefined) {
|
|
271
317
|
return failMissingOptionValue("epic.list", missingListOption);
|
|
@@ -274,6 +320,7 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
274
320
|
const includeAll: boolean = hasFlag(parsed.flags, "all");
|
|
275
321
|
const rawStatuses: string | undefined = readOption(parsed.options, "status");
|
|
276
322
|
const rawLimit: string | undefined = readOption(parsed.options, "limit");
|
|
323
|
+
const rawCursor: string | undefined = readOption(parsed.options, "cursor");
|
|
277
324
|
const rawView: string | undefined = readOption(parsed.options, "view");
|
|
278
325
|
const view = readEnumOption(parsed.options, VIEW_MODES, "view");
|
|
279
326
|
if (rawView !== undefined && view === undefined) {
|
|
@@ -320,11 +367,28 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
320
367
|
});
|
|
321
368
|
}
|
|
322
369
|
|
|
323
|
-
const
|
|
370
|
+
const cursor = parseStrictNonNegativeInt(rawCursor) ?? 0;
|
|
371
|
+
if (Number.isNaN(cursor)) {
|
|
372
|
+
return invalidEpicListInput("Invalid --cursor value. Use an integer >= 0.", "Invalid --cursor value", {
|
|
373
|
+
code: "invalid_input",
|
|
374
|
+
cursor: rawCursor,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (includeAll && rawCursor !== undefined) {
|
|
379
|
+
return invalidEpicListInput("Use either --all or --cursor, not both.", "--all and --cursor are mutually exclusive", {
|
|
380
|
+
code: "invalid_input",
|
|
381
|
+
flags: ["all", "cursor"],
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const listed = filterSortAndLimitEpics(domain.listEpics(), {
|
|
324
386
|
includeAll,
|
|
325
387
|
statuses,
|
|
326
388
|
limit,
|
|
389
|
+
cursor,
|
|
327
390
|
});
|
|
391
|
+
const epics = listed.epics;
|
|
328
392
|
const listView = view ?? "table";
|
|
329
393
|
const human = epics.length === 0 ? "No epics found." : listView === "compact" ? epics.map(formatEpic).join("\n") : formatEpicListTable(epics);
|
|
330
394
|
|
|
@@ -332,6 +396,28 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
332
396
|
command: "epic.list",
|
|
333
397
|
human,
|
|
334
398
|
data: { epics },
|
|
399
|
+
...(context.mode === "human"
|
|
400
|
+
? {}
|
|
401
|
+
: {
|
|
402
|
+
meta: {
|
|
403
|
+
pagination: listed.pagination,
|
|
404
|
+
defaults: {
|
|
405
|
+
statuses: !includeAll && statuses === undefined ? [...DEFAULT_OPEN_STATUSES] : null,
|
|
406
|
+
limit: !includeAll && limit === undefined ? DEFAULT_LIST_LIMIT : null,
|
|
407
|
+
cursor: rawCursor === undefined ? 0 : null,
|
|
408
|
+
view: view === undefined ? "table" : null,
|
|
409
|
+
},
|
|
410
|
+
filters: {
|
|
411
|
+
statuses: includeAll ? null : (statuses ?? [...DEFAULT_OPEN_STATUSES]),
|
|
412
|
+
includeAll,
|
|
413
|
+
},
|
|
414
|
+
truncation: {
|
|
415
|
+
applied: listed.pagination.hasMore,
|
|
416
|
+
returned: epics.length,
|
|
417
|
+
limit: includeAll ? null : (limit ?? DEFAULT_LIST_LIMIT),
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
}),
|
|
335
421
|
});
|
|
336
422
|
}
|
|
337
423
|
case "show": {
|
|
@@ -365,6 +451,22 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
365
451
|
command: "epic.show",
|
|
366
452
|
human: formatEpic(epic),
|
|
367
453
|
data: { epic, includeAll: false },
|
|
454
|
+
...(context.mode === "human"
|
|
455
|
+
? {}
|
|
456
|
+
: {
|
|
457
|
+
meta: {
|
|
458
|
+
defaults: {
|
|
459
|
+
view: view === undefined ? effectiveView : null,
|
|
460
|
+
},
|
|
461
|
+
filters: {
|
|
462
|
+
includeAll: false,
|
|
463
|
+
},
|
|
464
|
+
truncation: {
|
|
465
|
+
applied: true,
|
|
466
|
+
scope: "compact",
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
}),
|
|
368
470
|
});
|
|
369
471
|
}
|
|
370
472
|
|
|
@@ -375,6 +477,22 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
375
477
|
command: "epic.show",
|
|
376
478
|
human: formatEpicShowCompact(tree),
|
|
377
479
|
data: { tree, includeAll: false },
|
|
480
|
+
...(context.mode === "human"
|
|
481
|
+
? {}
|
|
482
|
+
: {
|
|
483
|
+
meta: {
|
|
484
|
+
defaults: {
|
|
485
|
+
view: view === undefined ? effectiveView : null,
|
|
486
|
+
},
|
|
487
|
+
filters: {
|
|
488
|
+
includeAll: false,
|
|
489
|
+
},
|
|
490
|
+
truncation: {
|
|
491
|
+
applied: true,
|
|
492
|
+
scope: "tree",
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
}),
|
|
378
496
|
});
|
|
379
497
|
}
|
|
380
498
|
|
|
@@ -384,6 +502,22 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
384
502
|
command: "epic.show",
|
|
385
503
|
human: effectiveView === "table" ? formatEpicShowTable(tree) : formatEpicShowDetailed(tree),
|
|
386
504
|
data: { tree, includeAll: true },
|
|
505
|
+
...(context.mode === "human"
|
|
506
|
+
? {}
|
|
507
|
+
: {
|
|
508
|
+
meta: {
|
|
509
|
+
defaults: {
|
|
510
|
+
view: view === undefined ? effectiveView : null,
|
|
511
|
+
},
|
|
512
|
+
filters: {
|
|
513
|
+
includeAll: true,
|
|
514
|
+
},
|
|
515
|
+
truncation: {
|
|
516
|
+
applied: false,
|
|
517
|
+
scope: "full",
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
}),
|
|
387
521
|
});
|
|
388
522
|
}
|
|
389
523
|
case "update": {
|
package/src/commands/help.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { okResult } from "../io/output";
|
|
2
2
|
import { type CliContext, type CliResult } from "../runtime/command-types";
|
|
3
|
+
import { CLI_VERSION } from "../runtime/version";
|
|
3
4
|
|
|
4
5
|
const ROOT_HELP = [
|
|
5
6
|
"Trekoon - AI-first local issue tracker",
|
|
7
|
+
`Version: ${CLI_VERSION}`,
|
|
6
8
|
"",
|
|
7
9
|
"Usage:",
|
|
8
10
|
" trekoon [global-options] <command> [command-options]",
|
|
@@ -10,12 +12,14 @@ const ROOT_HELP = [
|
|
|
10
12
|
"Global options:",
|
|
11
13
|
" --json Emit stable JSON machine output",
|
|
12
14
|
" --toon Emit true TOON-encoded output",
|
|
15
|
+
" --compat <mode> Enable explicit machine compatibility mode",
|
|
13
16
|
" --help Show root or command help",
|
|
14
17
|
" --version Print CLI version",
|
|
15
18
|
"",
|
|
16
19
|
"Commands:",
|
|
20
|
+
" help Show root or command help",
|
|
17
21
|
" init Initialize .trekoon storage and local DB",
|
|
18
|
-
" quickstart Show
|
|
22
|
+
" quickstart Show AI execution loop + task detail workflow",
|
|
19
23
|
" wipe Remove local Trekoon state (requires --yes)",
|
|
20
24
|
" epic Epic lifecycle commands",
|
|
21
25
|
" task Task lifecycle commands",
|
|
@@ -24,25 +28,269 @@ const ROOT_HELP = [
|
|
|
24
28
|
" events Event retention and cleanup commands",
|
|
25
29
|
" migrate Migration status and rollback commands",
|
|
26
30
|
" sync Cross-branch sync commands",
|
|
27
|
-
" skills Project-local skill install/link
|
|
31
|
+
" skills Project-local skill install/update/link",
|
|
32
|
+
].join("\n");
|
|
33
|
+
|
|
34
|
+
const INIT_HELP = [
|
|
35
|
+
"Usage: trekoon init [--json|--toon]",
|
|
36
|
+
"",
|
|
37
|
+
"Purpose:",
|
|
38
|
+
" Initialize local Trekoon storage (.trekoon) and database.",
|
|
39
|
+
"",
|
|
40
|
+
"Examples:",
|
|
41
|
+
" trekoon init",
|
|
42
|
+
" trekoon --json init",
|
|
43
|
+
].join("\n");
|
|
44
|
+
|
|
45
|
+
const QUICKSTART_HELP = [
|
|
46
|
+
"Usage: trekoon quickstart [--json|--toon]",
|
|
47
|
+
"",
|
|
48
|
+
"Purpose:",
|
|
49
|
+
" Show the canonical Trekoon AI execution loop and task-detail workflow.",
|
|
50
|
+
"",
|
|
51
|
+
"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",
|
|
57
|
+
"",
|
|
58
|
+
"Examples:",
|
|
59
|
+
" trekoon quickstart",
|
|
60
|
+
" trekoon --toon quickstart",
|
|
61
|
+
].join("\n");
|
|
62
|
+
|
|
63
|
+
const WIPE_HELP = [
|
|
64
|
+
"Usage: trekoon wipe --yes [--json|--toon]",
|
|
65
|
+
"",
|
|
66
|
+
"Purpose:",
|
|
67
|
+
" Remove local Trekoon state for the current repository.",
|
|
68
|
+
"",
|
|
69
|
+
"Options:",
|
|
70
|
+
" --yes Required safety confirmation.",
|
|
71
|
+
"",
|
|
72
|
+
"Examples:",
|
|
73
|
+
" trekoon wipe --yes",
|
|
74
|
+
].join("\n");
|
|
75
|
+
|
|
76
|
+
const EPIC_HELP = [
|
|
77
|
+
"Usage: trekoon epic <create|list|show|update|delete> [options]",
|
|
78
|
+
"",
|
|
79
|
+
"List behavior:",
|
|
80
|
+
" Defaults:",
|
|
81
|
+
" - Open statuses only: in_progress, in-progress, todo",
|
|
82
|
+
" - Limit: 10",
|
|
83
|
+
" Flags:",
|
|
84
|
+
" --status <csv> | --limit <n> | --cursor <n> | --all | --view table|compact",
|
|
85
|
+
" Pagination:",
|
|
86
|
+
" - --cursor is offset-like",
|
|
87
|
+
" - Machine modes expose meta.pagination.hasMore / nextCursor",
|
|
88
|
+
" Constraints:",
|
|
89
|
+
" - --all is mutually exclusive with --status, --limit, and --cursor",
|
|
90
|
+
"",
|
|
91
|
+
"Show behavior:",
|
|
92
|
+
" Views:",
|
|
93
|
+
" - table: default view",
|
|
94
|
+
" - compact: epic summary",
|
|
95
|
+
" - tree: hierarchy",
|
|
96
|
+
" - detail: descriptions",
|
|
97
|
+
" Machine default:",
|
|
98
|
+
" - With --all, machine modes default to detail",
|
|
99
|
+
"",
|
|
100
|
+
"Update behavior:",
|
|
101
|
+
" Bulk target flags:",
|
|
102
|
+
" --all | --ids <csv>",
|
|
103
|
+
" Bulk fields:",
|
|
104
|
+
" --append <text> and/or --status <status>",
|
|
105
|
+
].join("\n");
|
|
106
|
+
|
|
107
|
+
const TASK_HELP = [
|
|
108
|
+
"Usage: trekoon task <create|list|show|ready|next|update|delete> [options]",
|
|
109
|
+
"",
|
|
110
|
+
"List behavior:",
|
|
111
|
+
" Defaults:",
|
|
112
|
+
" - Open statuses only: in_progress, in-progress, todo",
|
|
113
|
+
" - Limit: 10",
|
|
114
|
+
" Flags:",
|
|
115
|
+
" --epic <id> | --status <csv> | --limit <n> | --cursor <n> | --all | --view table|compact",
|
|
116
|
+
" Pagination:",
|
|
117
|
+
" - --cursor is offset-like",
|
|
118
|
+
" - Machine modes expose meta.pagination.hasMore / nextCursor",
|
|
119
|
+
" Constraints:",
|
|
120
|
+
" - --all is mutually exclusive with --status, --limit, and --cursor",
|
|
121
|
+
"",
|
|
122
|
+
"Show behavior:",
|
|
123
|
+
" Views:",
|
|
124
|
+
" - table: default view",
|
|
125
|
+
" - compact: task summary",
|
|
126
|
+
" - tree: hierarchy",
|
|
127
|
+
" - detail: descriptions",
|
|
128
|
+
" Machine default:",
|
|
129
|
+
" - With --all, machine modes default to detail",
|
|
130
|
+
"",
|
|
131
|
+
"Ready/Next behavior:",
|
|
132
|
+
" ready:",
|
|
133
|
+
" - Returns deterministic unblocked candidates",
|
|
134
|
+
" - Sort order: status, blockers, createdAt, id",
|
|
135
|
+
" - Options: --limit <n>, --epic <id>",
|
|
136
|
+
" next:",
|
|
137
|
+
" - Returns top ready candidate",
|
|
138
|
+
" - Option: --epic <id>",
|
|
139
|
+
"",
|
|
140
|
+
"Update behavior:",
|
|
141
|
+
" Bulk target flags:",
|
|
142
|
+
" --all | --ids <csv>",
|
|
143
|
+
" Bulk fields:",
|
|
144
|
+
" --append <text> and/or --status <status>",
|
|
145
|
+
].join("\n");
|
|
146
|
+
|
|
147
|
+
const SUBTASK_HELP = [
|
|
148
|
+
"Usage: trekoon subtask <create|list|update|delete> [options]",
|
|
149
|
+
"",
|
|
150
|
+
"List behavior:",
|
|
151
|
+
" Defaults:",
|
|
152
|
+
" - Open statuses only: in_progress, in-progress, todo",
|
|
153
|
+
" - Limit: 10",
|
|
154
|
+
" Flags:",
|
|
155
|
+
" --task <id> | --status <csv> | --limit <n> | --cursor <n> | --all | --view table|compact",
|
|
156
|
+
" Pagination:",
|
|
157
|
+
" - --cursor is offset-like",
|
|
158
|
+
" - Machine modes expose meta.pagination.hasMore / nextCursor",
|
|
159
|
+
" Constraints:",
|
|
160
|
+
" - --all is mutually exclusive with --status, --limit, and --cursor",
|
|
161
|
+
"",
|
|
162
|
+
"Update behavior:",
|
|
163
|
+
" Bulk target flags:",
|
|
164
|
+
" --all | --ids <csv>",
|
|
165
|
+
" Bulk fields:",
|
|
166
|
+
" --append <text> and/or --status <status>",
|
|
167
|
+
].join("\n");
|
|
168
|
+
|
|
169
|
+
const DEP_HELP = [
|
|
170
|
+
"Usage: trekoon dep <add|remove|list|reverse> [options]",
|
|
171
|
+
"",
|
|
172
|
+
"Subcommands:",
|
|
173
|
+
" add <source-id> <depends-on-id>",
|
|
174
|
+
" Create dependency edge: source depends on depends-on.",
|
|
175
|
+
" remove <source-id> <depends-on-id>",
|
|
176
|
+
" Remove one dependency edge if it exists.",
|
|
177
|
+
" list <source-id>",
|
|
178
|
+
" Show direct dependencies for a node.",
|
|
179
|
+
" reverse <target-id>",
|
|
180
|
+
" Show downstream nodes blocked by target (with distance).",
|
|
181
|
+
"",
|
|
182
|
+
"Examples:",
|
|
183
|
+
" trekoon dep add <task-a> <task-b>",
|
|
184
|
+
" trekoon dep remove <task-a> <task-b>",
|
|
185
|
+
" trekoon dep list <task-a>",
|
|
186
|
+
" trekoon dep reverse <task-b>",
|
|
187
|
+
].join("\n");
|
|
188
|
+
|
|
189
|
+
const EVENTS_HELP = [
|
|
190
|
+
"Usage: trekoon events prune [--dry-run] [--archive] [--retention-days <n>]",
|
|
191
|
+
"",
|
|
192
|
+
"Purpose:",
|
|
193
|
+
" Manage retention for internal sync event log rows.",
|
|
194
|
+
"",
|
|
195
|
+
"Options:",
|
|
196
|
+
" --dry-run Preview candidate/archive/delete counts only.",
|
|
197
|
+
" --archive Copy pruned rows to event_archive before delete.",
|
|
198
|
+
" --retention-days <n> Keep last n days (positive integer, default 90).",
|
|
199
|
+
"",
|
|
200
|
+
"Examples:",
|
|
201
|
+
" trekoon events prune --dry-run",
|
|
202
|
+
" trekoon events prune --retention-days 30",
|
|
203
|
+
" trekoon events prune --archive",
|
|
204
|
+
].join("\n");
|
|
205
|
+
|
|
206
|
+
const MIGRATE_HELP = [
|
|
207
|
+
"Usage: trekoon migrate <status|rollback> [--to-version <n>]",
|
|
208
|
+
"",
|
|
209
|
+
"Subcommands:",
|
|
210
|
+
" status",
|
|
211
|
+
" Show current schema version, latest version, and pending count.",
|
|
212
|
+
" rollback [--to-version <n>]",
|
|
213
|
+
" Roll back migrations; default target is one version back.",
|
|
214
|
+
"",
|
|
215
|
+
"Examples:",
|
|
216
|
+
" trekoon migrate status",
|
|
217
|
+
" trekoon migrate rollback",
|
|
218
|
+
" trekoon migrate rollback --to-version 1",
|
|
219
|
+
].join("\n");
|
|
220
|
+
|
|
221
|
+
const SYNC_HELP = [
|
|
222
|
+
"Usage: trekoon sync <status|pull|resolve|conflicts> [options]",
|
|
223
|
+
"",
|
|
224
|
+
"Subcommands:",
|
|
225
|
+
" status [--from <branch>]",
|
|
226
|
+
" Show ahead/behind counts and pending conflicts vs source branch (default: main).",
|
|
227
|
+
" pull --from <branch>",
|
|
228
|
+
" Pull and apply upstream tracker events from a source branch.",
|
|
229
|
+
" conflicts list [--mode pending|all]",
|
|
230
|
+
" List sync conflicts (default mode: pending).",
|
|
231
|
+
" conflicts show <conflict-id>",
|
|
232
|
+
" Show full details for one conflict.",
|
|
233
|
+
" resolve <conflict-id> --use ours|theirs",
|
|
234
|
+
" Resolve a pending conflict by selecting ours or theirs.",
|
|
235
|
+
"",
|
|
236
|
+
"Compatibility mode:",
|
|
237
|
+
" --compat legacy-sync-command-ids",
|
|
238
|
+
" Emits legacy sync command IDs (sync_status, sync_pull, ...)",
|
|
239
|
+
" in machine output only and includes deprecation metadata.",
|
|
240
|
+
" Migration: remove --compat and consume dotted IDs (sync.status).",
|
|
241
|
+
" Planned compatibility window closes after 2026-09-30.",
|
|
242
|
+
"",
|
|
243
|
+
"Examples:",
|
|
244
|
+
" trekoon sync status",
|
|
245
|
+
" trekoon sync status --from main",
|
|
246
|
+
" trekoon sync pull --from main",
|
|
247
|
+
" trekoon sync conflicts list",
|
|
248
|
+
" trekoon sync conflicts list --mode all",
|
|
249
|
+
" trekoon sync conflicts show <conflict-id>",
|
|
250
|
+
" trekoon sync resolve <conflict-id> --use ours",
|
|
251
|
+
].join("\n");
|
|
252
|
+
|
|
253
|
+
const SKILLS_HELP = [
|
|
254
|
+
"Usage:",
|
|
255
|
+
" trekoon skills install [--link --editor opencode|claude|pi] [--to <path>] [--allow-outside-repo]",
|
|
256
|
+
" trekoon skills update",
|
|
257
|
+
"",
|
|
258
|
+
"Purpose:",
|
|
259
|
+
" Install or refresh the project-local Trekoon skill asset.",
|
|
260
|
+
"",
|
|
261
|
+
"Install behavior:",
|
|
262
|
+
" - Always installs canonical file to:",
|
|
263
|
+
" <cwd>/.agents/skills/trekoon/SKILL.md",
|
|
264
|
+
" - Use --link to also create an editor symlink named 'trekoon'.",
|
|
265
|
+
" - --editor is required when --link is used (opencode|claude|pi).",
|
|
266
|
+
" - --to overrides the symlink root for --link only.",
|
|
267
|
+
" - Without --allow-outside-repo, link targets must resolve inside repo.",
|
|
268
|
+
" - --allow-outside-repo requires --link and disables that boundary check.",
|
|
269
|
+
"",
|
|
270
|
+
"Update behavior:",
|
|
271
|
+
" - Refreshes canonical SKILL file in the install path above.",
|
|
272
|
+
" - Reports default link states for opencode/claude/pi.",
|
|
273
|
+
"",
|
|
274
|
+
"Examples:",
|
|
275
|
+
" trekoon skills install",
|
|
276
|
+
" trekoon skills install --link --editor opencode",
|
|
277
|
+
" trekoon skills install --link --editor claude --to .claude/skills",
|
|
278
|
+
" trekoon skills install --link --editor pi --to ../shared/skills --allow-outside-repo",
|
|
279
|
+
" trekoon skills update",
|
|
28
280
|
].join("\n");
|
|
29
281
|
|
|
30
282
|
const COMMAND_HELP: Record<string, string> = {
|
|
31
|
-
init:
|
|
32
|
-
quickstart:
|
|
33
|
-
wipe:
|
|
34
|
-
epic:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
migrate: "Usage: trekoon migrate <status|rollback> [--to-version <n>]",
|
|
43
|
-
sync: "Usage: trekoon sync <subcommand> [options]",
|
|
44
|
-
skills:
|
|
45
|
-
"Usage: trekoon skills install [--link --editor opencode|claude|pi] [--to <path>] [--allow-outside-repo] | trekoon skills update (--to sets symlink root for --link only; install path always <cwd>/.agents/skills/trekoon/SKILL.md; links must resolve inside repo unless --allow-outside-repo is set; update refreshes canonical SKILL and reports default link states)",
|
|
283
|
+
init: INIT_HELP,
|
|
284
|
+
quickstart: QUICKSTART_HELP,
|
|
285
|
+
wipe: WIPE_HELP,
|
|
286
|
+
epic: EPIC_HELP,
|
|
287
|
+
task: TASK_HELP,
|
|
288
|
+
subtask: SUBTASK_HELP,
|
|
289
|
+
dep: DEP_HELP,
|
|
290
|
+
events: EVENTS_HELP,
|
|
291
|
+
migrate: MIGRATE_HELP,
|
|
292
|
+
sync: SYNC_HELP,
|
|
293
|
+
skills: SKILLS_HELP,
|
|
46
294
|
help: "Usage: trekoon help [command] [--json|--toon]",
|
|
47
295
|
};
|
|
48
296
|
|
|
@@ -64,6 +312,7 @@ export async function runHelp(context: CliContext): Promise<CliResult> {
|
|
|
64
312
|
data: {
|
|
65
313
|
topic,
|
|
66
314
|
text,
|
|
315
|
+
version: CLI_VERSION,
|
|
67
316
|
},
|
|
68
317
|
});
|
|
69
318
|
}
|