@jamesaphoenix/tx-cli 0.4.3 → 0.4.5
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/dist/cli.d.ts +1 -1
- package/dist/cli.js +2 -7
- package/dist/commands/attempt.js +5 -4
- package/dist/commands/bulk.js +8 -7
- package/dist/commands/claim.js +4 -3
- package/dist/commands/cycle.js +2 -1
- package/dist/commands/dep.js +3 -2
- package/dist/commands/doc.js +13 -12
- package/dist/commands/hierarchy.js +3 -2
- package/dist/commands/invariant.js +2 -1
- package/dist/commands/sync-platform.js +4 -3
- package/dist/commands/sync.js +3 -2
- package/dist/commands/task.js +8 -7
- package/dist/commands/trace.js +14 -13
- package/dist/commands/validate.js +2 -1
- package/package.json +10 -3
- package/dist/cli-exit.d.ts.map +0 -1
- package/dist/cli-exit.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/attempt.d.ts.map +0 -1
- package/dist/commands/attempt.js.map +0 -1
- package/dist/commands/bulk.d.ts.map +0 -1
- package/dist/commands/bulk.js.map +0 -1
- package/dist/commands/claim.d.ts.map +0 -1
- package/dist/commands/claim.js.map +0 -1
- package/dist/commands/compact.d.ts.map +0 -1
- package/dist/commands/compact.js.map +0 -1
- package/dist/commands/coordinator.d.ts.map +0 -1
- package/dist/commands/coordinator.js.map +0 -1
- package/dist/commands/cycle.d.ts.map +0 -1
- package/dist/commands/cycle.js.map +0 -1
- package/dist/commands/daemon.d.ts.map +0 -1
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/dashboard.d.ts.map +0 -1
- package/dist/commands/dashboard.js.map +0 -1
- package/dist/commands/dashboard.test.d.ts +0 -2
- package/dist/commands/dashboard.test.d.ts.map +0 -1
- package/dist/commands/dashboard.test.js +0 -99
- package/dist/commands/dashboard.test.js.map +0 -1
- package/dist/commands/dep.d.ts.map +0 -1
- package/dist/commands/dep.js.map +0 -1
- package/dist/commands/doc.d.ts.map +0 -1
- package/dist/commands/doc.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/graph.d.ts.map +0 -1
- package/dist/commands/graph.js.map +0 -1
- package/dist/commands/hierarchy.d.ts.map +0 -1
- package/dist/commands/hierarchy.js.map +0 -1
- package/dist/commands/hooks.d.ts.map +0 -1
- package/dist/commands/hooks.js.map +0 -1
- package/dist/commands/invariant.d.ts.map +0 -1
- package/dist/commands/invariant.js.map +0 -1
- package/dist/commands/learning.d.ts.map +0 -1
- package/dist/commands/learning.js.map +0 -1
- package/dist/commands/migrate.d.ts.map +0 -1
- package/dist/commands/migrate.js.map +0 -1
- package/dist/commands/orchestrator.d.ts.map +0 -1
- package/dist/commands/orchestrator.js.map +0 -1
- package/dist/commands/stats.d.ts.map +0 -1
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/sync-platform.d.ts.map +0 -1
- package/dist/commands/sync-platform.js.map +0 -1
- package/dist/commands/sync.d.ts.map +0 -1
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/task.d.ts.map +0 -1
- package/dist/commands/task.js.map +0 -1
- package/dist/commands/test.d.ts.map +0 -1
- package/dist/commands/test.js.map +0 -1
- package/dist/commands/trace.d.ts.map +0 -1
- package/dist/commands/trace.js.map +0 -1
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/worker.d.ts.map +0 -1
- package/dist/commands/worker.js.map +0 -1
- package/dist/help.d.ts.map +0 -1
- package/dist/help.js.map +0 -1
- package/dist/output.d.ts.map +0 -1
- package/dist/output.js.map +0 -1
- package/dist/tx +0 -0
- package/dist/utils/parse.d.ts.map +0 -1
- package/dist/utils/parse.js.map +0 -1
- package/dist/utils/parse.test.d.ts +0 -2
- package/dist/utils/parse.test.d.ts.map +0 -1
- package/dist/utils/parse.test.js +0 -140
- package/dist/utils/parse.test.js.map +0 -1
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js.map +0 -1
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
3
|
* TX CLI - Task management for AI agents and humans
|
|
4
4
|
*
|
|
@@ -291,6 +291,7 @@ const errorExitCodes = {
|
|
|
291
291
|
ClaimNotFoundError: 2,
|
|
292
292
|
DocNotFoundError: 2,
|
|
293
293
|
InvariantNotFoundError: 2,
|
|
294
|
+
HasChildrenError: 1,
|
|
294
295
|
ValidationError: 1,
|
|
295
296
|
CircularDependencyError: 1,
|
|
296
297
|
DatabaseError: 1,
|
|
@@ -315,12 +316,6 @@ Effect.catchAll((error) => {
|
|
|
315
316
|
_exitCode = errorExitCodes[tag] ?? 1;
|
|
316
317
|
return Effect.void;
|
|
317
318
|
}
|
|
318
|
-
if (tag === "HasChildrenError") {
|
|
319
|
-
console.error(err.message ?? `Cannot delete task with children`);
|
|
320
|
-
console.error("Hint: use --cascade to delete with all children, or delete/move children first.");
|
|
321
|
-
_exitCode = 1;
|
|
322
|
-
return Effect.void;
|
|
323
|
-
}
|
|
324
319
|
console.error(`Error: ${err.message ?? String(error)}`);
|
|
325
320
|
_exitCode = 1;
|
|
326
321
|
return Effect.void;
|
package/dist/commands/attempt.js
CHANGED
|
@@ -5,12 +5,13 @@ import { Effect } from "effect";
|
|
|
5
5
|
import { AttemptService, TaskService } from "@jamesaphoenix/tx-core";
|
|
6
6
|
import { toJson } from "../output.js";
|
|
7
7
|
import { flag, parseTaskId } from "../utils/parse.js";
|
|
8
|
+
import { CliExitError } from "../cli-exit.js";
|
|
8
9
|
export const tryAttempt = (pos, flags) => Effect.gen(function* () {
|
|
9
10
|
const rawTaskId = pos[0];
|
|
10
11
|
const approach = pos[1];
|
|
11
12
|
if (!rawTaskId || !approach) {
|
|
12
13
|
console.error("Usage: tx try <task-id> <approach> --failed|--succeeded [reason]");
|
|
13
|
-
|
|
14
|
+
throw new CliExitError(1);
|
|
14
15
|
}
|
|
15
16
|
const taskId = parseTaskId(rawTaskId);
|
|
16
17
|
// Check for --failed and --succeeded flags
|
|
@@ -23,11 +24,11 @@ export const tryAttempt = (pos, flags) => Effect.gen(function* () {
|
|
|
23
24
|
// Validate mutually exclusive flags
|
|
24
25
|
if (hasFailedFlag && hasSucceededFlag) {
|
|
25
26
|
console.error("Error: --failed and --succeeded are mutually exclusive");
|
|
26
|
-
|
|
27
|
+
throw new CliExitError(1);
|
|
27
28
|
}
|
|
28
29
|
if (!hasFailedFlag && !hasSucceededFlag) {
|
|
29
30
|
console.error("Error: Must specify either --failed or --succeeded");
|
|
30
|
-
|
|
31
|
+
throw new CliExitError(1);
|
|
31
32
|
}
|
|
32
33
|
const outcome = hasFailedFlag ? "failed" : "succeeded";
|
|
33
34
|
// Reason can be the value of the flag (if string) or positional arg
|
|
@@ -61,7 +62,7 @@ export const attempts = (pos, flags) => Effect.gen(function* () {
|
|
|
61
62
|
const rawTaskId = pos[0];
|
|
62
63
|
if (!rawTaskId) {
|
|
63
64
|
console.error("Usage: tx attempts <task-id> [--json]");
|
|
64
|
-
|
|
65
|
+
throw new CliExitError(1);
|
|
65
66
|
}
|
|
66
67
|
const taskId = parseTaskId(rawTaskId);
|
|
67
68
|
const attemptSvc = yield* AttemptService;
|
package/dist/commands/bulk.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Effect } from "effect";
|
|
|
5
5
|
import { TaskService, ReadyService } from "@jamesaphoenix/tx-core";
|
|
6
6
|
import { flag, parseTaskId } from "../utils/parse.js";
|
|
7
7
|
import { toJson } from "../output.js";
|
|
8
|
+
import { CliExitError } from "../cli-exit.js";
|
|
8
9
|
/** Extract error message safely without unsafe 'as' casts. */
|
|
9
10
|
function extractErrorMessage(error) {
|
|
10
11
|
if (error instanceof Error)
|
|
@@ -30,7 +31,7 @@ export const bulk = (pos, flags) => Effect.gen(function* () {
|
|
|
30
31
|
if (!subcommand) {
|
|
31
32
|
console.error("Usage: tx bulk <done|score|reset|delete> <id...> [options]");
|
|
32
33
|
console.error("Run 'tx bulk --help' for more information");
|
|
33
|
-
|
|
34
|
+
throw new CliExitError(1);
|
|
34
35
|
}
|
|
35
36
|
switch (subcommand) {
|
|
36
37
|
case "done":
|
|
@@ -44,13 +45,13 @@ export const bulk = (pos, flags) => Effect.gen(function* () {
|
|
|
44
45
|
default:
|
|
45
46
|
console.error(`Unknown bulk subcommand: ${subcommand}`);
|
|
46
47
|
console.error("Valid subcommands: done, score, reset, delete");
|
|
47
|
-
|
|
48
|
+
throw new CliExitError(1);
|
|
48
49
|
}
|
|
49
50
|
});
|
|
50
51
|
const bulkDone = (pos, flags) => Effect.gen(function* () {
|
|
51
52
|
if (pos.length === 0) {
|
|
52
53
|
console.error("Usage: tx bulk done <id> [id...] [--json]");
|
|
53
|
-
|
|
54
|
+
throw new CliExitError(1);
|
|
54
55
|
}
|
|
55
56
|
const taskSvc = yield* TaskService;
|
|
56
57
|
const readySvc = yield* ReadyService;
|
|
@@ -90,12 +91,12 @@ const bulkDone = (pos, flags) => Effect.gen(function* () {
|
|
|
90
91
|
const bulkScore = (pos, flags) => Effect.gen(function* () {
|
|
91
92
|
if (pos.length < 2) {
|
|
92
93
|
console.error("Usage: tx bulk score <score> <id> [id...] [--json]");
|
|
93
|
-
|
|
94
|
+
throw new CliExitError(1);
|
|
94
95
|
}
|
|
95
96
|
const scoreVal = parseInt(pos[0], 10);
|
|
96
97
|
if (Number.isNaN(scoreVal)) {
|
|
97
98
|
console.error(`Invalid score: "${pos[0]}" is not a valid number`);
|
|
98
|
-
|
|
99
|
+
throw new CliExitError(1);
|
|
99
100
|
}
|
|
100
101
|
const ids = pos.slice(1);
|
|
101
102
|
const taskSvc = yield* TaskService;
|
|
@@ -120,7 +121,7 @@ const bulkScore = (pos, flags) => Effect.gen(function* () {
|
|
|
120
121
|
const bulkReset = (pos, flags) => Effect.gen(function* () {
|
|
121
122
|
if (pos.length === 0) {
|
|
122
123
|
console.error("Usage: tx bulk reset <id> [id...] [--json]");
|
|
123
|
-
|
|
124
|
+
throw new CliExitError(1);
|
|
124
125
|
}
|
|
125
126
|
const taskSvc = yield* TaskService;
|
|
126
127
|
const result = { succeeded: [], failed: [] };
|
|
@@ -144,7 +145,7 @@ const bulkReset = (pos, flags) => Effect.gen(function* () {
|
|
|
144
145
|
const bulkDelete = (pos, flags) => Effect.gen(function* () {
|
|
145
146
|
if (pos.length === 0) {
|
|
146
147
|
console.error("Usage: tx bulk delete <id> [id...] [--json]");
|
|
147
|
-
|
|
148
|
+
throw new CliExitError(1);
|
|
148
149
|
}
|
|
149
150
|
const taskSvc = yield* TaskService;
|
|
150
151
|
const result = { succeeded: [], failed: [] };
|
package/dist/commands/claim.js
CHANGED
|
@@ -9,6 +9,7 @@ import { Effect } from "effect";
|
|
|
9
9
|
import { ClaimService } from "@jamesaphoenix/tx-core";
|
|
10
10
|
import { toJson } from "../output.js";
|
|
11
11
|
import { flag, parseIntOpt, parseTaskId } from "../utils/parse.js";
|
|
12
|
+
import { CliExitError } from "../cli-exit.js";
|
|
12
13
|
/**
|
|
13
14
|
* Claim a task for a worker with a lease.
|
|
14
15
|
*
|
|
@@ -27,7 +28,7 @@ export const claim = (pos, flags) => Effect.gen(function* () {
|
|
|
27
28
|
console.error("Options:");
|
|
28
29
|
console.error(" --lease <m> Lease duration in minutes (default: 30)");
|
|
29
30
|
console.error(" --json Output in JSON format");
|
|
30
|
-
|
|
31
|
+
throw new CliExitError(1);
|
|
31
32
|
}
|
|
32
33
|
const taskId = parseTaskId(rawTaskId);
|
|
33
34
|
const leaseMinutes = parseIntOpt(flags, "lease", "lease");
|
|
@@ -54,7 +55,7 @@ export const claimRelease = (pos, flags) => Effect.gen(function* () {
|
|
|
54
55
|
const workerId = pos[1];
|
|
55
56
|
if (!rawTaskId || !workerId) {
|
|
56
57
|
console.error("Usage: tx claim:release <task-id> <worker-id> [--json]");
|
|
57
|
-
|
|
58
|
+
throw new CliExitError(1);
|
|
58
59
|
}
|
|
59
60
|
const taskId = parseTaskId(rawTaskId);
|
|
60
61
|
const svc = yield* ClaimService;
|
|
@@ -79,7 +80,7 @@ export const claimRenew = (pos, flags) => Effect.gen(function* () {
|
|
|
79
80
|
const workerId = pos[1];
|
|
80
81
|
if (!rawTaskId || !workerId) {
|
|
81
82
|
console.error("Usage: tx claim:renew <task-id> <worker-id> [--json]");
|
|
82
|
-
|
|
83
|
+
throw new CliExitError(1);
|
|
83
84
|
}
|
|
84
85
|
const taskId = parseTaskId(rawTaskId);
|
|
85
86
|
const svc = yield* ClaimService;
|
package/dist/commands/cycle.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Effect } from "effect";
|
|
|
8
8
|
import { CycleScanService } from "@jamesaphoenix/tx-core";
|
|
9
9
|
import { toJson } from "../output.js";
|
|
10
10
|
import { flag, opt, parseIntOpt } from "../utils/parse.js";
|
|
11
|
+
import { CliExitError } from "../cli-exit.js";
|
|
11
12
|
/** Dispatch cycle command. */
|
|
12
13
|
export const cycle = (_pos, flags) => {
|
|
13
14
|
const taskPrompt = opt(flags, "task-prompt");
|
|
@@ -32,7 +33,7 @@ export const cycle = (_pos, flags) => {
|
|
|
32
33
|
console.error(" --dry-run Report only, no DB writes");
|
|
33
34
|
console.error(" --score <N> Base score for new tasks (default: 500)");
|
|
34
35
|
console.error(" --json Output as JSON");
|
|
35
|
-
|
|
36
|
+
throw new CliExitError(1);
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
return Effect.gen(function* () {
|
package/dist/commands/dep.js
CHANGED
|
@@ -5,12 +5,13 @@ import { Effect } from "effect";
|
|
|
5
5
|
import { TaskService, DependencyService } from "@jamesaphoenix/tx-core";
|
|
6
6
|
import { toJson } from "../output.js";
|
|
7
7
|
import { flag, parseTaskId } from "../utils/parse.js";
|
|
8
|
+
import { CliExitError } from "../cli-exit.js";
|
|
8
9
|
export const block = (pos, flags) => Effect.gen(function* () {
|
|
9
10
|
const rawId = pos[0];
|
|
10
11
|
const rawBlocker = pos[1];
|
|
11
12
|
if (!rawId || !rawBlocker) {
|
|
12
13
|
console.error("Usage: tx block <task-id> <blocker-id> [--json]");
|
|
13
|
-
|
|
14
|
+
throw new CliExitError(1);
|
|
14
15
|
}
|
|
15
16
|
const id = parseTaskId(rawId);
|
|
16
17
|
const blocker = parseTaskId(rawBlocker);
|
|
@@ -31,7 +32,7 @@ export const unblock = (pos, flags) => Effect.gen(function* () {
|
|
|
31
32
|
const rawBlocker = pos[1];
|
|
32
33
|
if (!rawId || !rawBlocker) {
|
|
33
34
|
console.error("Usage: tx unblock <task-id> <blocker-id> [--json]");
|
|
34
|
-
|
|
35
|
+
throw new CliExitError(1);
|
|
35
36
|
}
|
|
36
37
|
const id = parseTaskId(rawId);
|
|
37
38
|
const blocker = parseTaskId(rawBlocker);
|
package/dist/commands/doc.js
CHANGED
|
@@ -9,6 +9,7 @@ import { DocService } from "@jamesaphoenix/tx-core";
|
|
|
9
9
|
import { DOC_KINDS } from "@jamesaphoenix/tx-types";
|
|
10
10
|
import { toJson } from "../output.js";
|
|
11
11
|
import { flag, opt } from "../utils/parse.js";
|
|
12
|
+
import { CliExitError } from "../cli-exit.js";
|
|
12
13
|
const docKindStrings = DOC_KINDS;
|
|
13
14
|
/** Dispatch doc subcommands. */
|
|
14
15
|
export const doc = (pos, flags) => {
|
|
@@ -31,7 +32,7 @@ export const doc = (pos, flags) => {
|
|
|
31
32
|
return Effect.sync(() => {
|
|
32
33
|
console.error(`Unknown doc subcommand: ${sub ?? "(none)"}`);
|
|
33
34
|
console.error("Run 'tx doc --help' for usage information");
|
|
34
|
-
|
|
35
|
+
throw new CliExitError(1);
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
38
|
};
|
|
@@ -41,11 +42,11 @@ const docAdd = (pos, flags) => Effect.gen(function* () {
|
|
|
41
42
|
if (!kind || !name) {
|
|
42
43
|
console.error("Usage: tx doc add <kind> <name> [--title <title>]");
|
|
43
44
|
console.error(" Kinds: overview, prd, design");
|
|
44
|
-
|
|
45
|
+
throw new CliExitError(1);
|
|
45
46
|
}
|
|
46
47
|
if (!docKindStrings.includes(kind)) {
|
|
47
48
|
console.error(`Invalid kind: ${kind}. Must be one of: ${DOC_KINDS.join(", ")}`);
|
|
48
|
-
|
|
49
|
+
throw new CliExitError(1);
|
|
49
50
|
}
|
|
50
51
|
const title = opt(flags, "title", "t") ?? name;
|
|
51
52
|
// Generate template YAML
|
|
@@ -70,7 +71,7 @@ const docEdit = (pos, _flags) => Effect.gen(function* () {
|
|
|
70
71
|
const name = pos[0];
|
|
71
72
|
if (!name) {
|
|
72
73
|
console.error("Usage: tx doc edit <name>");
|
|
73
|
-
|
|
74
|
+
throw new CliExitError(1);
|
|
74
75
|
}
|
|
75
76
|
const svc = yield* DocService;
|
|
76
77
|
const doc = yield* svc.get(name);
|
|
@@ -81,14 +82,14 @@ const docEdit = (pos, _flags) => Effect.gen(function* () {
|
|
|
81
82
|
}
|
|
82
83
|
catch {
|
|
83
84
|
console.error(`Failed to open editor: ${editor}`);
|
|
84
|
-
|
|
85
|
+
throw new CliExitError(1);
|
|
85
86
|
}
|
|
86
87
|
});
|
|
87
88
|
const docShow = (pos, flags) => Effect.gen(function* () {
|
|
88
89
|
const name = pos[0];
|
|
89
90
|
if (!name) {
|
|
90
91
|
console.error("Usage: tx doc show <name> [--md] [--json]");
|
|
91
|
-
|
|
92
|
+
throw new CliExitError(1);
|
|
92
93
|
}
|
|
93
94
|
const svc = yield* DocService;
|
|
94
95
|
const doc = yield* svc.get(name);
|
|
@@ -162,7 +163,7 @@ const docLock = (pos, flags) => Effect.gen(function* () {
|
|
|
162
163
|
const name = pos[0];
|
|
163
164
|
if (!name) {
|
|
164
165
|
console.error("Usage: tx doc lock <name>");
|
|
165
|
-
|
|
166
|
+
throw new CliExitError(1);
|
|
166
167
|
}
|
|
167
168
|
const svc = yield* DocService;
|
|
168
169
|
const doc = yield* svc.lock(name);
|
|
@@ -182,7 +183,7 @@ const docVersion = (pos, flags) => Effect.gen(function* () {
|
|
|
182
183
|
const name = pos[0];
|
|
183
184
|
if (!name) {
|
|
184
185
|
console.error("Usage: tx doc version <name>");
|
|
185
|
-
|
|
186
|
+
throw new CliExitError(1);
|
|
186
187
|
}
|
|
187
188
|
const svc = yield* DocService;
|
|
188
189
|
const doc = yield* svc.createVersion(name);
|
|
@@ -200,7 +201,7 @@ const docLink = (pos, flags) => Effect.gen(function* () {
|
|
|
200
201
|
const to = pos[1];
|
|
201
202
|
if (!from || !to) {
|
|
202
203
|
console.error("Usage: tx doc link <from-name> <to-name> [--type <link-type>]");
|
|
203
|
-
|
|
204
|
+
throw new CliExitError(1);
|
|
204
205
|
}
|
|
205
206
|
const linkType = opt(flags, "type");
|
|
206
207
|
const svc = yield* DocService;
|
|
@@ -217,7 +218,7 @@ const docAttach = (pos, flags) => Effect.gen(function* () {
|
|
|
217
218
|
const docName = pos[1];
|
|
218
219
|
if (!taskId || !docName) {
|
|
219
220
|
console.error("Usage: tx doc attach <task-id> <doc-name> [--type implements|references]");
|
|
220
|
-
|
|
221
|
+
throw new CliExitError(1);
|
|
221
222
|
}
|
|
222
223
|
const linkType = (opt(flags, "type") ?? "implements");
|
|
223
224
|
const svc = yield* DocService;
|
|
@@ -234,7 +235,7 @@ const docPatch = (pos, flags) => Effect.gen(function* () {
|
|
|
234
235
|
const patchName = pos[1];
|
|
235
236
|
if (!designName || !patchName) {
|
|
236
237
|
console.error("Usage: tx doc patch <design-name> <patch-name> [--title <title>]");
|
|
237
|
-
|
|
238
|
+
throw new CliExitError(1);
|
|
238
239
|
}
|
|
239
240
|
const title = opt(flags, "title", "t") ?? patchName;
|
|
240
241
|
const svc = yield* DocService;
|
|
@@ -270,7 +271,7 @@ const docDrift = (pos, flags) => Effect.gen(function* () {
|
|
|
270
271
|
const name = pos[0];
|
|
271
272
|
if (!name) {
|
|
272
273
|
console.error("Usage: tx doc drift <name>");
|
|
273
|
-
|
|
274
|
+
throw new CliExitError(1);
|
|
274
275
|
}
|
|
275
276
|
const svc = yield* DocService;
|
|
276
277
|
const warnings = yield* svc.detectDrift(name);
|
|
@@ -5,11 +5,12 @@ import { Effect } from "effect";
|
|
|
5
5
|
import { TaskService } from "@jamesaphoenix/tx-core";
|
|
6
6
|
import { toJson, formatTaskLine } from "../output.js";
|
|
7
7
|
import { flag, parseTaskId } from "../utils/parse.js";
|
|
8
|
+
import { CliExitError } from "../cli-exit.js";
|
|
8
9
|
export const children = (pos, flags) => Effect.gen(function* () {
|
|
9
10
|
const raw = pos[0];
|
|
10
11
|
if (!raw) {
|
|
11
12
|
console.error("Usage: tx children <id> [--json]");
|
|
12
|
-
|
|
13
|
+
throw new CliExitError(1);
|
|
13
14
|
}
|
|
14
15
|
const id = parseTaskId(raw);
|
|
15
16
|
const svc = yield* TaskService;
|
|
@@ -34,7 +35,7 @@ export const tree = (pos, flags) => Effect.gen(function* () {
|
|
|
34
35
|
const raw = pos[0];
|
|
35
36
|
if (!raw) {
|
|
36
37
|
console.error("Usage: tx tree <id> [--json]");
|
|
37
|
-
|
|
38
|
+
throw new CliExitError(1);
|
|
38
39
|
}
|
|
39
40
|
const id = parseTaskId(raw);
|
|
40
41
|
const svc = yield* TaskService;
|
|
@@ -5,6 +5,7 @@ import { Effect } from "effect";
|
|
|
5
5
|
import { DocService } from "@jamesaphoenix/tx-core";
|
|
6
6
|
import { toJson } from "../output.js";
|
|
7
7
|
import { flag, opt } from "../utils/parse.js";
|
|
8
|
+
import { CliExitError } from "../cli-exit.js";
|
|
8
9
|
/** Dispatch invariant subcommands. */
|
|
9
10
|
export const invariant = (pos, flags) => {
|
|
10
11
|
const sub = pos[0];
|
|
@@ -18,7 +19,7 @@ export const invariant = (pos, flags) => {
|
|
|
18
19
|
return Effect.sync(() => {
|
|
19
20
|
console.error(`Unknown invariant subcommand: ${sub ?? "(none)"}`);
|
|
20
21
|
console.error("Run 'tx invariant --help' for usage information");
|
|
21
|
-
|
|
22
|
+
throw new CliExitError(1);
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
};
|
|
@@ -11,6 +11,7 @@ import { homedir } from "node:os";
|
|
|
11
11
|
import { TaskService, buildClaudeTaskFiles } from "@jamesaphoenix/tx-core";
|
|
12
12
|
import { toJson } from "../output.js";
|
|
13
13
|
import { flag, opt } from "../utils/parse.js";
|
|
14
|
+
import { CliExitError } from "../cli-exit.js";
|
|
14
15
|
export const syncClaude = (_pos, flags) => Effect.gen(function* () {
|
|
15
16
|
const taskSvc = yield* TaskService;
|
|
16
17
|
// Resolve target directory
|
|
@@ -21,7 +22,7 @@ export const syncClaude = (_pos, flags) => Effect.gen(function* () {
|
|
|
21
22
|
// Validate team name to prevent path traversal (e.g. --team ../../.ssh)
|
|
22
23
|
if (!/^[a-zA-Z0-9_-]+$/.test(teamName)) {
|
|
23
24
|
console.error("Invalid team name: must contain only alphanumeric characters, hyphens, and underscores");
|
|
24
|
-
|
|
25
|
+
throw new CliExitError(1);
|
|
25
26
|
}
|
|
26
27
|
targetDir = join(homedir(), ".claude", "tasks", teamName);
|
|
27
28
|
}
|
|
@@ -30,7 +31,7 @@ export const syncClaude = (_pos, flags) => Effect.gen(function* () {
|
|
|
30
31
|
}
|
|
31
32
|
else {
|
|
32
33
|
console.error("Either --team <name> or --dir <path> is required");
|
|
33
|
-
|
|
34
|
+
throw new CliExitError(1);
|
|
34
35
|
}
|
|
35
36
|
// Create directory if it doesn't exist
|
|
36
37
|
if (!existsSync(targetDir)) {
|
|
@@ -69,6 +70,6 @@ export const syncClaude = (_pos, flags) => Effect.gen(function* () {
|
|
|
69
70
|
});
|
|
70
71
|
export const syncCodex = (_pos, _flags) => Effect.sync(() => {
|
|
71
72
|
console.error("Codex sync is not yet implemented. Use 'tx sync claude' for Claude Code.");
|
|
72
|
-
|
|
73
|
+
throw new CliExitError(1);
|
|
73
74
|
});
|
|
74
75
|
//# sourceMappingURL=sync-platform.js.map
|
package/dist/commands/sync.js
CHANGED
|
@@ -6,6 +6,7 @@ import { SyncService } from "@jamesaphoenix/tx-core";
|
|
|
6
6
|
import { toJson } from "../output.js";
|
|
7
7
|
import { commandHelp } from "../help.js";
|
|
8
8
|
import { flag, opt } from "../utils/parse.js";
|
|
9
|
+
import { CliExitError } from "../cli-exit.js";
|
|
9
10
|
import { syncClaude, syncCodex } from "./sync-platform.js";
|
|
10
11
|
export const sync = (pos, flags) => Effect.gen(function* () {
|
|
11
12
|
const subcommand = pos[0];
|
|
@@ -79,7 +80,7 @@ export const sync = (pos, flags) => Effect.gen(function* () {
|
|
|
79
80
|
const disableFlag = flag(flags, "disable");
|
|
80
81
|
if (enableFlag && disableFlag) {
|
|
81
82
|
console.error("Cannot specify both --enable and --disable");
|
|
82
|
-
|
|
83
|
+
throw new CliExitError(1);
|
|
83
84
|
}
|
|
84
85
|
if (enableFlag) {
|
|
85
86
|
yield* syncSvc.enableAutoSync();
|
|
@@ -122,7 +123,7 @@ export const sync = (pos, flags) => Effect.gen(function* () {
|
|
|
122
123
|
else {
|
|
123
124
|
console.error(`Unknown sync subcommand: ${subcommand}`);
|
|
124
125
|
console.error(`Run 'tx sync --help' for usage information`);
|
|
125
|
-
|
|
126
|
+
throw new CliExitError(1);
|
|
126
127
|
}
|
|
127
128
|
});
|
|
128
129
|
//# sourceMappingURL=sync.js.map
|
package/dist/commands/task.js
CHANGED
|
@@ -6,11 +6,12 @@ import { TaskService, ReadyService, AttemptService } from "@jamesaphoenix/tx-cor
|
|
|
6
6
|
import { assertTaskStatus, TASK_STATUSES } from "@jamesaphoenix/tx-types";
|
|
7
7
|
import { toJson, formatTaskWithDeps, formatTaskLine, formatReadyTaskLine } from "../output.js";
|
|
8
8
|
import { flag, opt, parseIntOpt, parseTaskId } from "../utils/parse.js";
|
|
9
|
+
import { CliExitError } from "../cli-exit.js";
|
|
9
10
|
export const add = (pos, flags) => Effect.gen(function* () {
|
|
10
11
|
const title = pos[0];
|
|
11
12
|
if (!title) {
|
|
12
13
|
console.error("Usage: tx add <title> [--parent/-p <id>] [--score/-s <n>] [--description/-d <text>] [--json]");
|
|
13
|
-
|
|
14
|
+
throw new CliExitError(1);
|
|
14
15
|
}
|
|
15
16
|
const svc = yield* TaskService;
|
|
16
17
|
const task = yield* svc.create({
|
|
@@ -44,7 +45,7 @@ export const list = (_pos, flags) => Effect.gen(function* () {
|
|
|
44
45
|
}
|
|
45
46
|
catch {
|
|
46
47
|
console.error(`Invalid status filter. Valid statuses: ${TASK_STATUSES.join(", ")}`);
|
|
47
|
-
|
|
48
|
+
throw new CliExitError(1);
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
const tasks = yield* svc.listWithDeps({
|
|
@@ -100,7 +101,7 @@ export const show = (pos, flags) => Effect.gen(function* () {
|
|
|
100
101
|
const raw = pos[0];
|
|
101
102
|
if (!raw) {
|
|
102
103
|
console.error("Usage: tx show <id> [--json]");
|
|
103
|
-
|
|
104
|
+
throw new CliExitError(1);
|
|
104
105
|
}
|
|
105
106
|
const id = parseTaskId(raw);
|
|
106
107
|
const svc = yield* TaskService;
|
|
@@ -133,7 +134,7 @@ export const update = (pos, flags) => Effect.gen(function* () {
|
|
|
133
134
|
const raw = pos[0];
|
|
134
135
|
if (!raw) {
|
|
135
136
|
console.error("Usage: tx update <id> [--status <s>] [--title <t>] [--score <n>] [--description <d>] [--parent <p>] [--json]");
|
|
136
|
-
|
|
137
|
+
throw new CliExitError(1);
|
|
137
138
|
}
|
|
138
139
|
const id = parseTaskId(raw);
|
|
139
140
|
const svc = yield* TaskService;
|
|
@@ -164,7 +165,7 @@ export const done = (pos, flags) => Effect.gen(function* () {
|
|
|
164
165
|
const raw = pos[0];
|
|
165
166
|
if (!raw) {
|
|
166
167
|
console.error("Usage: tx done <id> [--json]");
|
|
167
|
-
|
|
168
|
+
throw new CliExitError(1);
|
|
168
169
|
}
|
|
169
170
|
const id = parseTaskId(raw);
|
|
170
171
|
const taskSvc = yield* TaskService;
|
|
@@ -194,7 +195,7 @@ export const deleteTask = (pos, flags) => Effect.gen(function* () {
|
|
|
194
195
|
const raw = pos[0];
|
|
195
196
|
if (!raw) {
|
|
196
197
|
console.error("Usage: tx delete <id> [--cascade] [--json]");
|
|
197
|
-
|
|
198
|
+
throw new CliExitError(1);
|
|
198
199
|
}
|
|
199
200
|
const id = parseTaskId(raw);
|
|
200
201
|
const cascade = flag(flags, "cascade");
|
|
@@ -212,7 +213,7 @@ export const reset = (pos, flags) => Effect.gen(function* () {
|
|
|
212
213
|
const raw = pos[0];
|
|
213
214
|
if (!raw) {
|
|
214
215
|
console.error("Usage: tx reset <id> [--json]");
|
|
215
|
-
|
|
216
|
+
throw new CliExitError(1);
|
|
216
217
|
}
|
|
217
218
|
const id = parseTaskId(raw);
|
|
218
219
|
const taskSvc = yield* TaskService;
|
package/dist/commands/trace.js
CHANGED
|
@@ -10,6 +10,7 @@ import { RunRepository, SqliteClient, getAdapter } from "@jamesaphoenix/tx-core"
|
|
|
10
10
|
import { toJson, truncate } from "../output.js";
|
|
11
11
|
import { commandHelp } from "../help.js";
|
|
12
12
|
import { flag, parseIntOpt } from "../utils/parse.js";
|
|
13
|
+
import { CliExitError } from "../cli-exit.js";
|
|
13
14
|
/**
|
|
14
15
|
* Calculate relative time string (e.g., "2h ago", "3d ago").
|
|
15
16
|
*/
|
|
@@ -191,19 +192,19 @@ export const traceTranscript = (pos, _flags) => Effect.gen(function* () {
|
|
|
191
192
|
if (!runId) {
|
|
192
193
|
console.error("Error: run-id is required");
|
|
193
194
|
console.error("Usage: tx trace transcript <run-id>");
|
|
194
|
-
|
|
195
|
+
throw new CliExitError(1);
|
|
195
196
|
}
|
|
196
197
|
const runRepo = yield* RunRepository;
|
|
197
198
|
// Get run details
|
|
198
199
|
const run = yield* runRepo.findById(runId);
|
|
199
200
|
if (!run) {
|
|
200
201
|
console.error(`Error: Run not found: ${runId}`);
|
|
201
|
-
|
|
202
|
+
throw new CliExitError(1);
|
|
202
203
|
}
|
|
203
204
|
// Check if transcript path exists
|
|
204
205
|
if (!run.transcriptPath) {
|
|
205
206
|
console.error(`Error: No transcript recorded for run: ${runId}`);
|
|
206
|
-
|
|
207
|
+
throw new CliExitError(1);
|
|
207
208
|
}
|
|
208
209
|
// Resolve transcript path relative to .tx directory
|
|
209
210
|
const txDir = join(process.cwd(), ".tx");
|
|
@@ -212,7 +213,7 @@ export const traceTranscript = (pos, _flags) => Effect.gen(function* () {
|
|
|
212
213
|
: resolve(txDir, run.transcriptPath);
|
|
213
214
|
if (!existsSync(fullPath)) {
|
|
214
215
|
console.error(`Error: Transcript file not found: ${fullPath}`);
|
|
215
|
-
|
|
216
|
+
throw new CliExitError(1);
|
|
216
217
|
}
|
|
217
218
|
// Read and output raw content
|
|
218
219
|
try {
|
|
@@ -222,7 +223,7 @@ export const traceTranscript = (pos, _flags) => Effect.gen(function* () {
|
|
|
222
223
|
catch (err) {
|
|
223
224
|
const message = err instanceof Error ? err.message : String(err);
|
|
224
225
|
console.error(`Error: Failed to read transcript file: ${message}`);
|
|
225
|
-
|
|
226
|
+
throw new CliExitError(1);
|
|
226
227
|
}
|
|
227
228
|
});
|
|
228
229
|
/**
|
|
@@ -236,19 +237,19 @@ export const traceStderr = (pos, _flags) => Effect.gen(function* () {
|
|
|
236
237
|
if (!runId) {
|
|
237
238
|
console.error("Error: run-id is required");
|
|
238
239
|
console.error("Usage: tx trace stderr <run-id>");
|
|
239
|
-
|
|
240
|
+
throw new CliExitError(1);
|
|
240
241
|
}
|
|
241
242
|
const runRepo = yield* RunRepository;
|
|
242
243
|
// Get run details
|
|
243
244
|
const run = yield* runRepo.findById(runId);
|
|
244
245
|
if (!run) {
|
|
245
246
|
console.error(`Error: Run not found: ${runId}`);
|
|
246
|
-
|
|
247
|
+
throw new CliExitError(1);
|
|
247
248
|
}
|
|
248
249
|
// Check if stderr path exists
|
|
249
250
|
if (!run.stderrPath) {
|
|
250
251
|
console.error(`Error: No stderr recorded for run: ${runId}`);
|
|
251
|
-
|
|
252
|
+
throw new CliExitError(1);
|
|
252
253
|
}
|
|
253
254
|
// Resolve stderr path relative to .tx directory
|
|
254
255
|
const txDir = join(process.cwd(), ".tx");
|
|
@@ -257,7 +258,7 @@ export const traceStderr = (pos, _flags) => Effect.gen(function* () {
|
|
|
257
258
|
: resolve(txDir, run.stderrPath);
|
|
258
259
|
if (!existsSync(fullPath)) {
|
|
259
260
|
console.error(`Error: Stderr file not found: ${fullPath}`);
|
|
260
|
-
|
|
261
|
+
throw new CliExitError(1);
|
|
261
262
|
}
|
|
262
263
|
// Read and output raw content
|
|
263
264
|
try {
|
|
@@ -267,7 +268,7 @@ export const traceStderr = (pos, _flags) => Effect.gen(function* () {
|
|
|
267
268
|
catch (err) {
|
|
268
269
|
const message = err instanceof Error ? err.message : String(err);
|
|
269
270
|
console.error(`Error: Failed to read stderr file: ${message}`);
|
|
270
|
-
|
|
271
|
+
throw new CliExitError(1);
|
|
271
272
|
}
|
|
272
273
|
});
|
|
273
274
|
/**
|
|
@@ -278,7 +279,7 @@ export const traceShow = (pos, flags) => Effect.gen(function* () {
|
|
|
278
279
|
if (!runId) {
|
|
279
280
|
console.error("Error: run-id is required");
|
|
280
281
|
console.error("Usage: tx trace show <run-id> [--full] [--json]");
|
|
281
|
-
|
|
282
|
+
throw new CliExitError(1);
|
|
282
283
|
}
|
|
283
284
|
const runRepo = yield* RunRepository;
|
|
284
285
|
const db = yield* SqliteClient;
|
|
@@ -286,7 +287,7 @@ export const traceShow = (pos, flags) => Effect.gen(function* () {
|
|
|
286
287
|
const run = yield* runRepo.findById(runId);
|
|
287
288
|
if (!run) {
|
|
288
289
|
console.error(`Error: Run not found: ${runId}`);
|
|
289
|
-
|
|
290
|
+
throw new CliExitError(1);
|
|
290
291
|
}
|
|
291
292
|
// Get events for this run
|
|
292
293
|
const eventRows = getEventsForRun(db, runId);
|
|
@@ -614,7 +615,7 @@ Options:
|
|
|
614
615
|
else {
|
|
615
616
|
console.error(`Unknown trace subcommand: ${subcommand}`);
|
|
616
617
|
console.error(`Run 'tx trace --help' for usage information`);
|
|
617
|
-
|
|
618
|
+
throw new CliExitError(1);
|
|
618
619
|
}
|
|
619
620
|
});
|
|
620
621
|
//# sourceMappingURL=trace.js.map
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { Effect } from "effect";
|
|
5
5
|
import { ValidationService } from "@jamesaphoenix/tx-core";
|
|
6
6
|
import { toJson } from "../output.js";
|
|
7
|
+
import { CliExitError } from "../cli-exit.js";
|
|
7
8
|
function flag(flags, ...names) {
|
|
8
9
|
return names.some(n => flags[n] === true);
|
|
9
10
|
}
|
|
@@ -88,7 +89,7 @@ export const validate = (_pos, flags) => Effect.gen(function* () {
|
|
|
88
89
|
}
|
|
89
90
|
// Exit with code 1 if validation failed (errors found)
|
|
90
91
|
if (!result.valid) {
|
|
91
|
-
|
|
92
|
+
throw new CliExitError(1);
|
|
92
93
|
}
|
|
93
94
|
});
|
|
94
95
|
//# sourceMappingURL=validate.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jamesaphoenix/tx-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "TX command line tool - task management for AI agents and humans",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -15,7 +15,15 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"!dist/tx",
|
|
20
|
+
"!dist/tx-*",
|
|
21
|
+
"!dist/**/*.test.*",
|
|
22
|
+
"!dist/**/*.test.d.ts",
|
|
23
|
+
"!dist/**/*.test.d.ts.map",
|
|
24
|
+
"!dist/**/*.js.map",
|
|
25
|
+
"!dist/**/*.d.ts.map",
|
|
26
|
+
"README.md"
|
|
19
27
|
],
|
|
20
28
|
"scripts": {
|
|
21
29
|
"build": "tsc -b",
|
|
@@ -31,7 +39,6 @@
|
|
|
31
39
|
},
|
|
32
40
|
"dependencies": {
|
|
33
41
|
"@jamesaphoenix/tx-core": "*",
|
|
34
|
-
"@jamesaphoenix/tx-test-utils": "*",
|
|
35
42
|
"@jamesaphoenix/tx-types": "*",
|
|
36
43
|
"effect": "^3.19.15"
|
|
37
44
|
},
|
package/dist/cli-exit.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-exit.d.ts","sourceRoot":"","sources":["../src/cli-exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAG,cAAc,CAAS;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;gBAET,IAAI,EAAE,MAAM;CAIzB"}
|
package/dist/cli-exit.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-exit.js","sourceRoot":"","sources":["../src/cli-exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,GAAG,cAAuB,CAAA;IAC9B,IAAI,CAAQ;IAErB,YAAY,IAAY;QACtB,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF"}
|
package/dist/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
|