@mrciphersmith/keryx 0.2.43 → 0.2.44
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 +789 -389
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12095,6 +12095,10 @@ function touchesAgentCredentials(command) {
|
|
|
12095
12095
|
const text = command.toLowerCase();
|
|
12096
12096
|
return CREDENTIAL_MARKERS.some((marker2) => text.includes(marker2));
|
|
12097
12097
|
}
|
|
12098
|
+
function touchesSacConfirmReview(command) {
|
|
12099
|
+
const text = command.toLowerCase();
|
|
12100
|
+
return SAC_REVIEW_MARKERS.some((marker2) => text.includes(marker2));
|
|
12101
|
+
}
|
|
12098
12102
|
var CATASTROPHIC_TARGETS, RECURSIVE_FLAG, PRIVILEGE, INTERPRETERS, DOWNLOADERS, CONTAINER_RUNTIMES, PROTECTED_BRANCHES, BLOCK_DEVICE, rulePrivilege = (v) => PRIVILEGE.has(v.cmd), ruleBlockDeviceRedirect = (v) => BLOCK_DEVICE.test(v.raw) && /(?:^|\s)(?:>|>>)\s*\/dev\//.test(v.raw), ruleRm = (v) => v.cmd === "rm" && v.positionals.some(isCatastrophicTarget), ruleDd = (v) => v.cmd === "dd" && v.args.some((x) => /^of=/i.test(x) && BLOCK_DEVICE.test(x)), rulePermissionSweep = (v) => (v.cmd === "chmod" || v.cmd === "chown" || v.cmd === "chgrp") && hasRecursive(v.words) && v.positionals.some(isCatastrophicTarget), ruleHostState = (v) => {
|
|
12099
12103
|
if (v.cmd === "shutdown" || v.cmd === "reboot" || v.cmd === "halt" || v.cmd === "poweroff")
|
|
12100
12104
|
return true;
|
|
@@ -12115,7 +12119,7 @@ var CATASTROPHIC_TARGETS, RECURSIVE_FLAG, PRIVILEGE, INTERPRETERS, DOWNLOADERS,
|
|
|
12115
12119
|
return true;
|
|
12116
12120
|
const named = after.map((x) => x.split("/").pop()?.toLowerCase() ?? "");
|
|
12117
12121
|
return named.some((n) => PROTECTED_BRANCHES.includes(n));
|
|
12118
|
-
}, RULES3, CREDENTIAL_MARKERS;
|
|
12122
|
+
}, RULES3, CREDENTIAL_MARKERS, SAC_REVIEW_MARKERS;
|
|
12119
12123
|
var init_command_risk = __esm(() => {
|
|
12120
12124
|
init_shell_syntax();
|
|
12121
12125
|
CATASTROPHIC_TARGETS = new Set([
|
|
@@ -12180,6 +12184,7 @@ var init_command_risk = __esm(() => {
|
|
|
12180
12184
|
".local/share/keryx",
|
|
12181
12185
|
".config/keryx"
|
|
12182
12186
|
];
|
|
12187
|
+
SAC_REVIEW_MARKERS = ["confirm-review", "workspace review"];
|
|
12183
12188
|
});
|
|
12184
12189
|
|
|
12185
12190
|
// src/commands/permission-mode.ts
|
|
@@ -12187,11 +12192,11 @@ function isPermissionMode(value) {
|
|
|
12187
12192
|
return PERMISSION_MODES.includes(value);
|
|
12188
12193
|
}
|
|
12189
12194
|
function resolveApprovalDecision(input2) {
|
|
12190
|
-
const { mode, risk, destructive, credentials } = input2;
|
|
12195
|
+
const { mode, risk, destructive, credentials, sacReviewConfirmation } = input2;
|
|
12191
12196
|
if (risk === "read") {
|
|
12192
12197
|
return "auto";
|
|
12193
12198
|
}
|
|
12194
|
-
if (credentials) {
|
|
12199
|
+
if (credentials || sacReviewConfirmation) {
|
|
12195
12200
|
return "ask";
|
|
12196
12201
|
}
|
|
12197
12202
|
if (mode === "auto") {
|
|
@@ -17667,7 +17672,8 @@ async function executeCall(call, toolByName, requestApproval, permissionMode, on
|
|
|
17667
17672
|
const command = typeof input2.command === "string" ? input2.command : "";
|
|
17668
17673
|
const destructive = risk === "destructive" || isDestructiveCommand(command);
|
|
17669
17674
|
const credentials = touchesAgentCredentials(command);
|
|
17670
|
-
const
|
|
17675
|
+
const sacReviewConfirmation = touchesSacConfirmReview(command);
|
|
17676
|
+
const decision = resolveApprovalDecision({ mode, risk, destructive, credentials, sacReviewConfirmation });
|
|
17671
17677
|
if (decision === "auto") {
|
|
17672
17678
|
onAutoApproved?.(call.name, call.input, { destructive, credentials });
|
|
17673
17679
|
} else {
|
|
@@ -17682,7 +17688,7 @@ async function executeCall(call, toolByName, requestApproval, permissionMode, on
|
|
|
17682
17688
|
}
|
|
17683
17689
|
}
|
|
17684
17690
|
} else if (risk === "delegate") {
|
|
17685
|
-
const decision = resolveApprovalDecision({ mode, risk, destructive: false, credentials: false });
|
|
17691
|
+
const decision = resolveApprovalDecision({ mode, risk, destructive: false, credentials: false, sacReviewConfirmation: false });
|
|
17686
17692
|
if (decision === "auto") {
|
|
17687
17693
|
onAutoApproved?.(call.name, call.input, { destructive: false, credentials: false });
|
|
17688
17694
|
} else {
|
|
@@ -45817,7 +45823,7 @@ function harnessWave(args2, deps) {
|
|
|
45817
45823
|
init_make_provider();
|
|
45818
45824
|
init_orient();
|
|
45819
45825
|
init_metaproject_adapter();
|
|
45820
|
-
import { randomUUID as
|
|
45826
|
+
import { randomUUID as randomUUID25 } from "crypto";
|
|
45821
45827
|
import * as readline2 from "readline";
|
|
45822
45828
|
|
|
45823
45829
|
// src/commands/agent-approval-context.ts
|
|
@@ -47104,6 +47110,9 @@ function buildInteractiveAgentTools(input2) {
|
|
|
47104
47110
|
];
|
|
47105
47111
|
}
|
|
47106
47112
|
|
|
47113
|
+
// src/commands/shell-approval.ts
|
|
47114
|
+
init_command_risk();
|
|
47115
|
+
|
|
47107
47116
|
// src/lib/shell-permissions.ts
|
|
47108
47117
|
init_config_dir();
|
|
47109
47118
|
init_shell_config();
|
|
@@ -47254,6 +47263,12 @@ function validateShellPattern(pattern) {
|
|
|
47254
47263
|
reason: "touches the agent's own permission/credential files; remembering it would let one approved command disable the approval gate for every future session"
|
|
47255
47264
|
};
|
|
47256
47265
|
}
|
|
47266
|
+
if (touchesSacConfirmReview(trimmed)) {
|
|
47267
|
+
return {
|
|
47268
|
+
ok: false,
|
|
47269
|
+
reason: "touches SAC's proposal-review/confirm-token family; that guarantee depends on a human answering a real approval prompt, so it is never remembered"
|
|
47270
|
+
};
|
|
47271
|
+
}
|
|
47257
47272
|
const banned = bannedPrefixGrant(trimmed, firstToken);
|
|
47258
47273
|
if (banned !== undefined) {
|
|
47259
47274
|
return { ok: false, reason: banned.reason };
|
|
@@ -47391,6 +47406,9 @@ function isShellCommandAllowed(command, allow) {
|
|
|
47391
47406
|
if (touchesAgentCredentials(cmd)) {
|
|
47392
47407
|
return false;
|
|
47393
47408
|
}
|
|
47409
|
+
if (touchesSacConfirmReview(cmd)) {
|
|
47410
|
+
return false;
|
|
47411
|
+
}
|
|
47394
47412
|
return allow.some((pat) => matchShellPattern(pat, cmd));
|
|
47395
47413
|
}
|
|
47396
47414
|
function shellPermissionsFingerprint(dir) {
|
|
@@ -47416,12 +47434,12 @@ function suggestShellPatterns(command) {
|
|
|
47416
47434
|
const collapsed = firstLine2.replace(/\s+/g, " ").trim();
|
|
47417
47435
|
const first = collapsed.split(" ")[0] ?? collapsed;
|
|
47418
47436
|
const prefix = first.length > 0 ? `${first} *` : exact;
|
|
47419
|
-
const
|
|
47437
|
+
const neverRemember = trimmed.length > 0 && (isDestructiveCommand(trimmed) || touchesSacConfirmReview(trimmed));
|
|
47420
47438
|
return {
|
|
47421
47439
|
exact,
|
|
47422
47440
|
prefix,
|
|
47423
|
-
offerExact: !
|
|
47424
|
-
offerPrefix: !
|
|
47441
|
+
offerExact: !neverRemember && validateShellPattern(exact).ok,
|
|
47442
|
+
offerPrefix: !neverRemember && validateShellPattern(prefix).ok
|
|
47425
47443
|
};
|
|
47426
47444
|
}
|
|
47427
47445
|
function parseShellExecCommand(inputJson) {
|
|
@@ -47444,16 +47462,18 @@ function evaluateShellApproval(input2) {
|
|
|
47444
47462
|
const command = parseShellExecCommand(input2.inputJson);
|
|
47445
47463
|
const destructive = input2.meta?.destructive === true;
|
|
47446
47464
|
const credentials = input2.meta?.credentials === true;
|
|
47465
|
+
const sacReviewConfirmation = touchesSacConfirmReview(command);
|
|
47447
47466
|
const audit = io.loadAudit();
|
|
47448
47467
|
for (const pattern of audit.permissions.allow) {
|
|
47449
47468
|
input2.sessionAllow.add(pattern);
|
|
47450
47469
|
}
|
|
47451
47470
|
const tampered = io.fingerprint() !== input2.fingerprintAtStart;
|
|
47452
|
-
const autoApprove = !destructive && !credentials && isShellCommandAllowed(command, [...input2.sessionAllow]);
|
|
47471
|
+
const autoApprove = !destructive && !credentials && !sacReviewConfirmation && isShellCommandAllowed(command, [...input2.sessionAllow]);
|
|
47453
47472
|
return {
|
|
47454
47473
|
command,
|
|
47455
47474
|
destructive,
|
|
47456
47475
|
credentials,
|
|
47476
|
+
sacReviewConfirmation,
|
|
47457
47477
|
autoApprove,
|
|
47458
47478
|
rejected: audit.rejected,
|
|
47459
47479
|
tampered
|
|
@@ -47478,6 +47498,9 @@ function formatShellApprovalHints(evaled) {
|
|
|
47478
47498
|
if (evaled.credentials) {
|
|
47479
47499
|
lines.push("touches agent credentials \u2014 will not be remembered");
|
|
47480
47500
|
}
|
|
47501
|
+
if (evaled.sacReviewConfirmation) {
|
|
47502
|
+
lines.push("SAC proposal review/confirm-token \u2014 will not be remembered");
|
|
47503
|
+
}
|
|
47481
47504
|
return lines;
|
|
47482
47505
|
}
|
|
47483
47506
|
|
|
@@ -48582,7 +48605,7 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
48582
48605
|
// package.json
|
|
48583
48606
|
var package_default = {
|
|
48584
48607
|
name: "@mrciphersmith/keryx",
|
|
48585
|
-
version: "0.2.
|
|
48608
|
+
version: "0.2.44",
|
|
48586
48609
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
48587
48610
|
private: false,
|
|
48588
48611
|
publishConfig: {
|
|
@@ -49832,8 +49855,195 @@ function openModal(otui, chrome, input2) {
|
|
|
49832
49855
|
// src/tui/inspector-sources.ts
|
|
49833
49856
|
init_store2();
|
|
49834
49857
|
init_workspace_service();
|
|
49858
|
+
import { randomUUID as randomUUID24 } from "crypto";
|
|
49859
|
+
|
|
49860
|
+
// src/sac/catch-up.ts
|
|
49861
|
+
init_fs();
|
|
49862
|
+
init_config_dir();
|
|
49863
|
+
init_paths();
|
|
49835
49864
|
init_slate();
|
|
49865
|
+
init_store3();
|
|
49866
|
+
init_proposal_lifecycle();
|
|
49867
|
+
init_workspace_service();
|
|
49868
|
+
import { randomUUID as randomUUID23 } from "crypto";
|
|
49869
|
+
import { readdir as readdir24 } from "fs/promises";
|
|
49870
|
+
import path145 from "path";
|
|
49871
|
+
|
|
49872
|
+
// src/sac/lifecycle-flag.ts
|
|
49873
|
+
init_store();
|
|
49874
|
+
init_service3();
|
|
49875
|
+
init_decision_dedup();
|
|
49876
|
+
init_workspace_service();
|
|
49836
49877
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
49878
|
+
function normalize3(raw) {
|
|
49879
|
+
return raw.replace(/^\.\//, "");
|
|
49880
|
+
}
|
|
49881
|
+
function isStillPresent(recorded, valid) {
|
|
49882
|
+
const normalized = normalize3(recorded);
|
|
49883
|
+
return valid.has(normalized) || valid.has(moduleNameFromProjectPath(normalized));
|
|
49884
|
+
}
|
|
49885
|
+
async function computeLifecycleFlags(cwd, now = () => new Date) {
|
|
49886
|
+
const valid = await validModuleNames(cwd);
|
|
49887
|
+
if (valid === undefined)
|
|
49888
|
+
return [];
|
|
49889
|
+
const flaggedAt = now().toISOString();
|
|
49890
|
+
const flags = [];
|
|
49891
|
+
const workspaceService = new WorkspaceService({
|
|
49892
|
+
workspaceRoot: cwd,
|
|
49893
|
+
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
49894
|
+
strictGuard: { mode: "strict", availability: "available", decision: "pass", policyRevision: "local-offline-v1" }
|
|
49895
|
+
});
|
|
49896
|
+
const workspaces = await workspaceService.list({ request: undefined, requestCorrelationId: randomUUID22(), includeArchived: true });
|
|
49897
|
+
for (const workspace of workspaces) {
|
|
49898
|
+
const component = workspace.resources.find((r) => r.kind === "component")?.uri;
|
|
49899
|
+
if (component !== undefined && !isStillPresent(component, valid)) {
|
|
49900
|
+
flags.push({ kind: "workspace", ref: workspace.id, missingComponent: normalize3(component), flaggedAt });
|
|
49901
|
+
}
|
|
49902
|
+
}
|
|
49903
|
+
for (const entry of await collectEntries(cwd)) {
|
|
49904
|
+
const module = entry.scopes.module;
|
|
49905
|
+
if (module !== null && module.length > 0 && !isStillPresent(module, valid)) {
|
|
49906
|
+
flags.push({ kind: "memory-entry", ref: entry.relativePath, missingComponent: normalize3(module), flaggedAt });
|
|
49907
|
+
}
|
|
49908
|
+
}
|
|
49909
|
+
for (const decision of await collectWikiDecisionEntries(cwd)) {
|
|
49910
|
+
const module = decision.scopes.module;
|
|
49911
|
+
if (module !== null && module.length > 0 && !isStillPresent(module, valid)) {
|
|
49912
|
+
flags.push({ kind: "wiki-decision", ref: decision.relativePath, missingComponent: normalize3(module), flaggedAt });
|
|
49913
|
+
}
|
|
49914
|
+
}
|
|
49915
|
+
return flags;
|
|
49916
|
+
}
|
|
49917
|
+
|
|
49918
|
+
// src/sac/catch-up.ts
|
|
49919
|
+
async function buildCatchUp(input2) {
|
|
49920
|
+
const [proposals, sessionCategories, lifecycleFlagsAll] = await Promise.all([
|
|
49921
|
+
collectProposals(input2.cwd, input2.workspaceId),
|
|
49922
|
+
collectSessionCategories(input2.cwd),
|
|
49923
|
+
computeLifecycleFlags(input2.cwd)
|
|
49924
|
+
]);
|
|
49925
|
+
const lifecycleFlags = input2.workspaceId === undefined ? lifecycleFlagsAll : lifecycleFlagsAll.filter((flag) => flag.kind !== "workspace" || flag.ref === input2.workspaceId);
|
|
49926
|
+
return { proposals, ...sessionCategories, lifecycleFlags };
|
|
49927
|
+
}
|
|
49928
|
+
async function collectProposals(cwd, workspaceId) {
|
|
49929
|
+
const authorizationServer = localWorkspaceAuthorizationServer();
|
|
49930
|
+
const actor = await authorizationServer.actorContextFor(undefined, randomUUID23());
|
|
49931
|
+
if (!actor)
|
|
49932
|
+
throw new Error("trusted ActorContext is required for catch-up");
|
|
49933
|
+
const proposalService = createLocalProposalLifecycleService(cwd);
|
|
49934
|
+
const groups = await proposalService.listVisibleProposedProposals(actor);
|
|
49935
|
+
const scoped = workspaceId === undefined ? groups : groups.filter((group) => group.workspace.id === workspaceId);
|
|
49936
|
+
const flattened = scoped.flatMap((group) => group.proposals.map((proposal) => ({ group, proposal })));
|
|
49937
|
+
return Promise.all(flattened.map(async ({ group, proposal }) => {
|
|
49938
|
+
const fresh = await proposalService.isEvidenceFresh(proposal, actor);
|
|
49939
|
+
return { type: "proposal", workspaceId: group.workspace.id, proposalId: proposal.id, fresh };
|
|
49940
|
+
}));
|
|
49941
|
+
}
|
|
49942
|
+
async function classifySession(session) {
|
|
49943
|
+
const dir = sessionDir(session.projectPath, session.id);
|
|
49944
|
+
if (await isLockHeld(slateLockPath(dir)))
|
|
49945
|
+
return;
|
|
49946
|
+
const terminalState = await readTerminalState(dir);
|
|
49947
|
+
if (terminalState !== undefined) {
|
|
49948
|
+
const workspaceId2 = (await safeReadSlate(dir))?.workspaceId;
|
|
49949
|
+
return { kind: "blocked", item: { type: "blocked", sessionId: session.id, ...workspaceId2 !== undefined ? { workspaceId: workspaceId2 } : {}, terminalState } };
|
|
49950
|
+
}
|
|
49951
|
+
const unboundCandidate = await readNewestUnboundCandidate(dir);
|
|
49952
|
+
if (unboundCandidate !== undefined) {
|
|
49953
|
+
return {
|
|
49954
|
+
kind: "unbound-candidate",
|
|
49955
|
+
item: { type: "unbound-candidate", sessionId: session.id, evidencePath: unboundCandidate.evidencePath, summary: unboundCandidate.summary }
|
|
49956
|
+
};
|
|
49957
|
+
}
|
|
49958
|
+
if (!await isSlateEngaged(dir))
|
|
49959
|
+
return;
|
|
49960
|
+
const workspaceId = (await safeReadSlate(dir))?.workspaceId;
|
|
49961
|
+
return { kind: "unknown", item: { type: "unknown", sessionId: session.id, ...workspaceId !== undefined ? { workspaceId } : {}, lastSeenAt: session.updatedAt } };
|
|
49962
|
+
}
|
|
49963
|
+
async function collectSessionCategories(cwd) {
|
|
49964
|
+
const classified = await Promise.all(listSessions(cwd).map((session) => classifySession(session)));
|
|
49965
|
+
const blocked2 = [];
|
|
49966
|
+
const unboundCandidates = [];
|
|
49967
|
+
const unknown = [];
|
|
49968
|
+
for (const category of classified) {
|
|
49969
|
+
if (category === undefined)
|
|
49970
|
+
continue;
|
|
49971
|
+
if (category.kind === "blocked")
|
|
49972
|
+
blocked2.push(category.item);
|
|
49973
|
+
else if (category.kind === "unbound-candidate")
|
|
49974
|
+
unboundCandidates.push(category.item);
|
|
49975
|
+
else
|
|
49976
|
+
unknown.push(category.item);
|
|
49977
|
+
}
|
|
49978
|
+
return { blocked: blocked2, unboundCandidates, unknown };
|
|
49979
|
+
}
|
|
49980
|
+
async function isSlateEngaged(dir) {
|
|
49981
|
+
if (await pathExists(path145.join(dir, "slate.json")))
|
|
49982
|
+
return true;
|
|
49983
|
+
if (await pathExists(path145.join(dir, "terminal-state.json")))
|
|
49984
|
+
return true;
|
|
49985
|
+
try {
|
|
49986
|
+
const entries = await readdir24(path145.join(dir, "slate-archive"));
|
|
49987
|
+
return entries.length > 0;
|
|
49988
|
+
} catch {
|
|
49989
|
+
return false;
|
|
49990
|
+
}
|
|
49991
|
+
}
|
|
49992
|
+
async function safeReadSlate(dir) {
|
|
49993
|
+
try {
|
|
49994
|
+
return await readSlate(dir);
|
|
49995
|
+
} catch {
|
|
49996
|
+
return;
|
|
49997
|
+
}
|
|
49998
|
+
}
|
|
49999
|
+
async function readTerminalState(dir) {
|
|
50000
|
+
const result = readConfigFile(path145.join(dir, "terminal-state.json"));
|
|
50001
|
+
if (!result.ok) {
|
|
50002
|
+
return;
|
|
50003
|
+
}
|
|
50004
|
+
try {
|
|
50005
|
+
return JSON.parse(result.text);
|
|
50006
|
+
} catch {
|
|
50007
|
+
return;
|
|
50008
|
+
}
|
|
50009
|
+
}
|
|
50010
|
+
async function readNewestUnboundCandidate(dir) {
|
|
50011
|
+
const archiveDir = path145.join(dir, "slate-archive");
|
|
50012
|
+
let entries;
|
|
50013
|
+
try {
|
|
50014
|
+
entries = (await readdir24(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
50015
|
+
} catch {
|
|
50016
|
+
return;
|
|
50017
|
+
}
|
|
50018
|
+
entries.sort();
|
|
50019
|
+
for (let i = entries.length - 1;i >= 0; i--) {
|
|
50020
|
+
const evidencePath = path145.join(archiveDir, entries[i]);
|
|
50021
|
+
const result = readConfigFile(evidencePath);
|
|
50022
|
+
if (!result.ok) {
|
|
50023
|
+
continue;
|
|
50024
|
+
}
|
|
50025
|
+
try {
|
|
50026
|
+
const parsed = JSON.parse(result.text);
|
|
50027
|
+
if (parsed.recordType !== "unbound-candidate")
|
|
50028
|
+
continue;
|
|
50029
|
+
return { evidencePath, summary: summarizeUnboundCandidate(parsed.groups) };
|
|
50030
|
+
} catch {
|
|
50031
|
+
continue;
|
|
50032
|
+
}
|
|
50033
|
+
}
|
|
50034
|
+
return;
|
|
50035
|
+
}
|
|
50036
|
+
function summarizeUnboundCandidate(groups) {
|
|
50037
|
+
const safeGroups = groups ?? [];
|
|
50038
|
+
if (safeGroups.length === 0)
|
|
50039
|
+
return "no seeds captured";
|
|
50040
|
+
const seedCount = safeGroups.reduce((sum, group) => sum + (group.seeds?.length ?? 0), 0);
|
|
50041
|
+
const kinds = safeGroups.map((group) => typeof group.kind === "string" ? group.kind : "unknown").join(", ");
|
|
50042
|
+
return `${seedCount} untriaged seed(s) across ${safeGroups.length} kind(s) (${kinds})`;
|
|
50043
|
+
}
|
|
50044
|
+
|
|
50045
|
+
// src/tui/inspector-sources.ts
|
|
50046
|
+
init_slate();
|
|
49837
50047
|
|
|
49838
50048
|
// src/session/index.ts
|
|
49839
50049
|
init_paths();
|
|
@@ -49912,7 +50122,7 @@ async function loadInspectorWorkspaces(cwd) {
|
|
|
49912
50122
|
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
49913
50123
|
strictGuard: localSacGuard()
|
|
49914
50124
|
});
|
|
49915
|
-
const listed = await service5.list({ request: undefined, requestCorrelationId:
|
|
50125
|
+
const listed = await service5.list({ request: undefined, requestCorrelationId: randomUUID24() });
|
|
49916
50126
|
return listed.map(workspaceFromManifest);
|
|
49917
50127
|
} catch {
|
|
49918
50128
|
return [];
|
|
@@ -49925,7 +50135,7 @@ async function loadInspectorWorkspace(cwd, workspaceId) {
|
|
|
49925
50135
|
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
49926
50136
|
strictGuard: localSacGuard()
|
|
49927
50137
|
});
|
|
49928
|
-
const manifest = await service5.show({ request: undefined, requestCorrelationId:
|
|
50138
|
+
const manifest = await service5.show({ request: undefined, requestCorrelationId: randomUUID24(), workspaceId });
|
|
49929
50139
|
return workspaceFromManifest(manifest);
|
|
49930
50140
|
} catch {
|
|
49931
50141
|
return;
|
|
@@ -49998,6 +50208,16 @@ function formatWorkspaceLines(workspaces) {
|
|
|
49998
50208
|
const width = workspaces.reduce((max, workspace) => Math.max(max, workspace.id.length), 0);
|
|
49999
50209
|
return workspaces.map((workspace) => `${workspace.id.padEnd(width)} ${workspace.status} ${workspace.title}`);
|
|
50000
50210
|
}
|
|
50211
|
+
async function loadInspectorCatchUp(cwd) {
|
|
50212
|
+
try {
|
|
50213
|
+
return await buildCatchUp({ cwd });
|
|
50214
|
+
} catch {
|
|
50215
|
+
return { proposals: [], blocked: [], unboundCandidates: [], unknown: [], lifecycleFlags: [] };
|
|
50216
|
+
}
|
|
50217
|
+
}
|
|
50218
|
+
function catchUpItems(report) {
|
|
50219
|
+
return [...report.proposals, ...report.blocked, ...report.unboundCandidates, ...report.unknown];
|
|
50220
|
+
}
|
|
50001
50221
|
function formatSessionFlowLines(flows) {
|
|
50002
50222
|
if (flows.length === 0) {
|
|
50003
50223
|
return ["No flows recorded in this session."];
|
|
@@ -50490,6 +50710,332 @@ function openWorkspace(otui, chrome, options) {
|
|
|
50490
50710
|
return presentWorkspace((hostOtui, hostChrome, input2) => openModal(hostOtui, hostChrome, input2), otui, chrome, options);
|
|
50491
50711
|
}
|
|
50492
50712
|
|
|
50713
|
+
// src/tui/review-inspector.ts
|
|
50714
|
+
var REVIEW_COMMAND = "/review";
|
|
50715
|
+
var REVIEW_FOOTER = [
|
|
50716
|
+
{ key: "[/]", label: "item" },
|
|
50717
|
+
{ key: "a y", label: "accept" },
|
|
50718
|
+
{ key: "\u2191/\u2193", label: "scroll" },
|
|
50719
|
+
{ key: "\u2190/\u2192", label: "tabs" },
|
|
50720
|
+
{ key: "esc", label: "close" }
|
|
50721
|
+
];
|
|
50722
|
+
function isReviewCommand(line) {
|
|
50723
|
+
const token = line.trim().split(/\s+/)[0] ?? "";
|
|
50724
|
+
return token === REVIEW_COMMAND;
|
|
50725
|
+
}
|
|
50726
|
+
var TYPE_LABEL = {
|
|
50727
|
+
proposal: "PROPOSAL",
|
|
50728
|
+
blocked: "BLOCKED",
|
|
50729
|
+
"unbound-candidate": "UNBOUND",
|
|
50730
|
+
unknown: "UNKNOWN"
|
|
50731
|
+
};
|
|
50732
|
+
function summarizeReviewItem(item) {
|
|
50733
|
+
switch (item.type) {
|
|
50734
|
+
case "proposal":
|
|
50735
|
+
return `${item.proposalId} in ${item.workspaceId}${item.fresh ? "" : " (stale)"}`;
|
|
50736
|
+
case "blocked":
|
|
50737
|
+
return `${item.sessionId} \u2014 ${item.terminalState.reason}`;
|
|
50738
|
+
case "unbound-candidate":
|
|
50739
|
+
return `${item.sessionId} \u2014 ${item.summary}`;
|
|
50740
|
+
case "unknown":
|
|
50741
|
+
return `${item.sessionId} \u2014 last seen ${item.lastSeenAt}`;
|
|
50742
|
+
}
|
|
50743
|
+
}
|
|
50744
|
+
function formatReviewListLines(items, selected) {
|
|
50745
|
+
if (items.length === 0) {
|
|
50746
|
+
return ["Nothing needs review right now."];
|
|
50747
|
+
}
|
|
50748
|
+
return items.map((item, index) => {
|
|
50749
|
+
const mark = index === selected ? ">" : " ";
|
|
50750
|
+
return `${mark} ${TYPE_LABEL[item.type].padEnd(8)} ${summarizeReviewItem(item)}`;
|
|
50751
|
+
});
|
|
50752
|
+
}
|
|
50753
|
+
function describeReviewItem(item) {
|
|
50754
|
+
switch (item.type) {
|
|
50755
|
+
case "proposal":
|
|
50756
|
+
return [
|
|
50757
|
+
`Proposal ${item.proposalId}`,
|
|
50758
|
+
`Workspace ${item.workspaceId}`,
|
|
50759
|
+
`Evidence ${item.fresh ? "fresh" : "stale \u2014 evidence has drifted since this proposal was created; re-run wrap-up before deciding"}`,
|
|
50760
|
+
"",
|
|
50761
|
+
`Reject/dismiss from a terminal: keryx workspace review ${item.workspaceId} ${item.proposalId} --decision <rejected|dismissed>`
|
|
50762
|
+
];
|
|
50763
|
+
case "blocked":
|
|
50764
|
+
return [
|
|
50765
|
+
`Session ${item.sessionId}${item.workspaceId !== undefined ? ` (workspace ${item.workspaceId})` : ""}`,
|
|
50766
|
+
`Stopped unattended: ${item.terminalState.reason}`,
|
|
50767
|
+
`Occurred ${item.terminalState.occurredAt}`,
|
|
50768
|
+
"",
|
|
50769
|
+
`Resume: keryx shell -r ${item.sessionId}`
|
|
50770
|
+
];
|
|
50771
|
+
case "unbound-candidate":
|
|
50772
|
+
return [
|
|
50773
|
+
`Session ${item.sessionId}`,
|
|
50774
|
+
`Untriaged seeds: ${item.summary}`,
|
|
50775
|
+
`Evidence ${item.evidencePath}`,
|
|
50776
|
+
"",
|
|
50777
|
+
`Bind: keryx workspace propose <workspace-id> --kind <kind> --session ${item.sessionId}`
|
|
50778
|
+
];
|
|
50779
|
+
case "unknown":
|
|
50780
|
+
return [
|
|
50781
|
+
`Session ${item.sessionId}${item.workspaceId !== undefined ? ` (workspace ${item.workspaceId})` : ""}`,
|
|
50782
|
+
`Last seen ${item.lastSeenAt}`,
|
|
50783
|
+
"No proposal, terminal state, or unbound-candidate artifact recorded.",
|
|
50784
|
+
"",
|
|
50785
|
+
`Investigate: keryx sessions list / keryx shell -r ${item.sessionId}`
|
|
50786
|
+
];
|
|
50787
|
+
}
|
|
50788
|
+
}
|
|
50789
|
+
function formatReviewDetailLines(item, status) {
|
|
50790
|
+
if (item === undefined) {
|
|
50791
|
+
return ["No item selected.", "", "Press Enter (or click a row) on the Review tab to view one."];
|
|
50792
|
+
}
|
|
50793
|
+
const lines = describeReviewItem(item);
|
|
50794
|
+
if (item.type !== "proposal") {
|
|
50795
|
+
return lines;
|
|
50796
|
+
}
|
|
50797
|
+
const withAction = [...lines, ""];
|
|
50798
|
+
if (status.kind === "armed") {
|
|
50799
|
+
withAction.push("Press [y] to CONFIRM accept, any other key cancels.");
|
|
50800
|
+
} else if (status.kind === "running") {
|
|
50801
|
+
withAction.push("Accepting\u2026 running `keryx workspace confirm-review` then `keryx workspace review`.");
|
|
50802
|
+
} else if (status.kind === "done" && status.outcome.ok) {
|
|
50803
|
+
withAction.push("\u2713 Accepted.");
|
|
50804
|
+
} else if (status.kind === "done" && !status.outcome.ok) {
|
|
50805
|
+
withAction.push(`\u2717 Accept failed: ${status.outcome.message}`);
|
|
50806
|
+
} else {
|
|
50807
|
+
withAction.push("[a] Accept this proposal");
|
|
50808
|
+
}
|
|
50809
|
+
return withAction;
|
|
50810
|
+
}
|
|
50811
|
+
function clampScroll3(offset, lineCount, height) {
|
|
50812
|
+
const max = Math.max(0, lineCount - height);
|
|
50813
|
+
return Math.min(max, Math.max(0, offset));
|
|
50814
|
+
}
|
|
50815
|
+
function windowLines3(lines, offset, height) {
|
|
50816
|
+
if (height < 1) {
|
|
50817
|
+
return [];
|
|
50818
|
+
}
|
|
50819
|
+
const start = clampScroll3(offset, lines.length, height);
|
|
50820
|
+
return lines.slice(start, start + height);
|
|
50821
|
+
}
|
|
50822
|
+
function scrollToReveal3(index, offset, height) {
|
|
50823
|
+
if (index < offset) {
|
|
50824
|
+
return index;
|
|
50825
|
+
}
|
|
50826
|
+
if (index >= offset + height) {
|
|
50827
|
+
return index - height + 1;
|
|
50828
|
+
}
|
|
50829
|
+
return offset;
|
|
50830
|
+
}
|
|
50831
|
+
function wrapLines3(text, width) {
|
|
50832
|
+
if (width === undefined || width < 8) {
|
|
50833
|
+
return text;
|
|
50834
|
+
}
|
|
50835
|
+
return text.split(`
|
|
50836
|
+
`).flatMap((line) => {
|
|
50837
|
+
if (line.length <= width) {
|
|
50838
|
+
return [line];
|
|
50839
|
+
}
|
|
50840
|
+
const chunks = [];
|
|
50841
|
+
for (let i = 0;i < line.length; i += width) {
|
|
50842
|
+
chunks.push(line.slice(i, i + width));
|
|
50843
|
+
}
|
|
50844
|
+
return chunks;
|
|
50845
|
+
}).join(`
|
|
50846
|
+
`);
|
|
50847
|
+
}
|
|
50848
|
+
function paintLines3(otui, renderer, body, lines, width) {
|
|
50849
|
+
if (otui === undefined || otui === null || body === undefined || body === null) {
|
|
50850
|
+
return;
|
|
50851
|
+
}
|
|
50852
|
+
const parent = body;
|
|
50853
|
+
const ctor = otui.TextRenderable;
|
|
50854
|
+
if (parent.add === undefined || ctor === undefined) {
|
|
50855
|
+
return;
|
|
50856
|
+
}
|
|
50857
|
+
const node = new ctor(renderer, { id: "review-body", content: wrapLines3(lines.join(`
|
|
50858
|
+
`), width) });
|
|
50859
|
+
parent.add(node);
|
|
50860
|
+
return node;
|
|
50861
|
+
}
|
|
50862
|
+
function presentReview(openModal2, otui, chrome, options) {
|
|
50863
|
+
const items = [...options.items];
|
|
50864
|
+
let selected = 0;
|
|
50865
|
+
let listScroll = 0;
|
|
50866
|
+
let detailScroll = 0;
|
|
50867
|
+
let status = { kind: "idle" };
|
|
50868
|
+
let listNode;
|
|
50869
|
+
let detailNode;
|
|
50870
|
+
let unsubscribeKey;
|
|
50871
|
+
const rendererHint = options.renderer ?? chrome?.renderer;
|
|
50872
|
+
const bodyRows = options.visibleRows ?? (typeof rendererHint?.width === "number" && typeof rendererHint.height === "number" ? modalBodyRows(resolveModalPanelSize(rendererHint.width, rendererHint.height).height) : 13);
|
|
50873
|
+
let tabWidth;
|
|
50874
|
+
const listLines = () => formatReviewListLines(items, selected);
|
|
50875
|
+
const detailLines = () => wrapLines3(formatReviewDetailLines(items[selected], status).join(`
|
|
50876
|
+
`), tabWidth).split(`
|
|
50877
|
+
`);
|
|
50878
|
+
const paintSelection = () => {
|
|
50879
|
+
listScroll = scrollToReveal3(selected, listScroll, bodyRows);
|
|
50880
|
+
listScroll = clampScroll3(listScroll, items.length, bodyRows);
|
|
50881
|
+
detailScroll = clampScroll3(detailScroll, detailLines().length, bodyRows);
|
|
50882
|
+
if (listNode !== undefined) {
|
|
50883
|
+
listNode.content = windowLines3(listLines(), listScroll, bodyRows).join(`
|
|
50884
|
+
`);
|
|
50885
|
+
}
|
|
50886
|
+
if (detailNode !== undefined) {
|
|
50887
|
+
detailNode.content = windowLines3(detailLines(), detailScroll, bodyRows).join(`
|
|
50888
|
+
`);
|
|
50889
|
+
}
|
|
50890
|
+
};
|
|
50891
|
+
const moveSelection = (next) => {
|
|
50892
|
+
if (items.length === 0) {
|
|
50893
|
+
return;
|
|
50894
|
+
}
|
|
50895
|
+
const clamped = Math.min(items.length - 1, Math.max(0, next));
|
|
50896
|
+
if (clamped === selected) {
|
|
50897
|
+
return;
|
|
50898
|
+
}
|
|
50899
|
+
selected = clamped;
|
|
50900
|
+
detailScroll = 0;
|
|
50901
|
+
status = { kind: "idle" };
|
|
50902
|
+
paintSelection();
|
|
50903
|
+
};
|
|
50904
|
+
const runAccept = () => {
|
|
50905
|
+
const item = items[selected];
|
|
50906
|
+
if (item === undefined || item.type !== "proposal" || options.acceptProposal === undefined) {
|
|
50907
|
+
return;
|
|
50908
|
+
}
|
|
50909
|
+
status = { kind: "running" };
|
|
50910
|
+
paintSelection();
|
|
50911
|
+
options.acceptProposal(item).then((outcome) => {
|
|
50912
|
+
status = { kind: "done", outcome };
|
|
50913
|
+
if (outcome.ok) {
|
|
50914
|
+
options.onAccepted?.(item);
|
|
50915
|
+
}
|
|
50916
|
+
paintSelection();
|
|
50917
|
+
});
|
|
50918
|
+
};
|
|
50919
|
+
const handle = openModal2(otui, chrome, {
|
|
50920
|
+
title: REVIEW_COMMAND,
|
|
50921
|
+
tabs: [
|
|
50922
|
+
{ id: "list", label: "Review" },
|
|
50923
|
+
{ id: "detail", label: "Detail" }
|
|
50924
|
+
],
|
|
50925
|
+
initialTab: "list",
|
|
50926
|
+
footer: REVIEW_FOOTER,
|
|
50927
|
+
renderTab: (tabId, body, ctx) => {
|
|
50928
|
+
const renderer = options.renderer ?? chrome?.renderer;
|
|
50929
|
+
tabWidth = ctx?.width;
|
|
50930
|
+
if (tabId === "list") {
|
|
50931
|
+
listScroll = scrollToReveal3(selected, listScroll, bodyRows);
|
|
50932
|
+
listNode = paintLines3(otui, renderer, body, windowLines3(listLines(), listScroll, bodyRows));
|
|
50933
|
+
return;
|
|
50934
|
+
}
|
|
50935
|
+
detailScroll = clampScroll3(detailScroll, detailLines().length, bodyRows);
|
|
50936
|
+
detailNode = paintLines3(otui, renderer, body, windowLines3(detailLines(), detailScroll, bodyRows), tabWidth);
|
|
50937
|
+
},
|
|
50938
|
+
onClose: () => {
|
|
50939
|
+
unsubscribeKey?.();
|
|
50940
|
+
}
|
|
50941
|
+
});
|
|
50942
|
+
if (handle === undefined) {
|
|
50943
|
+
return;
|
|
50944
|
+
}
|
|
50945
|
+
if (options.onKeypress !== undefined) {
|
|
50946
|
+
unsubscribeKey = options.onKeypress((key) => {
|
|
50947
|
+
const token = key.name || key.sequence;
|
|
50948
|
+
if (items.length === 0) {
|
|
50949
|
+
return;
|
|
50950
|
+
}
|
|
50951
|
+
const onDetail = handle.activeTab() === "detail";
|
|
50952
|
+
if (onDetail && status.kind === "armed") {
|
|
50953
|
+
if (token === "y") {
|
|
50954
|
+
runAccept();
|
|
50955
|
+
} else {
|
|
50956
|
+
status = { kind: "idle" };
|
|
50957
|
+
paintSelection();
|
|
50958
|
+
}
|
|
50959
|
+
return;
|
|
50960
|
+
}
|
|
50961
|
+
if (token === "[" || token === "p") {
|
|
50962
|
+
moveSelection(selected - 1);
|
|
50963
|
+
return;
|
|
50964
|
+
}
|
|
50965
|
+
if (token === "]" || token === "n") {
|
|
50966
|
+
moveSelection(selected + 1);
|
|
50967
|
+
return;
|
|
50968
|
+
}
|
|
50969
|
+
if (token === "return" || token === "enter") {
|
|
50970
|
+
handle.setTab("detail");
|
|
50971
|
+
return;
|
|
50972
|
+
}
|
|
50973
|
+
if (onDetail && token === "a" && items[selected]?.type === "proposal" && options.acceptProposal !== undefined && status.kind !== "running") {
|
|
50974
|
+
status = { kind: "armed" };
|
|
50975
|
+
paintSelection();
|
|
50976
|
+
return;
|
|
50977
|
+
}
|
|
50978
|
+
if (token === "up" || token === "k") {
|
|
50979
|
+
if (onDetail) {
|
|
50980
|
+
detailScroll = clampScroll3(detailScroll - 1, detailLines().length, bodyRows);
|
|
50981
|
+
paintSelection();
|
|
50982
|
+
} else {
|
|
50983
|
+
moveSelection(selected - 1);
|
|
50984
|
+
}
|
|
50985
|
+
return;
|
|
50986
|
+
}
|
|
50987
|
+
if (token === "down" || token === "j") {
|
|
50988
|
+
if (onDetail) {
|
|
50989
|
+
detailScroll = clampScroll3(detailScroll + 1, detailLines().length, bodyRows);
|
|
50990
|
+
paintSelection();
|
|
50991
|
+
} else {
|
|
50992
|
+
moveSelection(selected + 1);
|
|
50993
|
+
}
|
|
50994
|
+
return;
|
|
50995
|
+
}
|
|
50996
|
+
if (onDetail && (token === "pageup" || token === "pagedown")) {
|
|
50997
|
+
const step = token === "pageup" ? -bodyRows : bodyRows;
|
|
50998
|
+
detailScroll = clampScroll3(detailScroll + step, detailLines().length, bodyRows);
|
|
50999
|
+
paintSelection();
|
|
51000
|
+
}
|
|
51001
|
+
});
|
|
51002
|
+
}
|
|
51003
|
+
return handle;
|
|
51004
|
+
}
|
|
51005
|
+
function openReview(otui, chrome, options) {
|
|
51006
|
+
return presentReview((hostOtui, hostChrome, input2) => openModal(hostOtui, hostChrome, input2), otui, chrome, options);
|
|
51007
|
+
}
|
|
51008
|
+
|
|
51009
|
+
// src/tui/review-accept.ts
|
|
51010
|
+
function shQuote(value) {
|
|
51011
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
51012
|
+
}
|
|
51013
|
+
async function acceptProposalViaShell(run, workspaceId, proposalId) {
|
|
51014
|
+
const mint = await run(`keryx workspace confirm-review ${shQuote(workspaceId)} ${shQuote(proposalId)}`);
|
|
51015
|
+
if (mint.isError) {
|
|
51016
|
+
return { ok: false, message: mint.output };
|
|
51017
|
+
}
|
|
51018
|
+
let token;
|
|
51019
|
+
try {
|
|
51020
|
+
const parsed = JSON.parse(mint.output);
|
|
51021
|
+
const candidate = parsed?.token;
|
|
51022
|
+
if (typeof candidate !== "string" || candidate.length === 0) {
|
|
51023
|
+
throw new Error("no token in confirm-review output");
|
|
51024
|
+
}
|
|
51025
|
+
token = candidate;
|
|
51026
|
+
} catch (cause) {
|
|
51027
|
+
return {
|
|
51028
|
+
ok: false,
|
|
51029
|
+
message: `could not parse \`keryx workspace confirm-review\` output: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
51030
|
+
};
|
|
51031
|
+
}
|
|
51032
|
+
const accept = await run(`keryx workspace review ${shQuote(workspaceId)} ${shQuote(proposalId)} --decision accepted --confirm-token ${shQuote(token)}`);
|
|
51033
|
+
if (accept.isError) {
|
|
51034
|
+
return { ok: false, message: accept.output };
|
|
51035
|
+
}
|
|
51036
|
+
return { ok: true };
|
|
51037
|
+
}
|
|
51038
|
+
|
|
50493
51039
|
// src/tui/tui-shell.ts
|
|
50494
51040
|
init_slate();
|
|
50495
51041
|
|
|
@@ -50854,6 +51400,11 @@ var AGENT_SLASH_COMMANDS = [
|
|
|
50854
51400
|
description: "Show this session's SAC workspace and its slates",
|
|
50855
51401
|
modes: AGENT_ONLY
|
|
50856
51402
|
},
|
|
51403
|
+
{
|
|
51404
|
+
name: "/review",
|
|
51405
|
+
description: "Show project-wide items needing review (proposals, blocked sessions)",
|
|
51406
|
+
modes: AGENT_ONLY
|
|
51407
|
+
},
|
|
50857
51408
|
{
|
|
50858
51409
|
name: "/compact",
|
|
50859
51410
|
description: "Compact model context \u2014 /compact [focus] (archive kept)",
|
|
@@ -51217,10 +51768,10 @@ init_shell_config();
|
|
|
51217
51768
|
// src/lib/permission-mode-config.ts
|
|
51218
51769
|
init_permission_mode();
|
|
51219
51770
|
init_config_dir();
|
|
51220
|
-
import
|
|
51771
|
+
import path146 from "path";
|
|
51221
51772
|
var EMPTY3 = { schemaVersion: 1, projects: {} };
|
|
51222
51773
|
function permissionModeConfigPath(dir) {
|
|
51223
|
-
return
|
|
51774
|
+
return path146.join(keryxConfigDir(dir), "permission-mode.json");
|
|
51224
51775
|
}
|
|
51225
51776
|
function withRegistryLock2(dir, fn) {
|
|
51226
51777
|
return withFileLock(`${permissionModeConfigPath(dir)}.lock`, fn, {
|
|
@@ -51565,7 +52116,7 @@ function showComposerChoice(otui, r, dock, request) {
|
|
|
51565
52116
|
// src/lib/version-check.ts
|
|
51566
52117
|
init_config_dir();
|
|
51567
52118
|
init_fs();
|
|
51568
|
-
import
|
|
52119
|
+
import path147 from "path";
|
|
51569
52120
|
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
51570
52121
|
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
51571
52122
|
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
@@ -51767,7 +52318,7 @@ async function checkVersion(options) {
|
|
|
51767
52318
|
const now = options.now ?? Date.now;
|
|
51768
52319
|
const timestamp = now();
|
|
51769
52320
|
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
51770
|
-
const cacheFile =
|
|
52321
|
+
const cacheFile = path147.join(configDir, "version-check.json");
|
|
51771
52322
|
const cache = parseCache(cacheFile);
|
|
51772
52323
|
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
51773
52324
|
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
@@ -53950,6 +54501,20 @@ async function launchTuiAgentShell(opts) {
|
|
|
53950
54501
|
currentSlates = slates;
|
|
53951
54502
|
sbWorkspaceV.content = workspace === undefined ? otui.t`${otui.dim("\u2014")}` : otui.t`${otui.dim(`${shortenCwd(workspace.title, SIDEBAR_TEXT_WIDTH)} \xB7 ${workspace.status} \xB7 ${slates.length} slate${slates.length === 1 ? "" : "s"}`)}`;
|
|
53952
54503
|
};
|
|
54504
|
+
sidebar.add(new otui.TextRenderable(r, { id: "sb-review-k", content: otui.t`${otui.dim("Review")}`, marginTop: 1 }));
|
|
54505
|
+
const sbReviewV = new otui.TextRenderable(r, {
|
|
54506
|
+
id: "sb-review-v",
|
|
54507
|
+
content: otui.t`${otui.dim("\u2014")}`,
|
|
54508
|
+
onMouseDown: () => {
|
|
54509
|
+
showReview();
|
|
54510
|
+
}
|
|
54511
|
+
});
|
|
54512
|
+
sidebar.add(sbReviewV);
|
|
54513
|
+
const refreshReviewSidebar = async () => {
|
|
54514
|
+
const cwd = opts.session?.cwd ?? process.cwd();
|
|
54515
|
+
const count = catchUpItems(await loadInspectorCatchUp(cwd)).length;
|
|
54516
|
+
sbReviewV.content = count === 0 ? otui.t`${otui.dim("\u2014 nothing to review")}` : otui.t`${otui.yellow(`${count} item${count === 1 ? "" : "s"} need review`)}`;
|
|
54517
|
+
};
|
|
53953
54518
|
sidebar.add(new otui.TextRenderable(r, { id: "sb-ctx-k", content: otui.t`${otui.dim("Context")}`, marginTop: 1 }));
|
|
53954
54519
|
const sbContext = new otui.TextRenderable(r, { id: "sb-ctx-v", content: otui.t`${otui.dim("0 tokens")}` });
|
|
53955
54520
|
sidebar.add(sbContext);
|
|
@@ -54390,6 +54955,7 @@ async function launchTuiAgentShell(opts) {
|
|
|
54390
54955
|
}
|
|
54391
54956
|
slateSession = { dir: liveSession.dir, cwd: sessionCwd, opened: false };
|
|
54392
54957
|
refreshWorkspaceSidebar();
|
|
54958
|
+
refreshReviewSidebar();
|
|
54393
54959
|
const paintSessionHeader = () => {
|
|
54394
54960
|
const label = `${currentSel.provider}/${currentSel.model}`;
|
|
54395
54961
|
const sid = shortSessionId(liveSession.summary.id);
|
|
@@ -54559,6 +55125,21 @@ Staying in the current session.
|
|
|
54559
55125
|
});
|
|
54560
55126
|
})();
|
|
54561
55127
|
};
|
|
55128
|
+
const showReview = () => {
|
|
55129
|
+
(async () => {
|
|
55130
|
+
const cwd = inspectorCwd();
|
|
55131
|
+
const items = catchUpItems(await loadInspectorCatchUp(cwd));
|
|
55132
|
+
openReview(otui, chrome, {
|
|
55133
|
+
items,
|
|
55134
|
+
acceptProposal: (item) => acceptProposalViaShell(makeCommandRunner(cwd), item.workspaceId, item.proposalId),
|
|
55135
|
+
onAccepted: () => {
|
|
55136
|
+
refreshReviewSidebar();
|
|
55137
|
+
},
|
|
55138
|
+
renderer: r,
|
|
55139
|
+
...inspectorKeys
|
|
55140
|
+
});
|
|
55141
|
+
})();
|
|
55142
|
+
};
|
|
54562
55143
|
const updateModelLabels = () => {
|
|
54563
55144
|
paintSessionHeader();
|
|
54564
55145
|
const label = `${currentSel.provider}/${currentSel.model}`;
|
|
@@ -55078,6 +55659,7 @@ Staying in the current session.
|
|
|
55078
55659
|
startNewSession();
|
|
55079
55660
|
slateSession = { dir: liveSession.dir, cwd: sessionCwd, opened: false };
|
|
55080
55661
|
refreshWorkspaceSidebar();
|
|
55662
|
+
refreshReviewSidebar();
|
|
55081
55663
|
sessions.clear();
|
|
55082
55664
|
deps.resetSubagentBudget?.();
|
|
55083
55665
|
io.onSystem?.(`New session ${shortSessionId(liveSession.summary.id)} (previous kept on disk \xB7 /resume)
|
|
@@ -55216,6 +55798,10 @@ Staying in the current session.
|
|
|
55216
55798
|
showWorkspace();
|
|
55217
55799
|
return;
|
|
55218
55800
|
}
|
|
55801
|
+
if (isReviewCommand(command.name)) {
|
|
55802
|
+
showReview();
|
|
55803
|
+
return;
|
|
55804
|
+
}
|
|
55219
55805
|
if (command.name === "/copy") {
|
|
55220
55806
|
const target = newestBlock();
|
|
55221
55807
|
if (target === undefined || !copyBlock(target.id)) {
|
|
@@ -55535,6 +56121,7 @@ ${formatThemeList(getThemeId())}`);
|
|
|
55535
56121
|
const secs = ((Date.now() - startedAt) / 1000).toFixed(1);
|
|
55536
56122
|
stopBusy();
|
|
55537
56123
|
refreshWorkspaceSidebar();
|
|
56124
|
+
refreshReviewSidebar();
|
|
55538
56125
|
setMainAgent(turnFailed ? "failed" : "done", turnFailed ? "error" : "idle");
|
|
55539
56126
|
try {
|
|
55540
56127
|
flushSessionCheckpoint();
|
|
@@ -56903,7 +57490,7 @@ ${indentBlock(style.dim(context), GUTTER)}`);
|
|
|
56903
57490
|
out(`${GUTTER}${style.yellow(hint)}
|
|
56904
57491
|
`);
|
|
56905
57492
|
}
|
|
56906
|
-
const rememberable = !evaled.destructive && !evaled.credentials;
|
|
57493
|
+
const rememberable = !evaled.destructive && !evaled.credentials && !evaled.sacReviewConfirmation;
|
|
56907
57494
|
const prompt = rememberable ? "[y/N/A=always] " : "[y/N] ";
|
|
56908
57495
|
out(`
|
|
56909
57496
|
${GUTTER}${style.yellow(`Run: ${evaled.command}`)} ${style.dim(prompt)}`);
|
|
@@ -57445,7 +58032,7 @@ async function shellCommand(args2, runtime = {}) {
|
|
|
57445
58032
|
modelId: sel.model
|
|
57446
58033
|
}),
|
|
57447
58034
|
maxToolCalls: resolveAgentMaxToolCalls(),
|
|
57448
|
-
idSeq: () =>
|
|
58035
|
+
idSeq: () => randomUUID25(),
|
|
57449
58036
|
...resetSubagentBudget !== undefined ? { resetSubagentBudget } : {}
|
|
57450
58037
|
};
|
|
57451
58038
|
};
|
|
@@ -57477,7 +58064,7 @@ async function shellCommand(args2, runtime = {}) {
|
|
|
57477
58064
|
makeShellDeps: (sel) => ({
|
|
57478
58065
|
makeProvider: chatFactory,
|
|
57479
58066
|
clock: () => new Date().toISOString(),
|
|
57480
|
-
idSeq: () =>
|
|
58067
|
+
idSeq: () => randomUUID25(),
|
|
57481
58068
|
initial: sel,
|
|
57482
58069
|
session: {
|
|
57483
58070
|
cwd,
|
|
@@ -57548,7 +58135,7 @@ async function shellCommand(args2, runtime = {}) {
|
|
|
57548
58135
|
const deps = {
|
|
57549
58136
|
makeProvider: baseFactory,
|
|
57550
58137
|
clock: () => new Date().toISOString(),
|
|
57551
|
-
idSeq: () =>
|
|
58138
|
+
idSeq: () => randomUUID25(),
|
|
57552
58139
|
initial: baseUrl2 === undefined ? { provider, model } : { provider, model, baseUrl: baseUrl2 },
|
|
57553
58140
|
selectProviderModel: realSelectProviderModel(baseUrl2)
|
|
57554
58141
|
};
|
|
@@ -57599,7 +58186,7 @@ async function shellCommand(args2, runtime = {}) {
|
|
|
57599
58186
|
modelId: model
|
|
57600
58187
|
}),
|
|
57601
58188
|
maxToolCalls: resolveAgentMaxToolCalls(),
|
|
57602
|
-
idSeq: () =>
|
|
58189
|
+
idSeq: () => randomUUID25(),
|
|
57603
58190
|
...resetSubagentBudget !== undefined ? { resetSubagentBudget } : {}
|
|
57604
58191
|
};
|
|
57605
58192
|
let resumeId = flags.resumeId;
|
|
@@ -57771,7 +58358,7 @@ Shell:
|
|
|
57771
58358
|
init_fs();
|
|
57772
58359
|
import { readFile as readFile78 } from "fs/promises";
|
|
57773
58360
|
import { stdin } from "process";
|
|
57774
|
-
import
|
|
58361
|
+
import path148 from "path";
|
|
57775
58362
|
var MODULES = [
|
|
57776
58363
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
57777
58364
|
{ name: "gdctx", flag: "--no-gdctx", desc: "token-aware command/read output", defaultEnabled: true },
|
|
@@ -57817,8 +58404,8 @@ async function modulesCommand(args2 = []) {
|
|
|
57817
58404
|
return;
|
|
57818
58405
|
}
|
|
57819
58406
|
const wantsJson = args2.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
57820
|
-
const metaprojectRoot =
|
|
57821
|
-
const manifestPath =
|
|
58407
|
+
const metaprojectRoot = path148.join(process.cwd(), ".metaproject");
|
|
58408
|
+
const manifestPath = path148.join(metaprojectRoot, "metaproject.json");
|
|
57822
58409
|
if (!await pathExists(manifestPath)) {
|
|
57823
58410
|
if (wantsJson) {
|
|
57824
58411
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -57932,18 +58519,18 @@ function printHelp16() {
|
|
|
57932
58519
|
}
|
|
57933
58520
|
|
|
57934
58521
|
// src/commands/serve.ts
|
|
57935
|
-
import { randomUUID as
|
|
58522
|
+
import { randomUUID as randomUUID28 } from "crypto";
|
|
57936
58523
|
|
|
57937
58524
|
// src/lib/serve-config.ts
|
|
57938
58525
|
init_config_dir();
|
|
57939
58526
|
import { existsSync as existsSync27 } from "fs";
|
|
57940
|
-
import
|
|
58527
|
+
import path149 from "path";
|
|
57941
58528
|
var SERVE_CONFIG_SCHEMA_VERSION = "1.0.0";
|
|
57942
58529
|
var DEFAULT_SERVE_BIND_ADDRESS = "127.0.0.1";
|
|
57943
58530
|
var DEFAULT_SERVE_PORT = 7377;
|
|
57944
58531
|
var DEFAULT_SERVE_PROFILE = "remote-restricted";
|
|
57945
58532
|
function serveConfigPath(dir) {
|
|
57946
|
-
return
|
|
58533
|
+
return path149.join(keryxConfigDir(dir), "serve.json");
|
|
57947
58534
|
}
|
|
57948
58535
|
function parseIpv4(value) {
|
|
57949
58536
|
const parts = value.split(".");
|
|
@@ -58259,7 +58846,7 @@ function saveServeConfig(config, dir, onWarn) {
|
|
|
58259
58846
|
|
|
58260
58847
|
// src/lib/serve-credential.ts
|
|
58261
58848
|
init_config_dir();
|
|
58262
|
-
import { createHash as createHash33, randomBytes as randomBytes3, randomUUID as
|
|
58849
|
+
import { createHash as createHash33, randomBytes as randomBytes3, randomUUID as randomUUID26 } from "crypto";
|
|
58263
58850
|
import {
|
|
58264
58851
|
chmodSync as chmodSync4,
|
|
58265
58852
|
closeSync as closeSync3,
|
|
@@ -58271,9 +58858,9 @@ import {
|
|
|
58271
58858
|
unlinkSync as unlinkSync3,
|
|
58272
58859
|
writeFileSync as writeFileSync8
|
|
58273
58860
|
} from "fs";
|
|
58274
|
-
import
|
|
58861
|
+
import path150 from "path";
|
|
58275
58862
|
function serveCredentialPath(dir) {
|
|
58276
|
-
return
|
|
58863
|
+
return path150.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
58277
58864
|
}
|
|
58278
58865
|
function constantTimeEqual(a, b) {
|
|
58279
58866
|
const width = Math.max(a.length, b.length);
|
|
@@ -58343,7 +58930,7 @@ function readServeCredential(dir) {
|
|
|
58343
58930
|
}
|
|
58344
58931
|
function writeStore(store, dir) {
|
|
58345
58932
|
const file = serveCredentialPath(dir);
|
|
58346
|
-
const temp = `${file}.${
|
|
58933
|
+
const temp = `${file}.${randomUUID26()}.tmp`;
|
|
58347
58934
|
try {
|
|
58348
58935
|
ensureKeryxConfigDir(dir);
|
|
58349
58936
|
const handle = openSync3(temp, "wx", 384);
|
|
@@ -58383,7 +58970,7 @@ function mintRecord(now) {
|
|
|
58383
58970
|
const salt = randomBytes3(32).toString("hex");
|
|
58384
58971
|
return {
|
|
58385
58972
|
token,
|
|
58386
|
-
record: { id:
|
|
58973
|
+
record: { id: randomUUID26(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
|
|
58387
58974
|
};
|
|
58388
58975
|
}
|
|
58389
58976
|
function issueServeToken(dir, now = () => new Date().toISOString(), onWaiting) {
|
|
@@ -58507,22 +59094,22 @@ class AuthFailureThrottle {
|
|
|
58507
59094
|
init_config_dir();
|
|
58508
59095
|
import { createHash as createHash34 } from "crypto";
|
|
58509
59096
|
import { existsSync as existsSync29, readdirSync as readdirSync2, rmSync as rmSync2 } from "fs";
|
|
58510
|
-
import
|
|
59097
|
+
import path151 from "path";
|
|
58511
59098
|
var MAX_TURN_EVENTS = 1e4;
|
|
58512
59099
|
function turnsRoot(dir) {
|
|
58513
|
-
return
|
|
59100
|
+
return path151.join(keryxConfigDir(dir), "turns");
|
|
58514
59101
|
}
|
|
58515
59102
|
function turnDir(turnId, dir) {
|
|
58516
|
-
return
|
|
59103
|
+
return path151.join(turnsRoot(dir), turnId);
|
|
58517
59104
|
}
|
|
58518
59105
|
function keyPath(project, idempotencyKey, dir) {
|
|
58519
59106
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
58520
59107
|
const digest2 = createHash34("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
58521
|
-
return
|
|
59108
|
+
return path151.join(turnsRoot(dir), "keys", `${digest2}.json`);
|
|
58522
59109
|
}
|
|
58523
59110
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
58524
59111
|
const digest2 = createHash34("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
58525
|
-
return
|
|
59112
|
+
return path151.join(turnsRoot(dir), "keys", `${digest2}.json`);
|
|
58526
59113
|
}
|
|
58527
59114
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
58528
59115
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -58586,7 +59173,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
58586
59173
|
}
|
|
58587
59174
|
function createTurnRecord(record, dir) {
|
|
58588
59175
|
ensureTurnDir(record.turnId, dir);
|
|
58589
|
-
writeOwnerOnlyFile(
|
|
59176
|
+
writeOwnerOnlyFile(path151.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
58590
59177
|
`);
|
|
58591
59178
|
}
|
|
58592
59179
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -58595,12 +59182,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
58595
59182
|
}
|
|
58596
59183
|
const line = JSON.stringify(event);
|
|
58597
59184
|
try {
|
|
58598
|
-
appendOwnerOnlyLine(
|
|
59185
|
+
appendOwnerOnlyLine(path151.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
58599
59186
|
} catch (error2) {
|
|
58600
59187
|
if (error2?.code !== "ENOENT") {
|
|
58601
59188
|
throw error2;
|
|
58602
59189
|
}
|
|
58603
|
-
appendOwnerOnlyLine(
|
|
59190
|
+
appendOwnerOnlyLine(path151.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
58604
59191
|
}
|
|
58605
59192
|
return true;
|
|
58606
59193
|
}
|
|
@@ -58608,7 +59195,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
58608
59195
|
if (!isTurnId(turnId)) {
|
|
58609
59196
|
return { ok: false, reason: "not-a-turn-id" };
|
|
58610
59197
|
}
|
|
58611
|
-
const read = readTurnFile(
|
|
59198
|
+
const read = readTurnFile(path151.join(turnDir(turnId, dir), "events.jsonl"));
|
|
58612
59199
|
if (!read.ok) {
|
|
58613
59200
|
if (isDefiniteAbsence2(read.reason)) {
|
|
58614
59201
|
return { ok: true, value: [] };
|
|
@@ -58636,7 +59223,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
58636
59223
|
if (!isTurnId(turnId)) {
|
|
58637
59224
|
return { ok: false, reason: "not-a-turn-id" };
|
|
58638
59225
|
}
|
|
58639
|
-
const read = readTurnFile(
|
|
59226
|
+
const read = readTurnFile(path151.join(turnDir(turnId, dir), "turn.json"));
|
|
58640
59227
|
if (!read.ok) {
|
|
58641
59228
|
return { ok: false, reason: read.reason };
|
|
58642
59229
|
}
|
|
@@ -58655,7 +59242,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
58655
59242
|
if (!record.ok) {
|
|
58656
59243
|
return false;
|
|
58657
59244
|
}
|
|
58658
|
-
writeOwnerOnlyFile(
|
|
59245
|
+
writeOwnerOnlyFile(path151.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
58659
59246
|
`);
|
|
58660
59247
|
return true;
|
|
58661
59248
|
}
|
|
@@ -58700,8 +59287,8 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
58700
59287
|
}
|
|
58701
59288
|
|
|
58702
59289
|
// src/lib/serve-turn.ts
|
|
58703
|
-
import { randomUUID as
|
|
58704
|
-
import
|
|
59290
|
+
import { randomUUID as randomUUID27 } from "crypto";
|
|
59291
|
+
import path152 from "path";
|
|
58705
59292
|
init_service();
|
|
58706
59293
|
var REMOTE_ORIGIN = "remote:http";
|
|
58707
59294
|
var MAX_PROMPT_CHARS = 32000;
|
|
@@ -58770,9 +59357,9 @@ function isUuid(value) {
|
|
|
58770
59357
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(value);
|
|
58771
59358
|
}
|
|
58772
59359
|
function resolveProject(declared, dir) {
|
|
58773
|
-
const wanted =
|
|
59360
|
+
const wanted = path152.resolve(declared);
|
|
58774
59361
|
for (const entry of listProjects(dir, () => {})) {
|
|
58775
|
-
if (
|
|
59362
|
+
if (path152.resolve(entry.path) === wanted) {
|
|
58776
59363
|
return { ok: true, project: entry.path };
|
|
58777
59364
|
}
|
|
58778
59365
|
}
|
|
@@ -58819,7 +59406,7 @@ async function redactOut(security, text) {
|
|
|
58819
59406
|
async function runRemoteTurn(input2) {
|
|
58820
59407
|
const scanRoot = input2.scanRoot;
|
|
58821
59408
|
const security = createSecurityService(scanRoot);
|
|
58822
|
-
const newId = input2.newId ?? (() =>
|
|
59409
|
+
const newId = input2.newId ?? (() => randomUUID27());
|
|
58823
59410
|
const clock = input2.clock ?? (() => new Date().toISOString());
|
|
58824
59411
|
const turnId = input2.turnId ?? newId();
|
|
58825
59412
|
const sessionId = input2.request.sessionId ?? newId();
|
|
@@ -58962,7 +59549,7 @@ function outcomeOf(status, gate, unresolvedBlockerIds) {
|
|
|
58962
59549
|
}
|
|
58963
59550
|
function createSubmitTurn(deps) {
|
|
58964
59551
|
return async (request, project) => {
|
|
58965
|
-
const turnId = (deps.newId ?? (() =>
|
|
59552
|
+
const turnId = (deps.newId ?? (() => randomUUID27()))();
|
|
58966
59553
|
const scanned = await scanPrompt(deps.dir, request.prompt);
|
|
58967
59554
|
if (scanned.rejected) {
|
|
58968
59555
|
return { kind: "rejected" };
|
|
@@ -59649,7 +60236,7 @@ function runConfig(args2) {
|
|
|
59649
60236
|
return;
|
|
59650
60237
|
}
|
|
59651
60238
|
const credential2 = readServeCredential();
|
|
59652
|
-
const credentialId = credential2.status === "ok" ? credential2.record.id :
|
|
60239
|
+
const credentialId = credential2.status === "ok" ? credential2.record.id : randomUUID28();
|
|
59653
60240
|
const config = defaultServeConfig(credentialId, {
|
|
59654
60241
|
address: parsed.parsed.values.get("--bind") ?? DEFAULT_SERVE_BIND_ADDRESS,
|
|
59655
60242
|
port: port ?? DEFAULT_SERVE_PORT,
|
|
@@ -59805,9 +60392,9 @@ function printHelp17() {
|
|
|
59805
60392
|
|
|
59806
60393
|
// src/commands/update.ts
|
|
59807
60394
|
import { spawn as spawn5 } from "child_process";
|
|
59808
|
-
import { chmod as chmod4, mkdir as mkdir54, readFile as readFile79, readdir as
|
|
60395
|
+
import { chmod as chmod4, mkdir as mkdir54, readFile as readFile79, readdir as readdir25, writeFile as writeFile48 } from "fs/promises";
|
|
59809
60396
|
import { access as access4, constants as constants2, existsSync as existsSync30 } from "fs";
|
|
59810
|
-
import
|
|
60397
|
+
import path153 from "path";
|
|
59811
60398
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
59812
60399
|
init_config();
|
|
59813
60400
|
init_config2();
|
|
@@ -59823,8 +60410,8 @@ async function updateCommand(args2 = []) {
|
|
|
59823
60410
|
return;
|
|
59824
60411
|
}
|
|
59825
60412
|
const projectRoot = process.cwd();
|
|
59826
|
-
const metaprojectRoot =
|
|
59827
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
60413
|
+
const metaprojectRoot = path153.join(projectRoot, ".metaproject");
|
|
60414
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path153.basename(projectRoot)}/`);
|
|
59828
60415
|
if (!await pathExists(metaprojectRoot)) {
|
|
59829
60416
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
59830
60417
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -59870,12 +60457,12 @@ async function updateCommand(args2 = []) {
|
|
|
59870
60457
|
nextSteps(steps);
|
|
59871
60458
|
}
|
|
59872
60459
|
async function refreshServiceFiles(projectRoot, options) {
|
|
59873
|
-
const metaprojectRoot =
|
|
60460
|
+
const metaprojectRoot = path153.join(projectRoot, ".metaproject");
|
|
59874
60461
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
59875
60462
|
const manifest = manifestState.manifest;
|
|
59876
60463
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
59877
60464
|
if (manifestState.migrated) {
|
|
59878
|
-
await writeFile48(
|
|
60465
|
+
await writeFile48(path153.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
59879
60466
|
`, "utf8");
|
|
59880
60467
|
}
|
|
59881
60468
|
const enableGdgraph = moduleEnabled2(manifest, "gdgraph");
|
|
@@ -59912,11 +60499,11 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
59912
60499
|
enableSecurity,
|
|
59913
60500
|
enableSac
|
|
59914
60501
|
});
|
|
59915
|
-
await writeTextIfChanged4(
|
|
59916
|
-
await writeTextIfChanged4(
|
|
59917
|
-
await writeTextIfChanged4(
|
|
59918
|
-
await writeTextIfChanged4(
|
|
59919
|
-
await writeTextIfChanged4(
|
|
60502
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
60503
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
60504
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "rules", "README.md"), renderProjectRulesReadme());
|
|
60505
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
60506
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "index.md"), renderIndexMarkdown({
|
|
59920
60507
|
enableGdgraph,
|
|
59921
60508
|
enableGdctx,
|
|
59922
60509
|
enableGdwiki,
|
|
@@ -59929,7 +60516,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
59929
60516
|
ruleSources,
|
|
59930
60517
|
hasDistilledEntrypoints: await hasDistilledEntrypoints(metaprojectRoot)
|
|
59931
60518
|
}));
|
|
59932
|
-
await writeTextIfChanged4(
|
|
60519
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
59933
60520
|
enableGdgraph,
|
|
59934
60521
|
enableGdctx,
|
|
59935
60522
|
enableGdwiki,
|
|
@@ -59941,7 +60528,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
59941
60528
|
enableSecurity,
|
|
59942
60529
|
data: dashboardData
|
|
59943
60530
|
}));
|
|
59944
|
-
await writeTextIfMissing4(
|
|
60531
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
59945
60532
|
enableGdgraph,
|
|
59946
60533
|
enableGdctx,
|
|
59947
60534
|
enableGdwiki,
|
|
@@ -59954,31 +60541,31 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
59954
60541
|
}));
|
|
59955
60542
|
if (enableGdgraph) {
|
|
59956
60543
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
59957
|
-
await writeTextIfChanged4(
|
|
59958
|
-
await writeTextIfChanged4(
|
|
59959
|
-
await writeTextIfChanged4(
|
|
60544
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
60545
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
60546
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
59960
60547
|
await seedAssetsLock(metaprojectRoot);
|
|
59961
60548
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
59962
60549
|
await installManagedHook2(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
59963
60550
|
}
|
|
59964
60551
|
}
|
|
59965
60552
|
if (enableGdctx) {
|
|
59966
|
-
await writeTextIfMissing4(
|
|
59967
|
-
await writeTextIfChanged4(
|
|
59968
|
-
await writeTextIfChanged4(
|
|
59969
|
-
await writeTextIfChanged4(
|
|
60553
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
60554
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
60555
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
60556
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
59970
60557
|
}
|
|
59971
60558
|
if (enableGdwiki) {
|
|
59972
|
-
await writeTextIfMissing4(
|
|
59973
|
-
await writeTextIfChanged4(
|
|
59974
|
-
await writeTextIfChanged4(
|
|
60559
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
60560
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
60561
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
59975
60562
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
59976
60563
|
await installManagedHook2(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
59977
60564
|
}
|
|
59978
60565
|
}
|
|
59979
60566
|
if (enableSac) {
|
|
59980
|
-
await writeTextIfMissing4(
|
|
59981
|
-
await writeTextIfChanged4(
|
|
60567
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
|
|
60568
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
|
|
59982
60569
|
}
|
|
59983
60570
|
if (enableGdskills) {
|
|
59984
60571
|
await installGdskills(metaprojectRoot, gdskillsProfile, { createDataDirs: false });
|
|
@@ -59987,25 +60574,25 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
59987
60574
|
}
|
|
59988
60575
|
}
|
|
59989
60576
|
if (enableHealth) {
|
|
59990
|
-
await writeTextIfMissing4(
|
|
59991
|
-
await writeTextIfChanged4(
|
|
59992
|
-
await writeTextIfChanged4(
|
|
59993
|
-
await writeTextIfChanged4(
|
|
60577
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
60578
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
60579
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
60580
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
59994
60581
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
59995
60582
|
await installManagedHook2(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
59996
60583
|
}
|
|
59997
60584
|
}
|
|
59998
60585
|
if (enableTesting) {
|
|
59999
|
-
await writeTextIfMissing4(
|
|
60586
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
60000
60587
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
60001
60588
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
60002
60589
|
}));
|
|
60003
|
-
await writeTextIfChanged4(
|
|
60004
|
-
await writeTextIfChanged4(
|
|
60005
|
-
await writeTextIfChanged4(
|
|
60590
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
60591
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
60592
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
60006
60593
|
if (enableGdwiki) {
|
|
60007
|
-
await writeTextIfMissing4(
|
|
60008
|
-
await writeTextIfMissing4(
|
|
60594
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
60595
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
60009
60596
|
}
|
|
60010
60597
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
60011
60598
|
await installManagedHook2(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -60018,24 +60605,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
60018
60605
|
await installManagedHook2(projectRoot, "post-commit", "metaproject-dashboard-post-commit", renderMetaprojectDashboardPostCommitHook());
|
|
60019
60606
|
}
|
|
60020
60607
|
if (enableMemory) {
|
|
60021
|
-
await writeTextIfMissing4(
|
|
60022
|
-
await writeTextIfMissing4(
|
|
60023
|
-
await writeTextIfChanged4(
|
|
60024
|
-
await writeTextIfChanged4(
|
|
60025
|
-
await writeTextIfChanged4(
|
|
60608
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
60609
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
60610
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
60611
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
60612
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
60026
60613
|
}
|
|
60027
60614
|
if (enableTasks) {
|
|
60028
|
-
await writeTextIfChanged4(
|
|
60029
|
-
await writeTextIfChanged4(
|
|
60030
|
-
await writeTextIfChanged4(
|
|
60031
|
-
await writeTextIfChanged4(
|
|
60032
|
-
await writeTextIfChanged4(
|
|
60033
|
-
await writeTextIfChanged4(
|
|
60615
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
60616
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
60617
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
60618
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
60619
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
60620
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
60034
60621
|
}
|
|
60035
60622
|
if (enableSecurity) {
|
|
60036
|
-
await writeTextIfMissing4(
|
|
60037
|
-
await writeTextIfChanged4(
|
|
60038
|
-
await writeTextIfChanged4(
|
|
60623
|
+
await writeTextIfMissing4(path153.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
60624
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
60625
|
+
await writeTextIfChanged4(path153.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
60039
60626
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
60040
60627
|
await installManagedHook2(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
60041
60628
|
}
|
|
@@ -60086,13 +60673,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
60086
60673
|
};
|
|
60087
60674
|
}
|
|
60088
60675
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
60089
|
-
const metaprojectRoot =
|
|
60676
|
+
const metaprojectRoot = path153.join(projectRoot, ".metaproject");
|
|
60090
60677
|
if (!await pathExists(metaprojectRoot)) {
|
|
60091
60678
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
60092
60679
|
}
|
|
60093
60680
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
60094
60681
|
const data = await collectDashboardData(metaprojectRoot);
|
|
60095
|
-
const dashboardPath =
|
|
60682
|
+
const dashboardPath = path153.join(metaprojectRoot, "keryx-dashboard.html");
|
|
60096
60683
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
60097
60684
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
60098
60685
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -60112,7 +60699,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
60112
60699
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
60113
60700
|
return true;
|
|
60114
60701
|
}
|
|
60115
|
-
const hookPath =
|
|
60702
|
+
const hookPath = path153.join(projectRoot, ".git", "hooks", "post-commit");
|
|
60116
60703
|
if (!await pathExists(hookPath)) {
|
|
60117
60704
|
return false;
|
|
60118
60705
|
}
|
|
@@ -60132,11 +60719,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
60132
60719
|
if (testing) {
|
|
60133
60720
|
data.testing = testing;
|
|
60134
60721
|
}
|
|
60135
|
-
const wiki = await collectMarkdownPages(
|
|
60722
|
+
const wiki = await collectMarkdownPages(path153.join(metaprojectRoot, "wiki"), "wiki");
|
|
60136
60723
|
if (wiki.length > 0) {
|
|
60137
60724
|
data.wiki = { pages: wiki };
|
|
60138
60725
|
}
|
|
60139
|
-
const memory = await collectMarkdownPages(
|
|
60726
|
+
const memory = await collectMarkdownPages(path153.join(metaprojectRoot, "memory"), "memory");
|
|
60140
60727
|
if (memory.length > 0) {
|
|
60141
60728
|
data.memory = { entries: memory };
|
|
60142
60729
|
}
|
|
@@ -60151,19 +60738,19 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
60151
60738
|
return data;
|
|
60152
60739
|
}
|
|
60153
60740
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
60154
|
-
const flowsRoot2 =
|
|
60741
|
+
const flowsRoot2 = path153.join(metaprojectRoot, "flows");
|
|
60155
60742
|
if (!await pathExists(flowsRoot2)) {
|
|
60156
60743
|
return null;
|
|
60157
60744
|
}
|
|
60158
60745
|
let dirEntries;
|
|
60159
60746
|
try {
|
|
60160
|
-
dirEntries = (await
|
|
60747
|
+
dirEntries = (await readdir25(flowsRoot2, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^\d{3}-/.test(entry.name)).map((entry) => entry.name).sort();
|
|
60161
60748
|
} catch {
|
|
60162
60749
|
return null;
|
|
60163
60750
|
}
|
|
60164
60751
|
const flows = [];
|
|
60165
60752
|
for (const dir of dirEntries) {
|
|
60166
|
-
const flowPath =
|
|
60753
|
+
const flowPath = path153.join(flowsRoot2, dir, "flow.json");
|
|
60167
60754
|
if (!await pathExists(flowPath)) {
|
|
60168
60755
|
continue;
|
|
60169
60756
|
}
|
|
@@ -60171,7 +60758,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
60171
60758
|
const flow = JSON.parse(await readFile79(flowPath, "utf8"));
|
|
60172
60759
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
60173
60760
|
let acTotal = 0;
|
|
60174
|
-
const acPath2 =
|
|
60761
|
+
const acPath2 = path153.join(flowsRoot2, dir, "acceptance-criteria.md");
|
|
60175
60762
|
if (await pathExists(acPath2)) {
|
|
60176
60763
|
const acContent = await readFile79(acPath2, "utf8");
|
|
60177
60764
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
@@ -60225,7 +60812,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
60225
60812
|
"data/testing/context.md"
|
|
60226
60813
|
];
|
|
60227
60814
|
for (const href of staticHrefs) {
|
|
60228
|
-
const filePath =
|
|
60815
|
+
const filePath = path153.join(metaprojectRoot, ...href.split("/"));
|
|
60229
60816
|
if (!await pathExists(filePath)) {
|
|
60230
60817
|
continue;
|
|
60231
60818
|
}
|
|
@@ -60242,7 +60829,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
60242
60829
|
return docs;
|
|
60243
60830
|
}
|
|
60244
60831
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
60245
|
-
const reportPath2 =
|
|
60832
|
+
const reportPath2 = path153.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
60246
60833
|
if (!await pathExists(reportPath2)) {
|
|
60247
60834
|
return;
|
|
60248
60835
|
}
|
|
@@ -60351,8 +60938,8 @@ function metricToScope(metric) {
|
|
|
60351
60938
|
};
|
|
60352
60939
|
}
|
|
60353
60940
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
60354
|
-
const nodesPath =
|
|
60355
|
-
const edgesPath =
|
|
60941
|
+
const nodesPath = path153.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
60942
|
+
const edgesPath = path153.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
60356
60943
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
60357
60944
|
return;
|
|
60358
60945
|
}
|
|
@@ -60403,8 +60990,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
60403
60990
|
};
|
|
60404
60991
|
}
|
|
60405
60992
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
60406
|
-
const reportPath2 =
|
|
60407
|
-
const contextPath =
|
|
60993
|
+
const reportPath2 = path153.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
60994
|
+
const contextPath = path153.join(metaprojectRoot, "data", "testing", "context.md");
|
|
60408
60995
|
if (await pathExists(reportPath2)) {
|
|
60409
60996
|
const report = JSON.parse(await readFile79(reportPath2, "utf8"));
|
|
60410
60997
|
const totalTests = numberOrUndefined(report.total);
|
|
@@ -60433,7 +61020,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
60433
61020
|
const files = await listMarkdownFiles(root);
|
|
60434
61021
|
const pages = [];
|
|
60435
61022
|
for (const filePath of files.slice(0, 40)) {
|
|
60436
|
-
const relativePath =
|
|
61023
|
+
const relativePath = path153.relative(root, filePath).split(path153.sep).join("/");
|
|
60437
61024
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
60438
61025
|
continue;
|
|
60439
61026
|
}
|
|
@@ -60451,10 +61038,10 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
60451
61038
|
return pages;
|
|
60452
61039
|
}
|
|
60453
61040
|
async function listMarkdownFiles(root) {
|
|
60454
|
-
const entries = await
|
|
61041
|
+
const entries = await readdir25(root, { withFileTypes: true });
|
|
60455
61042
|
const files = [];
|
|
60456
61043
|
for (const entry of entries) {
|
|
60457
|
-
const fullPath =
|
|
61044
|
+
const fullPath = path153.join(root, entry.name);
|
|
60458
61045
|
if (entry.isDirectory()) {
|
|
60459
61046
|
files.push(...await listMarkdownFiles(fullPath));
|
|
60460
61047
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -60502,7 +61089,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
60502
61089
|
const manifest = {
|
|
60503
61090
|
schemaVersion: 1,
|
|
60504
61091
|
standardVersion: STANDARD_VERSION,
|
|
60505
|
-
name: `${
|
|
61092
|
+
name: `${path153.basename(path153.dirname(metaprojectRoot))}-metaproject`,
|
|
60506
61093
|
createdBy: "keryx",
|
|
60507
61094
|
profiles: computeProfiles(enabledModuleKeys2),
|
|
60508
61095
|
paths: {
|
|
@@ -60603,11 +61190,11 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
60603
61190
|
metaproject: ".metaproject/index.md"
|
|
60604
61191
|
}
|
|
60605
61192
|
};
|
|
60606
|
-
await writeFile48(
|
|
61193
|
+
await writeFile48(path153.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
60607
61194
|
`, "utf8");
|
|
60608
61195
|
}
|
|
60609
61196
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
60610
|
-
const manifestPath =
|
|
61197
|
+
const manifestPath = path153.join(metaprojectRoot, "metaproject.json");
|
|
60611
61198
|
if (!await pathExists(manifestPath)) {
|
|
60612
61199
|
return;
|
|
60613
61200
|
}
|
|
@@ -60630,7 +61217,7 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
60630
61217
|
`, "utf8");
|
|
60631
61218
|
}
|
|
60632
61219
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
60633
|
-
const manifestPath =
|
|
61220
|
+
const manifestPath = path153.join(metaprojectRoot, "metaproject.json");
|
|
60634
61221
|
if (!await pathExists(manifestPath)) {
|
|
60635
61222
|
return;
|
|
60636
61223
|
}
|
|
@@ -60666,72 +61253,72 @@ async function updateRuntime(projectRoot) {
|
|
|
60666
61253
|
}
|
|
60667
61254
|
}
|
|
60668
61255
|
async function findRuntimeRoot(projectRoot) {
|
|
60669
|
-
const projectRuntime =
|
|
60670
|
-
if (await pathExists(
|
|
61256
|
+
const projectRuntime = path153.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
61257
|
+
if (await pathExists(path153.join(projectRuntime, ".git"))) {
|
|
60671
61258
|
return projectRuntime;
|
|
60672
61259
|
}
|
|
60673
61260
|
const home = process.env.HOME;
|
|
60674
61261
|
if (!home) {
|
|
60675
61262
|
return null;
|
|
60676
61263
|
}
|
|
60677
|
-
const globalRuntime =
|
|
60678
|
-
if (await pathExists(
|
|
61264
|
+
const globalRuntime = path153.join(home, ".keryx", "keryx");
|
|
61265
|
+
if (await pathExists(path153.join(globalRuntime, ".git"))) {
|
|
60679
61266
|
return globalRuntime;
|
|
60680
61267
|
}
|
|
60681
61268
|
return null;
|
|
60682
61269
|
}
|
|
60683
61270
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
60684
61271
|
const dirs = [
|
|
60685
|
-
|
|
60686
|
-
|
|
60687
|
-
|
|
60688
|
-
|
|
60689
|
-
|
|
61272
|
+
path153.join(metaprojectRoot, "core"),
|
|
61273
|
+
path153.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
61274
|
+
path153.join(metaprojectRoot, "modules"),
|
|
61275
|
+
path153.join(metaprojectRoot, "rules"),
|
|
61276
|
+
path153.join(metaprojectRoot, "skills", "project-rules"),
|
|
60690
61277
|
...modules.enableGdgraph ? [
|
|
60691
|
-
|
|
60692
|
-
|
|
61278
|
+
path153.join(metaprojectRoot, "core", "gdgraph"),
|
|
61279
|
+
path153.join(metaprojectRoot, "skills", "gdgraph")
|
|
60693
61280
|
] : [],
|
|
60694
61281
|
...modules.enableGdctx ? [
|
|
60695
|
-
|
|
60696
|
-
|
|
61282
|
+
path153.join(metaprojectRoot, "core", "gdctx"),
|
|
61283
|
+
path153.join(metaprojectRoot, "skills", "gdctx")
|
|
60697
61284
|
] : [],
|
|
60698
61285
|
...modules.enableGdwiki ? [
|
|
60699
|
-
|
|
60700
|
-
|
|
61286
|
+
path153.join(metaprojectRoot, "skills", "gdwiki"),
|
|
61287
|
+
path153.join(metaprojectRoot, "wiki", "templates")
|
|
60701
61288
|
] : [],
|
|
60702
61289
|
...modules.enableHealth ? [
|
|
60703
|
-
|
|
60704
|
-
|
|
61290
|
+
path153.join(metaprojectRoot, "core", "health"),
|
|
61291
|
+
path153.join(metaprojectRoot, "skills", "health")
|
|
60705
61292
|
] : [],
|
|
60706
61293
|
...modules.enableTesting ? [
|
|
60707
|
-
|
|
60708
|
-
|
|
61294
|
+
path153.join(metaprojectRoot, "core", "testing"),
|
|
61295
|
+
path153.join(metaprojectRoot, "skills", "testing")
|
|
60709
61296
|
] : [],
|
|
60710
61297
|
...modules.enableMemory ? [
|
|
60711
|
-
|
|
60712
|
-
|
|
60713
|
-
|
|
61298
|
+
path153.join(metaprojectRoot, "core", "memory"),
|
|
61299
|
+
path153.join(metaprojectRoot, "skills", "memory"),
|
|
61300
|
+
path153.join(metaprojectRoot, "memory", "templates")
|
|
60714
61301
|
] : [],
|
|
60715
61302
|
...modules.enableTasks ? [
|
|
60716
|
-
|
|
60717
|
-
|
|
61303
|
+
path153.join(metaprojectRoot, "flows"),
|
|
61304
|
+
path153.join(metaprojectRoot, "skills", "flow")
|
|
60718
61305
|
] : [],
|
|
60719
61306
|
...modules.enableSecurity ? [
|
|
60720
|
-
|
|
61307
|
+
path153.join(metaprojectRoot, "core", "security")
|
|
60721
61308
|
] : [],
|
|
60722
61309
|
...modules.enableSac ? [
|
|
60723
|
-
|
|
61310
|
+
path153.join(metaprojectRoot, "skills", "sac")
|
|
60724
61311
|
] : []
|
|
60725
61312
|
];
|
|
60726
61313
|
await Promise.all(dirs.map((dir) => mkdir54(dir, { recursive: true })));
|
|
60727
61314
|
}
|
|
60728
61315
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
60729
|
-
const gdgraphCoreRoot =
|
|
61316
|
+
const gdgraphCoreRoot = path153.join(metaprojectRoot, "core", "gdgraph");
|
|
60730
61317
|
await mkdir54(gdgraphCoreRoot, { recursive: true });
|
|
60731
61318
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
60732
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
61319
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path153.join(gdgraphCoreRoot, file));
|
|
60733
61320
|
}
|
|
60734
|
-
await writeTextIfChanged4(
|
|
61321
|
+
await writeTextIfChanged4(path153.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
60735
61322
|
}
|
|
60736
61323
|
async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
60737
61324
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
@@ -60739,7 +61326,7 @@ async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
|
60739
61326
|
return;
|
|
60740
61327
|
}
|
|
60741
61328
|
await mkdir54(hooksRoot, { recursive: true });
|
|
60742
|
-
const hookPath =
|
|
61329
|
+
const hookPath = path153.join(hooksRoot, hookName);
|
|
60743
61330
|
const blockStart = `# keryx:${blockId}:begin`;
|
|
60744
61331
|
const blockEnd = `# keryx:${blockId}:end`;
|
|
60745
61332
|
const managedBlock = `${blockStart}
|
|
@@ -60760,7 +61347,7 @@ async function removeManagedHook2(projectRoot, hookName, blockId) {
|
|
|
60760
61347
|
if (!hooksRoot) {
|
|
60761
61348
|
return;
|
|
60762
61349
|
}
|
|
60763
|
-
const hookPath =
|
|
61350
|
+
const hookPath = path153.join(hooksRoot, hookName);
|
|
60764
61351
|
if (!await pathExists(hookPath)) {
|
|
60765
61352
|
return;
|
|
60766
61353
|
}
|
|
@@ -60782,7 +61369,7 @@ async function prePushHasSecurityBlock2(projectRoot) {
|
|
|
60782
61369
|
if (!hooksRoot) {
|
|
60783
61370
|
return false;
|
|
60784
61371
|
}
|
|
60785
|
-
const hookPath =
|
|
61372
|
+
const hookPath = path153.join(hooksRoot, "pre-push");
|
|
60786
61373
|
if (!await pathExists(hookPath)) {
|
|
60787
61374
|
return false;
|
|
60788
61375
|
}
|
|
@@ -60797,7 +61384,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
60797
61384
|
return (await readFile79(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
60798
61385
|
}
|
|
60799
61386
|
async function readManifest5(metaprojectRoot) {
|
|
60800
|
-
const manifestPath =
|
|
61387
|
+
const manifestPath = path153.join(metaprojectRoot, "metaproject.json");
|
|
60801
61388
|
if (!await pathExists(manifestPath)) {
|
|
60802
61389
|
return {
|
|
60803
61390
|
exists: false,
|
|
@@ -60866,7 +61453,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
60866
61453
|
}
|
|
60867
61454
|
async function anyPathExists(root, candidates) {
|
|
60868
61455
|
for (const candidate of candidates) {
|
|
60869
|
-
if (await pathExists(
|
|
61456
|
+
if (await pathExists(path153.join(root, candidate))) {
|
|
60870
61457
|
return true;
|
|
60871
61458
|
}
|
|
60872
61459
|
}
|
|
@@ -60887,13 +61474,13 @@ function parseUpdateArgs(args2) {
|
|
|
60887
61474
|
};
|
|
60888
61475
|
}
|
|
60889
61476
|
async function runPostUpdateHooks(projectRoot) {
|
|
60890
|
-
const hooksDir =
|
|
61477
|
+
const hooksDir = path153.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
60891
61478
|
if (!await pathExists(hooksDir)) {
|
|
60892
61479
|
return;
|
|
60893
61480
|
}
|
|
60894
|
-
const entries = (await
|
|
61481
|
+
const entries = (await readdir25(hooksDir)).sort();
|
|
60895
61482
|
for (const entry of entries) {
|
|
60896
|
-
const hookPath =
|
|
61483
|
+
const hookPath = path153.join(hooksDir, entry);
|
|
60897
61484
|
try {
|
|
60898
61485
|
await accessExecutable(hookPath);
|
|
60899
61486
|
} catch {
|
|
@@ -60934,14 +61521,14 @@ async function writeTextIfChanged4(filePath, content) {
|
|
|
60934
61521
|
if (await pathExists(filePath) && await readFile79(filePath, "utf8") === content) {
|
|
60935
61522
|
return;
|
|
60936
61523
|
}
|
|
60937
|
-
await mkdir54(
|
|
61524
|
+
await mkdir54(path153.dirname(filePath), { recursive: true });
|
|
60938
61525
|
await writeFile48(filePath, content, "utf8");
|
|
60939
61526
|
}
|
|
60940
61527
|
async function writeTextIfMissing4(filePath, content) {
|
|
60941
61528
|
if (await pathExists(filePath)) {
|
|
60942
61529
|
return;
|
|
60943
61530
|
}
|
|
60944
|
-
await mkdir54(
|
|
61531
|
+
await mkdir54(path153.dirname(filePath), { recursive: true });
|
|
60945
61532
|
await writeFile48(filePath, content, "utf8");
|
|
60946
61533
|
}
|
|
60947
61534
|
async function copyFileIfChanged2(from, to) {
|
|
@@ -60949,7 +61536,7 @@ async function copyFileIfChanged2(from, to) {
|
|
|
60949
61536
|
if (await pathExists(to) && await readFile79(to, "utf8") === next) {
|
|
60950
61537
|
return;
|
|
60951
61538
|
}
|
|
60952
|
-
await mkdir54(
|
|
61539
|
+
await mkdir54(path153.dirname(to), { recursive: true });
|
|
60953
61540
|
await writeFile48(to, next, "utf8");
|
|
60954
61541
|
}
|
|
60955
61542
|
function runtimeSourcePath2(relativePath) {
|
|
@@ -60958,7 +61545,7 @@ function runtimeSourcePath2(relativePath) {
|
|
|
60958
61545
|
return directPath;
|
|
60959
61546
|
}
|
|
60960
61547
|
if (relativePath.startsWith("../")) {
|
|
60961
|
-
const packagedSourcePath =
|
|
61548
|
+
const packagedSourcePath = path153.join(path153.dirname(fileURLToPath7(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
60962
61549
|
if (existsSync30(packagedSourcePath)) {
|
|
60963
61550
|
return packagedSourcePath;
|
|
60964
61551
|
}
|
|
@@ -60990,7 +61577,7 @@ function printHelp18() {
|
|
|
60990
61577
|
|
|
60991
61578
|
// src/commands/dashboard.ts
|
|
60992
61579
|
import { spawn as spawn6 } from "child_process";
|
|
60993
|
-
import
|
|
61580
|
+
import path154 from "path";
|
|
60994
61581
|
init_args();
|
|
60995
61582
|
async function dashboardCommand(args2 = []) {
|
|
60996
61583
|
const options = parseOptions(args2);
|
|
@@ -61001,7 +61588,7 @@ async function dashboardCommand(args2 = []) {
|
|
|
61001
61588
|
}
|
|
61002
61589
|
if (subcommand === "build") {
|
|
61003
61590
|
const result = await buildDashboard();
|
|
61004
|
-
const rel =
|
|
61591
|
+
const rel = path154.relative(process.cwd(), result.path);
|
|
61005
61592
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
61006
61593
|
note(`Open it: keryx dashboard open`);
|
|
61007
61594
|
return;
|
|
@@ -61009,7 +61596,7 @@ async function dashboardCommand(args2 = []) {
|
|
|
61009
61596
|
if (subcommand === "open") {
|
|
61010
61597
|
const result = await buildDashboard();
|
|
61011
61598
|
await openFile(result.path);
|
|
61012
|
-
const rel =
|
|
61599
|
+
const rel = path154.relative(process.cwd(), result.path);
|
|
61013
61600
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
61014
61601
|
return;
|
|
61015
61602
|
}
|
|
@@ -61058,7 +61645,7 @@ import { readFileSync as readFileSync10 } from "fs";
|
|
|
61058
61645
|
// src/agents/bootstrap.ts
|
|
61059
61646
|
import { mkdir as mkdir55, readFile as readFile80, writeFile as writeFile49 } from "fs/promises";
|
|
61060
61647
|
import { homedir as homedir7 } from "os";
|
|
61061
|
-
import
|
|
61648
|
+
import path155 from "path";
|
|
61062
61649
|
init_fs();
|
|
61063
61650
|
var AGENT_BOOTSTRAP_START = "<!-- keryx:global-bootstrap -->";
|
|
61064
61651
|
var AGENT_BOOTSTRAP_END = "<!-- /keryx:global-bootstrap -->";
|
|
@@ -61068,35 +61655,35 @@ var AGENT_BOOTSTRAP_RUNTIMES = [
|
|
|
61068
61655
|
aliases: ["claude-code"],
|
|
61069
61656
|
label: "Claude Code",
|
|
61070
61657
|
fileName: "CLAUDE.md",
|
|
61071
|
-
filePath: (homeRoot) =>
|
|
61658
|
+
filePath: (homeRoot) => path155.join(homeRoot, ".claude", "CLAUDE.md")
|
|
61072
61659
|
},
|
|
61073
61660
|
{
|
|
61074
61661
|
id: "opencode",
|
|
61075
61662
|
aliases: ["open-code"],
|
|
61076
61663
|
label: "OpenCode",
|
|
61077
61664
|
fileName: "AGENTS.md",
|
|
61078
|
-
filePath: (homeRoot) =>
|
|
61665
|
+
filePath: (homeRoot) => path155.join(homeRoot, ".config", "opencode", "AGENTS.md")
|
|
61079
61666
|
},
|
|
61080
61667
|
{
|
|
61081
61668
|
id: "zcode",
|
|
61082
61669
|
aliases: ["zed", "zed-code"],
|
|
61083
61670
|
label: "ZCode",
|
|
61084
61671
|
fileName: "AGENTS.md",
|
|
61085
|
-
filePath: (homeRoot) =>
|
|
61672
|
+
filePath: (homeRoot) => path155.join(homeRoot, ".zcode", "AGENTS.md")
|
|
61086
61673
|
},
|
|
61087
61674
|
{
|
|
61088
61675
|
id: "codex",
|
|
61089
61676
|
aliases: [],
|
|
61090
61677
|
label: "Codex",
|
|
61091
61678
|
fileName: "AGENTS.md",
|
|
61092
|
-
filePath: (homeRoot) =>
|
|
61679
|
+
filePath: (homeRoot) => path155.join(homeRoot, ".codex", "AGENTS.md")
|
|
61093
61680
|
},
|
|
61094
61681
|
{
|
|
61095
61682
|
id: "antigravity",
|
|
61096
61683
|
aliases: ["antigravuty", "antigravity-code"],
|
|
61097
61684
|
label: "Antigravity",
|
|
61098
61685
|
fileName: "AGENTS.md",
|
|
61099
|
-
filePath: (homeRoot) =>
|
|
61686
|
+
filePath: (homeRoot) => path155.join(homeRoot, ".config", "antigravity", "AGENTS.md")
|
|
61100
61687
|
}
|
|
61101
61688
|
];
|
|
61102
61689
|
function agentBootstrapRuntimeIds() {
|
|
@@ -61144,7 +61731,7 @@ async function installAgentBootstrap(runtime, options = {}) {
|
|
|
61144
61731
|
const dryRun = options.dryRun === true;
|
|
61145
61732
|
const wrote = next !== current;
|
|
61146
61733
|
if (wrote && !dryRun) {
|
|
61147
|
-
await mkdir55(
|
|
61734
|
+
await mkdir55(path155.dirname(filePath), { recursive: true });
|
|
61148
61735
|
await writeFile49(filePath, next, "utf8");
|
|
61149
61736
|
}
|
|
61150
61737
|
const status = dryRun ? statusFromContent(runtime, filePath, exists2, next) : await agentBootstrapStatus(runtime, homeRoot);
|
|
@@ -61492,7 +62079,7 @@ function printBootstrapHelp() {
|
|
|
61492
62079
|
// src/commands/metrics.ts
|
|
61493
62080
|
init_args();
|
|
61494
62081
|
import { readFile as readFile81 } from "fs/promises";
|
|
61495
|
-
import
|
|
62082
|
+
import path157 from "path";
|
|
61496
62083
|
|
|
61497
62084
|
// src/metrics/benchmark.ts
|
|
61498
62085
|
var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -62271,7 +62858,7 @@ function buildContainmentManifest(inputs, options = {}) {
|
|
|
62271
62858
|
|
|
62272
62859
|
// src/metrics/oracle-runner.ts
|
|
62273
62860
|
import { mkdir as mkdir56, writeFile as writeFile50 } from "fs/promises";
|
|
62274
|
-
import
|
|
62861
|
+
import path156 from "path";
|
|
62275
62862
|
|
|
62276
62863
|
// src/metrics/ir.ts
|
|
62277
62864
|
function toIdSet(ids) {
|
|
@@ -62713,9 +63300,9 @@ function buildEvidenceBundle(input2, options = {}) {
|
|
|
62713
63300
|
async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
62714
63301
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
62715
63302
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
62716
|
-
const dir =
|
|
63303
|
+
const dir = path156.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
62717
63304
|
await mkdir56(dir, { recursive: true });
|
|
62718
|
-
const write = (name, value) => writeFile50(
|
|
63305
|
+
const write = (name, value) => writeFile50(path156.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
62719
63306
|
`, "utf8");
|
|
62720
63307
|
await Promise.all([
|
|
62721
63308
|
write("inputs.json", bundle.inputs),
|
|
@@ -62755,7 +63342,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62755
63342
|
console.log("# metrics status");
|
|
62756
63343
|
console.log("");
|
|
62757
63344
|
console.log(`root: ${root}`);
|
|
62758
|
-
console.log(`enabled: ${await Bun.file(
|
|
63345
|
+
console.log(`enabled: ${await Bun.file(path157.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
62759
63346
|
const latest2 = await readLatestPointer(root);
|
|
62760
63347
|
console.log(`latest: ${latest2.status}`);
|
|
62761
63348
|
return;
|
|
@@ -62767,7 +63354,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62767
63354
|
process.exitCode = 1;
|
|
62768
63355
|
return;
|
|
62769
63356
|
}
|
|
62770
|
-
const record2 = JSON.parse(await readFile81(
|
|
63357
|
+
const record2 = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
62771
63358
|
const result = validateRunRecord(record2);
|
|
62772
63359
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
62773
63360
|
for (const error2 of result.errors)
|
|
@@ -62792,7 +63379,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62792
63379
|
process.exitCode = 1;
|
|
62793
63380
|
return;
|
|
62794
63381
|
}
|
|
62795
|
-
const file =
|
|
63382
|
+
const file = path157.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
62796
63383
|
if (!await Bun.file(file).exists()) {
|
|
62797
63384
|
console.error(`Run not found: ${runId}`);
|
|
62798
63385
|
process.exitCode = 1;
|
|
@@ -62809,8 +63396,8 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62809
63396
|
process.exitCode = 1;
|
|
62810
63397
|
return;
|
|
62811
63398
|
}
|
|
62812
|
-
const a = JSON.parse(await readFile81(
|
|
62813
|
-
const b = JSON.parse(await readFile81(
|
|
63399
|
+
const a = JSON.parse(await readFile81(path157.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
63400
|
+
const b = JSON.parse(await readFile81(path157.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
62814
63401
|
const comparison = compareExecutionRuns(a, b);
|
|
62815
63402
|
console.log(stableJson(comparison));
|
|
62816
63403
|
return;
|
|
@@ -62844,8 +63431,8 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62844
63431
|
return;
|
|
62845
63432
|
}
|
|
62846
63433
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
62847
|
-
await Bun.write(
|
|
62848
|
-
console.log(`manifest: ${
|
|
63434
|
+
await Bun.write(path157.resolve(projectRoot, out), stableJson(template));
|
|
63435
|
+
console.log(`manifest: ${path157.relative(projectRoot, path157.resolve(projectRoot, out))}`);
|
|
62849
63436
|
return;
|
|
62850
63437
|
}
|
|
62851
63438
|
if (subcommand === "benchmark" && args2[1] === "run") {
|
|
@@ -62859,7 +63446,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62859
63446
|
process.exitCode = 1;
|
|
62860
63447
|
return;
|
|
62861
63448
|
}
|
|
62862
|
-
const raw = JSON.parse(await readFile81(
|
|
63449
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
62863
63450
|
const input2 = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
62864
63451
|
const result = validatePairedBenchmark(input2);
|
|
62865
63452
|
console.log(stableJson(result));
|
|
@@ -62871,7 +63458,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
62871
63458
|
process.exitCode = 1;
|
|
62872
63459
|
}
|
|
62873
63460
|
async function loadAffectedSets(projectRoot, file) {
|
|
62874
|
-
const raw = JSON.parse(await readFile81(
|
|
63461
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
62875
63462
|
const map = new Map;
|
|
62876
63463
|
for (const entry of raw.targets ?? []) {
|
|
62877
63464
|
if (typeof entry.target === "string")
|
|
@@ -62942,7 +63529,7 @@ async function runHarnessLayer(projectRoot, args2, ladder) {
|
|
|
62942
63529
|
let tasks;
|
|
62943
63530
|
let model;
|
|
62944
63531
|
try {
|
|
62945
|
-
const raw = JSON.parse(await readFile81(
|
|
63532
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, resultsPath), "utf8"));
|
|
62946
63533
|
tasks = raw.tasks ?? [];
|
|
62947
63534
|
model = raw.model;
|
|
62948
63535
|
} catch (error2) {
|
|
@@ -62973,7 +63560,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args2, ladder) {
|
|
|
62973
63560
|
let cases;
|
|
62974
63561
|
let model;
|
|
62975
63562
|
try {
|
|
62976
|
-
const raw = JSON.parse(await readFile81(
|
|
63563
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, resultsPath), "utf8"));
|
|
62977
63564
|
cases = raw.cases ?? [];
|
|
62978
63565
|
model = raw.model;
|
|
62979
63566
|
} catch (error2) {
|
|
@@ -62998,7 +63585,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args2, ladder) {
|
|
|
62998
63585
|
let cases;
|
|
62999
63586
|
let model;
|
|
63000
63587
|
try {
|
|
63001
|
-
const raw = JSON.parse(await readFile81(
|
|
63588
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, resultsPath), "utf8"));
|
|
63002
63589
|
cases = raw.cases ?? [];
|
|
63003
63590
|
model = raw.model;
|
|
63004
63591
|
} catch (error2) {
|
|
@@ -63023,7 +63610,7 @@ async function runSafetyContainmentLayer(projectRoot, args2, ladder, caseClass)
|
|
|
63023
63610
|
let cases;
|
|
63024
63611
|
let model;
|
|
63025
63612
|
try {
|
|
63026
|
-
const raw = JSON.parse(await readFile81(
|
|
63613
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, resultsPath), "utf8"));
|
|
63027
63614
|
cases = raw.cases ?? [];
|
|
63028
63615
|
model = raw.model;
|
|
63029
63616
|
} catch (error2) {
|
|
@@ -63085,12 +63672,12 @@ async function runGdgraphLayer(projectRoot, args2, ladder) {
|
|
|
63085
63672
|
}
|
|
63086
63673
|
const manifests = buildOracleManifestsByGold(inputs, { ladder });
|
|
63087
63674
|
if (outDir) {
|
|
63088
|
-
const resolvedOut =
|
|
63675
|
+
const resolvedOut = path157.resolve(projectRoot, outDir);
|
|
63089
63676
|
for (const input2 of inputs) {
|
|
63090
63677
|
for (const named of input2.golds) {
|
|
63091
63678
|
const bundle = buildEvidenceBundle({ target: input2.target, system: input2.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
|
|
63092
|
-
const dir = await persistEvidenceBundle(
|
|
63093
|
-
console.error(`bundle[${named.kind}]: ${
|
|
63679
|
+
const dir = await persistEvidenceBundle(path157.join(resolvedOut, named.kind), bundle, ladder);
|
|
63680
|
+
console.error(`bundle[${named.kind}]: ${path157.relative(projectRoot, dir)}`);
|
|
63094
63681
|
}
|
|
63095
63682
|
}
|
|
63096
63683
|
}
|
|
@@ -63114,7 +63701,7 @@ async function runGdgraphLayer(projectRoot, args2, ladder) {
|
|
|
63114
63701
|
return allValid;
|
|
63115
63702
|
}
|
|
63116
63703
|
async function loadCoverageMap2(projectRoot, file) {
|
|
63117
|
-
const raw = JSON.parse(await readFile81(
|
|
63704
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
63118
63705
|
return raw.coverageMap ?? {};
|
|
63119
63706
|
}
|
|
63120
63707
|
async function runTestingLayer(projectRoot, args2, ladder) {
|
|
@@ -63151,7 +63738,7 @@ async function runTestingLayer(projectRoot, args2, ladder) {
|
|
|
63151
63738
|
return result.valid;
|
|
63152
63739
|
}
|
|
63153
63740
|
async function loadMemoryGoldK(projectRoot, file) {
|
|
63154
|
-
const raw = JSON.parse(await readFile81(
|
|
63741
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
63155
63742
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
|
|
63156
63743
|
}
|
|
63157
63744
|
async function runMemoryLayer(projectRoot, args2, ladder) {
|
|
@@ -63188,11 +63775,11 @@ async function runMemoryLayer(projectRoot, args2, ladder) {
|
|
|
63188
63775
|
return result.valid;
|
|
63189
63776
|
}
|
|
63190
63777
|
async function loadWikiGoldK(projectRoot, file) {
|
|
63191
|
-
const raw = JSON.parse(await readFile81(
|
|
63778
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
63192
63779
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
|
|
63193
63780
|
}
|
|
63194
63781
|
async function loadWikiGroundedness(projectRoot, file) {
|
|
63195
|
-
const raw = JSON.parse(await readFile81(
|
|
63782
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
63196
63783
|
const map = new Map;
|
|
63197
63784
|
for (const entry of raw.targets ?? []) {
|
|
63198
63785
|
if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
|
|
@@ -63248,7 +63835,7 @@ async function runWikiLayer(projectRoot, args2, ladder) {
|
|
|
63248
63835
|
return result.valid;
|
|
63249
63836
|
}
|
|
63250
63837
|
async function loadGdctxFacts(projectRoot, file) {
|
|
63251
|
-
const raw = JSON.parse(await readFile81(
|
|
63838
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, file), "utf8"));
|
|
63252
63839
|
const inputs = [];
|
|
63253
63840
|
for (const entry of raw.inputs ?? []) {
|
|
63254
63841
|
if (typeof entry.input === "string") {
|
|
@@ -63286,7 +63873,7 @@ async function collect(projectRoot, args2) {
|
|
|
63286
63873
|
process.exitCode = 1;
|
|
63287
63874
|
return;
|
|
63288
63875
|
}
|
|
63289
|
-
const raw = JSON.parse(await readFile81(
|
|
63876
|
+
const raw = JSON.parse(await readFile81(path157.resolve(projectRoot, eventFile), "utf8"));
|
|
63290
63877
|
const events2 = Array.isArray(raw) ? raw : raw.events;
|
|
63291
63878
|
const startedAt = optionValue(args2, "--started-at") ?? events2[0]?.timestamp_utc ?? new Date().toISOString();
|
|
63292
63879
|
const finishedAt = optionValue(args2, "--finished-at") ?? events2.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -63302,11 +63889,11 @@ async function collect(projectRoot, args2) {
|
|
|
63302
63889
|
parentRunId: optionValue(args2, "--parent-run-id") ?? null
|
|
63303
63890
|
});
|
|
63304
63891
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record2, { cwd: projectRoot });
|
|
63305
|
-
console.log(`json: ${
|
|
63306
|
-
console.log(`markdown: ${
|
|
63892
|
+
console.log(`json: ${path157.relative(projectRoot, result.jsonPath)}`);
|
|
63893
|
+
console.log(`markdown: ${path157.relative(projectRoot, result.markdownPath)}`);
|
|
63307
63894
|
}
|
|
63308
63895
|
function metricsRoot(projectRoot) {
|
|
63309
|
-
return
|
|
63896
|
+
return path157.join(projectRoot, ".metaproject", "data", "metrics");
|
|
63310
63897
|
}
|
|
63311
63898
|
function printMetricsHelp() {
|
|
63312
63899
|
console.log(`keryx metrics
|
|
@@ -63412,193 +63999,6 @@ init_session_wrap_up();
|
|
|
63412
63999
|
init_proposal_evidence();
|
|
63413
64000
|
init_review_confirm_token();
|
|
63414
64001
|
init_store3();
|
|
63415
|
-
|
|
63416
|
-
// src/sac/catch-up.ts
|
|
63417
|
-
init_fs();
|
|
63418
|
-
init_config_dir();
|
|
63419
|
-
init_paths();
|
|
63420
|
-
init_slate();
|
|
63421
|
-
init_store3();
|
|
63422
|
-
init_proposal_lifecycle();
|
|
63423
|
-
init_workspace_service();
|
|
63424
|
-
import { randomUUID as randomUUID28 } from "crypto";
|
|
63425
|
-
import { readdir as readdir25 } from "fs/promises";
|
|
63426
|
-
import path157 from "path";
|
|
63427
|
-
|
|
63428
|
-
// src/sac/lifecycle-flag.ts
|
|
63429
|
-
init_store();
|
|
63430
|
-
init_service3();
|
|
63431
|
-
init_decision_dedup();
|
|
63432
|
-
init_workspace_service();
|
|
63433
|
-
import { randomUUID as randomUUID27 } from "crypto";
|
|
63434
|
-
function normalize3(raw) {
|
|
63435
|
-
return raw.replace(/^\.\//, "");
|
|
63436
|
-
}
|
|
63437
|
-
function isStillPresent(recorded, valid) {
|
|
63438
|
-
const normalized = normalize3(recorded);
|
|
63439
|
-
return valid.has(normalized) || valid.has(moduleNameFromProjectPath(normalized));
|
|
63440
|
-
}
|
|
63441
|
-
async function computeLifecycleFlags(cwd, now = () => new Date) {
|
|
63442
|
-
const valid = await validModuleNames(cwd);
|
|
63443
|
-
if (valid === undefined)
|
|
63444
|
-
return [];
|
|
63445
|
-
const flaggedAt = now().toISOString();
|
|
63446
|
-
const flags = [];
|
|
63447
|
-
const workspaceService = new WorkspaceService({
|
|
63448
|
-
workspaceRoot: cwd,
|
|
63449
|
-
authorizationServer: localWorkspaceAuthorizationServer(),
|
|
63450
|
-
strictGuard: { mode: "strict", availability: "available", decision: "pass", policyRevision: "local-offline-v1" }
|
|
63451
|
-
});
|
|
63452
|
-
const workspaces = await workspaceService.list({ request: undefined, requestCorrelationId: randomUUID27(), includeArchived: true });
|
|
63453
|
-
for (const workspace of workspaces) {
|
|
63454
|
-
const component = workspace.resources.find((r) => r.kind === "component")?.uri;
|
|
63455
|
-
if (component !== undefined && !isStillPresent(component, valid)) {
|
|
63456
|
-
flags.push({ kind: "workspace", ref: workspace.id, missingComponent: normalize3(component), flaggedAt });
|
|
63457
|
-
}
|
|
63458
|
-
}
|
|
63459
|
-
for (const entry of await collectEntries(cwd)) {
|
|
63460
|
-
const module = entry.scopes.module;
|
|
63461
|
-
if (module !== null && module.length > 0 && !isStillPresent(module, valid)) {
|
|
63462
|
-
flags.push({ kind: "memory-entry", ref: entry.relativePath, missingComponent: normalize3(module), flaggedAt });
|
|
63463
|
-
}
|
|
63464
|
-
}
|
|
63465
|
-
for (const decision of await collectWikiDecisionEntries(cwd)) {
|
|
63466
|
-
const module = decision.scopes.module;
|
|
63467
|
-
if (module !== null && module.length > 0 && !isStillPresent(module, valid)) {
|
|
63468
|
-
flags.push({ kind: "wiki-decision", ref: decision.relativePath, missingComponent: normalize3(module), flaggedAt });
|
|
63469
|
-
}
|
|
63470
|
-
}
|
|
63471
|
-
return flags;
|
|
63472
|
-
}
|
|
63473
|
-
|
|
63474
|
-
// src/sac/catch-up.ts
|
|
63475
|
-
async function buildCatchUp(input2) {
|
|
63476
|
-
const [proposals, sessionCategories, lifecycleFlagsAll] = await Promise.all([
|
|
63477
|
-
collectProposals(input2.cwd, input2.workspaceId),
|
|
63478
|
-
collectSessionCategories(input2.cwd),
|
|
63479
|
-
computeLifecycleFlags(input2.cwd)
|
|
63480
|
-
]);
|
|
63481
|
-
const lifecycleFlags = input2.workspaceId === undefined ? lifecycleFlagsAll : lifecycleFlagsAll.filter((flag) => flag.kind !== "workspace" || flag.ref === input2.workspaceId);
|
|
63482
|
-
return { proposals, ...sessionCategories, lifecycleFlags };
|
|
63483
|
-
}
|
|
63484
|
-
async function collectProposals(cwd, workspaceId) {
|
|
63485
|
-
const authorizationServer = localWorkspaceAuthorizationServer();
|
|
63486
|
-
const actor = await authorizationServer.actorContextFor(undefined, randomUUID28());
|
|
63487
|
-
if (!actor)
|
|
63488
|
-
throw new Error("trusted ActorContext is required for catch-up");
|
|
63489
|
-
const proposalService = createLocalProposalLifecycleService(cwd);
|
|
63490
|
-
const groups = await proposalService.listVisibleProposedProposals(actor);
|
|
63491
|
-
const scoped = workspaceId === undefined ? groups : groups.filter((group) => group.workspace.id === workspaceId);
|
|
63492
|
-
const flattened = scoped.flatMap((group) => group.proposals.map((proposal) => ({ group, proposal })));
|
|
63493
|
-
return Promise.all(flattened.map(async ({ group, proposal }) => {
|
|
63494
|
-
const fresh = await proposalService.isEvidenceFresh(proposal, actor);
|
|
63495
|
-
return { type: "proposal", workspaceId: group.workspace.id, proposalId: proposal.id, fresh };
|
|
63496
|
-
}));
|
|
63497
|
-
}
|
|
63498
|
-
async function classifySession(session) {
|
|
63499
|
-
const dir = sessionDir(session.projectPath, session.id);
|
|
63500
|
-
if (await isLockHeld(slateLockPath(dir)))
|
|
63501
|
-
return;
|
|
63502
|
-
const terminalState = await readTerminalState(dir);
|
|
63503
|
-
if (terminalState !== undefined) {
|
|
63504
|
-
const workspaceId2 = (await safeReadSlate(dir))?.workspaceId;
|
|
63505
|
-
return { kind: "blocked", item: { type: "blocked", sessionId: session.id, ...workspaceId2 !== undefined ? { workspaceId: workspaceId2 } : {}, terminalState } };
|
|
63506
|
-
}
|
|
63507
|
-
const unboundCandidate = await readNewestUnboundCandidate(dir);
|
|
63508
|
-
if (unboundCandidate !== undefined) {
|
|
63509
|
-
return {
|
|
63510
|
-
kind: "unbound-candidate",
|
|
63511
|
-
item: { type: "unbound-candidate", sessionId: session.id, evidencePath: unboundCandidate.evidencePath, summary: unboundCandidate.summary }
|
|
63512
|
-
};
|
|
63513
|
-
}
|
|
63514
|
-
if (!await isSlateEngaged(dir))
|
|
63515
|
-
return;
|
|
63516
|
-
const workspaceId = (await safeReadSlate(dir))?.workspaceId;
|
|
63517
|
-
return { kind: "unknown", item: { type: "unknown", sessionId: session.id, ...workspaceId !== undefined ? { workspaceId } : {}, lastSeenAt: session.updatedAt } };
|
|
63518
|
-
}
|
|
63519
|
-
async function collectSessionCategories(cwd) {
|
|
63520
|
-
const classified = await Promise.all(listSessions(cwd).map((session) => classifySession(session)));
|
|
63521
|
-
const blocked2 = [];
|
|
63522
|
-
const unboundCandidates = [];
|
|
63523
|
-
const unknown = [];
|
|
63524
|
-
for (const category of classified) {
|
|
63525
|
-
if (category === undefined)
|
|
63526
|
-
continue;
|
|
63527
|
-
if (category.kind === "blocked")
|
|
63528
|
-
blocked2.push(category.item);
|
|
63529
|
-
else if (category.kind === "unbound-candidate")
|
|
63530
|
-
unboundCandidates.push(category.item);
|
|
63531
|
-
else
|
|
63532
|
-
unknown.push(category.item);
|
|
63533
|
-
}
|
|
63534
|
-
return { blocked: blocked2, unboundCandidates, unknown };
|
|
63535
|
-
}
|
|
63536
|
-
async function isSlateEngaged(dir) {
|
|
63537
|
-
if (await pathExists(path157.join(dir, "slate.json")))
|
|
63538
|
-
return true;
|
|
63539
|
-
if (await pathExists(path157.join(dir, "terminal-state.json")))
|
|
63540
|
-
return true;
|
|
63541
|
-
try {
|
|
63542
|
-
const entries = await readdir25(path157.join(dir, "slate-archive"));
|
|
63543
|
-
return entries.length > 0;
|
|
63544
|
-
} catch {
|
|
63545
|
-
return false;
|
|
63546
|
-
}
|
|
63547
|
-
}
|
|
63548
|
-
async function safeReadSlate(dir) {
|
|
63549
|
-
try {
|
|
63550
|
-
return await readSlate(dir);
|
|
63551
|
-
} catch {
|
|
63552
|
-
return;
|
|
63553
|
-
}
|
|
63554
|
-
}
|
|
63555
|
-
async function readTerminalState(dir) {
|
|
63556
|
-
const result = readConfigFile(path157.join(dir, "terminal-state.json"));
|
|
63557
|
-
if (!result.ok) {
|
|
63558
|
-
return;
|
|
63559
|
-
}
|
|
63560
|
-
try {
|
|
63561
|
-
return JSON.parse(result.text);
|
|
63562
|
-
} catch {
|
|
63563
|
-
return;
|
|
63564
|
-
}
|
|
63565
|
-
}
|
|
63566
|
-
async function readNewestUnboundCandidate(dir) {
|
|
63567
|
-
const archiveDir = path157.join(dir, "slate-archive");
|
|
63568
|
-
let entries;
|
|
63569
|
-
try {
|
|
63570
|
-
entries = (await readdir25(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
63571
|
-
} catch {
|
|
63572
|
-
return;
|
|
63573
|
-
}
|
|
63574
|
-
entries.sort();
|
|
63575
|
-
for (let i = entries.length - 1;i >= 0; i--) {
|
|
63576
|
-
const evidencePath = path157.join(archiveDir, entries[i]);
|
|
63577
|
-
const result = readConfigFile(evidencePath);
|
|
63578
|
-
if (!result.ok) {
|
|
63579
|
-
continue;
|
|
63580
|
-
}
|
|
63581
|
-
try {
|
|
63582
|
-
const parsed = JSON.parse(result.text);
|
|
63583
|
-
if (parsed.recordType !== "unbound-candidate")
|
|
63584
|
-
continue;
|
|
63585
|
-
return { evidencePath, summary: summarizeUnboundCandidate(parsed.groups) };
|
|
63586
|
-
} catch {
|
|
63587
|
-
continue;
|
|
63588
|
-
}
|
|
63589
|
-
}
|
|
63590
|
-
return;
|
|
63591
|
-
}
|
|
63592
|
-
function summarizeUnboundCandidate(groups) {
|
|
63593
|
-
const safeGroups = groups ?? [];
|
|
63594
|
-
if (safeGroups.length === 0)
|
|
63595
|
-
return "no seeds captured";
|
|
63596
|
-
const seedCount = safeGroups.reduce((sum, group) => sum + (group.seeds?.length ?? 0), 0);
|
|
63597
|
-
const kinds = safeGroups.map((group) => typeof group.kind === "string" ? group.kind : "unknown").join(", ");
|
|
63598
|
-
return `${seedCount} untriaged seed(s) across ${safeGroups.length} kind(s) (${kinds})`;
|
|
63599
|
-
}
|
|
63600
|
-
|
|
63601
|
-
// src/commands/workspace.ts
|
|
63602
64002
|
var PROPOSAL_KINDS2 = ["decision", "wiki-update", "memory-entry", "follow-up", "contract-change", "risk"];
|
|
63603
64003
|
function service5() {
|
|
63604
64004
|
return new WorkspaceService({
|