@inteeka/task-cli 0.2.14 → 0.2.15
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.js +171 -33
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1731,6 +1731,95 @@ async function runProjectTest(args) {
|
|
|
1731
1731
|
});
|
|
1732
1732
|
}
|
|
1733
1733
|
|
|
1734
|
+
// src/util/progress.ts
|
|
1735
|
+
import { mkdir as mkdir6, writeFile as writeFile7, rename, unlink as unlink3, readdir, stat as stat2 } from "fs/promises";
|
|
1736
|
+
import { tmpdir } from "os";
|
|
1737
|
+
import { join as join7 } from "path";
|
|
1738
|
+
var PROGRESS_DIR = join7(tmpdir(), "task-progress");
|
|
1739
|
+
var STALE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
1740
|
+
var ProgressWriter = class {
|
|
1741
|
+
path;
|
|
1742
|
+
command;
|
|
1743
|
+
ticketId;
|
|
1744
|
+
writeInFlight = Promise.resolve();
|
|
1745
|
+
cleanedUp = false;
|
|
1746
|
+
constructor(command, ticketId) {
|
|
1747
|
+
this.command = command;
|
|
1748
|
+
this.ticketId = ticketId;
|
|
1749
|
+
const deliveryId = process.env["TASK_DELIVERY_ID"]?.trim();
|
|
1750
|
+
const fileBase = deliveryId && deliveryId.length > 0 ? deliveryId : `manual-${process.pid}`;
|
|
1751
|
+
this.path = join7(PROGRESS_DIR, `${fileBase}.json`);
|
|
1752
|
+
}
|
|
1753
|
+
/** Switch the in-flight ticket between phases (used by `task scan` which iterates). */
|
|
1754
|
+
setTicketId(ticketId) {
|
|
1755
|
+
this.ticketId = ticketId;
|
|
1756
|
+
}
|
|
1757
|
+
/** Write a phase transition. Failures are swallowed. */
|
|
1758
|
+
async setPhase(phase, extra) {
|
|
1759
|
+
if (this.cleanedUp) return;
|
|
1760
|
+
const deliveryId = process.env["TASK_DELIVERY_ID"]?.trim() ?? "";
|
|
1761
|
+
const payload = {
|
|
1762
|
+
schema_version: 1,
|
|
1763
|
+
delivery_id: deliveryId,
|
|
1764
|
+
ticket_id: this.ticketId,
|
|
1765
|
+
command: this.command,
|
|
1766
|
+
phase,
|
|
1767
|
+
phase_started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1768
|
+
...extra?.progress !== void 0 ? { phase_progress: extra.progress } : {},
|
|
1769
|
+
...extra?.detail !== void 0 ? { phase_detail: extra.detail.slice(0, 200) } : {}
|
|
1770
|
+
};
|
|
1771
|
+
this.writeInFlight = this.writeInFlight.then(() => this.writeAtomic(payload)).catch(() => {
|
|
1772
|
+
});
|
|
1773
|
+
await this.writeInFlight;
|
|
1774
|
+
}
|
|
1775
|
+
/** Remove the sidecar file. Idempotent; safe to call from finally. */
|
|
1776
|
+
async cleanup() {
|
|
1777
|
+
if (this.cleanedUp) return;
|
|
1778
|
+
this.cleanedUp = true;
|
|
1779
|
+
await this.writeInFlight.catch(() => {
|
|
1780
|
+
});
|
|
1781
|
+
await unlink3(this.path).catch(() => {
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
async writeAtomic(payload) {
|
|
1785
|
+
await mkdir6(PROGRESS_DIR, { recursive: true }).catch(() => {
|
|
1786
|
+
});
|
|
1787
|
+
const body = JSON.stringify(payload);
|
|
1788
|
+
const tmp = `${this.path}.tmp`;
|
|
1789
|
+
try {
|
|
1790
|
+
await writeFile7(tmp, body, { encoding: "utf8", mode: 384 });
|
|
1791
|
+
await rename(tmp, this.path);
|
|
1792
|
+
} catch {
|
|
1793
|
+
await unlink3(tmp).catch(() => {
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
/**
|
|
1798
|
+
* Delete sidecar files older than 24 h. Run once at CLI startup so
|
|
1799
|
+
* crashed runs from prior days don't accumulate in /tmp.
|
|
1800
|
+
*/
|
|
1801
|
+
static async sweepStale() {
|
|
1802
|
+
try {
|
|
1803
|
+
const entries = await readdir(PROGRESS_DIR);
|
|
1804
|
+
const cutoff = Date.now() - STALE_MAX_AGE_MS;
|
|
1805
|
+
await Promise.all(
|
|
1806
|
+
entries.filter((name) => name.endsWith(".json") || name.endsWith(".json.tmp")).map(async (name) => {
|
|
1807
|
+
const p = join7(PROGRESS_DIR, name);
|
|
1808
|
+
try {
|
|
1809
|
+
const s = await stat2(p);
|
|
1810
|
+
if (s.mtimeMs < cutoff) {
|
|
1811
|
+
await unlink3(p).catch(() => {
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
} catch {
|
|
1815
|
+
}
|
|
1816
|
+
})
|
|
1817
|
+
);
|
|
1818
|
+
} catch {
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1734
1823
|
// src/commands/work.ts
|
|
1735
1824
|
async function buildWorkContext(opts) {
|
|
1736
1825
|
const project = await readProjectConfig(findRepoRoot());
|
|
@@ -1762,6 +1851,7 @@ function registerWork(program2) {
|
|
|
1762
1851
|
});
|
|
1763
1852
|
}
|
|
1764
1853
|
async function runWork(ticketId, opts) {
|
|
1854
|
+
void ProgressWriter.sweepStale();
|
|
1765
1855
|
const ctx = await buildWorkContext(opts);
|
|
1766
1856
|
const max = opts.next ? 1 : Math.max(1, parseInt(opts.max, 10) || 1);
|
|
1767
1857
|
let processed = 0;
|
|
@@ -1788,7 +1878,21 @@ async function runWork(ticketId, opts) {
|
|
|
1788
1878
|
}
|
|
1789
1879
|
}
|
|
1790
1880
|
async function processOneTicket(ctx, opts, ticketIdHint) {
|
|
1881
|
+
const progress = new ProgressWriter("task work", ticketIdHint);
|
|
1882
|
+
try {
|
|
1883
|
+
return await processOneTicketImpl(ctx, opts, ticketIdHint, progress);
|
|
1884
|
+
} catch (err) {
|
|
1885
|
+
await progress.setPhase("failed", {
|
|
1886
|
+
detail: err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200)
|
|
1887
|
+
});
|
|
1888
|
+
throw err;
|
|
1889
|
+
} finally {
|
|
1890
|
+
await progress.cleanup();
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
async function processOneTicketImpl(ctx, opts, ticketIdHint, progress) {
|
|
1791
1894
|
const { cwd, baseBranch, silent } = ctx;
|
|
1895
|
+
await progress.setPhase("starting");
|
|
1792
1896
|
if (opts.reset) {
|
|
1793
1897
|
await purgeWorkingTreeWithConsent(ctx, opts);
|
|
1794
1898
|
}
|
|
@@ -1809,6 +1913,7 @@ async function processOneTicket(ctx, opts, ticketIdHint) {
|
|
|
1809
1913
|
}
|
|
1810
1914
|
const targetId = ticketIdHint ?? (opts.auto || opts.next ? await pickNextEligible(ctx.project.project_id) : await promptForTicket(ctx.project.project_id));
|
|
1811
1915
|
if (!targetId) return { kind: "no_eligible" };
|
|
1916
|
+
progress.setTicketId(targetId);
|
|
1812
1917
|
const detail = await apiCallOrThrow("GET", `/api/v1/cli/me/tickets/${targetId}`);
|
|
1813
1918
|
if (detail.ai_fix_status !== "approved" && detail.ai_fix_status !== "building") {
|
|
1814
1919
|
throw new CliError(
|
|
@@ -1962,6 +2067,9 @@ ${approvedFix.risk_notes}` : "",
|
|
|
1962
2067
|
${detail.ai_fix_approval_notes}` : ""
|
|
1963
2068
|
].filter(Boolean) : []
|
|
1964
2069
|
].join("\n");
|
|
2070
|
+
await progress.setPhase("analysing", {
|
|
2071
|
+
detail: `Claude is working on #${detail.sequence_number}`
|
|
2072
|
+
});
|
|
1965
2073
|
const agentResult = await runAgent({
|
|
1966
2074
|
ticketSystemPrompt: "You are a software engineer fixing a bug or implementing a small feature. An approved fix proposal is included in the ticket block as DATA \u2014 verify it against the actual code before acting on it. Read the code, make minimal targeted edits, and stop. Run tests if relevant.",
|
|
1967
2075
|
projectProtectedPaths: detail.project_protected_paths,
|
|
@@ -2059,6 +2167,9 @@ ${detail.ai_fix_approval_notes}` : ""
|
|
|
2059
2167
|
});
|
|
2060
2168
|
return { kind: "dry_run", sequenceNumber: detail.sequence_number, branchName };
|
|
2061
2169
|
}
|
|
2170
|
+
await progress.setPhase("testing", {
|
|
2171
|
+
detail: testCommand ?? "pnpm typecheck"
|
|
2172
|
+
});
|
|
2062
2173
|
if (!silent)
|
|
2063
2174
|
process.stdout.write(c.dim(` running pre-push test: ${testCommand ?? "pnpm typecheck"}
|
|
2064
2175
|
`));
|
|
@@ -2106,6 +2217,7 @@ ${detail.ai_fix_approval_notes}` : ""
|
|
|
2106
2217
|
if (!silent)
|
|
2107
2218
|
process.stdout.write(c.dim(` ${c.ok("\u2713")} tests passed in ${testResult.durationMs}ms
|
|
2108
2219
|
`));
|
|
2220
|
+
await progress.setPhase("committing");
|
|
2109
2221
|
const commitMessage = `task: ${detail.title}
|
|
2110
2222
|
|
|
2111
2223
|
Resolves ticket #${detail.sequence_number} via the agentic CLI.
|
|
@@ -2137,6 +2249,7 @@ Claude session: ${runId}
|
|
|
2137
2249
|
}
|
|
2138
2250
|
throw new CliError(CLI_EXIT_CODES.GENERIC_ERROR, msg);
|
|
2139
2251
|
}
|
|
2252
|
+
await progress.setPhase("pushing", { detail: branchName });
|
|
2140
2253
|
try {
|
|
2141
2254
|
pushBranch(cwd, branchName);
|
|
2142
2255
|
} catch (err) {
|
|
@@ -2166,6 +2279,7 @@ Claude session: ${runId}
|
|
|
2166
2279
|
});
|
|
2167
2280
|
let prNumber;
|
|
2168
2281
|
let prUrl;
|
|
2282
|
+
await progress.setPhase("opening_pr");
|
|
2169
2283
|
try {
|
|
2170
2284
|
const prResp = await apiCallOrThrow("POST", `/api/v1/cli/me/tickets/${detail.id}/pull-requests`, {
|
|
2171
2285
|
body: {
|
|
@@ -2218,6 +2332,9 @@ Claude session: ${runId}
|
|
|
2218
2332
|
claude_session_id: runId
|
|
2219
2333
|
}
|
|
2220
2334
|
});
|
|
2335
|
+
await progress.setPhase("done", {
|
|
2336
|
+
detail: prUrl ? `PR ${prUrl}` : void 0
|
|
2337
|
+
});
|
|
2221
2338
|
return {
|
|
2222
2339
|
kind: "completed",
|
|
2223
2340
|
sequenceNumber: detail.sequence_number,
|
|
@@ -3058,9 +3175,9 @@ function autopilotExitCode(code, status) {
|
|
|
3058
3175
|
|
|
3059
3176
|
// src/scan/llm.ts
|
|
3060
3177
|
import { spawn as spawn3 } from "child_process";
|
|
3061
|
-
import { mkdir as
|
|
3178
|
+
import { mkdir as mkdir7, writeFile as writeFile8 } from "fs/promises";
|
|
3062
3179
|
import { homedir as homedir5 } from "os";
|
|
3063
|
-
import { join as
|
|
3180
|
+
import { join as join8 } from "path";
|
|
3064
3181
|
var FIX_PROMPT_JSON_SCHEMA = {
|
|
3065
3182
|
type: "object",
|
|
3066
3183
|
// Phase 3 — confidence_reason is REQUIRED unconditionally so the
|
|
@@ -3275,10 +3392,10 @@ function readEnvelopeTokens(raw, userPrompt, innerText) {
|
|
|
3275
3392
|
async function maybeDumpDebug(ticketId, stdout, stderr) {
|
|
3276
3393
|
if (!DEBUG && stdout.length === 0 && stderr.length === 0) return null;
|
|
3277
3394
|
try {
|
|
3278
|
-
const dir =
|
|
3279
|
-
await
|
|
3280
|
-
const path =
|
|
3281
|
-
await
|
|
3395
|
+
const dir = join8(homedir5(), ".cache", "task", "scan-debug");
|
|
3396
|
+
await mkdir7(dir, { recursive: true });
|
|
3397
|
+
const path = join8(dir, `${ticketId}-${Date.now()}.log`);
|
|
3398
|
+
await writeFile8(
|
|
3282
3399
|
path,
|
|
3283
3400
|
["## ticket_id", ticketId, "", "## stdout", stdout, "", "## stderr", stderr].join("\n")
|
|
3284
3401
|
);
|
|
@@ -3356,6 +3473,22 @@ function registerScan(program2) {
|
|
|
3356
3473
|
});
|
|
3357
3474
|
}
|
|
3358
3475
|
async function runScan(opts) {
|
|
3476
|
+
void ProgressWriter.sweepStale();
|
|
3477
|
+
const progress = new ProgressWriter("task scan", null);
|
|
3478
|
+
await progress.setPhase("starting");
|
|
3479
|
+
try {
|
|
3480
|
+
await runScanImpl(opts, progress);
|
|
3481
|
+
await progress.setPhase("done");
|
|
3482
|
+
} catch (err) {
|
|
3483
|
+
await progress.setPhase("failed", {
|
|
3484
|
+
detail: err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200)
|
|
3485
|
+
});
|
|
3486
|
+
throw err;
|
|
3487
|
+
} finally {
|
|
3488
|
+
await progress.cleanup();
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
async function runScanImpl(opts, progress) {
|
|
3359
3492
|
const apiKey = process.env["TASK_API_KEY"];
|
|
3360
3493
|
if (!apiKey || apiKey.length < 32) {
|
|
3361
3494
|
throw new CliError(
|
|
@@ -3445,7 +3578,8 @@ async function runScan(opts) {
|
|
|
3445
3578
|
batchSize,
|
|
3446
3579
|
silent,
|
|
3447
3580
|
claudePath,
|
|
3448
|
-
isInterrupted: () => interrupted
|
|
3581
|
+
isInterrupted: () => interrupted,
|
|
3582
|
+
progress
|
|
3449
3583
|
});
|
|
3450
3584
|
aggregates.push(agg);
|
|
3451
3585
|
}
|
|
@@ -3474,7 +3608,7 @@ async function runScan(opts) {
|
|
|
3474
3608
|
}
|
|
3475
3609
|
}
|
|
3476
3610
|
async function scanProject(args) {
|
|
3477
|
-
const { api, project, maxSubmits, batchSize, silent, claudePath } = args;
|
|
3611
|
+
const { api, project, maxSubmits, batchSize, silent, claudePath, progress } = args;
|
|
3478
3612
|
const agg = {
|
|
3479
3613
|
project_id: project.project_id,
|
|
3480
3614
|
project_slug: project.project_slug,
|
|
@@ -3516,6 +3650,10 @@ ${c.bold(`${project.organisation_slug}/${project.project_slug}`)} ${c.dim(`(${pr
|
|
|
3516
3650
|
if (args.isInterrupted()) break;
|
|
3517
3651
|
inFlight.add(ticket.ticket_id);
|
|
3518
3652
|
const spinner = silent ? null : ora2(`#${ticket.sequence_number} ${ticket.title.slice(0, 60)}`).start();
|
|
3653
|
+
progress.setTicketId(ticket.ticket_id);
|
|
3654
|
+
await progress.setPhase("analysing", {
|
|
3655
|
+
detail: `Generating fix prompt for #${ticket.sequence_number}`
|
|
3656
|
+
});
|
|
3519
3657
|
try {
|
|
3520
3658
|
const generated = await safeGenerate(ticket, claudePath);
|
|
3521
3659
|
if (!generated.ok) {
|
|
@@ -3748,9 +3886,9 @@ import { randomUUID as randomUUID3 } from "crypto";
|
|
|
3748
3886
|
import { platform as platform2 } from "os";
|
|
3749
3887
|
|
|
3750
3888
|
// src/scheduler/launchd.ts
|
|
3751
|
-
import { mkdir as
|
|
3889
|
+
import { mkdir as mkdir8, readFile as readFile5, writeFile as writeFile9, unlink as unlink4, readdir as readdir2 } from "fs/promises";
|
|
3752
3890
|
import { homedir as homedir6 } from "os";
|
|
3753
|
-
import { join as
|
|
3891
|
+
import { join as join9 } from "path";
|
|
3754
3892
|
import { execFileSync as execFileSync9, spawn as spawn4 } from "child_process";
|
|
3755
3893
|
|
|
3756
3894
|
// src/scheduler/cron-translate.ts
|
|
@@ -3852,14 +3990,14 @@ function expandField(field, min, max) {
|
|
|
3852
3990
|
}
|
|
3853
3991
|
|
|
3854
3992
|
// src/scheduler/launchd.ts
|
|
3855
|
-
var PLIST_DIR =
|
|
3993
|
+
var PLIST_DIR = join9(homedir6(), "Library", "LaunchAgents");
|
|
3856
3994
|
var LABEL_PREFIX = "com.inteeka.task.cli.";
|
|
3857
3995
|
var SAFE_ID_RE = /^[0-9a-zA-Z._-]+$/;
|
|
3858
3996
|
function plistPath(id) {
|
|
3859
3997
|
if (!SAFE_ID_RE.test(id) || id.includes("..")) {
|
|
3860
3998
|
throw new Error(`Refusing to compute plist path for unsafe id: ${id}`);
|
|
3861
3999
|
}
|
|
3862
|
-
return
|
|
4000
|
+
return join9(PLIST_DIR, `${LABEL_PREFIX}${id}.plist`);
|
|
3863
4001
|
}
|
|
3864
4002
|
function buildPlist(entry) {
|
|
3865
4003
|
const calendars = translateToLaunchd(entry.cron);
|
|
@@ -3895,9 +4033,9 @@ ${fields}
|
|
|
3895
4033
|
` <string>/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin</string>`,
|
|
3896
4034
|
` </dict>`,
|
|
3897
4035
|
` <key>StandardOutPath</key>`,
|
|
3898
|
-
` <string>${escapeXml(
|
|
4036
|
+
` <string>${escapeXml(join9(homedir6(), ".cache", "task", "launchd-stdout.log"))}</string>`,
|
|
3899
4037
|
` <key>StandardErrorPath</key>`,
|
|
3900
|
-
` <string>${escapeXml(
|
|
4038
|
+
` <string>${escapeXml(join9(homedir6(), ".cache", "task", "launchd-stderr.log"))}</string>`,
|
|
3901
4039
|
!entry.enabled ? ` <key>Disabled</key>
|
|
3902
4040
|
<true/>` : "",
|
|
3903
4041
|
"</dict>",
|
|
@@ -3915,9 +4053,9 @@ function bootstrapDomain() {
|
|
|
3915
4053
|
}
|
|
3916
4054
|
var launchdAdapter = {
|
|
3917
4055
|
async upsert(entry) {
|
|
3918
|
-
await
|
|
4056
|
+
await mkdir8(PLIST_DIR, { recursive: true });
|
|
3919
4057
|
const path = plistPath(entry.id);
|
|
3920
|
-
await
|
|
4058
|
+
await writeFile9(path, buildPlist(entry));
|
|
3921
4059
|
try {
|
|
3922
4060
|
execFileSync9("launchctl", ["bootout", bootstrapDomain(), path], { stdio: "ignore" });
|
|
3923
4061
|
} catch {
|
|
@@ -3933,20 +4071,20 @@ var launchdAdapter = {
|
|
|
3933
4071
|
} catch {
|
|
3934
4072
|
}
|
|
3935
4073
|
try {
|
|
3936
|
-
await
|
|
4074
|
+
await unlink4(path);
|
|
3937
4075
|
} catch (err) {
|
|
3938
4076
|
if (err.code !== "ENOENT") throw err;
|
|
3939
4077
|
}
|
|
3940
4078
|
},
|
|
3941
4079
|
async list() {
|
|
3942
4080
|
try {
|
|
3943
|
-
const entries = await
|
|
4081
|
+
const entries = await readdir2(PLIST_DIR);
|
|
3944
4082
|
const ours = entries.filter((f) => f.startsWith(LABEL_PREFIX) && f.endsWith(".plist"));
|
|
3945
4083
|
const out = [];
|
|
3946
4084
|
for (const file of ours) {
|
|
3947
4085
|
const id = file.slice(LABEL_PREFIX.length, -".plist".length);
|
|
3948
4086
|
try {
|
|
3949
|
-
const xml = await readFile5(
|
|
4087
|
+
const xml = await readFile5(join9(PLIST_DIR, file), "utf8");
|
|
3950
4088
|
const cron = xml.match(/<key>StartCalendarInterval<\/key>[\s\S]*?<\/array>/)?.[0] ?? "";
|
|
3951
4089
|
const command = xml.match(/<key>ProgramArguments<\/key>\s*<array>([\s\S]*?)<\/array>/)?.[1] ?? "";
|
|
3952
4090
|
const disabled = /<key>Disabled<\/key>\s*<true\/>/.test(xml);
|
|
@@ -3992,7 +4130,7 @@ var launchdAdapter = {
|
|
|
3992
4130
|
}
|
|
3993
4131
|
if (enabled) {
|
|
3994
4132
|
xml = xml.replace(/\s*<key>Disabled<\/key>\s*<true\/>/, "");
|
|
3995
|
-
await
|
|
4133
|
+
await writeFile9(path, xml);
|
|
3996
4134
|
try {
|
|
3997
4135
|
execFileSync9("launchctl", ["bootout", bootstrapDomain(), path], { stdio: "ignore" });
|
|
3998
4136
|
} catch {
|
|
@@ -4004,7 +4142,7 @@ var launchdAdapter = {
|
|
|
4004
4142
|
"</dict>\n</plist>",
|
|
4005
4143
|
" <key>Disabled</key>\n <true/>\n</dict>\n</plist>"
|
|
4006
4144
|
);
|
|
4007
|
-
await
|
|
4145
|
+
await writeFile9(path, xml);
|
|
4008
4146
|
}
|
|
4009
4147
|
try {
|
|
4010
4148
|
execFileSync9("launchctl", ["bootout", bootstrapDomain(), path], { stdio: "ignore" });
|
|
@@ -4357,10 +4495,10 @@ var unsupportedAdapter = {
|
|
|
4357
4495
|
};
|
|
4358
4496
|
|
|
4359
4497
|
// src/scheduler/registry.ts
|
|
4360
|
-
import { mkdir as
|
|
4498
|
+
import { mkdir as mkdir9, readFile as readFile6, writeFile as writeFile10 } from "fs/promises";
|
|
4361
4499
|
import { homedir as homedir7 } from "os";
|
|
4362
|
-
import { dirname as dirname4, join as
|
|
4363
|
-
var REGISTRY_PATH =
|
|
4500
|
+
import { dirname as dirname4, join as join10 } from "path";
|
|
4501
|
+
var REGISTRY_PATH = join10(homedir7(), ".config", "task", "schedules.json");
|
|
4364
4502
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4365
4503
|
function looksLikeRegistryRow(value) {
|
|
4366
4504
|
if (!value || typeof value !== "object") return false;
|
|
@@ -4380,8 +4518,8 @@ async function readRegistry() {
|
|
|
4380
4518
|
}
|
|
4381
4519
|
}
|
|
4382
4520
|
async function writeRegistry(rows) {
|
|
4383
|
-
await
|
|
4384
|
-
await
|
|
4521
|
+
await mkdir9(dirname4(REGISTRY_PATH), { recursive: true });
|
|
4522
|
+
await writeFile10(REGISTRY_PATH, JSON.stringify(rows, null, 2));
|
|
4385
4523
|
}
|
|
4386
4524
|
async function upsertRegistry(row) {
|
|
4387
4525
|
if (!UUID_RE.test(row.id)) {
|
|
@@ -4622,7 +4760,7 @@ function stripAnsi(s) {
|
|
|
4622
4760
|
// src/commands/runs.ts
|
|
4623
4761
|
import { readFile as readFile7 } from "fs/promises";
|
|
4624
4762
|
import { homedir as homedir8 } from "os";
|
|
4625
|
-
import { join as
|
|
4763
|
+
import { join as join11 } from "path";
|
|
4626
4764
|
function registerRuns(program2) {
|
|
4627
4765
|
const cmd = program2.command("runs").description("Inspect agentic CLI run history");
|
|
4628
4766
|
cmd.command("list").description("List recent runs").option("--limit <n>", "Max rows", "50").option("--ticket <id>", "Filter by ticket").option("--schedule <id>", "Filter by schedule").action(async (opts) => {
|
|
@@ -4651,7 +4789,7 @@ function registerRuns(program2) {
|
|
|
4651
4789
|
process.stdout.write(JSON.stringify(row, null, 2) + "\n");
|
|
4652
4790
|
});
|
|
4653
4791
|
cmd.command("logs <id>").description("Show captured agent output for a run, if available").action(async (id) => {
|
|
4654
|
-
const localPath =
|
|
4792
|
+
const localPath = join11(homedir8(), ".cache", "task", "runs", `${id}.log`);
|
|
4655
4793
|
try {
|
|
4656
4794
|
const text = await readFile7(localPath, "utf8");
|
|
4657
4795
|
process.stdout.write(text);
|
|
@@ -4724,8 +4862,8 @@ function registerConfig(program2) {
|
|
|
4724
4862
|
|
|
4725
4863
|
// src/commands/doctor.ts
|
|
4726
4864
|
import { execFileSync as execFileSync12 } from "child_process";
|
|
4727
|
-
import { readFile as readFile8, writeFile as
|
|
4728
|
-
import { join as
|
|
4865
|
+
import { readFile as readFile8, writeFile as writeFile11 } from "fs/promises";
|
|
4866
|
+
import { join as join12 } from "path";
|
|
4729
4867
|
import { request as request5 } from "undici";
|
|
4730
4868
|
var ALLOWED_TEST_EXECUTABLES = /* @__PURE__ */ new Set(["pnpm", "npm", "yarn", "bun", "node", "npx"]);
|
|
4731
4869
|
var DEFAULT_TEST_COMMAND = "pnpm typecheck";
|
|
@@ -4890,7 +5028,7 @@ async function checkPrePushTest(root, configuredCommand, fix) {
|
|
|
4890
5028
|
detail: `${command} (non-script executable, not statically verifiable)`
|
|
4891
5029
|
};
|
|
4892
5030
|
}
|
|
4893
|
-
const pkgPath =
|
|
5031
|
+
const pkgPath = join12(root, "package.json");
|
|
4894
5032
|
let pkgRaw;
|
|
4895
5033
|
try {
|
|
4896
5034
|
pkgRaw = await readFile8(pkgPath, "utf8");
|
|
@@ -4926,7 +5064,7 @@ async function checkPrePushTest(root, configuredCommand, fix) {
|
|
|
4926
5064
|
pkg.scripts = { ...scripts, typecheck: "tsc --noEmit" };
|
|
4927
5065
|
const indent = detectIndent(pkgRaw);
|
|
4928
5066
|
const trailingNewline = pkgRaw.endsWith("\n") ? "\n" : "";
|
|
4929
|
-
await
|
|
5067
|
+
await writeFile11(pkgPath, JSON.stringify(pkg, null, indent) + trailingNewline);
|
|
4930
5068
|
return {
|
|
4931
5069
|
name: "pre-push test",
|
|
4932
5070
|
ok: true,
|
|
@@ -4975,7 +5113,7 @@ function checkBinary(name, command) {
|
|
|
4975
5113
|
}
|
|
4976
5114
|
|
|
4977
5115
|
// src/commands/version.ts
|
|
4978
|
-
var CLI_VERSION = true ? "0.2.
|
|
5116
|
+
var CLI_VERSION = true ? "0.2.15" : "0.0.0-dev";
|
|
4979
5117
|
function registerVersion(program2) {
|
|
4980
5118
|
program2.command("version").description("Print the CLI version").action(() => {
|
|
4981
5119
|
process.stdout.write(CLI_VERSION + "\n");
|