@chit-run/cli 0.5.0 → 0.6.0
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/chit.js +204 -111
- package/package.json +1 -1
package/dist/chit.js
CHANGED
|
@@ -970,6 +970,7 @@ function validateLoopRecord(raw) {
|
|
|
970
970
|
scope: str2(o, "scope", ctx),
|
|
971
971
|
task: str2(o, "task", ctx),
|
|
972
972
|
repo: str2(o, "repo", ctx),
|
|
973
|
+
repoKey: str2(o, "repoKey", ctx),
|
|
973
974
|
startedAt: str2(o, "startedAt", ctx),
|
|
974
975
|
maxIterations: int2(o, "maxIterations", ctx, 1)
|
|
975
976
|
};
|
|
@@ -988,8 +989,11 @@ function validateLoopRecord(raw) {
|
|
|
988
989
|
checkDurationMs: int2(o, "checkDurationMs", ctx, 0),
|
|
989
990
|
at: str2(o, "at", ctx)
|
|
990
991
|
};
|
|
991
|
-
if (o.
|
|
992
|
-
rec.
|
|
992
|
+
if (o.workspaceWarnings !== undefined) {
|
|
993
|
+
rec.workspaceWarnings = stringArray2(o, "workspaceWarnings", ctx);
|
|
994
|
+
}
|
|
995
|
+
if (o.auditRef !== undefined)
|
|
996
|
+
rec.auditRef = str2(o, "auditRef", ctx);
|
|
993
997
|
const usage = optUsage2(o, ctx);
|
|
994
998
|
if (usage !== undefined)
|
|
995
999
|
rec.usage = usage;
|
|
@@ -9964,11 +9968,11 @@ var init_dist = __esm(() => {
|
|
|
9964
9968
|
|
|
9965
9969
|
// ../studio/src/server/audit.ts
|
|
9966
9970
|
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
|
|
9967
|
-
import { homedir as
|
|
9968
|
-
import { join as
|
|
9971
|
+
import { homedir as homedir6 } from "os";
|
|
9972
|
+
import { join as join9 } from "path";
|
|
9969
9973
|
function defaultAuditDir2() {
|
|
9970
|
-
const xdg = process.env.XDG_STATE_HOME ||
|
|
9971
|
-
return
|
|
9974
|
+
const xdg = process.env.XDG_STATE_HOME || join9(homedir6(), ".local", "state");
|
|
9975
|
+
return join9(xdg, "chit", "audit");
|
|
9972
9976
|
}
|
|
9973
9977
|
function blobRefs(e) {
|
|
9974
9978
|
switch (e.type) {
|
|
@@ -9987,8 +9991,8 @@ function blobRefs(e) {
|
|
|
9987
9991
|
function readAuditRun(auditDir, runId, includeBlobs) {
|
|
9988
9992
|
if (!SAFE_RUN_ID2.test(runId))
|
|
9989
9993
|
return { kind: "invalid-id" };
|
|
9990
|
-
const runDir =
|
|
9991
|
-
const eventsPath =
|
|
9994
|
+
const runDir = join9(auditDir, "runs", runId);
|
|
9995
|
+
const eventsPath = join9(runDir, "events.jsonl");
|
|
9992
9996
|
if (!existsSync8(eventsPath))
|
|
9993
9997
|
return { kind: "not-found" };
|
|
9994
9998
|
let events2;
|
|
@@ -10001,13 +10005,13 @@ function readAuditRun(auditDir, runId, includeBlobs) {
|
|
|
10001
10005
|
}
|
|
10002
10006
|
if (!includeBlobs)
|
|
10003
10007
|
return { kind: "ok", events: events2 };
|
|
10004
|
-
const blobsDir =
|
|
10008
|
+
const blobsDir = join9(runDir, "blobs");
|
|
10005
10009
|
const blobs = {};
|
|
10006
10010
|
for (const e of events2) {
|
|
10007
10011
|
for (const ref of blobRefs(e)) {
|
|
10008
10012
|
if (!SHA256_HEX2.test(ref) || ref in blobs)
|
|
10009
10013
|
continue;
|
|
10010
|
-
const blobPath =
|
|
10014
|
+
const blobPath = join9(blobsDir, ref);
|
|
10011
10015
|
if (existsSync8(blobPath))
|
|
10012
10016
|
blobs[ref] = readFileSync9(blobPath, "utf-8");
|
|
10013
10017
|
}
|
|
@@ -10094,7 +10098,7 @@ var init_paths = __esm(() => {
|
|
|
10094
10098
|
|
|
10095
10099
|
// ../studio/src/server/discovery.ts
|
|
10096
10100
|
import { readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
|
|
10097
|
-
import { basename, join as
|
|
10101
|
+
import { basename, join as join10, relative } from "path";
|
|
10098
10102
|
function safeParseChit(absolutePath) {
|
|
10099
10103
|
try {
|
|
10100
10104
|
const raw2 = JSON.parse(readFileSync10(absolutePath, "utf-8"));
|
|
@@ -10124,7 +10128,7 @@ function discover(opts) {
|
|
|
10124
10128
|
continue;
|
|
10125
10129
|
if (!entry.name.endsWith(".json"))
|
|
10126
10130
|
continue;
|
|
10127
|
-
const absolutePath =
|
|
10131
|
+
const absolutePath = join10(opts.cwd, entry.name);
|
|
10128
10132
|
if (!safeParseChit(absolutePath))
|
|
10129
10133
|
continue;
|
|
10130
10134
|
candidates.push({
|
|
@@ -10149,14 +10153,14 @@ var init_discovery = __esm(() => {
|
|
|
10149
10153
|
});
|
|
10150
10154
|
|
|
10151
10155
|
// ../studio/src/server/docs.ts
|
|
10152
|
-
import { createHash as
|
|
10156
|
+
import { createHash as createHash6 } from "crypto";
|
|
10153
10157
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
|
|
10154
10158
|
import { basename as basename2, relative as relative2 } from "path";
|
|
10155
10159
|
function canonicalize(draft) {
|
|
10156
10160
|
return JSON.stringify(draft, null, "\t");
|
|
10157
10161
|
}
|
|
10158
10162
|
function hashRaw(raw2) {
|
|
10159
|
-
return
|
|
10163
|
+
return createHash6("sha256").update(raw2, "utf-8").digest("hex");
|
|
10160
10164
|
}
|
|
10161
10165
|
|
|
10162
10166
|
class DocStore {
|
|
@@ -10363,10 +10367,7 @@ var init_docs = __esm(() => {
|
|
|
10363
10367
|
|
|
10364
10368
|
// ../studio/src/server/loops.ts
|
|
10365
10369
|
import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
|
|
10366
|
-
import { join as
|
|
10367
|
-
function loopsDir2(cwd) {
|
|
10368
|
-
return join10(cwd, ".chit", "loops");
|
|
10369
|
-
}
|
|
10370
|
+
import { join as join11 } from "path";
|
|
10370
10371
|
function summarize(loopId, records) {
|
|
10371
10372
|
const header = records[0];
|
|
10372
10373
|
if (header?.type !== "loop")
|
|
@@ -10383,26 +10384,8 @@ function summarize(loopId, records) {
|
|
|
10383
10384
|
startedAt: header.startedAt
|
|
10384
10385
|
};
|
|
10385
10386
|
}
|
|
10386
|
-
function
|
|
10387
|
-
const
|
|
10388
|
-
if (!existsSync10(dir))
|
|
10389
|
-
return [];
|
|
10390
|
-
const summaries = [];
|
|
10391
|
-
for (const name of readdirSync4(dir)) {
|
|
10392
|
-
if (!name.endsWith(".jsonl"))
|
|
10393
|
-
continue;
|
|
10394
|
-
const loopId = name.slice(0, -".jsonl".length);
|
|
10395
|
-
const result = readLoop2(cwd, loopId);
|
|
10396
|
-
if (result.kind === "ok")
|
|
10397
|
-
summaries.push(summarize(loopId, result.records));
|
|
10398
|
-
}
|
|
10399
|
-
summaries.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
10400
|
-
return summaries;
|
|
10401
|
-
}
|
|
10402
|
-
function readLoop2(cwd, loopId) {
|
|
10403
|
-
if (!SAFE_LOOP_ID2.test(loopId))
|
|
10404
|
-
return { kind: "invalid-id" };
|
|
10405
|
-
const path = join10(loopsDir2(cwd), `${loopId}.jsonl`);
|
|
10387
|
+
function readLoopFrom(dir, loopId) {
|
|
10388
|
+
const path = join11(dir, `${loopId}.jsonl`);
|
|
10406
10389
|
if (!existsSync10(path))
|
|
10407
10390
|
return { kind: "not-found" };
|
|
10408
10391
|
try {
|
|
@@ -10418,6 +10401,30 @@ function readLoop2(cwd, loopId) {
|
|
|
10418
10401
|
throw e;
|
|
10419
10402
|
}
|
|
10420
10403
|
}
|
|
10404
|
+
function listLoops(loopsDir) {
|
|
10405
|
+
if (!loopsDir || !existsSync10(loopsDir))
|
|
10406
|
+
return [];
|
|
10407
|
+
const summaries = [];
|
|
10408
|
+
for (const name of readdirSync4(loopsDir)) {
|
|
10409
|
+
if (!name.endsWith(".jsonl"))
|
|
10410
|
+
continue;
|
|
10411
|
+
const loopId = name.slice(0, -".jsonl".length);
|
|
10412
|
+
if (!SAFE_LOOP_ID2.test(loopId))
|
|
10413
|
+
continue;
|
|
10414
|
+
const result = readLoopFrom(loopsDir, loopId);
|
|
10415
|
+
if (result.kind === "ok")
|
|
10416
|
+
summaries.push(summarize(loopId, result.records));
|
|
10417
|
+
}
|
|
10418
|
+
summaries.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
10419
|
+
return summaries;
|
|
10420
|
+
}
|
|
10421
|
+
function readLoop2(loopsDir, loopId) {
|
|
10422
|
+
if (!SAFE_LOOP_ID2.test(loopId))
|
|
10423
|
+
return { kind: "invalid-id" };
|
|
10424
|
+
if (!loopsDir)
|
|
10425
|
+
return { kind: "not-found" };
|
|
10426
|
+
return readLoopFrom(loopsDir, loopId);
|
|
10427
|
+
}
|
|
10421
10428
|
var SAFE_LOOP_ID2;
|
|
10422
10429
|
var init_loops = __esm(() => {
|
|
10423
10430
|
init_src();
|
|
@@ -10456,7 +10463,7 @@ __export(exports_server, {
|
|
|
10456
10463
|
PathError: () => PathError
|
|
10457
10464
|
});
|
|
10458
10465
|
import { existsSync as existsSync11 } from "fs";
|
|
10459
|
-
import { join as
|
|
10466
|
+
import { join as join12 } from "path";
|
|
10460
10467
|
async function startStudio(opts) {
|
|
10461
10468
|
const hostname3 = opts.hostname ?? "127.0.0.1";
|
|
10462
10469
|
const requestedPort = opts.port ?? 0;
|
|
@@ -10474,7 +10481,8 @@ async function startStudio(opts) {
|
|
|
10474
10481
|
store,
|
|
10475
10482
|
allowedHosts,
|
|
10476
10483
|
clientDistDir,
|
|
10477
|
-
lifecycle: opts.lifecycle
|
|
10484
|
+
lifecycle: opts.lifecycle,
|
|
10485
|
+
loopsDir: opts.loopsDir
|
|
10478
10486
|
});
|
|
10479
10487
|
const server2 = Bun.serve({
|
|
10480
10488
|
port: requestedPort,
|
|
@@ -10508,7 +10516,7 @@ function buildApp(opts) {
|
|
|
10508
10516
|
const asset = c.req.param("asset");
|
|
10509
10517
|
if (!CLIENT_ASSETS.has(asset))
|
|
10510
10518
|
return c.text("not found", 404);
|
|
10511
|
-
const path =
|
|
10519
|
+
const path = join12(opts.clientDistDir, asset);
|
|
10512
10520
|
if (!existsSync11(path)) {
|
|
10513
10521
|
return c.text(`client bundle missing at ${path}. Run: bun run studio:build`, 503);
|
|
10514
10522
|
}
|
|
@@ -10589,10 +10597,10 @@ function buildApp(opts) {
|
|
|
10589
10597
|
return c.json(result);
|
|
10590
10598
|
});
|
|
10591
10599
|
app.get("/api/loops", (c) => {
|
|
10592
|
-
return c.json(listLoops(opts.
|
|
10600
|
+
return c.json(listLoops(opts.loopsDir));
|
|
10593
10601
|
});
|
|
10594
10602
|
app.get("/api/loops/:loopId", (c) => {
|
|
10595
|
-
const result = readLoop2(opts.
|
|
10603
|
+
const result = readLoop2(opts.loopsDir, c.req.param("loopId"));
|
|
10596
10604
|
if (result.kind === "not-found")
|
|
10597
10605
|
return c.text("not found", 404);
|
|
10598
10606
|
if (result.kind === "invalid-id")
|
|
@@ -10684,15 +10692,15 @@ var init_server = __esm(() => {
|
|
|
10684
10692
|
init_loops();
|
|
10685
10693
|
init_token();
|
|
10686
10694
|
init_paths();
|
|
10687
|
-
CLIENT_DIST =
|
|
10695
|
+
CLIENT_DIST = join12(import.meta.dir, "..", "..", "dist", "client");
|
|
10688
10696
|
CLIENT_ASSETS = new Set(["index.js", "index.css"]);
|
|
10689
10697
|
});
|
|
10690
10698
|
|
|
10691
10699
|
// src/cli/run.ts
|
|
10692
10700
|
init_src();
|
|
10693
10701
|
import { readFileSync as readFileSync13 } from "fs";
|
|
10694
|
-
import { homedir as
|
|
10695
|
-
import { basename as basename3, dirname as dirname2, join as
|
|
10702
|
+
import { homedir as homedir7 } from "os";
|
|
10703
|
+
import { basename as basename3, dirname as dirname2, join as join13 } from "path";
|
|
10696
10704
|
|
|
10697
10705
|
// src/adapters/sanitize.ts
|
|
10698
10706
|
var SENSITIVE_KEY = /key|token|secret|password|auth/i;
|
|
@@ -11596,6 +11604,45 @@ function wrapAdaptersWithAudit(adapters, recorder) {
|
|
|
11596
11604
|
return out;
|
|
11597
11605
|
}
|
|
11598
11606
|
|
|
11607
|
+
// src/loops/location.ts
|
|
11608
|
+
import { spawnSync } from "child_process";
|
|
11609
|
+
import { createHash as createHash2 } from "crypto";
|
|
11610
|
+
import { realpathSync } from "fs";
|
|
11611
|
+
import { homedir as homedir3 } from "os";
|
|
11612
|
+
import { join as join3 } from "path";
|
|
11613
|
+
function gitTopLevel(cwd) {
|
|
11614
|
+
try {
|
|
11615
|
+
const out = spawnSync("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
|
|
11616
|
+
encoding: "utf-8",
|
|
11617
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
11618
|
+
});
|
|
11619
|
+
if (out.status !== 0)
|
|
11620
|
+
return;
|
|
11621
|
+
const top = out.stdout.trim();
|
|
11622
|
+
return top || undefined;
|
|
11623
|
+
} catch {
|
|
11624
|
+
return;
|
|
11625
|
+
}
|
|
11626
|
+
}
|
|
11627
|
+
function repoRoot(cwd) {
|
|
11628
|
+
const base = gitTopLevel(cwd) ?? cwd;
|
|
11629
|
+
try {
|
|
11630
|
+
return realpathSync(base);
|
|
11631
|
+
} catch {
|
|
11632
|
+
return base;
|
|
11633
|
+
}
|
|
11634
|
+
}
|
|
11635
|
+
function repoKey(cwd) {
|
|
11636
|
+
return createHash2("sha256").update(repoRoot(cwd)).digest("hex").slice(0, 16);
|
|
11637
|
+
}
|
|
11638
|
+
function loopStateDir() {
|
|
11639
|
+
const xdg = process.env.XDG_STATE_HOME || join3(homedir3(), ".local", "state");
|
|
11640
|
+
return join3(xdg, "chit", "loops");
|
|
11641
|
+
}
|
|
11642
|
+
function loopLogDir(cwd) {
|
|
11643
|
+
return join3(loopStateDir(), repoKey(cwd));
|
|
11644
|
+
}
|
|
11645
|
+
|
|
11599
11646
|
// src/runtime/render.ts
|
|
11600
11647
|
import { existsSync as existsSync3 } from "fs";
|
|
11601
11648
|
import { isAbsolute, resolve } from "path";
|
|
@@ -11818,7 +11865,7 @@ async function executeManifest(manifest, options) {
|
|
|
11818
11865
|
}
|
|
11819
11866
|
|
|
11820
11867
|
// src/sessions/fingerprint.ts
|
|
11821
|
-
import { createHash as
|
|
11868
|
+
import { createHash as createHash3 } from "crypto";
|
|
11822
11869
|
function computeFingerprint(input) {
|
|
11823
11870
|
const { agent, participant } = input;
|
|
11824
11871
|
const baseUrl = agent.env?.ANTHROPIC_BASE_URL ?? agent.env?.OPENAI_BASE_URL ?? agent.env?.OLLAMA_HOST ?? "";
|
|
@@ -11834,7 +11881,7 @@ function computeFingerprint(input) {
|
|
|
11834
11881
|
session: participant.session,
|
|
11835
11882
|
permissions: participant.permissions
|
|
11836
11883
|
});
|
|
11837
|
-
return
|
|
11884
|
+
return createHash3("sha256").update(material).digest("hex").slice(0, 16);
|
|
11838
11885
|
}
|
|
11839
11886
|
|
|
11840
11887
|
// src/sessions/coordinator.ts
|
|
@@ -11886,7 +11933,7 @@ function buildSessionAdapter(inner, manifestId, scope, trackedFingerprints, stor
|
|
|
11886
11933
|
}
|
|
11887
11934
|
|
|
11888
11935
|
// src/sessions/store.ts
|
|
11889
|
-
import { createHash as
|
|
11936
|
+
import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
|
|
11890
11937
|
import {
|
|
11891
11938
|
closeSync,
|
|
11892
11939
|
existsSync as existsSync4,
|
|
@@ -11898,8 +11945,8 @@ import {
|
|
|
11898
11945
|
writeFileSync as writeFileSync2,
|
|
11899
11946
|
writeSync
|
|
11900
11947
|
} from "fs";
|
|
11901
|
-
import { homedir as
|
|
11902
|
-
import { dirname, join as
|
|
11948
|
+
import { homedir as homedir4 } from "os";
|
|
11949
|
+
import { dirname, join as join4 } from "path";
|
|
11903
11950
|
function isObject4(v) {
|
|
11904
11951
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
11905
11952
|
}
|
|
@@ -11916,8 +11963,8 @@ function sleepSync(ms) {
|
|
|
11916
11963
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
11917
11964
|
}
|
|
11918
11965
|
function defaultSessionDir() {
|
|
11919
|
-
const xdg = process.env.XDG_STATE_HOME ||
|
|
11920
|
-
return
|
|
11966
|
+
const xdg = process.env.XDG_STATE_HOME || join4(homedir4(), ".local", "state");
|
|
11967
|
+
return join4(xdg, "chit", "sessions");
|
|
11921
11968
|
}
|
|
11922
11969
|
|
|
11923
11970
|
class FileSessionStore {
|
|
@@ -12012,16 +12059,16 @@ class FileSessionStore {
|
|
|
12012
12059
|
}
|
|
12013
12060
|
filePath(key) {
|
|
12014
12061
|
const readable = `${safeSegment(key.scope)}--${safeSegment(key.manifestId)}`;
|
|
12015
|
-
const hash =
|
|
12016
|
-
return
|
|
12062
|
+
const hash = createHash4("sha256").update(`${key.scope}${HASH_SEP}${key.manifestId}`).digest("hex").slice(0, 12);
|
|
12063
|
+
return join4(this.baseDir, `${readable}--${hash}.json`);
|
|
12017
12064
|
}
|
|
12018
12065
|
}
|
|
12019
12066
|
|
|
12020
12067
|
// src/surfaces/claude-skill.ts
|
|
12021
12068
|
init_src();
|
|
12022
|
-
import { createHash as
|
|
12069
|
+
import { createHash as createHash5, randomBytes } from "crypto";
|
|
12023
12070
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
12024
|
-
import { join as
|
|
12071
|
+
import { join as join5, resolve as resolvePath } from "path";
|
|
12025
12072
|
class SurfaceInstallError extends Error {
|
|
12026
12073
|
constructor(message) {
|
|
12027
12074
|
super(message);
|
|
@@ -12083,7 +12130,7 @@ ${formatEnforcementGaps(gaps)}
|
|
|
12083
12130
|
Pass allowUnenforcedPermissions=true to install anyway; the generated skill will warn on every run.`);
|
|
12084
12131
|
}
|
|
12085
12132
|
const installName = opts.overrideName ?? manifest.id;
|
|
12086
|
-
const skillDir =
|
|
12133
|
+
const skillDir = join5(outputDir, installName);
|
|
12087
12134
|
if (existsSync5(skillDir)) {
|
|
12088
12135
|
if (!opts.force) {
|
|
12089
12136
|
throw new SurfaceInstallError(`skill directory already exists: ${skillDir}
|
|
@@ -12093,9 +12140,9 @@ Pass force=true to remove and replace it, or use overrideName="<id>" to install
|
|
|
12093
12140
|
rmSync3(skillDir, { recursive: true, force: true });
|
|
12094
12141
|
}
|
|
12095
12142
|
mkdirSync3(skillDir, { recursive: true });
|
|
12096
|
-
const skillMdPath =
|
|
12097
|
-
const manifestPath =
|
|
12098
|
-
const markerPath =
|
|
12143
|
+
const skillMdPath = join5(skillDir, "SKILL.md");
|
|
12144
|
+
const manifestPath = join5(skillDir, "manifest.json");
|
|
12145
|
+
const markerPath = join5(skillDir, INSTALL_MARKER_FILENAME);
|
|
12099
12146
|
const manifestJson = `${JSON.stringify(rawJson, null, 2)}
|
|
12100
12147
|
`;
|
|
12101
12148
|
writeFileSync3(manifestPath, manifestJson);
|
|
@@ -12115,7 +12162,7 @@ Pass force=true to remove and replace it, or use overrideName="<id>" to install
|
|
|
12115
12162
|
manifestId: manifest.id,
|
|
12116
12163
|
runtimePath,
|
|
12117
12164
|
installedAt: new Date().toISOString(),
|
|
12118
|
-
manifestHash:
|
|
12165
|
+
manifestHash: createHash5("sha256").update(manifestJson).digest("hex")
|
|
12119
12166
|
};
|
|
12120
12167
|
writeFileSync3(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
12121
12168
|
`);
|
|
@@ -12182,10 +12229,10 @@ function escapeFrontmatter(s) {
|
|
|
12182
12229
|
// src/surfaces/lifecycle.ts
|
|
12183
12230
|
init_src();
|
|
12184
12231
|
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync4, statSync as statSync2 } from "fs";
|
|
12185
|
-
import { homedir as
|
|
12186
|
-
import { join as
|
|
12232
|
+
import { homedir as homedir5 } from "os";
|
|
12233
|
+
import { join as join6 } from "path";
|
|
12187
12234
|
function defaultSkillsDir() {
|
|
12188
|
-
return
|
|
12235
|
+
return join6(homedir5(), ".claude", "skills");
|
|
12189
12236
|
}
|
|
12190
12237
|
|
|
12191
12238
|
class LifecycleError extends Error {
|
|
@@ -12200,7 +12247,7 @@ function listInstalled(parentDir) {
|
|
|
12200
12247
|
const out = [];
|
|
12201
12248
|
const entries = readdirSync2(parentDir);
|
|
12202
12249
|
for (const name of entries) {
|
|
12203
|
-
const skillDir =
|
|
12250
|
+
const skillDir = join6(parentDir, name);
|
|
12204
12251
|
let stat;
|
|
12205
12252
|
try {
|
|
12206
12253
|
stat = statSync2(skillDir);
|
|
@@ -12209,7 +12256,7 @@ function listInstalled(parentDir) {
|
|
|
12209
12256
|
}
|
|
12210
12257
|
if (!stat.isDirectory())
|
|
12211
12258
|
continue;
|
|
12212
|
-
const markerPath =
|
|
12259
|
+
const markerPath = join6(skillDir, INSTALL_MARKER_FILENAME);
|
|
12213
12260
|
if (!existsSync6(markerPath))
|
|
12214
12261
|
continue;
|
|
12215
12262
|
let raw;
|
|
@@ -12229,14 +12276,14 @@ function uninstall(parentDir, name) {
|
|
|
12229
12276
|
if (!VALID_INSTALL_NAME_RE.test(name)) {
|
|
12230
12277
|
throw new LifecycleError(`install name "${name}" is invalid: must be kebab-case (lowercase letters, digits, hyphens; must start with a letter). Path-traversal sequences like ".." or "/" are rejected.`);
|
|
12231
12278
|
}
|
|
12232
|
-
const skillDir =
|
|
12279
|
+
const skillDir = join6(parentDir, name);
|
|
12233
12280
|
if (!existsSync6(skillDir)) {
|
|
12234
12281
|
throw new LifecycleError(`no install at ${skillDir}`);
|
|
12235
12282
|
}
|
|
12236
12283
|
if (!statSync2(skillDir).isDirectory()) {
|
|
12237
12284
|
throw new LifecycleError(`${skillDir} is not a directory`);
|
|
12238
12285
|
}
|
|
12239
|
-
const markerPath =
|
|
12286
|
+
const markerPath = join6(skillDir, INSTALL_MARKER_FILENAME);
|
|
12240
12287
|
if (!existsSync6(markerPath)) {
|
|
12241
12288
|
throw new LifecycleError(`refusing to uninstall ${skillDir}: no install marker (${INSTALL_MARKER_FILENAME}) present. ` + `This directory was not created by chit (or was created by a pre-marker version). ` + `If you're sure this is yours, remove it manually with rm -rf.`);
|
|
12242
12289
|
}
|
|
@@ -35061,8 +35108,7 @@ import { resolve as resolve2 } from "path";
|
|
|
35061
35108
|
// src/loops/log-store.ts
|
|
35062
35109
|
init_src();
|
|
35063
35110
|
import { appendFileSync as appendFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
35064
|
-
import { join as
|
|
35065
|
-
|
|
35111
|
+
import { join as join7 } from "path";
|
|
35066
35112
|
class LoopStoreError extends Error {
|
|
35067
35113
|
}
|
|
35068
35114
|
var SAFE_LOOP_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
@@ -35070,14 +35116,14 @@ var realClock2 = () => Date.now();
|
|
|
35070
35116
|
function iso(ms) {
|
|
35071
35117
|
return new Date(ms).toISOString();
|
|
35072
35118
|
}
|
|
35073
|
-
function
|
|
35074
|
-
return join6(cwd, ".chit", "loops");
|
|
35075
|
-
}
|
|
35076
|
-
function loopPath(cwd, loopId) {
|
|
35119
|
+
function safeId(loopId) {
|
|
35077
35120
|
if (!SAFE_LOOP_ID.test(loopId)) {
|
|
35078
35121
|
throw new LoopStoreError(`invalid loop id ${JSON.stringify(loopId)}`);
|
|
35079
35122
|
}
|
|
35080
|
-
return
|
|
35123
|
+
return loopId;
|
|
35124
|
+
}
|
|
35125
|
+
function loopPath(cwd, loopId) {
|
|
35126
|
+
return join7(loopLogDir(cwd), `${safeId(loopId)}.jsonl`);
|
|
35081
35127
|
}
|
|
35082
35128
|
function readRecords(path, loopId) {
|
|
35083
35129
|
if (!existsSync7(path)) {
|
|
@@ -35096,14 +35142,15 @@ function startLoop(cwd, opts) {
|
|
|
35096
35142
|
if (existsSync7(path) && !opts.force) {
|
|
35097
35143
|
throw new LoopStoreError(`loop log already exists at ${path} (pass force to overwrite)`);
|
|
35098
35144
|
}
|
|
35099
|
-
mkdirSync4(
|
|
35145
|
+
mkdirSync4(loopLogDir(cwd), { recursive: true });
|
|
35100
35146
|
const header = {
|
|
35101
35147
|
type: "loop",
|
|
35102
35148
|
schema: 1,
|
|
35103
35149
|
loopId,
|
|
35104
35150
|
scope: opts.scope,
|
|
35105
35151
|
task: opts.task,
|
|
35106
|
-
repo: cwd,
|
|
35152
|
+
repo: repoRoot(cwd),
|
|
35153
|
+
repoKey: repoKey(cwd),
|
|
35107
35154
|
startedAt: iso((opts.clock ?? realClock2)()),
|
|
35108
35155
|
maxIterations: opts.maxIterations
|
|
35109
35156
|
};
|
|
@@ -35134,8 +35181,11 @@ function appendIteration(cwd, loopId, opts) {
|
|
|
35134
35181
|
checkDurationMs: opts.checkDurationMs,
|
|
35135
35182
|
at: iso((opts.clock ?? realClock2)())
|
|
35136
35183
|
};
|
|
35137
|
-
if (opts.
|
|
35138
|
-
rec.
|
|
35184
|
+
if (opts.workspaceWarnings !== undefined && opts.workspaceWarnings.length > 0) {
|
|
35185
|
+
rec.workspaceWarnings = opts.workspaceWarnings;
|
|
35186
|
+
}
|
|
35187
|
+
if (opts.auditRef !== undefined)
|
|
35188
|
+
rec.auditRef = opts.auditRef;
|
|
35139
35189
|
if (opts.usage !== undefined)
|
|
35140
35190
|
rec.usage = opts.usage;
|
|
35141
35191
|
appendFileSync2(path, `${serializeLoopRecord(rec)}
|
|
@@ -35172,7 +35222,7 @@ function readLoop(cwd, loopId) {
|
|
|
35172
35222
|
var DEFAULT_CONVERGE_MANIFEST = {
|
|
35173
35223
|
schema: 1,
|
|
35174
35224
|
id: "converge",
|
|
35175
|
-
description: "Autonomous convergence: a write-capable Claude implements a slice, then a read-only Codex reviews the diff and returns proceed/revise/block. Drive it in a loop with the `chit converge` CLI driver, or stepwise from the MCP - one
|
|
35225
|
+
description: "Autonomous convergence: a write-capable Claude implements a slice, then a read-only Codex reviews the diff and returns proceed/revise/block. Drive it in a loop with the `chit converge` CLI driver, or stepwise from the MCP - one chit_run_start per iteration, same scope so both agents keep their thread, feeding the prior review back in via inputs.prior_review. The human sequences and checkpoints (inspect the diff each round, stop if it goes sideways); chit runs the agents. Run against an isolated worktree, not the main checkout.",
|
|
35176
35226
|
inputs: {
|
|
35177
35227
|
task: { type: "string" },
|
|
35178
35228
|
prior_review: { type: "string", optional: true }
|
|
@@ -35189,7 +35239,7 @@ var DEFAULT_CONVERGE_MANIFEST = {
|
|
|
35189
35239
|
},
|
|
35190
35240
|
reviewer: {
|
|
35191
35241
|
agent: "codex",
|
|
35192
|
-
role: "You are a skeptical implementation reviewer for a convergence loop. Claude just edited the repository at your cwd. Inspect the current git diff and the changed files, verify the work against the task, and
|
|
35242
|
+
role: "You are a skeptical implementation reviewer for a convergence loop. Claude just edited the repository at your cwd. Inspect the current git diff and the changed files, and verify the work against the task. Base your verdict on the TASK changes. Untracked generated build artifacts (e.g. __pycache__, *.pyc) are workspace hygiene, not task changes: note them at most as a minor aside and do NOT revise solely because of them. chit keeps its own control-plane state outside the repo, so it never appears in the diff. Run non-mutating checks if useful. Do not edit. Do not agree for the sake of agreeing. Use prior context from this scope. Cite file:line and command results.",
|
|
35193
35243
|
session: "per_scope",
|
|
35194
35244
|
permissions: { filesystem: "read_only" }
|
|
35195
35245
|
}
|
|
@@ -35238,6 +35288,32 @@ findingCount is the integer number of findings; checksRun is a short human strin
|
|
|
35238
35288
|
output: "out"
|
|
35239
35289
|
};
|
|
35240
35290
|
|
|
35291
|
+
// src/cli/workspace.ts
|
|
35292
|
+
function isChitOwned(path) {
|
|
35293
|
+
return path === ".chit" || path.startsWith(".chit/");
|
|
35294
|
+
}
|
|
35295
|
+
function isGeneratedArtifact(path) {
|
|
35296
|
+
const base = path.slice(path.lastIndexOf("/") + 1);
|
|
35297
|
+
return path === "__pycache__" || path.startsWith("__pycache__/") || path.includes("/__pycache__/") || path.endsWith(".pyc") || path.endsWith(".pyo") || base === ".DS_Store";
|
|
35298
|
+
}
|
|
35299
|
+
function classifyWorkspace(snap) {
|
|
35300
|
+
const changed = new Set;
|
|
35301
|
+
for (const f of snap.tracked) {
|
|
35302
|
+
if (!isChitOwned(f))
|
|
35303
|
+
changed.add(f);
|
|
35304
|
+
}
|
|
35305
|
+
const workspaceWarnings = [];
|
|
35306
|
+
for (const f of snap.untracked) {
|
|
35307
|
+
if (isChitOwned(f))
|
|
35308
|
+
continue;
|
|
35309
|
+
if (isGeneratedArtifact(f))
|
|
35310
|
+
workspaceWarnings.push(`untracked generated artifact: ${f}`);
|
|
35311
|
+
else
|
|
35312
|
+
changed.add(f);
|
|
35313
|
+
}
|
|
35314
|
+
return { changedFiles: [...changed], workspaceWarnings };
|
|
35315
|
+
}
|
|
35316
|
+
|
|
35241
35317
|
// src/cli/converge.ts
|
|
35242
35318
|
var defaultIO = {
|
|
35243
35319
|
out: (s) => process.stdout.write(s),
|
|
@@ -35330,13 +35406,14 @@ function gitLines(cwd, args) {
|
|
|
35330
35406
|
return [];
|
|
35331
35407
|
}
|
|
35332
35408
|
}
|
|
35333
|
-
function
|
|
35334
|
-
|
|
35335
|
-
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35409
|
+
function gitWorkspace(cwd) {
|
|
35410
|
+
return classifyWorkspace({
|
|
35411
|
+
tracked: [
|
|
35412
|
+
...gitLines(cwd, ["diff", "--name-only"]),
|
|
35413
|
+
...gitLines(cwd, ["diff", "--cached", "--name-only"])
|
|
35414
|
+
],
|
|
35415
|
+
untracked: gitLines(cwd, ["ls-files", "--others", "--exclude-standard"])
|
|
35416
|
+
});
|
|
35340
35417
|
}
|
|
35341
35418
|
|
|
35342
35419
|
class ConvergeExecuteError extends Error {
|
|
@@ -35366,17 +35443,18 @@ async function runConvergeIteration(ctx) {
|
|
|
35366
35443
|
const reviewText = result.outputs.review ?? "";
|
|
35367
35444
|
const review = parseReview(reviewText);
|
|
35368
35445
|
const usage = sumTraceUsage(result.trace);
|
|
35369
|
-
const changedFiles =
|
|
35446
|
+
const { changedFiles, workspaceWarnings } = gitWorkspace(ctx.cwd);
|
|
35370
35447
|
appendIteration(ctx.cwd, ctx.loopId, {
|
|
35371
35448
|
implementSummary: capSummary(result.outputs.implement ?? ""),
|
|
35372
35449
|
changedFiles,
|
|
35450
|
+
workspaceWarnings,
|
|
35373
35451
|
checksRun: review.checksRun,
|
|
35374
35452
|
verdict: review.verdict,
|
|
35375
35453
|
findingCount: review.findingCount,
|
|
35376
35454
|
decision: review.verdict,
|
|
35377
35455
|
checkDurationMs: reviewDurationMs(result.trace),
|
|
35378
35456
|
...usage && { usage },
|
|
35379
|
-
...result.auditRunId && {
|
|
35457
|
+
...result.auditRunId && { auditRef: result.auditRunId }
|
|
35380
35458
|
});
|
|
35381
35459
|
const stopStatus = review.verdict === "proceed" ? "converged" : review.verdict === "block" ? "blocked" : undefined;
|
|
35382
35460
|
return {
|
|
@@ -35386,6 +35464,7 @@ async function runConvergeIteration(ctx) {
|
|
|
35386
35464
|
checksRun: review.checksRun,
|
|
35387
35465
|
decision: review.verdict,
|
|
35388
35466
|
changedFiles,
|
|
35467
|
+
workspaceWarnings,
|
|
35389
35468
|
...usage && { usage },
|
|
35390
35469
|
...result.auditRunId && { auditRunId: result.auditRunId },
|
|
35391
35470
|
reviewText,
|
|
@@ -35512,8 +35591,8 @@ var CONVERGE_HELP = `chit converge --task <text> --scope <id> [options]
|
|
|
35512
35591
|
adapter cannot enforce (emits a warning each run).
|
|
35513
35592
|
Default off: such a manifest is refused before running.
|
|
35514
35593
|
|
|
35515
|
-
Runs the implement/check loop to convergence and records it under
|
|
35516
|
-
.
|
|
35594
|
+
Runs the implement/check loop to convergence and records it under chit's
|
|
35595
|
+
state dir (keyed by repo, not in the worktree). Stops at the reviewer's verdict: proceed ->
|
|
35517
35596
|
converged, block -> blocked, else revise and retry up to the budget. An
|
|
35518
35597
|
unparseable verdict is treated as block (never an implicit proceed).
|
|
35519
35598
|
`;
|
|
@@ -35764,6 +35843,7 @@ async function runNextIteration(session, signal) {
|
|
|
35764
35843
|
findingCount: iter.findingCount,
|
|
35765
35844
|
checksRun: iter.checksRun,
|
|
35766
35845
|
changedFiles: iter.changedFiles,
|
|
35846
|
+
workspaceWarnings: iter.workspaceWarnings,
|
|
35767
35847
|
...iter.usage !== undefined && { usage: iter.usage },
|
|
35768
35848
|
...iter.auditRunId !== undefined && { auditRunId: iter.auditRunId },
|
|
35769
35849
|
...session.terminalStatus !== undefined && { stopStatus: session.terminalStatus }
|
|
@@ -35878,7 +35958,7 @@ function startRun(runId, opts) {
|
|
|
35878
35958
|
}
|
|
35879
35959
|
const needsScope = Object.values(manifest.participants).some((p) => p.session === "per_scope");
|
|
35880
35960
|
if (needsScope && opts.scope === undefined) {
|
|
35881
|
-
throw new RuntimeError(`manifest "${manifest.id}" has per_scope participant(s); a scope is required (pass scope to
|
|
35961
|
+
throw new RuntimeError(`manifest "${manifest.id}" has per_scope participant(s); a scope is required (pass scope to chit_run_start)`);
|
|
35882
35962
|
}
|
|
35883
35963
|
const baseAdapters = {};
|
|
35884
35964
|
for (const p of Object.values(manifest.participants)) {
|
|
@@ -36179,7 +36259,7 @@ function describeRun(run) {
|
|
|
36179
36259
|
audit: run.recorder && run.recorder.lastError === undefined ? { runId: run.runId } : undefined
|
|
36180
36260
|
};
|
|
36181
36261
|
}
|
|
36182
|
-
server.registerTool("
|
|
36262
|
+
server.registerTool("chit_run_start", {
|
|
36183
36263
|
description: "Start a stepwise run of a chit manifest. Returns a run_id and the steps ready to run. chit owns the declared order; only ready steps can be run. Then call chit_run_step for each ready step.",
|
|
36184
36264
|
inputSchema: {
|
|
36185
36265
|
manifest_path: exports_external.string().describe("Path to the manifest .json (absolute, or relative to cwd)"),
|
|
@@ -36215,7 +36295,7 @@ server.registerTool("chit_start", {
|
|
|
36215
36295
|
runs.add(run, Date.now());
|
|
36216
36296
|
return jsonResult(describeRun(run));
|
|
36217
36297
|
});
|
|
36218
|
-
server.registerTool("
|
|
36298
|
+
server.registerTool("chit_run_next", {
|
|
36219
36299
|
description: "List the steps ready to run next for a run, or report that the run is complete.",
|
|
36220
36300
|
inputSchema: { run_id: exports_external.string() }
|
|
36221
36301
|
}, async ({ run_id }) => {
|
|
@@ -36274,7 +36354,7 @@ server.registerTool("chit_run_step", {
|
|
|
36274
36354
|
runs.touch(run_id, Date.now());
|
|
36275
36355
|
}
|
|
36276
36356
|
});
|
|
36277
|
-
server.registerTool("
|
|
36357
|
+
server.registerTool("chit_run_cancel", {
|
|
36278
36358
|
description: "Cancel a step that is currently running: aborts its controller, which kills the agent's child process and settles the step as cancelled (terminal, blocks dependents). Returns cancelled:true if it stopped a running step, or a reason (already_done | not_running) otherwise. Use after interrupting a long step.",
|
|
36279
36359
|
inputSchema: { run_id: exports_external.string(), step_id: exports_external.string() }
|
|
36280
36360
|
}, async ({ run_id, step_id }) => {
|
|
@@ -36291,7 +36371,7 @@ server.registerTool("chit_cancel", {
|
|
|
36291
36371
|
...describeRun(run)
|
|
36292
36372
|
});
|
|
36293
36373
|
});
|
|
36294
|
-
server.registerTool("
|
|
36374
|
+
server.registerTool("chit_run_trace", {
|
|
36295
36375
|
description: "Return the transcript of a run so far: each step's status, participant, agent, elapsed, and output.",
|
|
36296
36376
|
inputSchema: { run_id: exports_external.string() }
|
|
36297
36377
|
}, async ({ run_id }) => {
|
|
@@ -36349,7 +36429,7 @@ Pass allow_unenforced_permissions=true to run anyway.`
|
|
|
36349
36429
|
return { ok: true, execute: buildExecute(manifest, registry3, scope, cwd), warnings };
|
|
36350
36430
|
}
|
|
36351
36431
|
server.registerTool("chit_converge_start", {
|
|
36352
|
-
description: "Start an autonomous converge loop (a write-capable implementer slices the task, a read-only reviewer checks the diff) driven one iteration at a time. Returns a loop_id and the next action. Then call chit_converge_next per iteration. Records
|
|
36432
|
+
description: "Start an autonomous converge loop (a write-capable implementer slices the task, a read-only reviewer checks the diff) driven one iteration at a time. Returns a loop_id and the next action. Then call chit_converge_next per iteration. Records the loop under chit's state dir (keyed by repo), identical to `chit converge`.",
|
|
36353
36433
|
inputSchema: {
|
|
36354
36434
|
task: exports_external.string().describe("The slice to converge on"),
|
|
36355
36435
|
scope: exports_external.string().describe("Session scope id; both agents keep their thread across iterations"),
|
|
@@ -36454,6 +36534,7 @@ server.registerTool("chit_converge_next", {
|
|
|
36454
36534
|
findingCount: result.findingCount,
|
|
36455
36535
|
checksRun: result.checksRun,
|
|
36456
36536
|
changedFiles: result.changedFiles,
|
|
36537
|
+
workspaceWarnings: result.workspaceWarnings,
|
|
36457
36538
|
...result.usage && { usage: result.usage },
|
|
36458
36539
|
...result.auditRunId && { auditRunId: result.auditRunId },
|
|
36459
36540
|
...result.stopStatus && { stopStatus: result.stopStatus },
|
|
@@ -36520,7 +36601,7 @@ server.registerTool("chit_audit_show", {
|
|
|
36520
36601
|
}
|
|
36521
36602
|
});
|
|
36522
36603
|
server.registerTool("chit_status", {
|
|
36523
|
-
description: "Operator overview: the stepwise runs and converge loops live in THIS server right now (each loop with its status and next action), plus a compact list of recently audited runs (newest first). Read-only; answers 'what is active and what should I do next?'. Active state is per-session (a new session starts empty, and idle runs are evicted); recent state is durable. Drill into one item with chit_converge_status/
|
|
36604
|
+
description: "Operator overview: the stepwise runs and converge loops live in THIS server right now (each loop with its status and next action), plus a compact list of recently audited runs (newest first). Read-only; answers 'what is active and what should I do next?'. Active state is per-session (a new session starts empty, and idle runs are evicted); recent state is durable. Drill into one item with chit_converge_status/chit_run_trace, or chit_audit_show for a run's receipt.",
|
|
36524
36605
|
inputSchema: {
|
|
36525
36606
|
recent_limit: exports_external.number().int().min(0).default(5).describe("How many recently audited runs to include (newest first). Default 5; 0 for none.")
|
|
36526
36607
|
}
|
|
@@ -36757,7 +36838,7 @@ ${AUDIT_HELP}`);
|
|
|
36757
36838
|
// src/cli/doctor.ts
|
|
36758
36839
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
36759
36840
|
import { mkdirSync as mkdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
36760
|
-
import { join as
|
|
36841
|
+
import { join as join8 } from "path";
|
|
36761
36842
|
var defaultIO3 = {
|
|
36762
36843
|
out: (s) => process.stdout.write(s),
|
|
36763
36844
|
err: (s) => process.stderr.write(s)
|
|
@@ -36826,7 +36907,7 @@ function checkGitRepo(deps) {
|
|
|
36826
36907
|
function checkAuditDir(deps) {
|
|
36827
36908
|
try {
|
|
36828
36909
|
mkdirSync5(deps.auditDir, { recursive: true });
|
|
36829
|
-
const probeFile =
|
|
36910
|
+
const probeFile = join8(deps.auditDir, `.doctor-${randomUUID3()}`);
|
|
36830
36911
|
writeFileSync5(probeFile, "ok");
|
|
36831
36912
|
rmSync5(probeFile);
|
|
36832
36913
|
return { name: "audit dir", status: "pass", detail: `writable (${deps.auditDir})` };
|
|
@@ -36959,12 +37040,13 @@ var ALLOWED = {
|
|
|
36959
37040
|
"loop-id",
|
|
36960
37041
|
"summary",
|
|
36961
37042
|
"changed-files",
|
|
37043
|
+
"workspace-warnings",
|
|
36962
37044
|
"checks-run",
|
|
36963
37045
|
"verdict",
|
|
36964
37046
|
"finding-count",
|
|
36965
37047
|
"decision",
|
|
36966
37048
|
"duration-ms",
|
|
36967
|
-
"
|
|
37049
|
+
"audit-ref"
|
|
36968
37050
|
],
|
|
36969
37051
|
bools: []
|
|
36970
37052
|
},
|
|
@@ -36976,7 +37058,8 @@ var LOOP_LOG_HELP = `chit loop-log <start|append|stop|show> [flags]
|
|
|
36976
37058
|
start --scope <s> --task <t> --max-iterations <n> [--cwd <dir>] [--loop-id <id>] [--force]
|
|
36977
37059
|
append --loop-id <id> --summary <t> --changed-files <json> --checks-run <t>
|
|
36978
37060
|
--verdict <proceed|revise|block> --finding-count <n>
|
|
36979
|
-
--decision <proceed|revise|block> --duration-ms <n>
|
|
37061
|
+
--decision <proceed|revise|block> --duration-ms <n>
|
|
37062
|
+
[--workspace-warnings <json>] [--audit-ref <r>] [--cwd <dir>]
|
|
36980
37063
|
stop --loop-id <id> --status <converged|blocked|max-iterations|needs-decision> --reason <t> [--cwd <dir>]
|
|
36981
37064
|
show --loop-id <id> [--json] [--cwd <dir>]
|
|
36982
37065
|
|
|
@@ -37026,15 +37109,15 @@ function intFlag(p, key, verb) {
|
|
|
37026
37109
|
}
|
|
37027
37110
|
return n;
|
|
37028
37111
|
}
|
|
37029
|
-
function
|
|
37112
|
+
function parseStringArray(raw, flag) {
|
|
37030
37113
|
let parsed;
|
|
37031
37114
|
try {
|
|
37032
37115
|
parsed = JSON.parse(raw);
|
|
37033
37116
|
} catch {
|
|
37034
|
-
throw new UsageError3(
|
|
37117
|
+
throw new UsageError3(`--${flag} must be a JSON array of strings`);
|
|
37035
37118
|
}
|
|
37036
37119
|
if (!Array.isArray(parsed) || parsed.some((e) => typeof e !== "string")) {
|
|
37037
|
-
throw new UsageError3(
|
|
37120
|
+
throw new UsageError3(`--${flag} must be a JSON array of strings`);
|
|
37038
37121
|
}
|
|
37039
37122
|
return parsed;
|
|
37040
37123
|
}
|
|
@@ -37053,6 +37136,11 @@ function renderLoop(records) {
|
|
|
37053
37136
|
lines.push(` ${r.n}. ${r.implementSummary}`);
|
|
37054
37137
|
lines.push(` ${r.changedFiles.length} files \xB7 check ${r.verdict.toUpperCase()} \xB7 ` + `${Math.round(r.checkDurationMs / 1000)}s \xB7 ${r.findingCount} findings`);
|
|
37055
37138
|
lines.push(` decide ${r.decision}`);
|
|
37139
|
+
if (r.workspaceWarnings && r.workspaceWarnings.length > 0) {
|
|
37140
|
+
lines.push(` workspace: ${r.workspaceWarnings.length} warning(s)`);
|
|
37141
|
+
for (const w of r.workspaceWarnings)
|
|
37142
|
+
lines.push(` - ${w}`);
|
|
37143
|
+
}
|
|
37056
37144
|
} else if (r.type === "stop") {
|
|
37057
37145
|
lines.push("");
|
|
37058
37146
|
lines.push(` stopped: ${r.status} (${r.reason}) \xB7 ${r.iterations} iters \xB7 ` + `${Math.round(r.totalElapsedMs / 1000)}s`);
|
|
@@ -37084,15 +37172,19 @@ function runLoopLog(argv, io = defaultIO4) {
|
|
|
37084
37172
|
return 0;
|
|
37085
37173
|
}
|
|
37086
37174
|
if (verb === "append") {
|
|
37175
|
+
const warningsRaw = p.flags["workspace-warnings"];
|
|
37087
37176
|
const res = appendIteration(cwd, req(p, "loop-id", verb), {
|
|
37088
37177
|
implementSummary: req(p, "summary", verb),
|
|
37089
|
-
changedFiles:
|
|
37178
|
+
changedFiles: parseStringArray(req(p, "changed-files", verb), "changed-files"),
|
|
37179
|
+
...warningsRaw !== undefined && {
|
|
37180
|
+
workspaceWarnings: parseStringArray(warningsRaw, "workspace-warnings")
|
|
37181
|
+
},
|
|
37090
37182
|
checksRun: req(p, "checks-run", verb),
|
|
37091
37183
|
verdict: req(p, "verdict", verb),
|
|
37092
37184
|
findingCount: intFlag(p, "finding-count", verb),
|
|
37093
37185
|
decision: req(p, "decision", verb),
|
|
37094
37186
|
checkDurationMs: intFlag(p, "duration-ms", verb),
|
|
37095
|
-
|
|
37187
|
+
auditRef: p.flags["audit-ref"]
|
|
37096
37188
|
});
|
|
37097
37189
|
io.out(`${JSON.stringify(res)}
|
|
37098
37190
|
`);
|
|
@@ -37690,7 +37782,7 @@ ${HELP}`);
|
|
|
37690
37782
|
`);
|
|
37691
37783
|
return 2;
|
|
37692
37784
|
}
|
|
37693
|
-
const outputDir = args.outputDir ??
|
|
37785
|
+
const outputDir = args.outputDir ?? join13(homedir7(), ".claude", "skills");
|
|
37694
37786
|
const runtimePath = args.runtimePath ?? defaultRuntimePath();
|
|
37695
37787
|
try {
|
|
37696
37788
|
const result = installClaudeSkill({
|
|
@@ -37857,7 +37949,8 @@ async function runStudio(args) {
|
|
|
37857
37949
|
cwd: process.cwd(),
|
|
37858
37950
|
explicitPath: args.manifestPath,
|
|
37859
37951
|
registry: registry3,
|
|
37860
|
-
lifecycle: buildStudioLifecycle()
|
|
37952
|
+
lifecycle: buildStudioLifecycle(),
|
|
37953
|
+
loopsDir: loopLogDir(process.cwd())
|
|
37861
37954
|
});
|
|
37862
37955
|
} catch (e) {
|
|
37863
37956
|
if (e instanceof PathError2) {
|