trekoon 0.1.8 → 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 +42 -0
- package/README.md +71 -12
- package/package.json +1 -1
- package/src/commands/arg-parser.ts +82 -0
- package/src/commands/epic.ts +70 -1
- package/src/commands/help.ts +12 -1
- package/src/commands/subtask.ts +23 -1
- package/src/commands/sync.ts +130 -52
- package/src/commands/task.ts +71 -1
- package/src/index.ts +1 -1
- package/src/io/output.ts +98 -5
- package/src/runtime/cli-shell.ts +159 -22
- package/src/runtime/command-types.ts +18 -0
- package/src/storage/path.ts +58 -1
|
@@ -35,6 +35,9 @@ data:
|
|
|
35
35
|
status: in_progress
|
|
36
36
|
createdAt: 1700000001000
|
|
37
37
|
updatedAt: 1700000001000
|
|
38
|
+
metadata:
|
|
39
|
+
contractVersion: 1.0.0
|
|
40
|
+
requestId: req-abc12345
|
|
38
41
|
```
|
|
39
42
|
|
|
40
43
|
On error:
|
|
@@ -43,6 +46,9 @@ On error:
|
|
|
43
46
|
ok: false
|
|
44
47
|
command: task.show
|
|
45
48
|
data: {}
|
|
49
|
+
metadata:
|
|
50
|
+
contractVersion: 1.0.0
|
|
51
|
+
requestId: req-def67890
|
|
46
52
|
error:
|
|
47
53
|
code: not_found
|
|
48
54
|
message: task not found: invalid-id
|
|
@@ -55,10 +61,34 @@ error:
|
|
|
55
61
|
| `ok` | `true` if command succeeded, `false` on error |
|
|
56
62
|
| `command` | The command that was executed (e.g., `task.list`, `epic.create`) |
|
|
57
63
|
| `data` | The response payload (tasks, epics, dependencies, etc.) |
|
|
64
|
+
| `metadata` | Contract metadata (`contractVersion`, `requestId`) |
|
|
65
|
+
| `meta` | Optional command-specific metadata (pagination/defaults/filters/diagnostics) |
|
|
58
66
|
| `error` | Present only on failure, contains `code` and `message` |
|
|
59
67
|
|
|
60
68
|
Use long flags (`--status`, `--description`, etc.) and ALWAYS append `--toon` to every command.
|
|
61
69
|
|
|
70
|
+
### Contract details to rely on
|
|
71
|
+
|
|
72
|
+
- Machine responses include `metadata.contractVersion` and `metadata.requestId`.
|
|
73
|
+
- Command IDs are stable and typically dot namespaced (`task.list`, `sync.status`).
|
|
74
|
+
- Some root commands use single-token IDs (`help`, `init`, `quickstart`, `wipe`, `version`).
|
|
75
|
+
- Unknown options fail fast with deterministic `unknown_option` errors and may include:
|
|
76
|
+
- `data.option`
|
|
77
|
+
- `data.allowedOptions`
|
|
78
|
+
- `data.suggestions`
|
|
79
|
+
|
|
80
|
+
### Compatibility mode (legacy sync consumers)
|
|
81
|
+
|
|
82
|
+
Default behavior is strict canonical IDs (for example `sync.status`).
|
|
83
|
+
|
|
84
|
+
If a legacy consumer still expects underscore sync IDs, compatibility mode can be used:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
trekoon --toon --compat legacy-sync-command-ids sync status
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
When enabled, output includes `metadata.compatibility` with migration/deprecation details.
|
|
91
|
+
|
|
62
92
|
## 1) Status Management
|
|
63
93
|
|
|
64
94
|
### Status values
|
|
@@ -205,9 +235,21 @@ trekoon task list --all --toon
|
|
|
205
235
|
- `--all` cannot be combined with `--cursor`.
|
|
206
236
|
- Machine pagination contract is in `meta.pagination.hasMore` and
|
|
207
237
|
`meta.pagination.nextCursor`.
|
|
238
|
+
- Machine list/show responses may also include:
|
|
239
|
+
- `meta.defaults`
|
|
240
|
+
- `meta.filters`
|
|
241
|
+
- `meta.truncation`
|
|
208
242
|
- `epic show <id> --all --toon`: full epic tree (tasks + subtasks)
|
|
209
243
|
- `task show <id> --all --toon`: task plus its subtasks
|
|
210
244
|
|
|
245
|
+
### Canonical storage root behavior
|
|
246
|
+
|
|
247
|
+
- In git repos/worktrees, Trekoon resolves storage from repository top-level so
|
|
248
|
+
nested cwd invocations use one canonical `.trekoon/trekoon.db`.
|
|
249
|
+
- In non-git directories, Trekoon falls back to invocation cwd.
|
|
250
|
+
- If invocation cwd differs from canonical root, machine output may include
|
|
251
|
+
`meta.storageRootDiagnostics`.
|
|
252
|
+
|
|
211
253
|
### View Options
|
|
212
254
|
|
|
213
255
|
| Command | `--view` options |
|
package/README.md
CHANGED
|
@@ -46,12 +46,15 @@ npm i -g trekoon
|
|
|
46
46
|
## Command surface
|
|
47
47
|
|
|
48
48
|
- `trekoon init`
|
|
49
|
+
- `trekoon help [command]`
|
|
49
50
|
- `trekoon quickstart`
|
|
50
51
|
- `trekoon epic <create|list|show|update|delete>`
|
|
51
52
|
- `trekoon task <create|list|show|ready|next|update|delete>`
|
|
52
53
|
- `trekoon subtask <create|list|update|delete>`
|
|
53
54
|
- `trekoon dep <add|remove|list|reverse>`
|
|
54
|
-
- `trekoon
|
|
55
|
+
- `trekoon events prune [--dry-run] [--archive] [--retention-days <n>]`
|
|
56
|
+
- `trekoon migrate <status|rollback> [--to-version <n>]`
|
|
57
|
+
- `trekoon sync <status|pull|resolve|conflicts>`
|
|
55
58
|
- `trekoon skills install [--link --editor opencode|claude|pi] [--to <path>] [--allow-outside-repo]`
|
|
56
59
|
- `trekoon skills update`
|
|
57
60
|
- `trekoon wipe --yes`
|
|
@@ -60,6 +63,7 @@ Global output modes:
|
|
|
60
63
|
|
|
61
64
|
- `--json` for structured JSON output
|
|
62
65
|
- `--toon` for true TOON-encoded output (not JSON text)
|
|
66
|
+
- `--compat <mode>` for explicit machine compatibility behavior
|
|
63
67
|
- `--help` for root and command help
|
|
64
68
|
- `--version` for CLI version
|
|
65
69
|
|
|
@@ -72,7 +76,8 @@ trekoon --json quickstart
|
|
|
72
76
|
trekoon quickstart --json
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
Trekoon
|
|
79
|
+
Trekoon options use long form (`--option`) for command/subcommand flags.
|
|
80
|
+
Root help/version aliases `-h` and `-v` are also supported.
|
|
76
81
|
|
|
77
82
|
Human view options:
|
|
78
83
|
|
|
@@ -112,8 +117,15 @@ trekoon epic update --ids <epic-1>,<epic-2> --status done
|
|
|
112
117
|
|
|
113
118
|
## Quickstart
|
|
114
119
|
|
|
115
|
-
Trekoon is local-first:
|
|
116
|
-
|
|
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`.
|
|
123
|
+
|
|
124
|
+
Outside git repos, Trekoon falls back to the invocation cwd.
|
|
125
|
+
|
|
126
|
+
When machine output is enabled (`--json`/`--toon`) and a command resolves
|
|
127
|
+
storage from a non-canonical cwd, Trekoon emits
|
|
128
|
+
`meta.storageRootDiagnostics` to make the divergence explicit for automation.
|
|
117
129
|
|
|
118
130
|
### 1) Initialize
|
|
119
131
|
|
|
@@ -183,6 +195,8 @@ trekoon --json task show <task-id>
|
|
|
183
195
|
```bash
|
|
184
196
|
trekoon sync status
|
|
185
197
|
trekoon sync pull --from main
|
|
198
|
+
trekoon sync conflicts list
|
|
199
|
+
trekoon sync conflicts show <conflict-id>
|
|
186
200
|
trekoon sync resolve <conflict-id> --use ours
|
|
187
201
|
```
|
|
188
202
|
|
|
@@ -195,10 +209,31 @@ react deterministically:
|
|
|
195
209
|
- `diagnostics.conflictEvents`
|
|
196
210
|
- `diagnostics.errorHints`
|
|
197
211
|
|
|
212
|
+
Compatibility mode for legacy sync command IDs:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
trekoon --json --compat legacy-sync-command-ids sync status
|
|
216
|
+
trekoon --toon --compat legacy-sync-command-ids sync pull --from main
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Behavior:
|
|
220
|
+
|
|
221
|
+
- Default remains strict canonical IDs (`sync.status`, `sync.pull`, ...).
|
|
222
|
+
- Compatibility mode rewrites sync command IDs to legacy forms
|
|
223
|
+
(`sync_status`, `sync_pull`, ...).
|
|
224
|
+
- Compatibility mode is machine-only and valid only for `sync` commands.
|
|
225
|
+
- Machine output includes `metadata.compatibility` with:
|
|
226
|
+
- deprecation warning code
|
|
227
|
+
- migration guidance
|
|
228
|
+
- canonical + compatibility command IDs
|
|
229
|
+
- removal window (`removalAfter: 2026-09-30`)
|
|
230
|
+
- Migration path: remove `--compat legacy-sync-command-ids` and consume dotted
|
|
231
|
+
command IDs directly.
|
|
232
|
+
|
|
198
233
|
### 7) Install project-local Trekoon skill for agents
|
|
199
234
|
|
|
200
|
-
`trekoon skills install` always writes the bundled skill file
|
|
201
|
-
|
|
235
|
+
`trekoon skills install` always writes the bundled skill file under the current
|
|
236
|
+
working directory at:
|
|
202
237
|
|
|
203
238
|
- `.agents/skills/trekoon/SKILL.md`
|
|
204
239
|
|
|
@@ -220,7 +255,7 @@ Path behavior:
|
|
|
220
255
|
- Default pi link path: `.pi/skills/trekoon`
|
|
221
256
|
- `--to <path>` overrides the editor root for link creation only.
|
|
222
257
|
- `--to` does **not** move or copy `SKILL.md` to that path.
|
|
223
|
-
- By default, link targets must resolve inside the
|
|
258
|
+
- By default, link targets must resolve inside the current working directory root.
|
|
224
259
|
- Use `--allow-outside-repo` only for intentional external links.
|
|
225
260
|
- When override is used, install prints a warning and includes confirmation
|
|
226
261
|
fields in machine output.
|
|
@@ -237,11 +272,11 @@ Path behavior:
|
|
|
237
272
|
How `--to` works (step-by-step):
|
|
238
273
|
|
|
239
274
|
1. Trekoon always installs/copies to:
|
|
240
|
-
- `<
|
|
275
|
+
- `<cwd>/.agents/skills/trekoon/SKILL.md`
|
|
241
276
|
2. If `--link` is present, Trekoon creates a `trekoon` symlink directory entry.
|
|
242
277
|
3. `--to <path>` sets the symlink root directory.
|
|
243
278
|
4. Final link path is:
|
|
244
|
-
- `<resolved-to-path>/trekoon -> <
|
|
279
|
+
- `<resolved-to-path>/trekoon -> <cwd>/.agents/skills/trekoon`
|
|
245
280
|
|
|
246
281
|
Example:
|
|
247
282
|
|
|
@@ -251,9 +286,9 @@ trekoon skills install --link --editor opencode --to ./.custom-editor/skills
|
|
|
251
286
|
|
|
252
287
|
This produces:
|
|
253
288
|
|
|
254
|
-
- `<
|
|
255
|
-
- `<
|
|
256
|
-
- symlink target: `<
|
|
289
|
+
- `<cwd>/.agents/skills/trekoon/SKILL.md` (copied file)
|
|
290
|
+
- `<cwd>/.custom-editor/skills/trekoon` (symlink)
|
|
291
|
+
- symlink target: `<cwd>/.agents/skills/trekoon`
|
|
257
292
|
|
|
258
293
|
Trekoon does not mutate global editor config directories.
|
|
259
294
|
|
|
@@ -269,6 +304,27 @@ Trekoon does not mutate global editor config directories.
|
|
|
269
304
|
Use `--toon` for production agent loops. The examples below show command +
|
|
270
305
|
expected envelope fields.
|
|
271
306
|
|
|
307
|
+
Base envelope fields (all machine responses):
|
|
308
|
+
|
|
309
|
+
```text
|
|
310
|
+
ok: true|false
|
|
311
|
+
command: <stable command id>
|
|
312
|
+
data: <payload>
|
|
313
|
+
metadata:
|
|
314
|
+
contractVersion: "1.0.0"
|
|
315
|
+
requestId: req-<stable-id>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Most subcommand identifiers are dot-namespaced (`task.list`, `sync.pull`,
|
|
319
|
+
`epic.show`). Root-level commands may use single-token IDs (`help`, `init`,
|
|
320
|
+
`quickstart`, `wipe`, `version`).
|
|
321
|
+
|
|
322
|
+
Additional metadata can appear when relevant:
|
|
323
|
+
|
|
324
|
+
- `metadata.compatibility` when `--compat` mode is active
|
|
325
|
+
- `meta.storageRootDiagnostics` when a machine-readable command resolves
|
|
326
|
+
storage from a non-canonical cwd
|
|
327
|
+
|
|
272
328
|
### Ready queue (deterministic candidates)
|
|
273
329
|
|
|
274
330
|
```bash
|
|
@@ -336,6 +392,9 @@ ok: true
|
|
|
336
392
|
command: task.list
|
|
337
393
|
data:
|
|
338
394
|
tasks[]: ...
|
|
395
|
+
metadata:
|
|
396
|
+
contractVersion: "1.0.0"
|
|
397
|
+
requestId: req-<stable-id>
|
|
339
398
|
meta:
|
|
340
399
|
pagination: { hasMore, nextCursor }
|
|
341
400
|
```
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ export interface ParsedArgs {
|
|
|
3
3
|
readonly options: ReadonlyMap<string, string>;
|
|
4
4
|
readonly flags: ReadonlySet<string>;
|
|
5
5
|
readonly missingOptionValues: ReadonlySet<string>;
|
|
6
|
+
readonly providedOptions: readonly string[];
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
const LONG_PREFIX = "--";
|
|
@@ -12,6 +13,7 @@ export function parseArgs(args: readonly string[]): ParsedArgs {
|
|
|
12
13
|
const options = new Map<string, string>();
|
|
13
14
|
const flags = new Set<string>();
|
|
14
15
|
const missingOptionValues = new Set<string>();
|
|
16
|
+
const providedOptions: string[] = [];
|
|
15
17
|
|
|
16
18
|
for (let index = 0; index < args.length; index += 1) {
|
|
17
19
|
const token: string | undefined = args[index];
|
|
@@ -25,6 +27,7 @@ export function parseArgs(args: readonly string[]): ParsedArgs {
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const key = token.slice(LONG_PREFIX.length);
|
|
30
|
+
providedOptions.push(key);
|
|
28
31
|
const value = args[index + 1];
|
|
29
32
|
if (!value || value.startsWith(LONG_PREFIX)) {
|
|
30
33
|
flags.add(key);
|
|
@@ -41,6 +44,7 @@ export function parseArgs(args: readonly string[]): ParsedArgs {
|
|
|
41
44
|
options,
|
|
42
45
|
flags,
|
|
43
46
|
missingOptionValues,
|
|
47
|
+
providedOptions,
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -92,6 +96,84 @@ export function parseStrictNonNegativeInt(rawValue: string | undefined): number
|
|
|
92
96
|
return parsed;
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
function levenshteinDistance(source: string, target: string): number {
|
|
100
|
+
const sourceLength = source.length;
|
|
101
|
+
const targetLength = target.length;
|
|
102
|
+
if (sourceLength === 0) {
|
|
103
|
+
return targetLength;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (targetLength === 0) {
|
|
107
|
+
return sourceLength;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const previous: number[] = Array.from({ length: targetLength + 1 }, (_, index) => index);
|
|
111
|
+
const current: number[] = new Array<number>(targetLength + 1).fill(0);
|
|
112
|
+
|
|
113
|
+
for (let sourceIndex = 1; sourceIndex <= sourceLength; sourceIndex += 1) {
|
|
114
|
+
current[0] = sourceIndex;
|
|
115
|
+
for (let targetIndex = 1; targetIndex <= targetLength; targetIndex += 1) {
|
|
116
|
+
const replacementCost = source[sourceIndex - 1] === target[targetIndex - 1] ? 0 : 1;
|
|
117
|
+
const insertCost = (current[targetIndex - 1] ?? 0) + 1;
|
|
118
|
+
const deleteCost = (previous[targetIndex] ?? 0) + 1;
|
|
119
|
+
const replaceCost = (previous[targetIndex - 1] ?? 0) + replacementCost;
|
|
120
|
+
current[targetIndex] = Math.min(
|
|
121
|
+
insertCost,
|
|
122
|
+
deleteCost,
|
|
123
|
+
replaceCost,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (let targetIndex = 0; targetIndex <= targetLength; targetIndex += 1) {
|
|
128
|
+
previous[targetIndex] = current[targetIndex] ?? previous[targetIndex] ?? 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return previous[targetLength] ?? 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function normalizeOption(option: string): string {
|
|
136
|
+
return option.startsWith(LONG_PREFIX) ? option.slice(LONG_PREFIX.length) : option;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function findUnknownOption(parsed: ParsedArgs, allowedOptions: readonly string[]): string | undefined {
|
|
140
|
+
const allowed = new Set<string>(allowedOptions.map(normalizeOption));
|
|
141
|
+
for (const option of parsed.providedOptions) {
|
|
142
|
+
if (!allowed.has(option)) {
|
|
143
|
+
return option;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function suggestOptions(option: string, allowedOptions: readonly string[], limit = 3): string[] {
|
|
151
|
+
const normalizedOption = normalizeOption(option);
|
|
152
|
+
const normalizedAllowed = allowedOptions.map(normalizeOption);
|
|
153
|
+
return normalizedAllowed
|
|
154
|
+
.map((candidate) => {
|
|
155
|
+
const distance =
|
|
156
|
+
candidate.startsWith(normalizedOption) || normalizedOption.startsWith(candidate)
|
|
157
|
+
? 0
|
|
158
|
+
: levenshteinDistance(normalizedOption, candidate);
|
|
159
|
+
return {
|
|
160
|
+
candidate,
|
|
161
|
+
distance,
|
|
162
|
+
};
|
|
163
|
+
})
|
|
164
|
+
.sort((left, right) => {
|
|
165
|
+
const byDistance = left.distance - right.distance;
|
|
166
|
+
if (byDistance !== 0) {
|
|
167
|
+
return byDistance;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return left.candidate.localeCompare(right.candidate);
|
|
171
|
+
})
|
|
172
|
+
.filter((item) => item.distance <= Math.max(2, Math.floor(normalizedOption.length / 2)))
|
|
173
|
+
.slice(0, limit)
|
|
174
|
+
.map((item) => item.candidate);
|
|
175
|
+
}
|
|
176
|
+
|
|
95
177
|
export function readEnumOption<const T extends readonly string[]>(
|
|
96
178
|
options: ReadonlyMap<string, string>,
|
|
97
179
|
allowed: T,
|
package/src/commands/epic.ts
CHANGED
|
@@ -396,7 +396,28 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
396
396
|
command: "epic.list",
|
|
397
397
|
human,
|
|
398
398
|
data: { epics },
|
|
399
|
-
...(context.mode === "human"
|
|
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
|
+
}),
|
|
400
421
|
});
|
|
401
422
|
}
|
|
402
423
|
case "show": {
|
|
@@ -430,6 +451,22 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
430
451
|
command: "epic.show",
|
|
431
452
|
human: formatEpic(epic),
|
|
432
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
|
+
}),
|
|
433
470
|
});
|
|
434
471
|
}
|
|
435
472
|
|
|
@@ -440,6 +477,22 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
440
477
|
command: "epic.show",
|
|
441
478
|
human: formatEpicShowCompact(tree),
|
|
442
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
|
+
}),
|
|
443
496
|
});
|
|
444
497
|
}
|
|
445
498
|
|
|
@@ -449,6 +502,22 @@ export async function runEpic(context: CliContext): Promise<CliResult> {
|
|
|
449
502
|
command: "epic.show",
|
|
450
503
|
human: effectiveView === "table" ? formatEpicShowTable(tree) : formatEpicShowDetailed(tree),
|
|
451
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
|
+
}),
|
|
452
521
|
});
|
|
453
522
|
}
|
|
454
523
|
case "update": {
|
package/src/commands/help.ts
CHANGED
|
@@ -12,10 +12,12 @@ const ROOT_HELP = [
|
|
|
12
12
|
"Global options:",
|
|
13
13
|
" --json Emit stable JSON machine output",
|
|
14
14
|
" --toon Emit true TOON-encoded output",
|
|
15
|
+
" --compat <mode> Enable explicit machine compatibility mode",
|
|
15
16
|
" --help Show root or command help",
|
|
16
17
|
" --version Print CLI version",
|
|
17
18
|
"",
|
|
18
19
|
"Commands:",
|
|
20
|
+
" help Show root or command help",
|
|
19
21
|
" init Initialize .trekoon storage and local DB",
|
|
20
22
|
" quickstart Show AI execution loop + task detail workflow",
|
|
21
23
|
" wipe Remove local Trekoon state (requires --yes)",
|
|
@@ -88,6 +90,7 @@ const EPIC_HELP = [
|
|
|
88
90
|
"",
|
|
89
91
|
"Show behavior:",
|
|
90
92
|
" Views:",
|
|
93
|
+
" - table: default view",
|
|
91
94
|
" - compact: epic summary",
|
|
92
95
|
" - tree: hierarchy",
|
|
93
96
|
" - detail: descriptions",
|
|
@@ -109,7 +112,7 @@ const TASK_HELP = [
|
|
|
109
112
|
" - Open statuses only: in_progress, in-progress, todo",
|
|
110
113
|
" - Limit: 10",
|
|
111
114
|
" Flags:",
|
|
112
|
-
" --status <csv> | --limit <n> | --cursor <n> | --all | --view table|compact",
|
|
115
|
+
" --epic <id> | --status <csv> | --limit <n> | --cursor <n> | --all | --view table|compact",
|
|
113
116
|
" Pagination:",
|
|
114
117
|
" - --cursor is offset-like",
|
|
115
118
|
" - Machine modes expose meta.pagination.hasMore / nextCursor",
|
|
@@ -118,6 +121,7 @@ const TASK_HELP = [
|
|
|
118
121
|
"",
|
|
119
122
|
"Show behavior:",
|
|
120
123
|
" Views:",
|
|
124
|
+
" - table: default view",
|
|
121
125
|
" - compact: task summary",
|
|
122
126
|
" - tree: hierarchy",
|
|
123
127
|
" - detail: descriptions",
|
|
@@ -229,6 +233,13 @@ const SYNC_HELP = [
|
|
|
229
233
|
" resolve <conflict-id> --use ours|theirs",
|
|
230
234
|
" Resolve a pending conflict by selecting ours or theirs.",
|
|
231
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
|
+
"",
|
|
232
243
|
"Examples:",
|
|
233
244
|
" trekoon sync status",
|
|
234
245
|
" trekoon sync status --from main",
|
package/src/commands/subtask.ts
CHANGED
|
@@ -323,7 +323,29 @@ export async function runSubtask(context: CliContext): Promise<CliResult> {
|
|
|
323
323
|
command: "subtask.list",
|
|
324
324
|
human,
|
|
325
325
|
data: { subtasks },
|
|
326
|
-
...(context.mode === "human"
|
|
326
|
+
...(context.mode === "human"
|
|
327
|
+
? {}
|
|
328
|
+
: {
|
|
329
|
+
meta: {
|
|
330
|
+
pagination: listed.pagination,
|
|
331
|
+
defaults: {
|
|
332
|
+
statuses: !includeAll && statuses === undefined ? [...DEFAULT_OPEN_SUBTASK_STATUSES] : null,
|
|
333
|
+
limit: !includeAll && parsedLimit === undefined ? DEFAULT_SUBTASK_LIST_LIMIT : null,
|
|
334
|
+
cursor: parsedCursor === undefined ? 0 : null,
|
|
335
|
+
view: view === undefined ? "table" : null,
|
|
336
|
+
},
|
|
337
|
+
filters: {
|
|
338
|
+
taskId: taskId ?? null,
|
|
339
|
+
statuses: selectedStatuses ?? null,
|
|
340
|
+
includeAll,
|
|
341
|
+
},
|
|
342
|
+
truncation: {
|
|
343
|
+
applied: listed.pagination.hasMore,
|
|
344
|
+
returned: subtasks.length,
|
|
345
|
+
limit: selectedLimit ?? null,
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
}),
|
|
327
349
|
});
|
|
328
350
|
}
|
|
329
351
|
case "update": {
|