@jamesaphoenix/tx-cli 0.4.3
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-exit.d.ts +15 -0
- package/dist/cli-exit.d.ts.map +1 -0
- package/dist/cli-exit.js +18 -0
- package/dist/cli-exit.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +349 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/attempt.d.ts +9 -0
- package/dist/commands/attempt.d.ts.map +1 -0
- package/dist/commands/attempt.js +93 -0
- package/dist/commands/attempt.js.map +1 -0
- package/dist/commands/bulk.d.ts +8 -0
- package/dist/commands/bulk.d.ts.map +1 -0
- package/dist/commands/bulk.js +168 -0
- package/dist/commands/bulk.js.map +1 -0
- package/dist/commands/claim.d.ts +39 -0
- package/dist/commands/claim.d.ts.map +1 -0
- package/dist/commands/claim.js +96 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/compact.d.ts +17 -0
- package/dist/commands/compact.d.ts.map +1 -0
- package/dist/commands/compact.js +167 -0
- package/dist/commands/compact.js.map +1 -0
- package/dist/commands/coordinator.d.ts +12 -0
- package/dist/commands/coordinator.d.ts.map +1 -0
- package/dist/commands/coordinator.js +124 -0
- package/dist/commands/coordinator.js.map +1 -0
- package/dist/commands/cycle.d.ts +12 -0
- package/dist/commands/cycle.d.ts.map +1 -0
- package/dist/commands/cycle.js +109 -0
- package/dist/commands/cycle.js.map +1 -0
- package/dist/commands/daemon.d.ts +16 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +635 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/dashboard.d.ts +12 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +105 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/dashboard.test.d.ts +2 -0
- package/dist/commands/dashboard.test.d.ts.map +1 -0
- package/dist/commands/dashboard.test.js +99 -0
- package/dist/commands/dashboard.test.js.map +1 -0
- package/dist/commands/dep.d.ts +9 -0
- package/dist/commands/dep.d.ts.map +1 -0
- package/dist/commands/dep.js +50 -0
- package/dist/commands/dep.js.map +1 -0
- package/dist/commands/doc.d.ts +10 -0
- package/dist/commands/doc.d.ts.map +1 -0
- package/dist/commands/doc.js +397 -0
- package/dist/commands/doc.js.map +1 -0
- package/dist/commands/doctor.d.ts +9 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +168 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/graph.d.ts +58 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +441 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/hierarchy.d.ts +9 -0
- package/dist/commands/hierarchy.d.ts.map +1 -0
- package/dist/commands/hierarchy.js +68 -0
- package/dist/commands/hierarchy.js.map +1 -0
- package/dist/commands/hooks.d.ts +56 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +365 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/invariant.d.ts +9 -0
- package/dist/commands/invariant.d.ts.map +1 -0
- package/dist/commands/invariant.js +126 -0
- package/dist/commands/invariant.js.map +1 -0
- package/dist/commands/learning.d.ts +16 -0
- package/dist/commands/learning.d.ts.map +1 -0
- package/dist/commands/learning.js +362 -0
- package/dist/commands/learning.js.map +1 -0
- package/dist/commands/migrate.d.ts +9 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +56 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/orchestrator.d.ts +11 -0
- package/dist/commands/orchestrator.d.ts.map +1 -0
- package/dist/commands/orchestrator.js +129 -0
- package/dist/commands/orchestrator.js.map +1 -0
- package/dist/commands/stats.d.ts +8 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +128 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/sync-platform.d.ts +12 -0
- package/dist/commands/sync-platform.d.ts.map +1 -0
- package/dist/commands/sync-platform.js +74 -0
- package/dist/commands/sync-platform.js.map +1 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +128 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/task.d.ts +15 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +233 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/test.d.ts +16 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +112 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/trace.d.ts +39 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +620 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +94 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/worker.d.ts +10 -0
- package/dist/commands/worker.d.ts.map +1 -0
- package/dist/commands/worker.js +204 -0
- package/dist/commands/worker.js.map +1 -0
- package/dist/help.d.ts +3 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +1366 -0
- package/dist/help.js.map +1 -0
- package/dist/output.d.ts +12 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +76 -0
- package/dist/output.js.map +1 -0
- package/dist/tx +0 -0
- package/dist/utils/parse.d.ts +45 -0
- package/dist/utils/parse.d.ts.map +1 -0
- package/dist/utils/parse.js +79 -0
- package/dist/utils/parse.js.map +1 -0
- package/dist/utils/parse.test.d.ts +2 -0
- package/dist/utils/parse.test.d.ts.map +1 -0
- package/dist/utils/parse.test.js +140 -0
- package/dist/utils/parse.test.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stats command: Queue metrics and health overview
|
|
3
|
+
*/
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import { SqliteClient } from "@jamesaphoenix/tx-core";
|
|
6
|
+
import { toJson } from "../output.js";
|
|
7
|
+
import { flag } from "../utils/parse.js";
|
|
8
|
+
export const stats = (_pos, flags) => Effect.gen(function* () {
|
|
9
|
+
const db = yield* SqliteClient;
|
|
10
|
+
// 1. Status counts via GROUP BY (single query)
|
|
11
|
+
const statusRows = db.prepare("SELECT status, COUNT(*) as count FROM tasks GROUP BY status").all();
|
|
12
|
+
const byStatus = {};
|
|
13
|
+
let total = 0;
|
|
14
|
+
for (const row of statusRows) {
|
|
15
|
+
byStatus[row.status] = row.count;
|
|
16
|
+
total += row.count;
|
|
17
|
+
}
|
|
18
|
+
// 2+3. Ready count + priority breakdown via SQL aggregation (single query)
|
|
19
|
+
// A task is "ready" when status is workable AND all blockers are done
|
|
20
|
+
const priorityRows = db.prepare(`
|
|
21
|
+
SELECT
|
|
22
|
+
CASE
|
|
23
|
+
WHEN t.score >= 900 THEN 'critical'
|
|
24
|
+
WHEN t.score >= 700 THEN 'high'
|
|
25
|
+
WHEN t.score >= 500 THEN 'medium'
|
|
26
|
+
ELSE 'low'
|
|
27
|
+
END as bucket,
|
|
28
|
+
COUNT(*) as count
|
|
29
|
+
FROM tasks t
|
|
30
|
+
WHERE t.status IN ('backlog', 'ready', 'planning')
|
|
31
|
+
AND NOT EXISTS (
|
|
32
|
+
SELECT 1 FROM task_dependencies d
|
|
33
|
+
JOIN tasks blocker ON blocker.id = d.blocker_id
|
|
34
|
+
WHERE d.blocked_id = t.id
|
|
35
|
+
AND blocker.status != 'done'
|
|
36
|
+
)
|
|
37
|
+
GROUP BY bucket
|
|
38
|
+
`).all();
|
|
39
|
+
let readyCount = 0;
|
|
40
|
+
let critical = 0;
|
|
41
|
+
let high = 0;
|
|
42
|
+
let medium = 0;
|
|
43
|
+
let low = 0;
|
|
44
|
+
for (const row of priorityRows) {
|
|
45
|
+
readyCount += row.count;
|
|
46
|
+
if (row.bucket === "critical")
|
|
47
|
+
critical = row.count;
|
|
48
|
+
else if (row.bucket === "high")
|
|
49
|
+
high = row.count;
|
|
50
|
+
else if (row.bucket === "medium")
|
|
51
|
+
medium = row.count;
|
|
52
|
+
else
|
|
53
|
+
low = row.count;
|
|
54
|
+
}
|
|
55
|
+
// 4. Activity: completed tasks in time windows
|
|
56
|
+
const last24hRow = db.prepare("SELECT COUNT(*) as count FROM tasks WHERE status = 'done' AND completed_at > datetime('now', '-1 day')").get();
|
|
57
|
+
const last7dRow = db.prepare("SELECT COUNT(*) as count FROM tasks WHERE status = 'done' AND completed_at > datetime('now', '-7 days')").get();
|
|
58
|
+
const last24h = last24hRow?.count ?? 0;
|
|
59
|
+
const last7d = last7dRow?.count ?? 0;
|
|
60
|
+
// Avg completion rate: tasks per day over the full history
|
|
61
|
+
const dateRangeRow = db.prepare("SELECT MIN(completed_at) as earliest, COUNT(*) as total_done FROM tasks WHERE status = 'done' AND completed_at IS NOT NULL").get();
|
|
62
|
+
let avgPerDay = null;
|
|
63
|
+
if (dateRangeRow?.earliest && dateRangeRow.total_done > 0) {
|
|
64
|
+
const earliest = new Date(dateRangeRow.earliest);
|
|
65
|
+
const now = new Date();
|
|
66
|
+
const daysDiff = (now.getTime() - earliest.getTime()) / (1000 * 60 * 60 * 24);
|
|
67
|
+
if (daysDiff >= 1) {
|
|
68
|
+
avgPerDay = Math.round((dateRangeRow.total_done / daysDiff) * 10) / 10;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// 5. Claim stats
|
|
72
|
+
const activeClaimsRow = db.prepare("SELECT COUNT(*) as count FROM task_claims WHERE status = 'active' AND datetime(lease_expires_at) >= datetime('now')").get();
|
|
73
|
+
const expiredClaimsRow = db.prepare("SELECT COUNT(*) as count FROM task_claims WHERE status = 'active' AND datetime(lease_expires_at) < datetime('now')").get();
|
|
74
|
+
const result = {
|
|
75
|
+
total,
|
|
76
|
+
byStatus,
|
|
77
|
+
readyCount,
|
|
78
|
+
byPriority: { critical, high, medium, low },
|
|
79
|
+
activity: { last24h, last7d, avgPerDay },
|
|
80
|
+
claims: {
|
|
81
|
+
active: activeClaimsRow?.count ?? 0,
|
|
82
|
+
expired: expiredClaimsRow?.count ?? 0,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
if (flag(flags, "json")) {
|
|
86
|
+
console.log(toJson(result));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.log(formatStats(result));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
function pct(n, total) {
|
|
93
|
+
if (total === 0)
|
|
94
|
+
return "0%";
|
|
95
|
+
return `${Math.round((n / total) * 100)}%`;
|
|
96
|
+
}
|
|
97
|
+
function formatStats(s) {
|
|
98
|
+
const lines = [];
|
|
99
|
+
// Queue Status
|
|
100
|
+
lines.push("Queue Status:");
|
|
101
|
+
lines.push(` Total: ${s.total} tasks`);
|
|
102
|
+
lines.push(` Ready: ${s.readyCount} (${pct(s.readyCount, s.total)})`);
|
|
103
|
+
lines.push(` Active: ${s.byStatus.active ?? 0} (${pct(s.byStatus.active ?? 0, s.total)})`);
|
|
104
|
+
lines.push(` Blocked: ${s.byStatus.blocked ?? 0} (${pct(s.byStatus.blocked ?? 0, s.total)})`);
|
|
105
|
+
lines.push(` Done: ${s.byStatus.done ?? 0} (${pct(s.byStatus.done ?? 0, s.total)})`);
|
|
106
|
+
// By Priority (ready tasks only)
|
|
107
|
+
lines.push("");
|
|
108
|
+
lines.push("By Priority:");
|
|
109
|
+
lines.push(` Critical (900+): ${s.byPriority.critical} ready`);
|
|
110
|
+
lines.push(` High (700-899): ${s.byPriority.high} ready`);
|
|
111
|
+
lines.push(` Medium (500-699): ${s.byPriority.medium} ready`);
|
|
112
|
+
lines.push(` Low (<500): ${s.byPriority.low} ready`);
|
|
113
|
+
// Activity
|
|
114
|
+
lines.push("");
|
|
115
|
+
lines.push("Activity:");
|
|
116
|
+
lines.push(` Last 24h: ${s.activity.last24h} completed`);
|
|
117
|
+
lines.push(` Last 7d: ${s.activity.last7d} completed`);
|
|
118
|
+
if (s.activity.avgPerDay !== null) {
|
|
119
|
+
lines.push(` Avg completion: ${s.activity.avgPerDay} tasks/day`);
|
|
120
|
+
}
|
|
121
|
+
// Claims
|
|
122
|
+
lines.push("");
|
|
123
|
+
lines.push("Claims:");
|
|
124
|
+
lines.push(` Active: ${s.claims.active}`);
|
|
125
|
+
lines.push(` Expired: ${s.claims.expired}`);
|
|
126
|
+
return lines.join("\n");
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform sync commands: claude, codex
|
|
3
|
+
*
|
|
4
|
+
* One-way push of tx tasks to external agent task systems.
|
|
5
|
+
* Writes directly to the target platform's on-disk task format.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import { TaskService } from "@jamesaphoenix/tx-core";
|
|
9
|
+
import { type Flags } from "../utils/parse.js";
|
|
10
|
+
export declare const syncClaude: (_pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").DatabaseError, TaskService>;
|
|
11
|
+
export declare const syncCodex: (_pos: string[], _flags: Flags) => Effect.Effect<never, never, never>;
|
|
12
|
+
//# sourceMappingURL=sync-platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-platform.d.ts","sourceRoot":"","sources":["../../src/commands/sync-platform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAI/B,OAAO,EAAE,WAAW,EAAwB,MAAM,wBAAwB,CAAA;AAE1E,OAAO,EAAE,KAAK,KAAK,EAAa,MAAM,mBAAmB,CAAA;AAEzD,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,EAAE,OAAO,KAAK,qFA8DnD,CAAA;AAEJ,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,EAAE,QAAQ,KAAK,uCAInD,CAAA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform sync commands: claude, codex
|
|
3
|
+
*
|
|
4
|
+
* One-way push of tx tasks to external agent task systems.
|
|
5
|
+
* Writes directly to the target platform's on-disk task format.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
import { existsSync, writeFileSync, mkdirSync, readdirSync, unlinkSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { TaskService, buildClaudeTaskFiles } from "@jamesaphoenix/tx-core";
|
|
12
|
+
import { toJson } from "../output.js";
|
|
13
|
+
import { flag, opt } from "../utils/parse.js";
|
|
14
|
+
export const syncClaude = (_pos, flags) => Effect.gen(function* () {
|
|
15
|
+
const taskSvc = yield* TaskService;
|
|
16
|
+
// Resolve target directory
|
|
17
|
+
const teamName = opt(flags, "team");
|
|
18
|
+
const dirOverride = opt(flags, "dir");
|
|
19
|
+
let targetDir;
|
|
20
|
+
if (teamName) {
|
|
21
|
+
// Validate team name to prevent path traversal (e.g. --team ../../.ssh)
|
|
22
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(teamName)) {
|
|
23
|
+
console.error("Invalid team name: must contain only alphanumeric characters, hyphens, and underscores");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
targetDir = join(homedir(), ".claude", "tasks", teamName);
|
|
27
|
+
}
|
|
28
|
+
else if (dirOverride) {
|
|
29
|
+
targetDir = resolve(dirOverride);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.error("Either --team <name> or --dir <path> is required");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
// Create directory if it doesn't exist
|
|
36
|
+
if (!existsSync(targetDir)) {
|
|
37
|
+
mkdirSync(targetDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
const allTasks = yield* taskSvc.listWithDeps();
|
|
40
|
+
const { files, highwatermark } = buildClaudeTaskFiles(allTasks);
|
|
41
|
+
// Remove stale task files from previous syncs
|
|
42
|
+
const newIds = new Set(files.map(f => `${f.id}.json`));
|
|
43
|
+
const existing = readdirSync(targetDir).filter(f => /^\d+\.json$/.test(f));
|
|
44
|
+
for (const stale of existing) {
|
|
45
|
+
if (!newIds.has(stale)) {
|
|
46
|
+
unlinkSync(join(targetDir, stale));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Write individual task JSON files
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
writeFileSync(join(targetDir, `${file.id}.json`), JSON.stringify(file, null, 2));
|
|
52
|
+
}
|
|
53
|
+
// Write highwatermark
|
|
54
|
+
writeFileSync(join(targetDir, ".highwatermark"), String(highwatermark));
|
|
55
|
+
// Ensure .lock file exists
|
|
56
|
+
const lockPath = join(targetDir, ".lock");
|
|
57
|
+
if (!existsSync(lockPath)) {
|
|
58
|
+
writeFileSync(lockPath, "");
|
|
59
|
+
}
|
|
60
|
+
if (flag(flags, "json")) {
|
|
61
|
+
console.log(toJson({ tasksWritten: files.length, dir: targetDir, highwatermark }));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.log(`Wrote ${files.length} task(s) to ${targetDir}`);
|
|
65
|
+
const readyCount = files.filter(f => f.blockedBy.length === 0 && f.status === "pending").length;
|
|
66
|
+
const inProgressCount = files.filter(f => f.status === "in_progress").length;
|
|
67
|
+
console.log(` Ready: ${readyCount}, In-progress: ${inProgressCount}, Blocked: ${files.length - readyCount - inProgressCount}`);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
export const syncCodex = (_pos, _flags) => Effect.sync(() => {
|
|
71
|
+
console.error("Codex sync is not yet implemented. Use 'tx sync claude' for Claude Code.");
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=sync-platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-platform.js","sourceRoot":"","sources":["../../src/commands/sync-platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync commands: export, import, status, compact, auto
|
|
3
|
+
*/
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import { SyncService } from "@jamesaphoenix/tx-core";
|
|
6
|
+
import { type Flags } from "../utils/parse.js";
|
|
7
|
+
export declare const sync: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").ValidationError | import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError, import("@jamesaphoenix/tx-core").TaskService | SyncService>;
|
|
8
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAGpD,OAAO,EAAE,KAAK,KAAK,EAAa,MAAM,mBAAmB,CAAA;AAGzD,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,4OAoH5C,CAAA"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync commands: export, import, status, compact, auto
|
|
3
|
+
*/
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import { SyncService } from "@jamesaphoenix/tx-core";
|
|
6
|
+
import { toJson } from "../output.js";
|
|
7
|
+
import { commandHelp } from "../help.js";
|
|
8
|
+
import { flag, opt } from "../utils/parse.js";
|
|
9
|
+
import { syncClaude, syncCodex } from "./sync-platform.js";
|
|
10
|
+
export const sync = (pos, flags) => Effect.gen(function* () {
|
|
11
|
+
const subcommand = pos[0];
|
|
12
|
+
if (!subcommand || subcommand === "help") {
|
|
13
|
+
console.log(commandHelp["sync"]);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// Check for --help on subcommand
|
|
17
|
+
if (flag(flags, "help", "h")) {
|
|
18
|
+
const helpKey = `sync ${subcommand}`;
|
|
19
|
+
if (commandHelp[helpKey]) {
|
|
20
|
+
console.log(commandHelp[helpKey]);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Platform sync subcommands (don't need SyncService)
|
|
25
|
+
if (subcommand === "claude") {
|
|
26
|
+
return yield* syncClaude(pos.slice(1), flags);
|
|
27
|
+
}
|
|
28
|
+
else if (subcommand === "codex") {
|
|
29
|
+
return yield* syncCodex(pos.slice(1), flags);
|
|
30
|
+
}
|
|
31
|
+
const syncSvc = yield* SyncService;
|
|
32
|
+
if (subcommand === "export") {
|
|
33
|
+
const path = opt(flags, "path");
|
|
34
|
+
// Export tasks
|
|
35
|
+
const result = yield* syncSvc.export(path);
|
|
36
|
+
if (flag(flags, "json")) {
|
|
37
|
+
console.log(toJson(result));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log(`Exported ${result.opCount} operation(s) to ${result.path}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (subcommand === "import") {
|
|
44
|
+
const path = opt(flags, "path");
|
|
45
|
+
// Import tasks
|
|
46
|
+
const result = yield* syncSvc.import(path);
|
|
47
|
+
if (flag(flags, "json")) {
|
|
48
|
+
console.log(toJson(result));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(`Tasks: imported=${result.imported}, skipped=${result.skipped}, conflicts=${result.conflicts}`);
|
|
52
|
+
const deps = result.dependencies;
|
|
53
|
+
console.log(`Dependencies: added=${deps.added}, removed=${deps.removed}, skipped=${deps.skipped}, failures=${deps.failures.length}`);
|
|
54
|
+
if (deps.failures.length > 0) {
|
|
55
|
+
console.log(`\nDependency failures:`);
|
|
56
|
+
for (const f of deps.failures) {
|
|
57
|
+
console.log(` ${f.blockerId} -> ${f.blockedId}: ${f.error}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (subcommand === "status") {
|
|
63
|
+
const status = yield* syncSvc.status();
|
|
64
|
+
if (flag(flags, "json")) {
|
|
65
|
+
console.log(toJson(status));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.log(`Sync Status:`);
|
|
69
|
+
console.log(` Tasks in database: ${status.dbTaskCount}`);
|
|
70
|
+
console.log(` Operations in JSONL: ${status.jsonlOpCount}`);
|
|
71
|
+
console.log(` Last export: ${status.lastExport ? status.lastExport.toISOString() : "(never)"}`);
|
|
72
|
+
console.log(` Last import: ${status.lastImport ? status.lastImport.toISOString() : "(never)"}`);
|
|
73
|
+
console.log(` Dirty (unexported changes): ${status.isDirty ? "yes" : "no"}`);
|
|
74
|
+
console.log(` Auto-sync: ${status.autoSyncEnabled ? "enabled" : "disabled"}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (subcommand === "auto") {
|
|
78
|
+
const enableFlag = flag(flags, "enable");
|
|
79
|
+
const disableFlag = flag(flags, "disable");
|
|
80
|
+
if (enableFlag && disableFlag) {
|
|
81
|
+
console.error("Cannot specify both --enable and --disable");
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
if (enableFlag) {
|
|
85
|
+
yield* syncSvc.enableAutoSync();
|
|
86
|
+
if (flag(flags, "json")) {
|
|
87
|
+
console.log(toJson({ autoSync: true }));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.log("Auto-sync enabled");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (disableFlag) {
|
|
94
|
+
yield* syncSvc.disableAutoSync();
|
|
95
|
+
if (flag(flags, "json")) {
|
|
96
|
+
console.log(toJson({ autoSync: false }));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log("Auto-sync disabled");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const enabled = yield* syncSvc.isAutoSyncEnabled();
|
|
104
|
+
if (flag(flags, "json")) {
|
|
105
|
+
console.log(toJson({ autoSync: enabled }));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.log(`Auto-sync: ${enabled ? "enabled" : "disabled"}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (subcommand === "compact") {
|
|
113
|
+
const path = opt(flags, "path");
|
|
114
|
+
const result = yield* syncSvc.compact(path);
|
|
115
|
+
if (flag(flags, "json")) {
|
|
116
|
+
console.log(toJson(result));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
console.log(`Compacted: ${result.before} → ${result.after} operations`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.error(`Unknown sync subcommand: ${subcommand}`);
|
|
124
|
+
console.error(`Run 'tx sync --help' for usage information`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task commands: add, list, show, update, done, delete, reset
|
|
3
|
+
*/
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import { TaskService, ReadyService, AttemptService } from "@jamesaphoenix/tx-core";
|
|
6
|
+
import { type Flags } from "../utils/parse.js";
|
|
7
|
+
export declare const add: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").ValidationError | import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError, TaskService>;
|
|
8
|
+
export declare const list: (_pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").DatabaseError, TaskService>;
|
|
9
|
+
export declare const ready: (_pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").DatabaseError, ReadyService | AttemptService>;
|
|
10
|
+
export declare const show: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError, TaskService | AttemptService>;
|
|
11
|
+
export declare const update: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").ValidationError | import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError | import("@jamesaphoenix/tx-core").StaleDataError, TaskService>;
|
|
12
|
+
export declare const done: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").ValidationError | import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError | import("@jamesaphoenix/tx-core").StaleDataError, TaskService | ReadyService>;
|
|
13
|
+
export declare const deleteTask: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError | import("@jamesaphoenix/tx-core").HasChildrenError, TaskService>;
|
|
14
|
+
export declare const reset: (pos: string[], flags: Flags) => Effect.Effect<void, import("@jamesaphoenix/tx-core").ValidationError | import("@jamesaphoenix/tx-core").DatabaseError | import("@jamesaphoenix/tx-core").TaskNotFoundError | import("@jamesaphoenix/tx-core").StaleDataError, TaskService>;
|
|
15
|
+
//# sourceMappingURL=task.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGlF,OAAO,EAAE,KAAK,KAAK,EAAuC,MAAM,mBAAmB,CAAA;AAEnF,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,6LA0B3C,CAAA;AAEJ,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,EAAE,EAAE,OAAO,KAAK,qFAkC7C,CAAA;AAEJ,eAAO,MAAM,KAAK,GAAI,MAAM,MAAM,EAAE,EAAE,OAAO,KAAK,uGA8B9C,CAAA;AAEJ,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,2JAmC5C,CAAA;AAEJ,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,+OA4B9C,CAAA;AAEJ,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,8PAkC5C,CAAA;AAEJ,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,8LAmBlD,CAAA;AAEJ,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,EAAE,EAAE,OAAO,KAAK,+OAyB7C,CAAA"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task commands: add, list, show, update, done, delete, reset
|
|
3
|
+
*/
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import { TaskService, ReadyService, AttemptService } from "@jamesaphoenix/tx-core";
|
|
6
|
+
import { assertTaskStatus, TASK_STATUSES } from "@jamesaphoenix/tx-types";
|
|
7
|
+
import { toJson, formatTaskWithDeps, formatTaskLine, formatReadyTaskLine } from "../output.js";
|
|
8
|
+
import { flag, opt, parseIntOpt, parseTaskId } from "../utils/parse.js";
|
|
9
|
+
export const add = (pos, flags) => Effect.gen(function* () {
|
|
10
|
+
const title = pos[0];
|
|
11
|
+
if (!title) {
|
|
12
|
+
console.error("Usage: tx add <title> [--parent/-p <id>] [--score/-s <n>] [--description/-d <text>] [--json]");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const svc = yield* TaskService;
|
|
16
|
+
const task = yield* svc.create({
|
|
17
|
+
title,
|
|
18
|
+
description: opt(flags, "description", "d"),
|
|
19
|
+
parentId: opt(flags, "parent", "p"),
|
|
20
|
+
score: parseIntOpt(flags, "score", "score", "s"),
|
|
21
|
+
metadata: {}
|
|
22
|
+
});
|
|
23
|
+
if (flag(flags, "json")) {
|
|
24
|
+
const full = yield* svc.getWithDeps(task.id);
|
|
25
|
+
console.log(toJson(full));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.log(`Created task: ${task.id}`);
|
|
29
|
+
console.log(` Title: ${task.title}`);
|
|
30
|
+
console.log(` Score: ${task.score}`);
|
|
31
|
+
if (task.parentId)
|
|
32
|
+
console.log(` Parent: ${task.parentId}`);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
export const list = (_pos, flags) => Effect.gen(function* () {
|
|
36
|
+
const svc = yield* TaskService;
|
|
37
|
+
const statusFilter = opt(flags, "status");
|
|
38
|
+
const limit = parseIntOpt(flags, "limit", "limit", "n");
|
|
39
|
+
// Validate status values if provided
|
|
40
|
+
let validatedStatuses;
|
|
41
|
+
if (statusFilter) {
|
|
42
|
+
try {
|
|
43
|
+
validatedStatuses = statusFilter.split(",").map(s => assertTaskStatus(s.trim()));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
console.error(`Invalid status filter. Valid statuses: ${TASK_STATUSES.join(", ")}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const tasks = yield* svc.listWithDeps({
|
|
51
|
+
status: validatedStatuses,
|
|
52
|
+
limit
|
|
53
|
+
});
|
|
54
|
+
if (flag(flags, "json")) {
|
|
55
|
+
console.log(toJson(tasks));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
if (tasks.length === 0) {
|
|
59
|
+
console.log("No tasks found");
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log(`${tasks.length} task(s):`);
|
|
63
|
+
for (const t of tasks) {
|
|
64
|
+
console.log(formatTaskLine(t));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
export const ready = (_pos, flags) => Effect.gen(function* () {
|
|
70
|
+
const svc = yield* ReadyService;
|
|
71
|
+
const attemptSvc = yield* AttemptService;
|
|
72
|
+
const limit = parseIntOpt(flags, "limit", "limit", "n") ?? 10;
|
|
73
|
+
const tasks = yield* svc.getReady(limit);
|
|
74
|
+
// Get failed attempt counts for all tasks in a single query
|
|
75
|
+
const taskIds = tasks.map(t => t.id);
|
|
76
|
+
const failedCounts = yield* attemptSvc.getFailedCountsForTasks(taskIds);
|
|
77
|
+
if (flag(flags, "json")) {
|
|
78
|
+
// Add failedAttemptCount to each task in JSON output
|
|
79
|
+
const tasksWithCounts = tasks.map(t => ({
|
|
80
|
+
...t,
|
|
81
|
+
failedAttemptCount: failedCounts.get(t.id) ?? 0
|
|
82
|
+
}));
|
|
83
|
+
console.log(toJson(tasksWithCounts));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
if (tasks.length === 0) {
|
|
87
|
+
console.log("No ready tasks");
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.log(`${tasks.length} ready task(s):`);
|
|
91
|
+
for (const t of tasks) {
|
|
92
|
+
const failedCount = failedCounts.get(t.id) ?? 0;
|
|
93
|
+
const failedWarning = failedCount >= 2 ? ` \u26A0 ${failedCount} failed attempts` : "";
|
|
94
|
+
console.log(formatReadyTaskLine(t) + failedWarning);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
export const show = (pos, flags) => Effect.gen(function* () {
|
|
100
|
+
const raw = pos[0];
|
|
101
|
+
if (!raw) {
|
|
102
|
+
console.error("Usage: tx show <id> [--json]");
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const id = parseTaskId(raw);
|
|
106
|
+
const svc = yield* TaskService;
|
|
107
|
+
const attemptSvc = yield* AttemptService;
|
|
108
|
+
const task = yield* svc.getWithDeps(id);
|
|
109
|
+
// Get up to 10 most recent attempts
|
|
110
|
+
const allAttempts = yield* attemptSvc.listForTask(id);
|
|
111
|
+
const attempts = allAttempts.slice(0, 10);
|
|
112
|
+
if (flag(flags, "json")) {
|
|
113
|
+
console.log(toJson({ ...task, attempts }));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
console.log(formatTaskWithDeps(task));
|
|
117
|
+
// Show attempt history if there are any
|
|
118
|
+
if (attempts.length > 0) {
|
|
119
|
+
console.log("");
|
|
120
|
+
console.log("Previous Attempts:");
|
|
121
|
+
for (const a of attempts) {
|
|
122
|
+
const outcomeSymbol = a.outcome === "succeeded" ? "\u2713" : "\u2717";
|
|
123
|
+
console.log(` ${outcomeSymbol} ${a.approach}`);
|
|
124
|
+
if (a.reason) {
|
|
125
|
+
console.log(` Reason: ${a.reason}`);
|
|
126
|
+
}
|
|
127
|
+
console.log(` ${a.createdAt.toISOString()}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
export const update = (pos, flags) => Effect.gen(function* () {
|
|
133
|
+
const raw = pos[0];
|
|
134
|
+
if (!raw) {
|
|
135
|
+
console.error("Usage: tx update <id> [--status <s>] [--title <t>] [--score <n>] [--description <d>] [--parent <p>] [--json]");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const id = parseTaskId(raw);
|
|
139
|
+
const svc = yield* TaskService;
|
|
140
|
+
const input = {};
|
|
141
|
+
if (opt(flags, "status"))
|
|
142
|
+
input.status = opt(flags, "status");
|
|
143
|
+
if (opt(flags, "title"))
|
|
144
|
+
input.title = opt(flags, "title");
|
|
145
|
+
const scoreVal = parseIntOpt(flags, "score", "score");
|
|
146
|
+
if (scoreVal !== undefined)
|
|
147
|
+
input.score = scoreVal;
|
|
148
|
+
if (opt(flags, "description", "d"))
|
|
149
|
+
input.description = opt(flags, "description", "d");
|
|
150
|
+
if (opt(flags, "parent", "p"))
|
|
151
|
+
input.parentId = opt(flags, "parent", "p");
|
|
152
|
+
yield* svc.update(id, input);
|
|
153
|
+
const task = yield* svc.getWithDeps(id);
|
|
154
|
+
if (flag(flags, "json")) {
|
|
155
|
+
console.log(toJson(task));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
console.log(`Updated: ${task.id}`);
|
|
159
|
+
console.log(` Status: ${task.status}`);
|
|
160
|
+
console.log(` Score: ${task.score}`);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
export const done = (pos, flags) => Effect.gen(function* () {
|
|
164
|
+
const raw = pos[0];
|
|
165
|
+
if (!raw) {
|
|
166
|
+
console.error("Usage: tx done <id> [--json]");
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
const id = parseTaskId(raw);
|
|
170
|
+
const taskSvc = yield* TaskService;
|
|
171
|
+
const readySvc = yield* ReadyService;
|
|
172
|
+
// Get tasks blocked by this one BEFORE marking complete
|
|
173
|
+
const blocking = yield* readySvc.getBlocking(id);
|
|
174
|
+
yield* taskSvc.update(id, { status: "done" });
|
|
175
|
+
const task = yield* taskSvc.getWithDeps(id);
|
|
176
|
+
// Find newly unblocked tasks using batch query
|
|
177
|
+
// Filter to workable statuses and get their full deps info in one batch
|
|
178
|
+
const candidateIds = blocking
|
|
179
|
+
.filter(t => ["backlog", "ready", "planning"].includes(t.status))
|
|
180
|
+
.map(t => t.id);
|
|
181
|
+
const candidatesWithDeps = yield* taskSvc.getWithDepsBatch(candidateIds);
|
|
182
|
+
const nowReady = candidatesWithDeps.filter(t => t.isReady).map(t => t.id);
|
|
183
|
+
if (flag(flags, "json")) {
|
|
184
|
+
console.log(toJson({ task, nowReady }));
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.log(`Completed: ${task.id} - ${task.title}`);
|
|
188
|
+
if (nowReady.length > 0) {
|
|
189
|
+
console.log(`Now unblocked: ${nowReady.join(", ")}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
export const deleteTask = (pos, flags) => Effect.gen(function* () {
|
|
194
|
+
const raw = pos[0];
|
|
195
|
+
if (!raw) {
|
|
196
|
+
console.error("Usage: tx delete <id> [--cascade] [--json]");
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
const id = parseTaskId(raw);
|
|
200
|
+
const cascade = flag(flags, "cascade");
|
|
201
|
+
const svc = yield* TaskService;
|
|
202
|
+
const task = yield* svc.getWithDeps(id);
|
|
203
|
+
yield* svc.remove(id, { cascade });
|
|
204
|
+
if (flag(flags, "json")) {
|
|
205
|
+
console.log(toJson({ success: true, message: `Deleted task ${task.id}`, data: { id: task.id, title: task.title, cascade } }));
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.log(`Deleted: ${task.id} - ${task.title}${cascade ? " (with children)" : ""}`);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
export const reset = (pos, flags) => Effect.gen(function* () {
|
|
212
|
+
const raw = pos[0];
|
|
213
|
+
if (!raw) {
|
|
214
|
+
console.error("Usage: tx reset <id> [--json]");
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
const id = parseTaskId(raw);
|
|
218
|
+
const taskSvc = yield* TaskService;
|
|
219
|
+
// Get current task to show what we're resetting from
|
|
220
|
+
const before = yield* taskSvc.getWithDeps(id);
|
|
221
|
+
const oldStatus = before.status;
|
|
222
|
+
// Force update to ready status (bypass normal validation)
|
|
223
|
+
yield* taskSvc.forceStatus(id, "ready");
|
|
224
|
+
const task = yield* taskSvc.getWithDeps(id);
|
|
225
|
+
if (flag(flags, "json")) {
|
|
226
|
+
console.log(toJson({ task, oldStatus }));
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
console.log(`Reset: ${task.id} - ${task.title}`);
|
|
230
|
+
console.log(` ${oldStatus} -> ready`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
//# sourceMappingURL=task.js.map
|