@mrciphersmith/keryx 0.2.84 → 0.2.88
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
CHANGED
|
@@ -923,6 +923,7 @@ var init_providers = __esm(() => {
|
|
|
923
923
|
label: "xAI (Grok)",
|
|
924
924
|
baseUrl: "https://api.x.ai",
|
|
925
925
|
envKey: "XAI_API_KEY",
|
|
926
|
+
streamUsage: true,
|
|
926
927
|
models: ["grok-2-latest", "grok-2", "grok-beta"],
|
|
927
928
|
note: "xAI \xB7 OpenAI-compatible"
|
|
928
929
|
},
|
|
@@ -2343,6 +2344,7 @@ ${message.content}` });
|
|
|
2343
2344
|
const payload = {
|
|
2344
2345
|
model: request.modelId,
|
|
2345
2346
|
stream: true,
|
|
2347
|
+
...this.deps.grant?.streamUsage === true ? { stream_options: { include_usage: true } } : {},
|
|
2346
2348
|
messages,
|
|
2347
2349
|
...request.tools !== undefined ? {
|
|
2348
2350
|
tools: request.tools.map((tool) => ({
|
|
@@ -3696,6 +3698,7 @@ function makeProvider(name, _model, opts) {
|
|
|
3696
3698
|
}
|
|
3697
3699
|
const grant = {
|
|
3698
3700
|
network: true,
|
|
3701
|
+
...compat.streamUsage === true ? { streamUsage: true } : {},
|
|
3699
3702
|
baseUrl: opts.baseUrl ?? resolveProviderBaseUrl(compat, env),
|
|
3700
3703
|
...compat.allowLoopback === true ? { allowLoopback: true } : {},
|
|
3701
3704
|
...compat.allowPrivateLan === true ? { allowPrivateLan: true } : {},
|
|
@@ -35094,6 +35097,7 @@ function createFlowService(deps) {
|
|
|
35094
35097
|
acChecksum: null,
|
|
35095
35098
|
acConfirmed: {},
|
|
35096
35099
|
pr: { url: null },
|
|
35100
|
+
...input.baseBranch === undefined ? {} : { baseBranch: input.baseBranch },
|
|
35097
35101
|
tasks: DEFAULT_TASKS.map((task) => ({ ...task, status: "todo" })),
|
|
35098
35102
|
history: [{ at: createdAt, event: "created" }]
|
|
35099
35103
|
};
|
|
@@ -35302,6 +35306,10 @@ function createFlowService(deps) {
|
|
|
35302
35306
|
if (!pr.isDraft) {
|
|
35303
35307
|
detail += " (warning: PR is not a draft)";
|
|
35304
35308
|
}
|
|
35309
|
+
if (flow.baseBranch === undefined && typeof pr.baseRefName === "string" && pr.baseRefName !== "") {
|
|
35310
|
+
flow.baseBranch = pr.baseRefName;
|
|
35311
|
+
detail += ` (base: ${pr.baseRefName})`;
|
|
35312
|
+
}
|
|
35305
35313
|
} else {
|
|
35306
35314
|
detail += " (tracker unavailable: existence not verified)";
|
|
35307
35315
|
}
|
|
@@ -35353,6 +35361,7 @@ function createFlowService(deps) {
|
|
|
35353
35361
|
detail: "tracker unavailable; verify PR checks manually"
|
|
35354
35362
|
});
|
|
35355
35363
|
}
|
|
35364
|
+
gates.push(await baseBranchCondition(cwd, flow, mergedCommit ?? undefined, flow.pr.url && deps.tracker && await deps.tracker.detect() ? (await deps.tracker.prStatus(flow.pr.url)).baseRefName : undefined, commitContainedIn));
|
|
35356
35365
|
gates.push(taskGate(flow));
|
|
35357
35366
|
try {
|
|
35358
35367
|
gates.push(await reviewGate({
|
|
@@ -35657,6 +35666,70 @@ function buildIssueComment2(flow, gates) {
|
|
|
35657
35666
|
].join(`
|
|
35658
35667
|
`);
|
|
35659
35668
|
}
|
|
35669
|
+
async function baseBranchCondition(cwd, flow, mergedCommit, prBase, containedIn) {
|
|
35670
|
+
const recorded = flow.baseBranch;
|
|
35671
|
+
if (recorded === undefined || recorded.trim() === "") {
|
|
35672
|
+
return {
|
|
35673
|
+
name: "base-branch",
|
|
35674
|
+
status: "skipped",
|
|
35675
|
+
detail: "not recorded: this flow never named a base branch, so there is nothing to compare the merge against. Not a pass \u2014 `keryx flow init --base <branch>` or `flow implemented --pr <url>` records one."
|
|
35676
|
+
};
|
|
35677
|
+
}
|
|
35678
|
+
if (mergedCommit !== undefined) {
|
|
35679
|
+
const contained = await containedIn(cwd, mergedCommit, `origin/${recorded}`);
|
|
35680
|
+
if (contained === null) {
|
|
35681
|
+
return {
|
|
35682
|
+
name: "base-branch",
|
|
35683
|
+
status: "fail",
|
|
35684
|
+
detail: `unobserved: origin/${recorded} could not be resolved, so whether ${mergedCommit} landed there is unknown. Fetch the remote (\`git fetch origin ${recorded}\`) and re-run; an unresolvable base is not a passing one.`
|
|
35685
|
+
};
|
|
35686
|
+
}
|
|
35687
|
+
return contained ? {
|
|
35688
|
+
name: "base-branch",
|
|
35689
|
+
status: "pass",
|
|
35690
|
+
detail: `${mergedCommit} is contained in origin/${recorded}, the base this flow recorded`
|
|
35691
|
+
} : {
|
|
35692
|
+
name: "base-branch",
|
|
35693
|
+
status: "fail",
|
|
35694
|
+
detail: `violated: this flow recorded base ${recorded}, but ${mergedCommit} is not contained in origin/${recorded}. The merge landed somewhere else.`
|
|
35695
|
+
};
|
|
35696
|
+
}
|
|
35697
|
+
if (prBase === undefined || prBase === null || prBase === "") {
|
|
35698
|
+
return {
|
|
35699
|
+
name: "base-branch",
|
|
35700
|
+
status: "fail",
|
|
35701
|
+
detail: `unobserved: this flow recorded base ${recorded}, but the tracker did not report the pull request's base. An unread base is not a matching one.`
|
|
35702
|
+
};
|
|
35703
|
+
}
|
|
35704
|
+
return prBase === recorded ? {
|
|
35705
|
+
name: "base-branch",
|
|
35706
|
+
status: "pass",
|
|
35707
|
+
detail: `the pull request targets ${prBase}, the base this flow recorded`
|
|
35708
|
+
} : {
|
|
35709
|
+
name: "base-branch",
|
|
35710
|
+
status: "fail",
|
|
35711
|
+
detail: `violated: this flow recorded base ${recorded}, but the pull request now targets ${prBase}. It was retargeted after the base was recorded.`
|
|
35712
|
+
};
|
|
35713
|
+
}
|
|
35714
|
+
async function commitContainedIn(cwd, commit, ref) {
|
|
35715
|
+
if (!/^[0-9a-f]{7,64}$/i.test(commit)) {
|
|
35716
|
+
return null;
|
|
35717
|
+
}
|
|
35718
|
+
const resolved = Bun.spawn(["git", "rev-parse", "--verify", `${ref}^{commit}`], {
|
|
35719
|
+
cwd,
|
|
35720
|
+
stdout: "ignore",
|
|
35721
|
+
stderr: "ignore"
|
|
35722
|
+
});
|
|
35723
|
+
if (await resolved.exited !== 0) {
|
|
35724
|
+
return null;
|
|
35725
|
+
}
|
|
35726
|
+
const process2 = Bun.spawn(["git", "merge-base", "--is-ancestor", commit, ref], {
|
|
35727
|
+
cwd,
|
|
35728
|
+
stdout: "ignore",
|
|
35729
|
+
stderr: "ignore"
|
|
35730
|
+
});
|
|
35731
|
+
return await process2.exited === 0;
|
|
35732
|
+
}
|
|
35660
35733
|
async function verifyCommitOnMain(cwd, commit) {
|
|
35661
35734
|
if (!/^[0-9a-f]{7,64}$/i.test(commit)) {
|
|
35662
35735
|
return { status: "fail", detail: "merged commit must be a hexadecimal Git commit id" };
|
|
@@ -35736,9 +35809,9 @@ var init_github = __esm(() => {
|
|
|
35736
35809
|
},
|
|
35737
35810
|
async prStatus(url) {
|
|
35738
35811
|
try {
|
|
35739
|
-
const view = await gh(["pr", "view", url, "--json", "isDraft,state,headRefOid"]);
|
|
35812
|
+
const view = await gh(["pr", "view", url, "--json", "isDraft,state,headRefOid,baseRefName"]);
|
|
35740
35813
|
if (view.exitCode !== 0) {
|
|
35741
|
-
return { exists: false, isDraft: false, checksGreen: null, headSha: null };
|
|
35814
|
+
return { exists: false, isDraft: false, checksGreen: null, headSha: null, baseRefName: null };
|
|
35742
35815
|
}
|
|
35743
35816
|
const parsed = JSON.parse(view.stdout);
|
|
35744
35817
|
const checks = await gh(["pr", "checks", url]);
|
|
@@ -35746,10 +35819,11 @@ var init_github = __esm(() => {
|
|
|
35746
35819
|
exists: true,
|
|
35747
35820
|
isDraft: parsed.isDraft === true,
|
|
35748
35821
|
checksGreen: checks.exitCode === 0,
|
|
35749
|
-
headSha: typeof parsed.headRefOid === "string" && parsed.headRefOid !== "" ? parsed.headRefOid : null
|
|
35822
|
+
headSha: typeof parsed.headRefOid === "string" && parsed.headRefOid !== "" ? parsed.headRefOid : null,
|
|
35823
|
+
baseRefName: typeof parsed.baseRefName === "string" && parsed.baseRefName !== "" ? parsed.baseRefName : null
|
|
35750
35824
|
};
|
|
35751
35825
|
} catch {
|
|
35752
|
-
return { exists: false, isDraft: false, checksGreen: null, headSha: null };
|
|
35826
|
+
return { exists: false, isDraft: false, checksGreen: null, headSha: null, baseRefName: null };
|
|
35753
35827
|
}
|
|
35754
35828
|
},
|
|
35755
35829
|
async comment(ref, body) {
|
|
@@ -40091,9 +40165,9 @@ var init_memory = __esm(() => {
|
|
|
40091
40165
|
|
|
40092
40166
|
// src/lib/serve-config.ts
|
|
40093
40167
|
import { existsSync as existsSync25 } from "fs";
|
|
40094
|
-
import
|
|
40168
|
+
import path168 from "path";
|
|
40095
40169
|
function serveConfigPath(dir) {
|
|
40096
|
-
return
|
|
40170
|
+
return path168.join(keryxConfigDir(dir), "serve.json");
|
|
40097
40171
|
}
|
|
40098
40172
|
function parseIpv4(value) {
|
|
40099
40173
|
const parts = value.split(".");
|
|
@@ -43232,63 +43306,112 @@ var CONTRACTS = [
|
|
|
43232
43306
|
{
|
|
43233
43307
|
name: "agent-event",
|
|
43234
43308
|
fileName: "agent-event.schema.json",
|
|
43235
|
-
description: "Append-only lifecycle event emitted by orchestrators and subagents."
|
|
43309
|
+
description: "Append-only lifecycle event emitted by orchestrators and subagents.",
|
|
43310
|
+
enforcement: {
|
|
43311
|
+
kind: "none",
|
|
43312
|
+
reason: "Events are appended by whichever agent is running, in that agent's own runtime. No keryx process sits between the emitter and the log, so there is no point at which a malformed event could be refused rather than written."
|
|
43313
|
+
}
|
|
43236
43314
|
},
|
|
43237
43315
|
{
|
|
43238
43316
|
name: "flow-orchestrator-input",
|
|
43239
43317
|
fileName: "flow-orchestrator-input-contract.schema.json",
|
|
43240
43318
|
description: "Dispatch payload handed to flow-orchestrator (request + base branch + completion outcome + constraints).",
|
|
43241
|
-
sourcePath: "src/gdskills/bundled/skills/orchestration/flow-orchestrator/input-contract.schema.json"
|
|
43319
|
+
sourcePath: "src/gdskills/bundled/skills/orchestration/flow-orchestrator/input-contract.schema.json",
|
|
43320
|
+
enforcement: {
|
|
43321
|
+
kind: "none",
|
|
43322
|
+
reason: "This payload is handed from one AGENT to another. In a session driven by a host agent's own dispatch tool, no keryx process is on that path, so nothing can refuse a malformed dispatch. Same structural position as reviewer-input, recorded for the same reason. Registering it made `keryx skills contracts validate --schema flow-orchestrator-input` possible, which is a validator an agent must remember to run, not an enforcement."
|
|
43323
|
+
}
|
|
43242
43324
|
},
|
|
43243
43325
|
{
|
|
43244
43326
|
name: "review-pr-feedback-input",
|
|
43245
43327
|
fileName: "review-pr-feedback-input-contract.schema.json",
|
|
43246
43328
|
description: "Request handed to review-pr-feedback (PR reference, --fix, and the operator confirmation --fix requires).",
|
|
43247
|
-
sourcePath: "src/gdskills/bundled/skills/review/review-pr-feedback/input-contract.schema.json"
|
|
43329
|
+
sourcePath: "src/gdskills/bundled/skills/review/review-pr-feedback/input-contract.schema.json",
|
|
43330
|
+
enforcement: {
|
|
43331
|
+
kind: "none",
|
|
43332
|
+
reason: "The request is what an operator or a host agent hands the skill before any keryx command runs, so keryx is not yet in the path when the payload would have to be refused. This is the one where that hurts most: `--fix` merges third-party review comments into somebody else's pull request, and `operator_confirmed` is the fence. The conditional is expressed in the schema and `keryx skills contracts validate --schema review-pr-feedback-input` will apply it \u2014 but only when something invokes it."
|
|
43333
|
+
}
|
|
43248
43334
|
},
|
|
43249
43335
|
{
|
|
43250
43336
|
name: "review-pr-feedback-output",
|
|
43251
43337
|
fileName: "review-pr-feedback-output-contract.schema.json",
|
|
43252
43338
|
description: "Result review-pr-feedback returns: verdict counts, the injection-screen record, and what the fix run merged.",
|
|
43253
|
-
sourcePath: "src/gdskills/bundled/skills/review/review-pr-feedback/output-contract.schema.json"
|
|
43339
|
+
sourcePath: "src/gdskills/bundled/skills/review/review-pr-feedback/output-contract.schema.json",
|
|
43340
|
+
enforcement: {
|
|
43341
|
+
kind: "opt-in",
|
|
43342
|
+
module: "src/commands/review.ts",
|
|
43343
|
+
switchedOnBy: "keryx review comments reply --result <file>",
|
|
43344
|
+
refuses: "A result that contradicts itself, before the pass is built and before any network call: an analyze-mode run reporting a branch and a merge, or a record saying the injection screen never ran while claiming it excluded comments."
|
|
43345
|
+
}
|
|
43254
43346
|
},
|
|
43255
43347
|
{
|
|
43256
43348
|
name: "job-orchestrator-state",
|
|
43257
43349
|
fileName: "job-orchestrator-state.schema.json",
|
|
43258
43350
|
description: "Persisted job package state (.metaproject/jobs/<name>/state.json), written by `keryx job`.",
|
|
43259
|
-
sourcePath: "src/gdskills/bundled/skills/orchestration/job-orchestrator/state.schema.json"
|
|
43351
|
+
sourcePath: "src/gdskills/bundled/skills/orchestration/job-orchestrator/state.schema.json",
|
|
43352
|
+
enforcement: {
|
|
43353
|
+
kind: "production",
|
|
43354
|
+
module: "src/job/store.ts",
|
|
43355
|
+
refuses: "`writeJob` refuses to write a state file that does not satisfy the schema, so an invalid job package cannot reach disk."
|
|
43356
|
+
}
|
|
43260
43357
|
},
|
|
43261
43358
|
{
|
|
43262
43359
|
name: "orchestrator-state",
|
|
43263
43360
|
fileName: "orchestrator-state.schema.json",
|
|
43264
|
-
description: "Persisted resumable orchestrator state."
|
|
43361
|
+
description: "Persisted resumable orchestrator state.",
|
|
43362
|
+
enforcement: {
|
|
43363
|
+
kind: "none",
|
|
43364
|
+
reason: "No keryx command reads or writes this file. It describes state an orchestrator agent persists for itself, in its own runtime, so there is no keryx-owned write path to refuse at. Contrast job-orchestrator-state, which looks similar and IS enforced for exactly one reason: `keryx job` writes that one."
|
|
43365
|
+
}
|
|
43265
43366
|
},
|
|
43266
43367
|
{
|
|
43267
43368
|
name: "review-finding",
|
|
43268
43369
|
fileName: "review-finding.schema.json",
|
|
43269
|
-
description: "Normalized reviewer finding consumed by review-orchestrator and learning flows."
|
|
43370
|
+
description: "Normalized reviewer finding consumed by review-orchestrator and learning flows.",
|
|
43371
|
+
enforcement: {
|
|
43372
|
+
kind: "production",
|
|
43373
|
+
module: "src/review/managed.ts",
|
|
43374
|
+
refuses: "`createManagedReviewPackage` refuses to record findings that do not satisfy the schema, and the disposition sub-schema is applied the same way, so a review round cannot be written with a malformed finding or an unreadable outcome."
|
|
43375
|
+
}
|
|
43270
43376
|
},
|
|
43271
43377
|
{
|
|
43272
43378
|
name: "subagent-dispatch",
|
|
43273
43379
|
fileName: "subagent-dispatch.schema.json",
|
|
43274
|
-
description: "Orchestrator-to-subagent dispatch payload."
|
|
43380
|
+
description: "Orchestrator-to-subagent dispatch payload.",
|
|
43381
|
+
enforcement: {
|
|
43382
|
+
kind: "none",
|
|
43383
|
+
reason: "The dispatch is built and consumed inside the harness without the canonical schema being loaded: `subagent-dispatch` appears only as a label on the extension metadata. Its sibling `subagent-result` IS validated, because the harness parses a child's reply back and has to decide whether it is well-formed; nothing performs the equivalent act on the way out."
|
|
43384
|
+
}
|
|
43275
43385
|
},
|
|
43276
43386
|
{
|
|
43277
43387
|
name: "subagent-result",
|
|
43278
43388
|
fileName: "subagent-result.schema.json",
|
|
43279
|
-
description: "Subagent-to-orchestrator result payload."
|
|
43389
|
+
description: "Subagent-to-orchestrator result payload.",
|
|
43390
|
+
enforcement: {
|
|
43391
|
+
kind: "production",
|
|
43392
|
+
module: "src/harness/external/runtime.ts",
|
|
43393
|
+
refuses: "A child's reply that does not parse as a well-formed result is rejected when the harness reads it back, so a malformed result cannot be persisted as if the child had succeeded."
|
|
43394
|
+
}
|
|
43280
43395
|
},
|
|
43281
43396
|
{
|
|
43282
43397
|
name: "task-implementer-input",
|
|
43283
43398
|
fileName: "task-implementer-input-contract.schema.json",
|
|
43284
43399
|
description: "Task request handed to task-implementer (task + workspace + automation), validated before dispatch.",
|
|
43285
|
-
sourcePath: "src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json"
|
|
43400
|
+
sourcePath: "src/gdskills/bundled/skills/orchestration/task-implementer/input-contract.schema.json",
|
|
43401
|
+
enforcement: {
|
|
43402
|
+
kind: "none",
|
|
43403
|
+
reason: "Dispatched agent-to-agent, like flow-orchestrator-input. The skill's Phase 1.4 lists five `ASSERT \u2026 \u2192 ABORT(\u2026)` refusals; registering the contract is what lets `keryx skills contracts validate` perform them, and nothing forces that call. The comment beside this registration has said so since it was written."
|
|
43404
|
+
}
|
|
43286
43405
|
},
|
|
43287
43406
|
{
|
|
43288
43407
|
name: "task-implementer-output",
|
|
43289
43408
|
fileName: "task-implementer-output-contract.schema.json",
|
|
43290
43409
|
description: "JSON result task-implementer writes in Phase 6.1 before it emits its STATUS line.",
|
|
43291
|
-
sourcePath: "src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json"
|
|
43410
|
+
sourcePath: "src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json",
|
|
43411
|
+
enforcement: {
|
|
43412
|
+
kind: "none",
|
|
43413
|
+
reason: "The skill writes this file itself, in its own runtime, and no keryx command reads it back. Contrast subagent-result, which is the same shape of thing and IS enforced for one reason: the harness reads that one back and must decide whether it is well-formed."
|
|
43414
|
+
}
|
|
43292
43415
|
}
|
|
43293
43416
|
];
|
|
43294
43417
|
function normalizeContractName(value) {
|
|
@@ -44483,6 +44606,13 @@ function renderMetaprojectGitignoreBlock() {
|
|
|
44483
44606
|
.metaproject/data/security/raw/**
|
|
44484
44607
|
.metaproject/data/security/artifacts/latest.md
|
|
44485
44608
|
.metaproject/data/security/artifacts/latest.json
|
|
44609
|
+
# Forgetting/retention runtime state: the auto-sweep stamp is rewritten by the
|
|
44610
|
+
# gdctx write path on every call, not a project artifact. These lines were added
|
|
44611
|
+
# to this repository's .gitignore by hand INSIDE the managed block, where the
|
|
44612
|
+
# next \`keryx update\` regenerated them away \u2014 which is how they came to belong
|
|
44613
|
+
# here instead.
|
|
44614
|
+
.metaproject/data/forgetting/
|
|
44615
|
+
.metaproject/data/retention/
|
|
44486
44616
|
.metaproject/reports/
|
|
44487
44617
|
`;
|
|
44488
44618
|
}
|
|
@@ -46155,7 +46285,33 @@ function renderGdgraphPostCommitHook() {
|
|
|
46155
46285
|
return 0
|
|
46156
46286
|
fi
|
|
46157
46287
|
|
|
46158
|
-
|
|
46288
|
+
# Two questions, because the graph is fed by two different things.
|
|
46289
|
+
#
|
|
46290
|
+
# The second one is here because the first one alone was wrong. It lists
|
|
46291
|
+
# directory prefixes \u2014 src/, lib/, app/ and so on \u2014 while the builder indexes
|
|
46292
|
+
# any source file anywhere except the directories it never walks. Everything
|
|
46293
|
+
# in between was indexed AND undetected: a commit to \`vscode-extension/src/\`,
|
|
46294
|
+
# to a source file at the repository root, or to any directory not on the
|
|
46295
|
+
# list left the graph stale and printed NOTHING. Every other path in this
|
|
46296
|
+
# function says something when the graph may be stale; that one returned 0 in
|
|
46297
|
+
# silence, which is the failure this hook exists to end.
|
|
46298
|
+
#
|
|
46299
|
+
# The prefix list is kept rather than replaced, so nothing that rebuilt
|
|
46300
|
+
# before stops rebuilding: it covers paths that change how the graph resolves
|
|
46301
|
+
# without being indexed themselves, such as docs/ and the metaproject rules.
|
|
46302
|
+
# The extension test only widens.
|
|
46303
|
+
#
|
|
46304
|
+
# The exclusion mirrors IGNORE_DIRS in src/gdgraph/build.ts. It has to: a
|
|
46305
|
+
# rebuild triggered by a file the builder never reads is a rebuild that
|
|
46306
|
+
# cannot change the answer, and every dependency bump would pay for it.
|
|
46307
|
+
if printf '%s\\n' "$changed_files" | grep -E '(^src/|^lib/|^app/|^packages/|^services/|^scripts/|^docs/|^\\.metaproject/(modules|skills|rules)/|package\\.json$|tsconfig.*\\.json$|bun\\.lockb?$|pnpm-lock\\.yaml$|yarn\\.lock$|package-lock\\.json$)' >/dev/null 2>&1; then
|
|
46308
|
+
:
|
|
46309
|
+
elif printf '%s\\n' "$changed_files" \\
|
|
46310
|
+
| grep -E '\\.(ts|tsx|js|jsx|java|py)$' \\
|
|
46311
|
+
| grep -Ev '(^|/)(\\.git|\\.claude|\\.metaproject|node_modules|\\.cache|\\.docusaurus|\\.next|\\.turbo|dist|build|coverage|generated|out|public|storybook-static)/' \\
|
|
46312
|
+
>/dev/null 2>&1; then
|
|
46313
|
+
:
|
|
46314
|
+
else
|
|
46159
46315
|
return 0
|
|
46160
46316
|
fi
|
|
46161
46317
|
|
|
@@ -47005,7 +47161,7 @@ import path43 from "path";
|
|
|
47005
47161
|
// package.json
|
|
47006
47162
|
var package_default = {
|
|
47007
47163
|
name: "@mrciphersmith/keryx",
|
|
47008
|
-
version: "0.2.
|
|
47164
|
+
version: "0.2.88",
|
|
47009
47165
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
47010
47166
|
private: false,
|
|
47011
47167
|
publishConfig: {
|
|
@@ -47059,6 +47215,7 @@ var package_default = {
|
|
|
47059
47215
|
check: "bun run lint && bun run typecheck && bun run typecheck:scripts && bun test",
|
|
47060
47216
|
"check:core": "bun run lint && bun run typecheck && bun run typecheck:scripts && bun run test:core",
|
|
47061
47217
|
"check:doc-links": "bun scripts/check-doc-links.ts",
|
|
47218
|
+
"check:retired-spellings": "bun scripts/check-retired-cli-spellings.ts",
|
|
47062
47219
|
"baseline:review-precision": "bun scripts/review-precision-baseline.ts",
|
|
47063
47220
|
"test:guards": "bun test src/lib/config-dir.ast.test.ts src/lib/config-dir.readers.test.ts src/lib/production-graph.test.ts src/harness/policy/profiles.test.ts src/lib/serve-server.test.ts src/gdskills/agent-catalogue-xref.test.ts src/gdskills/enforcement-claims.test.ts",
|
|
47064
47221
|
lint: "eslint ."
|
|
@@ -48494,7 +48651,7 @@ var MCP_MANAGED_KEY = "_keryxManaged";
|
|
|
48494
48651
|
var MCP_MANAGED_SENTINEL = "mcp-client-config";
|
|
48495
48652
|
var MCP_SERVER_NAME = "keryx";
|
|
48496
48653
|
var MCP_SERVER_COMMAND = "keryx";
|
|
48497
|
-
var MCP_SERVER_ARGS = ["mcp"
|
|
48654
|
+
var MCP_SERVER_ARGS = ["serve-mcp"];
|
|
48498
48655
|
var MCP_SDK_HINT = "bun add @modelcontextprotocol/sdk";
|
|
48499
48656
|
function mcpServerEntry(projectRoot) {
|
|
48500
48657
|
const args = projectRoot ? [...MCP_SERVER_ARGS, "--cwd", projectRoot] : [...MCP_SERVER_ARGS];
|
|
@@ -48812,12 +48969,12 @@ protocol adapter \u2014 it defines no new module logic.
|
|
|
48812
48969
|
|
|
48813
48970
|
## Commands
|
|
48814
48971
|
|
|
48815
|
-
- \`keryx mcp
|
|
48816
|
-
- \`keryx mcp
|
|
48972
|
+
- \`keryx serve-mcp\` \u2014 stdio JSON-RPC MCP server (default transport).
|
|
48973
|
+
- \`keryx serve-mcp --http\` \u2014 isolated HTTP/SSE opt-in (localhost only;
|
|
48817
48974
|
requires \`http.enabled=true\` in this module's manifest entry).
|
|
48818
|
-
- \`keryx mcp
|
|
48975
|
+
- \`keryx serve-mcp --cwd <project-root>\` \u2014 expose a specific project,
|
|
48819
48976
|
independent of the MCP client's launch directory.
|
|
48820
|
-
- \`keryx
|
|
48977
|
+
- \`keryx integrate <cursor|claude|opencode|vscode|generic|all> [--dry-run]\` \u2014
|
|
48821
48978
|
wire this project into an editor/agent: writes a project-local client
|
|
48822
48979
|
config (cursor \u2192 \`.cursor/mcp.json\`, claude \u2192 \`.mcp.json\`, opencode \u2192
|
|
48823
48980
|
\`opencode.json\`, vscode \u2192 \`.vscode/mcp.json\`) and sets
|
|
@@ -48827,17 +48984,17 @@ protocol adapter \u2014 it defines no new module logic.
|
|
|
48827
48984
|
step; hand-editing a client config file directly is unnecessary and skips
|
|
48828
48985
|
setting \`modules.mcp.enabled\`. \`all\` expands to cursor + claude +
|
|
48829
48986
|
opencode; \`vscode\` is opt-in only (not bundled into \`all\`) \u2014 request it
|
|
48830
|
-
explicitly
|
|
48831
|
-
- \`keryx
|
|
48987
|
+
explicitly as \`keryx integrate vscode\`.
|
|
48988
|
+
- \`keryx integrate --remove <cursor|claude|opencode|vscode|generic|all>\` \u2014
|
|
48832
48989
|
remove the managed client config again.
|
|
48833
48990
|
- **codex CLI**: not a \`--runtime\` here \u2014 codex's client config is a single
|
|
48834
48991
|
GLOBAL \`~/.codex/config.toml\`, not a project-local file, and it already
|
|
48835
48992
|
ships its own safe, native installer for it. Run
|
|
48836
|
-
\`codex mcp add keryx -- keryx mcp
|
|
48993
|
+
\`codex mcp add keryx -- keryx serve-mcp --cwd <project-root>\` once
|
|
48837
48994
|
(verified live: codex successfully discovers and calls this server's
|
|
48838
48995
|
tools headlessly with \`codex exec --approve-for-me\`); \`codex mcp remove
|
|
48839
48996
|
keryx\` to undo. \`modules.mcp.enabled=true\` still needs
|
|
48840
|
-
\`keryx
|
|
48997
|
+
\`keryx integrate generic\` (or any other editor) run once,
|
|
48841
48998
|
since codex's own installer has no notion of the keryx manifest.
|
|
48842
48999
|
|
|
48843
49000
|
## Notes
|
|
@@ -48952,7 +49109,7 @@ async function installMcpClient(projectRoot, ids, options = {}) {
|
|
|
48952
49109
|
const sdk = await probeMcpSdk();
|
|
48953
49110
|
return { outcomes, unknown, manifest, sdk, dryRun };
|
|
48954
49111
|
}
|
|
48955
|
-
async function uninstallMcpClient(projectRoot, ids) {
|
|
49112
|
+
async function uninstallMcpClient(projectRoot, ids, options = {}) {
|
|
48956
49113
|
const absoluteProjectRoot = path52.resolve(projectRoot);
|
|
48957
49114
|
const { runtimes, unknown } = resolveMcpRuntimes(ids);
|
|
48958
49115
|
const outcomes = [];
|
|
@@ -48969,7 +49126,9 @@ async function uninstallMcpClient(projectRoot, ids) {
|
|
|
48969
49126
|
const settings = await readSettings2(file);
|
|
48970
49127
|
const hadManaged = runtime.hasManaged(settings);
|
|
48971
49128
|
const stripped = runtime.strip(settings);
|
|
48972
|
-
|
|
49129
|
+
if (options.dryRun !== true) {
|
|
49130
|
+
await writeSettings2(file, stripped);
|
|
49131
|
+
}
|
|
48973
49132
|
outcomes.push({ id: runtime.id, filePath: file, removed: hadManaged });
|
|
48974
49133
|
}
|
|
48975
49134
|
return { outcomes, unknown };
|
|
@@ -49589,7 +49748,7 @@ async function initCommand(args) {
|
|
|
49589
49748
|
}
|
|
49590
49749
|
}
|
|
49591
49750
|
if (!report.sdk.available) {
|
|
49592
|
-
note(`Optional MCP SDK not found \u2014 install it to run \`keryx mcp
|
|
49751
|
+
note(`Optional MCP SDK not found \u2014 install it to run \`keryx serve-mcp\`: ${report.sdk.hint}`);
|
|
49593
49752
|
}
|
|
49594
49753
|
}
|
|
49595
49754
|
const enabledModuleCount = [
|
|
@@ -49674,7 +49833,7 @@ async function initCommand(args) {
|
|
|
49674
49833
|
steps.push(`After pulling changes, run ${style.cyan("keryx update")} to refresh service files.`);
|
|
49675
49834
|
nextSteps(steps);
|
|
49676
49835
|
if (!enableMcp && !options.yes) {
|
|
49677
|
-
note(`Wire an editor/agent to the MCP server later with ${style.cyan("keryx
|
|
49836
|
+
note(`Wire an editor/agent to the MCP server later with ${style.cyan("keryx integrate <editor>")}.`);
|
|
49678
49837
|
}
|
|
49679
49838
|
}
|
|
49680
49839
|
function parseInitArgs(args) {
|
|
@@ -49929,7 +50088,7 @@ ${blockEnd}`;
|
|
|
49929
50088
|
const existing = await pathExists(hookPath) ? await readFile23(hookPath, "utf8") : `#!/usr/bin/env sh
|
|
49930
50089
|
`;
|
|
49931
50090
|
const blockPattern = new RegExp(`${escapeRegExp2(blockStart)}[\\s\\S]*?${escapeRegExp2(blockEnd)}`);
|
|
49932
|
-
const next = blockPattern.test(existing) ? existing.replace(blockPattern, managedBlock) : `${existing.trimEnd()}
|
|
50091
|
+
const next = blockPattern.test(existing) ? existing.replace(blockPattern, () => managedBlock) : `${existing.trimEnd()}
|
|
49933
50092
|
|
|
49934
50093
|
${managedBlock}
|
|
49935
50094
|
`;
|
|
@@ -59686,12 +59845,16 @@ async function runInit(args) {
|
|
|
59686
59845
|
cwd: process.cwd(),
|
|
59687
59846
|
title: optionValue(args, "--title"),
|
|
59688
59847
|
issue: optionValue(args, "--issue"),
|
|
59689
|
-
slug: optionValue(args, "--slug")
|
|
59848
|
+
slug: optionValue(args, "--slug"),
|
|
59849
|
+
baseBranch: optionValue(args, "--base")
|
|
59690
59850
|
});
|
|
59691
59851
|
banner("flow init", `Created flow ${result.flow.id}`);
|
|
59692
59852
|
console.log(` ${style.green(symbols.ok)} ${style.bold(result.flow.title)}`);
|
|
59693
59853
|
note(result.dir);
|
|
59694
59854
|
console.log(` status: ${flowStatusLabel(result.flow.status)}`);
|
|
59855
|
+
if (result.flow.baseBranch !== undefined) {
|
|
59856
|
+
console.log(` base: ${result.flow.baseBranch}`);
|
|
59857
|
+
}
|
|
59695
59858
|
if (result.contextNotes.length > 0) {
|
|
59696
59859
|
heading("Context collected");
|
|
59697
59860
|
for (const contextNote of result.contextNotes) {
|
|
@@ -60095,7 +60258,7 @@ function requireId(args) {
|
|
|
60095
60258
|
function printHelp10() {
|
|
60096
60259
|
helpTitle("keryx flow", "agent-first managed work (flows)");
|
|
60097
60260
|
helpUsage([
|
|
60098
|
-
'keryx flow init (--issue <url> | --title "<t>") [--slug <s>]',
|
|
60261
|
+
'keryx flow init (--issue <url> | --title "<t>") [--slug <s>] [--base <branch>]',
|
|
60099
60262
|
"keryx flow list",
|
|
60100
60263
|
"keryx flow status <id>",
|
|
60101
60264
|
"keryx flow freeze <id>",
|
|
@@ -64724,6 +64887,7 @@ var COMMENTS_REPLY_FLAGS = [
|
|
|
64724
64887
|
"--pr",
|
|
64725
64888
|
"--self",
|
|
64726
64889
|
"--outcomes",
|
|
64890
|
+
"--result",
|
|
64727
64891
|
"--sha",
|
|
64728
64892
|
"--round",
|
|
64729
64893
|
"--final",
|
|
@@ -65183,6 +65347,7 @@ async function runCommentsReply(args) {
|
|
|
65183
65347
|
const round = parseNonNegativeInteger(optionValue(args, "--round"), "--round") ?? 1;
|
|
65184
65348
|
const isFinal = args.includes("--final");
|
|
65185
65349
|
const dryRun = args.includes("--dry-run");
|
|
65350
|
+
await refuseInvalidResult(optionValue(args, "--result"), optionValue(args, "--outcomes"));
|
|
65186
65351
|
const cwd = process.cwd();
|
|
65187
65352
|
const port = await resolvePort(args);
|
|
65188
65353
|
const state = await readPrCommentState(cwd, repo, number);
|
|
@@ -65262,6 +65427,28 @@ async function resolveSelfLogin(args) {
|
|
|
65262
65427
|
}
|
|
65263
65428
|
return login;
|
|
65264
65429
|
}
|
|
65430
|
+
async function refuseInvalidResult(source, outcomesSource) {
|
|
65431
|
+
if (source === undefined) {
|
|
65432
|
+
return;
|
|
65433
|
+
}
|
|
65434
|
+
if (source === "-" && outcomesSource === "-") {
|
|
65435
|
+
throw new Error("`--result -` and `--outcomes -` both read standard input, which can only be consumed once. Pass at least one of them as a file path.");
|
|
65436
|
+
}
|
|
65437
|
+
const raw = source === "-" ? await Bun.stdin.text() : await readFile87(source, "utf8");
|
|
65438
|
+
let parsed;
|
|
65439
|
+
try {
|
|
65440
|
+
parsed = JSON.parse(raw);
|
|
65441
|
+
} catch (error) {
|
|
65442
|
+
throw new Error(`\`--result ${source}\` is not JSON: ${error instanceof Error ? error.message : String(error)}. Nothing was posted.`);
|
|
65443
|
+
}
|
|
65444
|
+
const schema = await loadSchema("review-pr-feedback-output");
|
|
65445
|
+
const errors = await validateJson(parsed, schema);
|
|
65446
|
+
if (errors.length > 0) {
|
|
65447
|
+
throw new Error(`\`--result ${source}\` does not satisfy the review-pr-feedback-output contract, so nothing was posted:
|
|
65448
|
+
${errors.map((error) => ` ${error.path}: ${error.message}`).join(`
|
|
65449
|
+
`)}`);
|
|
65450
|
+
}
|
|
65451
|
+
}
|
|
65265
65452
|
async function readOutcomes(source) {
|
|
65266
65453
|
if (source === undefined) {
|
|
65267
65454
|
throw new Error("`--outcomes <file|->` is required: it carries one disposition and one reply sentence per collected comment. The judgement is the model's; this command only enforces the budget, the threading and the once-at-the-end rule.");
|
|
@@ -69187,12 +69374,109 @@ async function sandboxCommand(args = [], deps = {}) {
|
|
|
69187
69374
|
|
|
69188
69375
|
// src/commands/mcp.ts
|
|
69189
69376
|
init_args();
|
|
69190
|
-
|
|
69377
|
+
|
|
69378
|
+
// src/commands/integrate.ts
|
|
69379
|
+
import path162 from "path";
|
|
69380
|
+
var EDITOR_USAGE = `<cursor|claude|opencode|vscode|generic|all>`;
|
|
69381
|
+
var DEFAULT_EDITORS = ["all"];
|
|
69382
|
+
async function integrateCommand(args = [], cwd = process.cwd(), label) {
|
|
69383
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
69384
|
+
printIntegrateHelp();
|
|
69385
|
+
return;
|
|
69386
|
+
}
|
|
69387
|
+
const editors = parseEditors(args);
|
|
69388
|
+
if (args.includes("--remove")) {
|
|
69389
|
+
await removeIntegration(cwd, editors, args.includes("--dry-run"), label ?? "keryx integrate --remove");
|
|
69390
|
+
return;
|
|
69391
|
+
}
|
|
69392
|
+
await addIntegration(cwd, editors, args.includes("--dry-run"), label ?? "keryx integrate");
|
|
69393
|
+
}
|
|
69394
|
+
function parseEditors(args) {
|
|
69395
|
+
const named = args.filter((argument) => !argument.startsWith("-")).flatMap((argument) => argument.split(",")).map((argument) => argument.trim()).filter(Boolean);
|
|
69396
|
+
return named.length > 0 ? named : [...DEFAULT_EDITORS];
|
|
69397
|
+
}
|
|
69398
|
+
async function addIntegration(cwd, editors, dryRun, label) {
|
|
69399
|
+
const report = await installMcpClient(cwd, editors, { dryRun });
|
|
69400
|
+
if (report.unknown.length > 0) {
|
|
69401
|
+
console.error(`Unknown runtime(s): ${report.unknown.join(", ")}`);
|
|
69402
|
+
process.exitCode = 1;
|
|
69403
|
+
return;
|
|
69404
|
+
}
|
|
69405
|
+
heading(`${label}${dryRun ? " (dry run)" : ""}`);
|
|
69406
|
+
for (const outcome of report.outcomes) {
|
|
69407
|
+
if (outcome.filePath === null) {
|
|
69408
|
+
console.log(` ${style.cyan(symbols.arrow)} ${outcome.id} \u2014 paste this into your MCP client config:`);
|
|
69409
|
+
console.log(outcome.snippet ?? "");
|
|
69410
|
+
continue;
|
|
69411
|
+
}
|
|
69412
|
+
const rel = path162.relative(cwd, outcome.filePath);
|
|
69413
|
+
if (outcome.errors.length > 0) {
|
|
69414
|
+
for (const e of outcome.errors) {
|
|
69415
|
+
console.log(` ${style.red(symbols.cross)} ${e}`);
|
|
69416
|
+
}
|
|
69417
|
+
process.exitCode = 1;
|
|
69418
|
+
continue;
|
|
69419
|
+
}
|
|
69420
|
+
if (dryRun) {
|
|
69421
|
+
console.log(` ${style.cyan(symbols.arrow)} ${outcome.id} \u2192 would write ${rel}:`);
|
|
69422
|
+
console.log(outcome.snippet ?? "");
|
|
69423
|
+
} else {
|
|
69424
|
+
console.log(` ${style.green(symbols.ok)} ${outcome.id} \u2192 ${rel}`);
|
|
69425
|
+
}
|
|
69426
|
+
}
|
|
69427
|
+
if (report.manifest.message) {
|
|
69428
|
+
note(report.manifest.message);
|
|
69429
|
+
} else if (dryRun && report.manifest.changed) {
|
|
69430
|
+
note("would set modules.mcp.enabled=true in .metaproject/metaproject.json");
|
|
69431
|
+
} else if (report.manifest.changed) {
|
|
69432
|
+
note("set modules.mcp.enabled=true in .metaproject/metaproject.json");
|
|
69433
|
+
}
|
|
69434
|
+
if (!report.sdk.available) {
|
|
69435
|
+
note(`Optional MCP SDK not found \u2014 install it to run \`keryx serve-mcp\`: ${report.sdk.hint}`);
|
|
69436
|
+
}
|
|
69437
|
+
}
|
|
69438
|
+
async function removeIntegration(cwd, editors, dryRun, label) {
|
|
69439
|
+
const report = await uninstallMcpClient(cwd, editors, { dryRun });
|
|
69440
|
+
if (report.unknown.length > 0) {
|
|
69441
|
+
console.error(`Unknown runtime(s): ${report.unknown.join(", ")}`);
|
|
69442
|
+
process.exitCode = 1;
|
|
69443
|
+
return;
|
|
69444
|
+
}
|
|
69445
|
+
heading(label);
|
|
69446
|
+
for (const outcome of report.outcomes) {
|
|
69447
|
+
if (outcome.filePath === null) {
|
|
69448
|
+
console.log(` ${style.gray(symbols.off)} ${outcome.id} ${style.dim("no file to change")}`);
|
|
69449
|
+
continue;
|
|
69450
|
+
}
|
|
69451
|
+
const rel = path162.relative(cwd, outcome.filePath);
|
|
69452
|
+
console.log(` ${outcome.removed ? style.green(symbols.ok) : style.gray(symbols.off)} ${outcome.id} ${style.dim(outcome.removed ? `${dryRun ? "would be removed from" : "removed from"} ${rel}` : "nothing to remove")}`);
|
|
69453
|
+
}
|
|
69454
|
+
}
|
|
69455
|
+
function printIntegrateHelp() {
|
|
69456
|
+
helpTitle("keryx integrate", "wire this project into an editor or agent as an MCP server");
|
|
69457
|
+
helpUsage([
|
|
69458
|
+
`keryx integrate ${EDITOR_USAGE} # write the client config`,
|
|
69459
|
+
`keryx integrate --remove ${EDITOR_USAGE} # remove the managed keryx server`,
|
|
69460
|
+
`keryx integrate ${EDITOR_USAGE} --dry-run # print the planned change, write nothing`
|
|
69461
|
+
]);
|
|
69462
|
+
helpOptions([
|
|
69463
|
+
{ flag: "--remove", desc: "Remove the managed keryx server instead of writing it." },
|
|
69464
|
+
{ flag: "--dry-run", desc: "Print the planned change and write nothing. Works with --remove too." }
|
|
69465
|
+
]);
|
|
69466
|
+
heading("Notes");
|
|
69467
|
+
console.log(` ${style.dim(`Editors: ${mcpRuntimeIds().join(", ")}, or all (=cursor,claude,opencode). Comma-separated. Default: all.`)}`);
|
|
69468
|
+
console.log(` ${style.dim("Writes a project-local MCP client config (cursor \u2192 .cursor/mcp.json, claude \u2192 .mcp.json, opencode \u2192 opencode.json, vscode \u2192 .vscode/mcp.json), sets modules.mcp.enabled=true, and prints a snippet for `generic`. `vscode` is opt-in only \u2014 not included in `all`.")}`);
|
|
69469
|
+
console.log(` ${style.dim("Only probes the optional @modelcontextprotocol/sdk \u2014 it never installs it and never opens a network connection.")}`);
|
|
69470
|
+
}
|
|
69471
|
+
|
|
69472
|
+
// src/commands/serve-mcp.ts
|
|
69473
|
+
init_args();
|
|
69474
|
+
import path169 from "path";
|
|
69191
69475
|
|
|
69192
69476
|
// src/mcp/discovery.ts
|
|
69193
69477
|
init_fs();
|
|
69194
69478
|
init_json();
|
|
69195
|
-
import
|
|
69479
|
+
import path163 from "path";
|
|
69196
69480
|
var MODULE_MANIFEST_KEY = {
|
|
69197
69481
|
gdgraph: "gdgraph",
|
|
69198
69482
|
security: "security",
|
|
@@ -69254,7 +69538,7 @@ function buildDiscovery(manifest) {
|
|
|
69254
69538
|
};
|
|
69255
69539
|
}
|
|
69256
69540
|
async function loadDiscovery(cwd) {
|
|
69257
|
-
const manifestPath =
|
|
69541
|
+
const manifestPath = path163.join(cwd, ".metaproject", "metaproject.json");
|
|
69258
69542
|
if (!await pathExists(manifestPath)) {
|
|
69259
69543
|
return buildDiscovery({});
|
|
69260
69544
|
}
|
|
@@ -69327,7 +69611,7 @@ init_store2();
|
|
|
69327
69611
|
init_fs();
|
|
69328
69612
|
import { createHash as createHash33, randomUUID as randomUUID17 } from "crypto";
|
|
69329
69613
|
import { appendFile as appendFile7, mkdir as mkdir58, open as open2, readFile as readFile93, rename as rename7, rm as rm12, stat as stat16, writeFile as writeFile50 } from "fs/promises";
|
|
69330
|
-
import
|
|
69614
|
+
import path164 from "path";
|
|
69331
69615
|
|
|
69332
69616
|
// src/sac/policy-experiment.ts
|
|
69333
69617
|
import { createHash as createHash32, createHmac as createHmac2 } from "crypto";
|
|
@@ -69683,7 +69967,7 @@ function hasReportIntegrity(report) {
|
|
|
69683
69967
|
return reportHashPattern.test(reportDigest) && sha2565(body) === reportDigest;
|
|
69684
69968
|
}
|
|
69685
69969
|
async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
|
|
69686
|
-
const configPath =
|
|
69970
|
+
const configPath = path164.join(workspaceRoot, ...policyExperimentConfigPath);
|
|
69687
69971
|
let configJson;
|
|
69688
69972
|
try {
|
|
69689
69973
|
const raw = await readFile93(configPath, "utf8").catch((error) => {
|
|
@@ -69785,7 +70069,7 @@ async function diagnosePolicyReadiness(workspaceRoot) {
|
|
|
69785
70069
|
const integrityReady = steps.every((entry) => entry.step === "activation-flags" || entry.status === "pass");
|
|
69786
70070
|
return Object.freeze({ configPresent, enabled, killSwitch, integrityReady, candidateWouldActivate: integrityReady && enabled && !killSwitch, steps: Object.freeze([...steps]) });
|
|
69787
70071
|
};
|
|
69788
|
-
const configPath =
|
|
70072
|
+
const configPath = path164.join(workspaceRoot, ...policyExperimentConfigPath);
|
|
69789
70073
|
let configJson;
|
|
69790
70074
|
try {
|
|
69791
70075
|
const raw = await readFile93(configPath, "utf8").catch((error) => {
|
|
@@ -70040,9 +70324,9 @@ class FwkReadService {
|
|
|
70040
70324
|
const recordedAt = nowIso2(now);
|
|
70041
70325
|
const id = `receipt-${randomUUID17().replace(/-/g, "").slice(0, 16)}`;
|
|
70042
70326
|
const base = { schemaVersion: "1.0", id, workspaceId, actor, action, decision, recordedAt, cost: { tokens: 0, toolCalls: 1, elapsedMs: 0 }, contextAssembly: { traceRef: assembly.traceRef, configurationRevision: assembly.configurationRevision, selected: assembly.selected.map((id) => `./ids/${id}`), omittedOptional: assembly.omittedOptional.map((id) => `./ids/${id}`) }, policy: { ref: assembly.policyRef, revision: assembly.policyRevision }, ...action === "resource" ? { resourceRef: `./ids/${resourceId ?? "unknown"}` } : {} };
|
|
70043
|
-
const ledger =
|
|
70044
|
-
const checkpointPath =
|
|
70045
|
-
await mkdir58(
|
|
70327
|
+
const ledger = path164.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
|
|
70328
|
+
const checkpointPath = path164.join(path164.dirname(ledger), "access-receipts.checkpoint.json");
|
|
70329
|
+
await mkdir58(path164.dirname(ledger), { recursive: true, mode: 448 });
|
|
70046
70330
|
return withFileLock2(`${ledger}.lock`, async () => {
|
|
70047
70331
|
const state = await resolveLedgerState(ledger, checkpointPath, this.options.verifyReceiptLedger ?? verifyAccessReceiptLedger);
|
|
70048
70332
|
const receipt = sealAccessReceipt(base, state.headHash);
|
|
@@ -70154,7 +70438,7 @@ init_workspace_service();
|
|
|
70154
70438
|
init_sac();
|
|
70155
70439
|
import { appendFile as appendFile8, mkdir as mkdir59, readFile as readFile94 } from "fs/promises";
|
|
70156
70440
|
import { randomUUID as randomUUID18 } from "crypto";
|
|
70157
|
-
import
|
|
70441
|
+
import path165 from "path";
|
|
70158
70442
|
|
|
70159
70443
|
class CollaborationServiceError extends Error {
|
|
70160
70444
|
code;
|
|
@@ -70170,7 +70454,7 @@ class CollaborationService {
|
|
|
70170
70454
|
this.input = input;
|
|
70171
70455
|
}
|
|
70172
70456
|
file(id) {
|
|
70173
|
-
return
|
|
70457
|
+
return path165.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
|
|
70174
70458
|
}
|
|
70175
70459
|
async overview(input) {
|
|
70176
70460
|
const manifest = await this.input.workspaces.show(input);
|
|
@@ -70207,7 +70491,7 @@ class CollaborationService {
|
|
|
70207
70491
|
occurredAt: (this.input.now ?? (() => new Date))().toISOString(),
|
|
70208
70492
|
...suppliedHandoff ? { handoff: { ...suppliedHandoff, from: actor.subject } } : {}
|
|
70209
70493
|
});
|
|
70210
|
-
await mkdir59(
|
|
70494
|
+
await mkdir59(path165.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
|
|
70211
70495
|
await appendFile8(this.file(manifest.id), `${JSON.stringify(activity)}
|
|
70212
70496
|
`, { mode: 384 });
|
|
70213
70497
|
return normalizeCollaborationResult(activity);
|
|
@@ -70262,9 +70546,9 @@ init_workspace_service();
|
|
|
70262
70546
|
init_fs();
|
|
70263
70547
|
init_machine_wrap_up();
|
|
70264
70548
|
import { mkdir as mkdir60, readdir as readdir31, readFile as readFile95 } from "fs/promises";
|
|
70265
|
-
import
|
|
70549
|
+
import path166 from "path";
|
|
70266
70550
|
function externalSlatesDir(cwd) {
|
|
70267
|
-
return
|
|
70551
|
+
return path166.join(cwd, ".keryx", "external-slates");
|
|
70268
70552
|
}
|
|
70269
70553
|
var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
70270
70554
|
function assertValidExternalSessionId(externalSessionId) {
|
|
@@ -70274,14 +70558,14 @@ function assertValidExternalSessionId(externalSessionId) {
|
|
|
70274
70558
|
}
|
|
70275
70559
|
function externalSlatePath(cwd, externalSessionId) {
|
|
70276
70560
|
assertValidExternalSessionId(externalSessionId);
|
|
70277
|
-
return
|
|
70561
|
+
return path166.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
|
|
70278
70562
|
}
|
|
70279
70563
|
function externalSlateLockPath(cwd, externalSessionId) {
|
|
70280
70564
|
return `${externalSlatePath(cwd, externalSessionId)}.lock`;
|
|
70281
70565
|
}
|
|
70282
70566
|
function externalSlateEvidenceDir(cwd, externalSessionId) {
|
|
70283
70567
|
assertValidExternalSessionId(externalSessionId);
|
|
70284
|
-
return
|
|
70568
|
+
return path166.join(externalSlatesDir(cwd), externalSessionId);
|
|
70285
70569
|
}
|
|
70286
70570
|
async function readExternalSlate(cwd, externalSessionId) {
|
|
70287
70571
|
try {
|
|
@@ -70926,7 +71210,7 @@ function buildToolRegistry() {
|
|
|
70926
71210
|
// src/mcp/resources.ts
|
|
70927
71211
|
init_fs();
|
|
70928
71212
|
init_contained_read();
|
|
70929
|
-
import
|
|
71213
|
+
import path167 from "path";
|
|
70930
71214
|
import { lstat as lstat4, readdir as readdir32, realpath as realpath7, stat as stat17 } from "fs/promises";
|
|
70931
71215
|
var URI_PREFIX = "metaproject://";
|
|
70932
71216
|
function mimeForPath(filePath) {
|
|
@@ -70939,13 +71223,13 @@ function mimeForPath(filePath) {
|
|
|
70939
71223
|
return "text/plain";
|
|
70940
71224
|
}
|
|
70941
71225
|
function dataRoot3(cwd) {
|
|
70942
|
-
return
|
|
71226
|
+
return path167.join(cwd, ".metaproject", "data");
|
|
70943
71227
|
}
|
|
70944
71228
|
function wikiRoot(cwd) {
|
|
70945
|
-
return
|
|
71229
|
+
return path167.join(cwd, ".metaproject", "wiki");
|
|
70946
71230
|
}
|
|
70947
71231
|
function memoryRoot2(cwd) {
|
|
70948
|
-
return
|
|
71232
|
+
return path167.join(cwd, ".metaproject", "memory");
|
|
70949
71233
|
}
|
|
70950
71234
|
var MAX_RESOURCE_BYTES = 8 * 1024 * 1024;
|
|
70951
71235
|
async function walkFiles(root, ownerRoot = root, ancestors = new Set) {
|
|
@@ -70971,7 +71255,7 @@ async function walkFiles(root, ownerRoot = root, ancestors = new Set) {
|
|
|
70971
71255
|
return [];
|
|
70972
71256
|
}
|
|
70973
71257
|
for (const entry of entries) {
|
|
70974
|
-
const full =
|
|
71258
|
+
const full = path167.join(root, entry.name);
|
|
70975
71259
|
const info = await stat17(full).catch(() => null);
|
|
70976
71260
|
if (!info || !isPathInside(ownerReal, await realpath7(full).catch(() => "")))
|
|
70977
71261
|
continue;
|
|
@@ -70999,9 +71283,9 @@ async function listArtifacts(cwd) {
|
|
|
70999
71283
|
if (!moduleEntry.isDirectory()) {
|
|
71000
71284
|
continue;
|
|
71001
71285
|
}
|
|
71002
|
-
const artifactsDir =
|
|
71286
|
+
const artifactsDir = path167.join(base, moduleEntry.name, "artifacts");
|
|
71003
71287
|
for (const file of await walkFiles(artifactsDir)) {
|
|
71004
|
-
const rel = toPosix(
|
|
71288
|
+
const rel = toPosix(path167.relative(artifactsDir, file));
|
|
71005
71289
|
const relPath = `${moduleEntry.name}/${rel}`;
|
|
71006
71290
|
listings.push({
|
|
71007
71291
|
uri: `${URI_PREFIX}artifacts/${relPath}`,
|
|
@@ -71015,7 +71299,7 @@ async function listArtifacts(cwd) {
|
|
|
71015
71299
|
async function listUnderRoot(cwd, cls, root) {
|
|
71016
71300
|
const listings = [];
|
|
71017
71301
|
for (const file of await walkFiles(root)) {
|
|
71018
|
-
const rel = toPosix(
|
|
71302
|
+
const rel = toPosix(path167.relative(root, file));
|
|
71019
71303
|
listings.push({
|
|
71020
71304
|
uri: `${URI_PREFIX}${cls}/${rel}`,
|
|
71021
71305
|
name: rel,
|
|
@@ -71065,12 +71349,12 @@ function resolveConfined(cwd, cls, relPath) {
|
|
|
71065
71349
|
if (moduleName.includes("..") || moduleName.length === 0) {
|
|
71066
71350
|
return null;
|
|
71067
71351
|
}
|
|
71068
|
-
const root =
|
|
71069
|
-
const absolute =
|
|
71352
|
+
const root = path167.join(dataRoot3(cwd), moduleName, "artifacts");
|
|
71353
|
+
const absolute = path167.resolve(root, rest);
|
|
71070
71354
|
return isPathInside(root, absolute) ? { root, absolute } : null;
|
|
71071
71355
|
}
|
|
71072
71356
|
const root = cls === "wiki" ? wikiRoot(cwd) : memoryRoot2(cwd);
|
|
71073
|
-
const absolute =
|
|
71357
|
+
const absolute = path167.resolve(root, relPath);
|
|
71074
71358
|
return isPathInside(root, absolute) ? { root, absolute } : null;
|
|
71075
71359
|
}
|
|
71076
71360
|
async function readResource(cwd, roots, uri) {
|
|
@@ -71183,7 +71467,7 @@ class McpSdkMissingError extends Error {
|
|
|
71183
71467
|
"Install it (it is an optional dependency):",
|
|
71184
71468
|
" bun add @modelcontextprotocol/sdk",
|
|
71185
71469
|
"",
|
|
71186
|
-
"Then re-run `keryx mcp
|
|
71470
|
+
"Then re-run `keryx serve-mcp`. All other commands run without the SDK."
|
|
71187
71471
|
].join(`
|
|
71188
71472
|
`));
|
|
71189
71473
|
this.name = "McpSdkMissingError";
|
|
@@ -71274,6 +71558,36 @@ function resolveServeRoot(explicitCwd, processCwd, env) {
|
|
|
71274
71558
|
return processCwd;
|
|
71275
71559
|
}
|
|
71276
71560
|
|
|
71561
|
+
// src/commands/serve-mcp.ts
|
|
71562
|
+
async function serveMcpCommand(args = [], cwd = process.cwd()) {
|
|
71563
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
71564
|
+
printServeMcpHelp();
|
|
71565
|
+
return;
|
|
71566
|
+
}
|
|
71567
|
+
const http = args.includes("--http");
|
|
71568
|
+
const projectRoot = path169.resolve(resolveServeRoot(optionValue(args, "--cwd"), cwd, process.env));
|
|
71569
|
+
try {
|
|
71570
|
+
await serveMcp({ cwd: projectRoot, http });
|
|
71571
|
+
} catch (error) {
|
|
71572
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
71573
|
+
process.exitCode = 1;
|
|
71574
|
+
}
|
|
71575
|
+
}
|
|
71576
|
+
function printServeMcpHelp() {
|
|
71577
|
+
helpTitle("keryx serve-mcp", "expose Metaproject services over the Model Context Protocol");
|
|
71578
|
+
helpUsage([
|
|
71579
|
+
"keryx serve-mcp [--cwd <project-root>] # stdio JSON-RPC MCP server (default)",
|
|
71580
|
+
"keryx serve-mcp --http [--cwd <project-root>] # HTTP/SSE opt-in (requires capabilities.http.enabled)"
|
|
71581
|
+
]);
|
|
71582
|
+
helpOptions([
|
|
71583
|
+
{ flag: "--http", desc: "Use the isolated HTTP/SSE transport (localhost only) instead of stdio." },
|
|
71584
|
+
{ flag: "--cwd", desc: "Project root whose .metaproject workspace should be exposed. Defaults to the process cwd." }
|
|
71585
|
+
]);
|
|
71586
|
+
heading("Notes");
|
|
71587
|
+
console.log(` ${style.dim("Requires the optional @modelcontextprotocol/sdk. Disabled by default (modules.mcp.enabled=false); `keryx integrate <editor>` turns it on and wires a client.")}`);
|
|
71588
|
+
console.log(` ${style.dim("`keryx mcp serve` is the retired spelling of this command. It still works and prints one deprecation line on stderr.")}`);
|
|
71589
|
+
}
|
|
71590
|
+
|
|
71277
71591
|
// src/commands/mcp.ts
|
|
71278
71592
|
async function mcpCommand(args = [], cwd = process.cwd()) {
|
|
71279
71593
|
const subcommand = args[0];
|
|
@@ -71282,127 +71596,65 @@ async function mcpCommand(args = [], cwd = process.cwd()) {
|
|
|
71282
71596
|
return;
|
|
71283
71597
|
}
|
|
71284
71598
|
if (subcommand === "install") {
|
|
71285
|
-
|
|
71599
|
+
announceRename("`keryx mcp install --runtime <editor>`", "`keryx integrate <editor>`");
|
|
71600
|
+
await integrateCommand(toIntegrateArgs(args.slice(1)), cwd, "keryx mcp install");
|
|
71286
71601
|
return;
|
|
71287
71602
|
}
|
|
71288
71603
|
if (subcommand === "uninstall") {
|
|
71289
|
-
|
|
71604
|
+
announceRename("`keryx mcp uninstall --runtime <editor>`", "`keryx integrate --remove <editor>`");
|
|
71605
|
+
await integrateCommand(["--remove", ...toIntegrateArgs(args.slice(1))], cwd, "keryx mcp uninstall");
|
|
71290
71606
|
return;
|
|
71291
71607
|
}
|
|
71292
71608
|
if (!subcommand || subcommand === "serve") {
|
|
71293
|
-
|
|
71294
|
-
|
|
71295
|
-
try {
|
|
71296
|
-
await serveMcp({ cwd: projectRoot, http });
|
|
71297
|
-
} catch (error) {
|
|
71298
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
71299
|
-
process.exitCode = 1;
|
|
71300
|
-
}
|
|
71609
|
+
announceRename("`keryx mcp serve`", "`keryx serve-mcp`");
|
|
71610
|
+
await serveMcpCommand(args.slice(1), cwd);
|
|
71301
71611
|
return;
|
|
71302
71612
|
}
|
|
71303
71613
|
console.error(`Unknown mcp command: ${subcommand}`);
|
|
71304
71614
|
printMcpHelp();
|
|
71305
71615
|
process.exitCode = 1;
|
|
71306
71616
|
}
|
|
71307
|
-
|
|
71308
|
-
|
|
71309
|
-
const runtimeArg = optionValue(args, "--runtime") ?? fallback;
|
|
71310
|
-
return runtimeArg.split(",").map((s) => s.trim()).filter(Boolean);
|
|
71311
|
-
}
|
|
71312
|
-
async function handleInstall2(cwd, args) {
|
|
71313
|
-
const dryRun = args.includes("--dry-run");
|
|
71314
|
-
const requested = parseRequestedRuntimes(args, "all");
|
|
71315
|
-
const report = await installMcpClient(cwd, requested, { dryRun });
|
|
71316
|
-
if (report.unknown.length > 0) {
|
|
71317
|
-
console.error(`Unknown runtime(s): ${report.unknown.join(", ")}`);
|
|
71318
|
-
process.exitCode = 1;
|
|
71319
|
-
return;
|
|
71320
|
-
}
|
|
71321
|
-
heading(`keryx mcp install${dryRun ? " (dry run)" : ""}`);
|
|
71322
|
-
for (const outcome of report.outcomes) {
|
|
71323
|
-
if (outcome.filePath === null) {
|
|
71324
|
-
console.log(` ${style.cyan(symbols.arrow)} ${outcome.id} \u2014 paste this into your MCP client config:`);
|
|
71325
|
-
console.log(outcome.snippet ?? "");
|
|
71326
|
-
continue;
|
|
71327
|
-
}
|
|
71328
|
-
const rel = path168.relative(cwd, outcome.filePath);
|
|
71329
|
-
if (outcome.errors.length > 0) {
|
|
71330
|
-
for (const e of outcome.errors) {
|
|
71331
|
-
console.log(` ${style.red(symbols.cross)} ${e}`);
|
|
71332
|
-
}
|
|
71333
|
-
process.exitCode = 1;
|
|
71334
|
-
continue;
|
|
71335
|
-
}
|
|
71336
|
-
if (dryRun) {
|
|
71337
|
-
console.log(` ${style.cyan(symbols.arrow)} ${outcome.id} \u2192 would write ${rel}:`);
|
|
71338
|
-
console.log(outcome.snippet ?? "");
|
|
71339
|
-
} else {
|
|
71340
|
-
console.log(` ${style.green(symbols.ok)} ${outcome.id} \u2192 ${rel}`);
|
|
71341
|
-
}
|
|
71342
|
-
}
|
|
71343
|
-
if (report.manifest.message) {
|
|
71344
|
-
note(report.manifest.message);
|
|
71345
|
-
} else if (dryRun && report.manifest.changed) {
|
|
71346
|
-
note("would set modules.mcp.enabled=true in .metaproject/metaproject.json");
|
|
71347
|
-
} else if (report.manifest.changed) {
|
|
71348
|
-
note("set modules.mcp.enabled=true in .metaproject/metaproject.json");
|
|
71349
|
-
}
|
|
71350
|
-
if (!report.sdk.available) {
|
|
71351
|
-
note(`Optional MCP SDK not found \u2014 install it to run \`keryx mcp serve\`: ${report.sdk.hint}`);
|
|
71352
|
-
}
|
|
71617
|
+
function announceRename(retired, replacement) {
|
|
71618
|
+
console.error(`${retired} is deprecated \u2014 use ${replacement} instead.`);
|
|
71353
71619
|
}
|
|
71354
|
-
|
|
71355
|
-
const
|
|
71356
|
-
const
|
|
71357
|
-
|
|
71358
|
-
|
|
71359
|
-
process.exitCode = 1;
|
|
71360
|
-
return;
|
|
71361
|
-
}
|
|
71362
|
-
heading("keryx mcp uninstall");
|
|
71363
|
-
for (const outcome of report.outcomes) {
|
|
71364
|
-
if (outcome.filePath === null) {
|
|
71365
|
-
console.log(` ${style.gray(symbols.off)} ${outcome.id} ${style.dim("no file to change")}`);
|
|
71366
|
-
continue;
|
|
71367
|
-
}
|
|
71368
|
-
const rel = path168.relative(cwd, outcome.filePath);
|
|
71369
|
-
console.log(` ${outcome.removed ? style.green(symbols.ok) : style.gray(symbols.off)} ${outcome.id} ${style.dim(outcome.removed ? `removed from ${rel}` : "nothing to remove")}`);
|
|
71370
|
-
}
|
|
71620
|
+
function toIntegrateArgs(rest) {
|
|
71621
|
+
const runtimeArg = optionValue(rest, "--runtime");
|
|
71622
|
+
const editors = runtimeArg === undefined ? ["all"] : [runtimeArg];
|
|
71623
|
+
const flags = rest.filter((argument) => argument.startsWith("-") && argument !== "--runtime" && !argument.startsWith("--runtime="));
|
|
71624
|
+
return [...editors, ...flags];
|
|
71371
71625
|
}
|
|
71372
71626
|
function printMcpHelp() {
|
|
71373
|
-
helpTitle("keryx mcp", "
|
|
71627
|
+
helpTitle("keryx mcp", "retired spelling of the MCP publisher surface \u2014 see the replacements below");
|
|
71374
71628
|
helpUsage([
|
|
71375
|
-
"keryx mcp
|
|
71376
|
-
|
|
71377
|
-
|
|
71378
|
-
`keryx mcp install --runtime ${RUNTIME_USAGE} # wire this project into an editor/agent`,
|
|
71379
|
-
`keryx mcp uninstall --runtime ${RUNTIME_USAGE} # remove the managed keryx server`
|
|
71629
|
+
"keryx serve-mcp [--http] [--cwd <project-root>] # replaces `keryx mcp serve`",
|
|
71630
|
+
`keryx integrate ${EDITOR_USAGE} # replaces \`keryx mcp install --runtime\``,
|
|
71631
|
+
`keryx integrate --remove ${EDITOR_USAGE} # replaces \`keryx mcp uninstall --runtime\``
|
|
71380
71632
|
]);
|
|
71381
71633
|
helpOptions([
|
|
71382
|
-
{ flag: "--http", desc: "
|
|
71383
|
-
{ flag: "--cwd", desc: "
|
|
71634
|
+
{ flag: "--http", desc: "serve only: use the isolated HTTP/SSE transport (localhost only) instead of stdio." },
|
|
71635
|
+
{ flag: "--cwd", desc: "serve only: project root whose .metaproject workspace should be exposed. Defaults to the process cwd." },
|
|
71384
71636
|
{
|
|
71385
71637
|
flag: "--runtime",
|
|
71386
|
-
desc: `
|
|
71638
|
+
desc: `install/uninstall only: target client(s) \u2014 ${mcpRuntimeIds().join(", ")}, or all (=cursor,claude,opencode). Comma-separated. Default: all.`
|
|
71387
71639
|
},
|
|
71388
71640
|
{ flag: "--dry-run", desc: "install only: print the planned change and write nothing." }
|
|
71389
71641
|
]);
|
|
71390
71642
|
heading("Notes");
|
|
71391
|
-
console.log(` ${style.dim("`
|
|
71392
|
-
console.log(` ${style.dim("
|
|
71643
|
+
console.log(` ${style.dim("Every `keryx mcp \u2026` invocation still works and still behaves identically; each prints one deprecation line on stderr naming its replacement.")}`);
|
|
71644
|
+
console.log(` ${style.dim("Run `keryx serve-mcp --help` or `keryx integrate --help` for the current surface.")}`);
|
|
71393
71645
|
}
|
|
71394
71646
|
|
|
71395
71647
|
// src/commands/status.ts
|
|
71396
71648
|
init_fs();
|
|
71397
71649
|
init_json();
|
|
71398
|
-
import
|
|
71650
|
+
import path170 from "path";
|
|
71399
71651
|
async function statusCommand(args = []) {
|
|
71400
71652
|
if (args.includes("--help") || args.includes("-h")) {
|
|
71401
71653
|
printHelp16();
|
|
71402
71654
|
return;
|
|
71403
71655
|
}
|
|
71404
|
-
const root =
|
|
71405
|
-
const manifestPath =
|
|
71656
|
+
const root = path170.join(process.cwd(), ".metaproject");
|
|
71657
|
+
const manifestPath = path170.join(root, "metaproject.json");
|
|
71406
71658
|
if (!await pathExists(root)) {
|
|
71407
71659
|
console.log("Metaproject: not initialized");
|
|
71408
71660
|
console.log("Run: keryx init");
|
|
@@ -71442,7 +71694,7 @@ Reports the workspace root and one enabled/disabled line per module. Use
|
|
|
71442
71694
|
|
|
71443
71695
|
// src/commands/harness.ts
|
|
71444
71696
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
71445
|
-
import
|
|
71697
|
+
import path173 from "path";
|
|
71446
71698
|
import { randomUUID as randomUUID20 } from "crypto";
|
|
71447
71699
|
|
|
71448
71700
|
// src/security/harness-scan.ts
|
|
@@ -72515,7 +72767,7 @@ ${command.argv.join(" ")}`);
|
|
|
72515
72767
|
}
|
|
72516
72768
|
|
|
72517
72769
|
// src/harness/process/sandbox/profile.ts
|
|
72518
|
-
import
|
|
72770
|
+
import path171 from "path";
|
|
72519
72771
|
var DEFAULT_SECRET_SUBPATHS = [
|
|
72520
72772
|
".ssh",
|
|
72521
72773
|
".gnupg",
|
|
@@ -72540,7 +72792,7 @@ function defaultReadDenyList(home) {
|
|
|
72540
72792
|
if (!home) {
|
|
72541
72793
|
return [];
|
|
72542
72794
|
}
|
|
72543
|
-
return DEFAULT_SECRET_SUBPATHS.map((sub) =>
|
|
72795
|
+
return DEFAULT_SECRET_SUBPATHS.map((sub) => path171.join(home, sub));
|
|
72544
72796
|
}
|
|
72545
72797
|
function defaultSandboxProfile(cwd, tmpDir, home) {
|
|
72546
72798
|
return {
|
|
@@ -72560,10 +72812,10 @@ function dedupe3(values) {
|
|
|
72560
72812
|
init_config_dir();
|
|
72561
72813
|
init_shell_config();
|
|
72562
72814
|
import { existsSync as existsSync26 } from "fs";
|
|
72563
|
-
import
|
|
72815
|
+
import path172 from "path";
|
|
72564
72816
|
var SECRET_KEY_PATTERN2 = /api[_-]?key|secret|token|password|credential/i;
|
|
72565
72817
|
function sandboxConfigPath(dir) {
|
|
72566
|
-
return
|
|
72818
|
+
return path172.join(path172.dirname(shellConfigPath(dir)), "sandbox.json");
|
|
72567
72819
|
}
|
|
72568
72820
|
function isShellDefault(v) {
|
|
72569
72821
|
return v === "off" || v === "workspace" || v === "strict" || v === "1";
|
|
@@ -73682,7 +73934,7 @@ async function harnessExec(args, deps) {
|
|
|
73682
73934
|
env: commandEnv,
|
|
73683
73935
|
cwd
|
|
73684
73936
|
};
|
|
73685
|
-
const worktreeRoot =
|
|
73937
|
+
const worktreeRoot = path173.parse(path173.resolve(cwd, commandPath)).root || cwd;
|
|
73686
73938
|
const budget = {
|
|
73687
73939
|
reservationId: idSeq(),
|
|
73688
73940
|
maxRuntimeMs: maxRuntimeMs ?? EXEC_DEFAULT_RUNTIME_MS
|
|
@@ -73869,6 +74121,8 @@ function harnessWave(args, deps) {
|
|
|
73869
74121
|
}
|
|
73870
74122
|
|
|
73871
74123
|
// src/commands/shell.ts
|
|
74124
|
+
init_grants();
|
|
74125
|
+
init_providers();
|
|
73872
74126
|
init_make_provider();
|
|
73873
74127
|
init_orient();
|
|
73874
74128
|
init_metaproject_adapter();
|
|
@@ -75544,7 +75798,7 @@ function workspaceReadTool(cwd) {
|
|
|
75544
75798
|
// src/harness/tool/builtin/workspace-lifecycle-tool.ts
|
|
75545
75799
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
75546
75800
|
import { writeFile as writeFile52 } from "fs/promises";
|
|
75547
|
-
import
|
|
75801
|
+
import path174 from "path";
|
|
75548
75802
|
init_slate();
|
|
75549
75803
|
init_store3();
|
|
75550
75804
|
init_guard2();
|
|
@@ -75690,7 +75944,7 @@ function workspaceProposeTool(cwd, getSessionDir) {
|
|
|
75690
75944
|
return { output: `workspace_propose: unrecognized 'kind' \u2014 expected one of: ${PROPOSAL_KINDS.join(", ")}`, isError: true };
|
|
75691
75945
|
}
|
|
75692
75946
|
const explicitSessionId = typeof input.sessionId === "string" && input.sessionId.length > 0 ? input.sessionId : undefined;
|
|
75693
|
-
const sessionRef = explicitSessionId ??
|
|
75947
|
+
const sessionRef = explicitSessionId ?? path174.basename(getSessionDir() ?? "");
|
|
75694
75948
|
if (sessionRef.length === 0) {
|
|
75695
75949
|
return { output: "workspace_propose: no 'sessionId' given and no active session in this run", isError: true };
|
|
75696
75950
|
}
|
|
@@ -75780,7 +76034,7 @@ init_shell_config();
|
|
|
75780
76034
|
init_command_risk();
|
|
75781
76035
|
init_shell_syntax();
|
|
75782
76036
|
import { existsSync as existsSync28 } from "fs";
|
|
75783
|
-
import
|
|
76037
|
+
import path175 from "path";
|
|
75784
76038
|
import { createHash as createHash40 } from "crypto";
|
|
75785
76039
|
var PREFIX_BANNED = new Set([
|
|
75786
76040
|
"sh",
|
|
@@ -75985,7 +76239,7 @@ function emptyShellPermissions() {
|
|
|
75985
76239
|
return { allow: [] };
|
|
75986
76240
|
}
|
|
75987
76241
|
function shellPermissionsPath(dir) {
|
|
75988
|
-
return
|
|
76242
|
+
return path175.join(path175.dirname(shellConfigPath(dir)), "permissions.json");
|
|
75989
76243
|
}
|
|
75990
76244
|
function loadShellPermissionsWithAudit(dir) {
|
|
75991
76245
|
try {
|
|
@@ -76023,7 +76277,7 @@ function loadShellPermissions(dir) {
|
|
|
76023
76277
|
function saveShellPermissions(perms, dir, options = {}) {
|
|
76024
76278
|
try {
|
|
76025
76279
|
const file = shellPermissionsPath(dir);
|
|
76026
|
-
ensureKeryxConfigDir(
|
|
76280
|
+
ensureKeryxConfigDir(path175.dirname(file));
|
|
76027
76281
|
const cleaned = Array.from(new Set(perms.allow.map((p) => p.trim()).filter((p) => p.length > 0)));
|
|
76028
76282
|
const body = {
|
|
76029
76283
|
allow: options.skipValidation === true ? cleaned : cleaned.filter((p) => validateShellPattern(p).ok)
|
|
@@ -76340,12 +76594,12 @@ function remoteRequest(providerId, endpoint, query, key) {
|
|
|
76340
76594
|
// src/lib/search-config.ts
|
|
76341
76595
|
init_config_dir();
|
|
76342
76596
|
import { existsSync as existsSync29 } from "fs";
|
|
76343
|
-
import
|
|
76597
|
+
import path176 from "path";
|
|
76344
76598
|
function searchConfigPath(dir) {
|
|
76345
|
-
return
|
|
76599
|
+
return path176.join(keryxConfigDir(dir), "search-providers.json");
|
|
76346
76600
|
}
|
|
76347
76601
|
function searchCredentialPath(dir) {
|
|
76348
|
-
return
|
|
76602
|
+
return path176.join(keryxConfigDir(dir), "search-credentials.json");
|
|
76349
76603
|
}
|
|
76350
76604
|
function readJson5(file) {
|
|
76351
76605
|
try {
|
|
@@ -76474,7 +76728,7 @@ function createDefaultSearchProviderController(configDir) {
|
|
|
76474
76728
|
import { createHash as createHash41, randomUUID as randomUUID24 } from "crypto";
|
|
76475
76729
|
import { mkdtemp, rm as rm13 } from "fs/promises";
|
|
76476
76730
|
import { tmpdir as tmpdir4 } from "os";
|
|
76477
|
-
import
|
|
76731
|
+
import path177 from "path";
|
|
76478
76732
|
init_metaproject_adapter();
|
|
76479
76733
|
init_ledger();
|
|
76480
76734
|
init_orchestrate();
|
|
@@ -76737,8 +76991,8 @@ function createSpawnSubagentTool(deps) {
|
|
|
76737
76991
|
let dispatchId = "";
|
|
76738
76992
|
let closing = false;
|
|
76739
76993
|
try {
|
|
76740
|
-
ephemeralDir = await mkdtemp(
|
|
76741
|
-
dispatchId =
|
|
76994
|
+
ephemeralDir = await mkdtemp(path177.join(tmpdir4(), "keryx-subagent-slate-"));
|
|
76995
|
+
dispatchId = path177.basename(ephemeralDir);
|
|
76742
76996
|
openedChildSlate = await openSlate({
|
|
76743
76997
|
dir: ephemeralDir,
|
|
76744
76998
|
cwd,
|
|
@@ -76981,7 +77235,7 @@ import { randomUUID as randomUUID25 } from "crypto";
|
|
|
76981
77235
|
import { execFile as execFile4 } from "child_process";
|
|
76982
77236
|
import { mkdir as mkdir61 } from "fs/promises";
|
|
76983
77237
|
import { tmpdir as tmpdir6 } from "os";
|
|
76984
|
-
import
|
|
77238
|
+
import path179 from "path";
|
|
76985
77239
|
import { promisify as promisify4 } from "util";
|
|
76986
77240
|
|
|
76987
77241
|
// src/harness/child/git-worktree-port.ts
|
|
@@ -77280,7 +77534,7 @@ function canNestExternalChild(env, maxDepth) {
|
|
|
77280
77534
|
// src/harness/external/runtime.ts
|
|
77281
77535
|
import { mkdtemp as mkdtemp2, rm as rm14, writeFile as writeFile53 } from "fs/promises";
|
|
77282
77536
|
import { tmpdir as tmpdir5 } from "os";
|
|
77283
|
-
import
|
|
77537
|
+
import path178 from "path";
|
|
77284
77538
|
|
|
77285
77539
|
// src/harness/external/prompt.ts
|
|
77286
77540
|
var EXTERNAL_RUNTIME_DIRECTIVE = [
|
|
@@ -78323,8 +78577,8 @@ async function prepareResultSchema() {
|
|
|
78323
78577
|
try {
|
|
78324
78578
|
const schema = await loadSchema("subagent-result");
|
|
78325
78579
|
const schemaText = JSON.stringify(schema, null, 2);
|
|
78326
|
-
schemaDir = await mkdtemp2(
|
|
78327
|
-
const schemaPath =
|
|
78580
|
+
schemaDir = await mkdtemp2(path178.join(tmpdir5(), "keryx-external-result-schema-"));
|
|
78581
|
+
const schemaPath = path178.join(schemaDir, "subagent-result.schema.json");
|
|
78328
78582
|
await writeFile53(schemaPath, schemaText, "utf8");
|
|
78329
78583
|
return { ok: true, schema, schemaText, schemaPath, schemaDir };
|
|
78330
78584
|
} catch (error) {
|
|
@@ -78581,7 +78835,7 @@ async function createRunExternal(options) {
|
|
|
78581
78835
|
}
|
|
78582
78836
|
const config = gate.config;
|
|
78583
78837
|
const idSeq = options.idSeq ?? (() => randomUUID25());
|
|
78584
|
-
const worktreesDir = options.worktreesDir ??
|
|
78838
|
+
const worktreesDir = options.worktreesDir ?? path179.join(tmpdir6(), "keryx-external-worktrees");
|
|
78585
78839
|
const spawn = options.spawn ?? createBunSpawnPort();
|
|
78586
78840
|
const worktree = options.worktree ?? ensuringParentDir(createGitWorktreePort({ repoRoot: options.cwd, worktreesDir }), worktreesDir);
|
|
78587
78841
|
const readWorkingDiff = options.readWorkingDiff ?? (() => defaultWorkingDiff(options.cwd));
|
|
@@ -78888,7 +79142,7 @@ class LiveMarkdownBlock {
|
|
|
78888
79142
|
// src/tui/theme.ts
|
|
78889
79143
|
init_config_dir();
|
|
78890
79144
|
import { existsSync as existsSync30 } from "fs";
|
|
78891
|
-
import
|
|
79145
|
+
import path180 from "path";
|
|
78892
79146
|
var THEME_NAMES = ["groknight", "grokday", "tokyonight", "keryx"];
|
|
78893
79147
|
var THEME_IDS = ["auto", ...THEME_NAMES];
|
|
78894
79148
|
var DEFAULT_THEME_ID = "groknight";
|
|
@@ -79018,7 +79272,7 @@ function onThemeChange(listener) {
|
|
|
79018
79272
|
};
|
|
79019
79273
|
}
|
|
79020
79274
|
function tuiConfigPath(dir) {
|
|
79021
|
-
return
|
|
79275
|
+
return path180.join(keryxConfigDir(dir), "tui.json");
|
|
79022
79276
|
}
|
|
79023
79277
|
function loadPersistedThemeId(dir) {
|
|
79024
79278
|
try {
|
|
@@ -79075,7 +79329,7 @@ init_workspace_service();
|
|
|
79075
79329
|
init_service8();
|
|
79076
79330
|
init_store2();
|
|
79077
79331
|
init_fs();
|
|
79078
|
-
import
|
|
79332
|
+
import path181 from "path";
|
|
79079
79333
|
import { readFile as readFile97 } from "fs/promises";
|
|
79080
79334
|
var POSITIVE_INTEGER = /^[1-9][0-9]*$/;
|
|
79081
79335
|
var DEFAULT_AUTO_GOAL_ROUNDS = 8;
|
|
@@ -79151,7 +79405,7 @@ function getFlowService() {
|
|
|
79151
79405
|
async function autoProvisionFlow(cwd, goalText) {
|
|
79152
79406
|
const service = getFlowService();
|
|
79153
79407
|
const result = await service.init({ cwd, title: goalText });
|
|
79154
|
-
const acFile =
|
|
79408
|
+
const acFile = path181.join(cwd, result.dir, "acceptance-criteria.md");
|
|
79155
79409
|
await writeFileAtomic(acFile, [
|
|
79156
79410
|
"# Acceptance Criteria",
|
|
79157
79411
|
"",
|
|
@@ -80702,7 +80956,7 @@ init_proposal_lifecycle();
|
|
|
80702
80956
|
init_workspace_service();
|
|
80703
80957
|
import { randomUUID as randomUUID27 } from "crypto";
|
|
80704
80958
|
import { readdir as readdir34, stat as stat18 } from "fs/promises";
|
|
80705
|
-
import
|
|
80959
|
+
import path182 from "path";
|
|
80706
80960
|
|
|
80707
80961
|
// src/sac/lifecycle-flag.ts
|
|
80708
80962
|
init_store();
|
|
@@ -80861,7 +81115,7 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
80861
81115
|
}
|
|
80862
81116
|
return groups;
|
|
80863
81117
|
}, []));
|
|
80864
|
-
const metaPath =
|
|
81118
|
+
const metaPath = path182.join(extDir, `${id}.json`);
|
|
80865
81119
|
if (await pathExists(unboundDismissedReceiptPath(metaPath)))
|
|
80866
81120
|
continue;
|
|
80867
81121
|
candidates.push({
|
|
@@ -80875,7 +81129,7 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
80875
81129
|
return candidates;
|
|
80876
81130
|
}
|
|
80877
81131
|
async function readNewestUnboundCandidateForExternal(cwd, externalSessionId) {
|
|
80878
|
-
const evidenceDir =
|
|
81132
|
+
const evidenceDir = path182.join(externalSlatesDir(cwd), externalSessionId);
|
|
80879
81133
|
let entries;
|
|
80880
81134
|
try {
|
|
80881
81135
|
entries = (await readdir34(evidenceDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
@@ -80884,7 +81138,7 @@ async function readNewestUnboundCandidateForExternal(cwd, externalSessionId) {
|
|
|
80884
81138
|
}
|
|
80885
81139
|
entries.sort();
|
|
80886
81140
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
80887
|
-
const evidencePath =
|
|
81141
|
+
const evidencePath = path182.join(evidenceDir, entries[i]);
|
|
80888
81142
|
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
80889
81143
|
continue;
|
|
80890
81144
|
const result = readConfigFile(evidencePath);
|
|
@@ -80927,7 +81181,7 @@ var SESSION_ATTRIBUTION_SLACK_MS = 5 * 60000;
|
|
|
80927
81181
|
var MTIME_CLOCK_SKEW_TOLERANCE_MS = 5000;
|
|
80928
81182
|
async function collectReceiptTargets(cwd, owner) {
|
|
80929
81183
|
const targets = new Set;
|
|
80930
|
-
const workspacesDir =
|
|
81184
|
+
const workspacesDir = path182.join(cwd, ".metaproject", "workspaces");
|
|
80931
81185
|
let workspaceIds;
|
|
80932
81186
|
try {
|
|
80933
81187
|
workspaceIds = (await readdir34(workspacesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
@@ -80935,7 +81189,7 @@ async function collectReceiptTargets(cwd, owner) {
|
|
|
80935
81189
|
return targets;
|
|
80936
81190
|
}
|
|
80937
81191
|
for (const workspaceId of workspaceIds) {
|
|
80938
|
-
const receiptsDir =
|
|
81192
|
+
const receiptsDir = path182.join(workspacesDir, workspaceId, `${owner}-write-receipts`);
|
|
80939
81193
|
let files;
|
|
80940
81194
|
try {
|
|
80941
81195
|
files = (await readdir34(receiptsDir)).filter((name) => name.endsWith(".json"));
|
|
@@ -80943,7 +81197,7 @@ async function collectReceiptTargets(cwd, owner) {
|
|
|
80943
81197
|
continue;
|
|
80944
81198
|
}
|
|
80945
81199
|
for (const file of files) {
|
|
80946
|
-
const result = readConfigFile(
|
|
81200
|
+
const result = readConfigFile(path182.join(receiptsDir, file));
|
|
80947
81201
|
if (!result.ok)
|
|
80948
81202
|
continue;
|
|
80949
81203
|
try {
|
|
@@ -80986,7 +81240,7 @@ async function findSkillFiles(dir) {
|
|
|
80986
81240
|
}
|
|
80987
81241
|
const found = [];
|
|
80988
81242
|
for (const entry of entries) {
|
|
80989
|
-
const full =
|
|
81243
|
+
const full = path182.join(dir, entry.name);
|
|
80990
81244
|
if (entry.isDirectory()) {
|
|
80991
81245
|
found.push(...await findSkillFiles(full));
|
|
80992
81246
|
} else if (entry.isFile() && entry.name === "SKILL.md") {
|
|
@@ -81045,10 +81299,10 @@ async function detectUnreviewedSacPathChanges(cwd, sessions) {
|
|
|
81045
81299
|
changedAt: attribution.changedAt
|
|
81046
81300
|
});
|
|
81047
81301
|
}
|
|
81048
|
-
const sacSkillsDir =
|
|
81302
|
+
const sacSkillsDir = path182.join(cwd, ".metaproject", "project-skills", "sac");
|
|
81049
81303
|
const skillFiles = await findSkillFiles(sacSkillsDir);
|
|
81050
81304
|
for (const absolutePath of skillFiles) {
|
|
81051
|
-
const targetRef =
|
|
81305
|
+
const targetRef = path182.relative(path182.join(cwd, ".metaproject"), absolutePath).split(path182.sep).join("/");
|
|
81052
81306
|
if (skillReceipts.has(targetRef))
|
|
81053
81307
|
continue;
|
|
81054
81308
|
const attribution = await attributeToSession(absolutePath, scoped);
|
|
@@ -81066,12 +81320,12 @@ async function detectUnreviewedSacPathChanges(cwd, sessions) {
|
|
|
81066
81320
|
return items;
|
|
81067
81321
|
}
|
|
81068
81322
|
async function isSlateEngaged(dir) {
|
|
81069
|
-
if (await pathExists(
|
|
81323
|
+
if (await pathExists(path182.join(dir, "slate.json")))
|
|
81070
81324
|
return true;
|
|
81071
|
-
if (await pathExists(
|
|
81325
|
+
if (await pathExists(path182.join(dir, "terminal-state.json")))
|
|
81072
81326
|
return true;
|
|
81073
81327
|
try {
|
|
81074
|
-
const entries = await readdir34(
|
|
81328
|
+
const entries = await readdir34(path182.join(dir, "slate-archive"));
|
|
81075
81329
|
return entries.length > 0;
|
|
81076
81330
|
} catch {
|
|
81077
81331
|
return false;
|
|
@@ -81085,7 +81339,7 @@ async function safeReadSlate(dir) {
|
|
|
81085
81339
|
}
|
|
81086
81340
|
}
|
|
81087
81341
|
async function readTerminalState(dir) {
|
|
81088
|
-
const result = readConfigFile(
|
|
81342
|
+
const result = readConfigFile(path182.join(dir, "terminal-state.json"));
|
|
81089
81343
|
if (!result.ok) {
|
|
81090
81344
|
return;
|
|
81091
81345
|
}
|
|
@@ -81109,7 +81363,7 @@ async function resolveUnboundCandidateTarget(cwd, target) {
|
|
|
81109
81363
|
if (session === undefined) {
|
|
81110
81364
|
throw new Error(`No session or evidence path matches "${target}"`);
|
|
81111
81365
|
}
|
|
81112
|
-
const archiveDir =
|
|
81366
|
+
const archiveDir = path182.join(sessionDir(session.projectPath, session.id), "slate-archive");
|
|
81113
81367
|
let entries;
|
|
81114
81368
|
try {
|
|
81115
81369
|
entries = (await readdir34(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
@@ -81119,7 +81373,7 @@ async function resolveUnboundCandidateTarget(cwd, target) {
|
|
|
81119
81373
|
if (entries.length === 0)
|
|
81120
81374
|
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
81121
81375
|
entries.sort();
|
|
81122
|
-
return
|
|
81376
|
+
return path182.join(archiveDir, entries[entries.length - 1]);
|
|
81123
81377
|
}
|
|
81124
81378
|
async function dismissUnboundByTarget(cwd, target, reason) {
|
|
81125
81379
|
const evidencePath = await resolveUnboundCandidateTarget(cwd, target);
|
|
@@ -81145,7 +81399,7 @@ async function dismissUnboundCandidate(candidatePath, reason) {
|
|
|
81145
81399
|
return { removed: candidatePath, receipt: receiptPath };
|
|
81146
81400
|
}
|
|
81147
81401
|
async function readNewestUnboundCandidate(dir) {
|
|
81148
|
-
const archiveDir =
|
|
81402
|
+
const archiveDir = path182.join(dir, "slate-archive");
|
|
81149
81403
|
let entries;
|
|
81150
81404
|
try {
|
|
81151
81405
|
entries = (await readdir34(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
@@ -81154,7 +81408,7 @@ async function readNewestUnboundCandidate(dir) {
|
|
|
81154
81408
|
}
|
|
81155
81409
|
entries.sort();
|
|
81156
81410
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
81157
|
-
const evidencePath =
|
|
81411
|
+
const evidencePath = path182.join(archiveDir, entries[i]);
|
|
81158
81412
|
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
81159
81413
|
continue;
|
|
81160
81414
|
const result = readConfigFile(evidencePath);
|
|
@@ -81184,7 +81438,7 @@ function isFailureOutcome(g) {
|
|
|
81184
81438
|
return g.outcome === "error" || g.outcome === "no_credential" || g.outcome === "conflict";
|
|
81185
81439
|
}
|
|
81186
81440
|
async function readNewestWrapUpOutcome(dir) {
|
|
81187
|
-
const archiveDir =
|
|
81441
|
+
const archiveDir = path182.join(dir, "slate-archive");
|
|
81188
81442
|
let entries;
|
|
81189
81443
|
try {
|
|
81190
81444
|
entries = (await readdir34(archiveDir)).filter((name) => name.endsWith("-wrap-up-outcome.json"));
|
|
@@ -81193,7 +81447,7 @@ async function readNewestWrapUpOutcome(dir) {
|
|
|
81193
81447
|
}
|
|
81194
81448
|
entries.sort();
|
|
81195
81449
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
81196
|
-
const evidencePath =
|
|
81450
|
+
const evidencePath = path182.join(archiveDir, entries[i]);
|
|
81197
81451
|
const result = readConfigFile(evidencePath);
|
|
81198
81452
|
if (!result.ok) {
|
|
81199
81453
|
continue;
|
|
@@ -82407,10 +82661,11 @@ var MCP_INSPECTOR_FOOTER = [
|
|
|
82407
82661
|
{ key: "\u2190/\u2192", label: "tabs" },
|
|
82408
82662
|
{ key: "esc", label: "close" }
|
|
82409
82663
|
];
|
|
82410
|
-
var MCP_TOOLS_COMMAND = "/
|
|
82664
|
+
var MCP_TOOLS_COMMAND = "/integrations";
|
|
82665
|
+
var MCP_TOOLS_COMMAND_RETIRED = "/mcp";
|
|
82411
82666
|
function isMcpToolsCommand(line) {
|
|
82412
82667
|
const token = line.trim().split(/\s+/)[0] ?? "";
|
|
82413
|
-
return token === MCP_TOOLS_COMMAND;
|
|
82668
|
+
return token === MCP_TOOLS_COMMAND || token === MCP_TOOLS_COMMAND_RETIRED;
|
|
82414
82669
|
}
|
|
82415
82670
|
var TOOLS_TAB_HEADER = "Built into keryx \u2014 not from an external MCP server (keryx doesn't consume MCP servers as a client yet).";
|
|
82416
82671
|
var MCP_TAB_HEADER_1 = "Connects/disconnects ONLY keryx's own MCP server, one editor config at a time.";
|
|
@@ -83453,9 +83708,14 @@ var AGENT_SLASH_COMMANDS = [
|
|
|
83453
83708
|
description: "Show project-wide items needing review (proposals, blocked sessions)",
|
|
83454
83709
|
modes: AGENT_ONLY
|
|
83455
83710
|
},
|
|
83711
|
+
{
|
|
83712
|
+
name: "/integrations",
|
|
83713
|
+
description: "Wire this project into an editor over MCP (keryx integrate)",
|
|
83714
|
+
modes: AGENT_ONLY
|
|
83715
|
+
},
|
|
83456
83716
|
{
|
|
83457
83717
|
name: "/mcp",
|
|
83458
|
-
description: "
|
|
83718
|
+
description: "Deprecated alias of /integrations",
|
|
83459
83719
|
modes: AGENT_ONLY
|
|
83460
83720
|
},
|
|
83461
83721
|
{
|
|
@@ -84649,10 +84909,10 @@ function describeElicitationPrompt(tool, inputJson) {
|
|
|
84649
84909
|
// src/lib/permission-mode-config.ts
|
|
84650
84910
|
init_permission_mode();
|
|
84651
84911
|
init_config_dir();
|
|
84652
|
-
import
|
|
84912
|
+
import path183 from "path";
|
|
84653
84913
|
var EMPTY3 = { schemaVersion: 1, projects: {} };
|
|
84654
84914
|
function permissionModeConfigPath(dir) {
|
|
84655
|
-
return
|
|
84915
|
+
return path183.join(keryxConfigDir(dir), "permission-mode.json");
|
|
84656
84916
|
}
|
|
84657
84917
|
function withRegistryLock2(dir, fn) {
|
|
84658
84918
|
return withFileLock(`${permissionModeConfigPath(dir)}.lock`, fn, {
|
|
@@ -84820,6 +85080,20 @@ async function runAfterForegroundSettlement(owner, action) {
|
|
|
84820
85080
|
action();
|
|
84821
85081
|
}
|
|
84822
85082
|
}
|
|
85083
|
+
async function forceForegroundQueueItem(owner, handoff, item, deps) {
|
|
85084
|
+
const ownsSettlement = handoff.enqueue(item);
|
|
85085
|
+
owner.cancel(deps.cancelReason ?? "queue item forced");
|
|
85086
|
+
deps.announce?.();
|
|
85087
|
+
if (!ownsSettlement) {
|
|
85088
|
+
return;
|
|
85089
|
+
}
|
|
85090
|
+
await runAfterForegroundSettlement(owner, () => {
|
|
85091
|
+
const next = handoff.takeAfterSettlement();
|
|
85092
|
+
if (next !== undefined) {
|
|
85093
|
+
deps.run(next);
|
|
85094
|
+
}
|
|
85095
|
+
});
|
|
85096
|
+
}
|
|
84823
85097
|
function createForegroundAgentIoFacade(owner, token, io) {
|
|
84824
85098
|
const accepts = () => owner.accepts(token);
|
|
84825
85099
|
return {
|
|
@@ -85156,7 +85430,7 @@ function showComposerChoice(otui, r, dock, request) {
|
|
|
85156
85430
|
// src/lib/version-check.ts
|
|
85157
85431
|
init_config_dir();
|
|
85158
85432
|
init_fs();
|
|
85159
|
-
import
|
|
85433
|
+
import path184 from "path";
|
|
85160
85434
|
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
85161
85435
|
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
85162
85436
|
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
@@ -85358,7 +85632,7 @@ async function checkVersion(options) {
|
|
|
85358
85632
|
const now = options.now ?? Date.now;
|
|
85359
85633
|
const timestamp = now();
|
|
85360
85634
|
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
85361
|
-
const cacheFile =
|
|
85635
|
+
const cacheFile = path184.join(configDir, "version-check.json");
|
|
85362
85636
|
const cache = parseCache(cacheFile);
|
|
85363
85637
|
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
85364
85638
|
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
@@ -90686,19 +90960,11 @@ Staying in the current session.
|
|
|
90686
90960
|
return;
|
|
90687
90961
|
mainQueue = removeMainQueueItem(mainQueue, index);
|
|
90688
90962
|
paintMainQueue();
|
|
90689
|
-
(
|
|
90690
|
-
|
|
90691
|
-
|
|
90692
|
-
|
|
90693
|
-
|
|
90694
|
-
if (!waitsForSettlement)
|
|
90695
|
-
return;
|
|
90696
|
-
await runAfterForegroundSettlement(foregroundOperation, () => {
|
|
90697
|
-
const next = forceHandoff.takeAfterSettlement();
|
|
90698
|
-
if (next !== undefined)
|
|
90699
|
-
runLine(next.question);
|
|
90700
|
-
});
|
|
90701
|
-
})();
|
|
90963
|
+
forceForegroundQueueItem(foregroundOperation, forceHandoff, item, {
|
|
90964
|
+
announce: () => io.onSystem?.(`\u25C7 main turn interrupted \u2014 q${index + 1} will run next.
|
|
90965
|
+
`),
|
|
90966
|
+
run: (next) => runLine(next.question)
|
|
90967
|
+
});
|
|
90702
90968
|
};
|
|
90703
90969
|
const handleQueueNavKey = (key) => {
|
|
90704
90970
|
if (!queueNavActive) {
|
|
@@ -92329,10 +92595,24 @@ function realMakeProvider(write) {
|
|
|
92329
92595
|
}
|
|
92330
92596
|
return makeProvider(name, model, {
|
|
92331
92597
|
fetch: globalThis.fetch,
|
|
92332
|
-
...baseUrl !== undefined ? { baseUrl } : {}
|
|
92598
|
+
...baseUrl !== undefined ? { baseUrl } : {},
|
|
92599
|
+
...oauthCredentialsFor(name)
|
|
92333
92600
|
});
|
|
92334
92601
|
};
|
|
92335
92602
|
}
|
|
92603
|
+
function oauthCredentialsFor(name) {
|
|
92604
|
+
const definition = providerByName(name);
|
|
92605
|
+
const envKey = definition?.envKey;
|
|
92606
|
+
if (envKey === undefined)
|
|
92607
|
+
return {};
|
|
92608
|
+
const fromEnv = process.env[envKey];
|
|
92609
|
+
if (fromEnv !== undefined && fromEnv.length > 0)
|
|
92610
|
+
return {};
|
|
92611
|
+
const grant = loadOAuthGrant(name);
|
|
92612
|
+
if (grant === undefined || grant.access.length === 0)
|
|
92613
|
+
return {};
|
|
92614
|
+
return { credentials: { ...process.env, [envKey]: grant.access } };
|
|
92615
|
+
}
|
|
92336
92616
|
function realSelectProviderModel(baseUrl) {
|
|
92337
92617
|
return async (io, opts) => {
|
|
92338
92618
|
const detected = await detectProviders({
|
|
@@ -93738,7 +94018,7 @@ Shell:
|
|
|
93738
94018
|
init_fs();
|
|
93739
94019
|
import { readFile as readFile98 } from "fs/promises";
|
|
93740
94020
|
import { stdin } from "process";
|
|
93741
|
-
import
|
|
94021
|
+
import path185 from "path";
|
|
93742
94022
|
var MODULES = [
|
|
93743
94023
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
93744
94024
|
{ name: "gdctx", flag: "--no-gdctx", desc: "token-aware command/read output", defaultEnabled: true },
|
|
@@ -93784,8 +94064,8 @@ async function modulesCommand(args = []) {
|
|
|
93784
94064
|
return;
|
|
93785
94065
|
}
|
|
93786
94066
|
const wantsJson = args.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
93787
|
-
const metaprojectRoot =
|
|
93788
|
-
const manifestPath =
|
|
94067
|
+
const metaprojectRoot = path185.join(process.cwd(), ".metaproject");
|
|
94068
|
+
const manifestPath = path185.join(metaprojectRoot, "metaproject.json");
|
|
93789
94069
|
if (!await pathExists(manifestPath)) {
|
|
93790
94070
|
if (wantsJson) {
|
|
93791
94071
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -93916,9 +94196,9 @@ import {
|
|
|
93916
94196
|
unlinkSync as unlinkSync3,
|
|
93917
94197
|
writeFileSync as writeFileSync8
|
|
93918
94198
|
} from "fs";
|
|
93919
|
-
import
|
|
94199
|
+
import path186 from "path";
|
|
93920
94200
|
function serveCredentialPath(dir) {
|
|
93921
|
-
return
|
|
94201
|
+
return path186.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
93922
94202
|
}
|
|
93923
94203
|
function constantTimeEqual(a, b) {
|
|
93924
94204
|
const width = Math.max(a.length, b.length);
|
|
@@ -94152,22 +94432,22 @@ class AuthFailureThrottle {
|
|
|
94152
94432
|
init_config_dir();
|
|
94153
94433
|
import { createHash as createHash43 } from "crypto";
|
|
94154
94434
|
import { existsSync as existsSync32, readdirSync as readdirSync3, rmSync as rmSync2 } from "fs";
|
|
94155
|
-
import
|
|
94435
|
+
import path187 from "path";
|
|
94156
94436
|
var MAX_TURN_EVENTS = 1e4;
|
|
94157
94437
|
function turnsRoot(dir) {
|
|
94158
|
-
return
|
|
94438
|
+
return path187.join(keryxConfigDir(dir), "turns");
|
|
94159
94439
|
}
|
|
94160
94440
|
function turnDir(turnId, dir) {
|
|
94161
|
-
return
|
|
94441
|
+
return path187.join(turnsRoot(dir), turnId);
|
|
94162
94442
|
}
|
|
94163
94443
|
function keyPath(project, idempotencyKey, dir) {
|
|
94164
94444
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
94165
94445
|
const digest = createHash43("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
94166
|
-
return
|
|
94446
|
+
return path187.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
94167
94447
|
}
|
|
94168
94448
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
94169
94449
|
const digest = createHash43("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
94170
|
-
return
|
|
94450
|
+
return path187.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
94171
94451
|
}
|
|
94172
94452
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
94173
94453
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -94231,7 +94511,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
94231
94511
|
}
|
|
94232
94512
|
function createTurnRecord(record, dir) {
|
|
94233
94513
|
ensureTurnDir(record.turnId, dir);
|
|
94234
|
-
writeOwnerOnlyFile(
|
|
94514
|
+
writeOwnerOnlyFile(path187.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
94235
94515
|
`);
|
|
94236
94516
|
}
|
|
94237
94517
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -94240,12 +94520,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
94240
94520
|
}
|
|
94241
94521
|
const line = JSON.stringify(event);
|
|
94242
94522
|
try {
|
|
94243
|
-
appendOwnerOnlyLine(
|
|
94523
|
+
appendOwnerOnlyLine(path187.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
94244
94524
|
} catch (error) {
|
|
94245
94525
|
if (error?.code !== "ENOENT") {
|
|
94246
94526
|
throw error;
|
|
94247
94527
|
}
|
|
94248
|
-
appendOwnerOnlyLine(
|
|
94528
|
+
appendOwnerOnlyLine(path187.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
94249
94529
|
}
|
|
94250
94530
|
return true;
|
|
94251
94531
|
}
|
|
@@ -94253,7 +94533,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
94253
94533
|
if (!isTurnId(turnId)) {
|
|
94254
94534
|
return { ok: false, reason: "not-a-turn-id" };
|
|
94255
94535
|
}
|
|
94256
|
-
const read = readTurnFile(
|
|
94536
|
+
const read = readTurnFile(path187.join(turnDir(turnId, dir), "events.jsonl"));
|
|
94257
94537
|
if (!read.ok) {
|
|
94258
94538
|
if (isDefiniteAbsence2(read.reason)) {
|
|
94259
94539
|
return { ok: true, value: [] };
|
|
@@ -94281,7 +94561,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
94281
94561
|
if (!isTurnId(turnId)) {
|
|
94282
94562
|
return { ok: false, reason: "not-a-turn-id" };
|
|
94283
94563
|
}
|
|
94284
|
-
const read = readTurnFile(
|
|
94564
|
+
const read = readTurnFile(path187.join(turnDir(turnId, dir), "turn.json"));
|
|
94285
94565
|
if (!read.ok) {
|
|
94286
94566
|
return { ok: false, reason: read.reason };
|
|
94287
94567
|
}
|
|
@@ -94300,7 +94580,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
94300
94580
|
if (!record.ok) {
|
|
94301
94581
|
return false;
|
|
94302
94582
|
}
|
|
94303
|
-
writeOwnerOnlyFile(
|
|
94583
|
+
writeOwnerOnlyFile(path187.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
94304
94584
|
`);
|
|
94305
94585
|
return true;
|
|
94306
94586
|
}
|
|
@@ -94346,7 +94626,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
94346
94626
|
|
|
94347
94627
|
// src/lib/serve-turn.ts
|
|
94348
94628
|
import { randomUUID as randomUUID31 } from "crypto";
|
|
94349
|
-
import
|
|
94629
|
+
import path188 from "path";
|
|
94350
94630
|
init_service();
|
|
94351
94631
|
var REMOTE_ORIGIN = "remote:http";
|
|
94352
94632
|
var MAX_PROMPT_CHARS = 32000;
|
|
@@ -94415,9 +94695,9 @@ function isUuid(value) {
|
|
|
94415
94695
|
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);
|
|
94416
94696
|
}
|
|
94417
94697
|
function resolveProject(declared, dir) {
|
|
94418
|
-
const wanted =
|
|
94698
|
+
const wanted = path188.resolve(declared);
|
|
94419
94699
|
for (const entry of listProjects(dir, () => {})) {
|
|
94420
|
-
if (
|
|
94700
|
+
if (path188.resolve(entry.path) === wanted) {
|
|
94421
94701
|
return { ok: true, project: entry.path };
|
|
94422
94702
|
}
|
|
94423
94703
|
}
|
|
@@ -95453,7 +95733,7 @@ function printHelp19() {
|
|
|
95453
95733
|
import { spawn as spawn6 } from "child_process";
|
|
95454
95734
|
import { chmod as chmod4, mkdir as mkdir62, readFile as readFile99, readdir as readdir35, writeFile as writeFile54 } from "fs/promises";
|
|
95455
95735
|
import { access as access4, constants as constants2, existsSync as existsSync33 } from "fs";
|
|
95456
|
-
import
|
|
95736
|
+
import path189 from "path";
|
|
95457
95737
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
95458
95738
|
init_config();
|
|
95459
95739
|
init_config2();
|
|
@@ -95470,8 +95750,8 @@ async function updateCommand(args = []) {
|
|
|
95470
95750
|
return;
|
|
95471
95751
|
}
|
|
95472
95752
|
const projectRoot = process.cwd();
|
|
95473
|
-
const metaprojectRoot =
|
|
95474
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
95753
|
+
const metaprojectRoot = path189.join(projectRoot, ".metaproject");
|
|
95754
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path189.basename(projectRoot)}/`);
|
|
95475
95755
|
if (!await pathExists(metaprojectRoot)) {
|
|
95476
95756
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
95477
95757
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -95532,7 +95812,7 @@ async function updateCommand(args = []) {
|
|
|
95532
95812
|
nextSteps(steps);
|
|
95533
95813
|
}
|
|
95534
95814
|
async function previewServiceFiles(projectRoot, options) {
|
|
95535
|
-
const metaprojectRoot =
|
|
95815
|
+
const metaprojectRoot = path189.join(projectRoot, ".metaproject");
|
|
95536
95816
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
95537
95817
|
const manifest = manifestState.manifest;
|
|
95538
95818
|
const enableTasks = moduleEnabled2(manifest, "tasks") || !options.noTasks;
|
|
@@ -95561,12 +95841,12 @@ async function previewServiceFiles(projectRoot, options) {
|
|
|
95561
95841
|
});
|
|
95562
95842
|
}
|
|
95563
95843
|
async function refreshServiceFiles(projectRoot, options) {
|
|
95564
|
-
const metaprojectRoot =
|
|
95844
|
+
const metaprojectRoot = path189.join(projectRoot, ".metaproject");
|
|
95565
95845
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
95566
95846
|
const manifest = manifestState.manifest;
|
|
95567
95847
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
95568
95848
|
if (manifestState.migrated) {
|
|
95569
|
-
await writeFile54(
|
|
95849
|
+
await writeFile54(path189.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
95570
95850
|
`, "utf8");
|
|
95571
95851
|
}
|
|
95572
95852
|
const enableGdgraph = moduleEnabled2(manifest, "gdgraph");
|
|
@@ -95603,9 +95883,9 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95603
95883
|
enableSecurity,
|
|
95604
95884
|
enableSac
|
|
95605
95885
|
});
|
|
95606
|
-
await writeTextIfChanged4(
|
|
95607
|
-
await writeTextIfChanged4(
|
|
95608
|
-
await writeTextIfChanged4(
|
|
95886
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
95887
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
95888
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
95609
95889
|
await writeRoutingEntrypointPair(metaprojectRoot, {
|
|
95610
95890
|
enableGdgraph,
|
|
95611
95891
|
enableGdctx,
|
|
@@ -95628,7 +95908,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95628
95908
|
}
|
|
95629
95909
|
}
|
|
95630
95910
|
});
|
|
95631
|
-
await writeTextIfChanged4(
|
|
95911
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
95632
95912
|
enableGdgraph,
|
|
95633
95913
|
enableGdctx,
|
|
95634
95914
|
enableGdwiki,
|
|
@@ -95640,7 +95920,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95640
95920
|
enableSecurity,
|
|
95641
95921
|
data: dashboardData
|
|
95642
95922
|
}));
|
|
95643
|
-
await writeTextIfMissing4(
|
|
95923
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
95644
95924
|
enableGdgraph,
|
|
95645
95925
|
enableGdctx,
|
|
95646
95926
|
enableGdwiki,
|
|
@@ -95653,31 +95933,31 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95653
95933
|
}));
|
|
95654
95934
|
if (enableGdgraph) {
|
|
95655
95935
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
95656
|
-
await writeTextIfChanged4(
|
|
95657
|
-
await writeTextIfChanged4(
|
|
95658
|
-
await writeTextIfChanged4(
|
|
95936
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
95937
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
95938
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
95659
95939
|
await seedAssetsLock(metaprojectRoot);
|
|
95660
95940
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
95661
95941
|
await installManagedHook2(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
95662
95942
|
}
|
|
95663
95943
|
}
|
|
95664
95944
|
if (enableGdctx) {
|
|
95665
|
-
await writeTextIfMissing4(
|
|
95666
|
-
await writeTextIfChanged4(
|
|
95667
|
-
await writeTextIfChanged4(
|
|
95668
|
-
await writeTextIfChanged4(
|
|
95945
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
95946
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
95947
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
95948
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
95669
95949
|
}
|
|
95670
95950
|
if (enableGdwiki) {
|
|
95671
|
-
await writeTextIfMissing4(
|
|
95672
|
-
await writeTextIfChanged4(
|
|
95673
|
-
await writeTextIfChanged4(
|
|
95951
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
95952
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
95953
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
95674
95954
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
95675
95955
|
await installManagedHook2(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
95676
95956
|
}
|
|
95677
95957
|
}
|
|
95678
95958
|
if (enableSac) {
|
|
95679
|
-
await writeTextIfMissing4(
|
|
95680
|
-
await writeTextIfChanged4(
|
|
95959
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "modules", "sac.md"), renderSacManifest());
|
|
95960
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "sac", "SKILL.md"), renderSacSkillReadme());
|
|
95681
95961
|
}
|
|
95682
95962
|
if (enableGdskills) {
|
|
95683
95963
|
await installGdskills(metaprojectRoot, gdskillsProfile, { createDataDirs: false });
|
|
@@ -95686,25 +95966,25 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95686
95966
|
}
|
|
95687
95967
|
}
|
|
95688
95968
|
if (enableHealth) {
|
|
95689
|
-
await writeTextIfMissing4(
|
|
95690
|
-
await writeTextIfChanged4(
|
|
95691
|
-
await writeTextIfChanged4(
|
|
95692
|
-
await writeTextIfChanged4(
|
|
95969
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
95970
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
95971
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
95972
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
95693
95973
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
95694
95974
|
await installManagedHook2(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
95695
95975
|
}
|
|
95696
95976
|
}
|
|
95697
95977
|
if (enableTesting) {
|
|
95698
|
-
await writeTextIfMissing4(
|
|
95978
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
95699
95979
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
95700
95980
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
95701
95981
|
}));
|
|
95702
|
-
await writeTextIfChanged4(
|
|
95703
|
-
await writeTextIfChanged4(
|
|
95704
|
-
await writeTextIfChanged4(
|
|
95982
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
95983
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
95984
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
95705
95985
|
if (enableGdwiki) {
|
|
95706
|
-
await writeTextIfMissing4(
|
|
95707
|
-
await writeTextIfMissing4(
|
|
95986
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
95987
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
95708
95988
|
}
|
|
95709
95989
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
95710
95990
|
await installManagedHook2(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -95717,24 +95997,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95717
95997
|
await installManagedHook2(projectRoot, "post-commit", "metaproject-dashboard-post-commit", renderMetaprojectDashboardPostCommitHook());
|
|
95718
95998
|
}
|
|
95719
95999
|
if (enableMemory) {
|
|
95720
|
-
await writeTextIfMissing4(
|
|
95721
|
-
await writeTextIfMissing4(
|
|
95722
|
-
await writeTextIfChanged4(
|
|
95723
|
-
await writeTextIfChanged4(
|
|
95724
|
-
await writeTextIfChanged4(
|
|
96000
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
96001
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
96002
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
96003
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
96004
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
95725
96005
|
}
|
|
95726
96006
|
if (enableTasks) {
|
|
95727
|
-
await writeTextIfChanged4(
|
|
95728
|
-
await writeTextIfChanged4(
|
|
95729
|
-
await writeTextIfChanged4(
|
|
95730
|
-
await writeTextIfChanged4(
|
|
95731
|
-
await writeTextIfChanged4(
|
|
95732
|
-
await writeTextIfChanged4(
|
|
96007
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
96008
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
96009
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
96010
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
96011
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
96012
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
95733
96013
|
}
|
|
95734
96014
|
if (enableSecurity) {
|
|
95735
|
-
await writeTextIfMissing4(
|
|
95736
|
-
await writeTextIfChanged4(
|
|
95737
|
-
await writeTextIfChanged4(
|
|
96015
|
+
await writeTextIfMissing4(path189.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
96016
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
96017
|
+
await writeTextIfChanged4(path189.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
95738
96018
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
95739
96019
|
await installManagedHook2(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
95740
96020
|
}
|
|
@@ -95785,13 +96065,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
95785
96065
|
};
|
|
95786
96066
|
}
|
|
95787
96067
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
95788
|
-
const metaprojectRoot =
|
|
96068
|
+
const metaprojectRoot = path189.join(projectRoot, ".metaproject");
|
|
95789
96069
|
if (!await pathExists(metaprojectRoot)) {
|
|
95790
96070
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
95791
96071
|
}
|
|
95792
96072
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
95793
96073
|
const data = await collectDashboardData(metaprojectRoot);
|
|
95794
|
-
const dashboardPath =
|
|
96074
|
+
const dashboardPath = path189.join(metaprojectRoot, "keryx-dashboard.html");
|
|
95795
96075
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
95796
96076
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
95797
96077
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -95811,7 +96091,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
95811
96091
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
95812
96092
|
return true;
|
|
95813
96093
|
}
|
|
95814
|
-
const hookPath =
|
|
96094
|
+
const hookPath = path189.join(projectRoot, ".git", "hooks", "post-commit");
|
|
95815
96095
|
if (!await pathExists(hookPath)) {
|
|
95816
96096
|
return false;
|
|
95817
96097
|
}
|
|
@@ -95831,11 +96111,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
95831
96111
|
if (testing) {
|
|
95832
96112
|
data.testing = testing;
|
|
95833
96113
|
}
|
|
95834
|
-
const wiki = await collectMarkdownPages(
|
|
96114
|
+
const wiki = await collectMarkdownPages(path189.join(metaprojectRoot, "wiki"), "wiki");
|
|
95835
96115
|
if (wiki.length > 0) {
|
|
95836
96116
|
data.wiki = { pages: wiki };
|
|
95837
96117
|
}
|
|
95838
|
-
const memory = await collectMarkdownPages(
|
|
96118
|
+
const memory = await collectMarkdownPages(path189.join(metaprojectRoot, "memory"), "memory");
|
|
95839
96119
|
if (memory.length > 0) {
|
|
95840
96120
|
data.memory = { entries: memory };
|
|
95841
96121
|
}
|
|
@@ -95850,7 +96130,7 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
95850
96130
|
return data;
|
|
95851
96131
|
}
|
|
95852
96132
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
95853
|
-
const flowsRoot =
|
|
96133
|
+
const flowsRoot = path189.join(metaprojectRoot, "flows");
|
|
95854
96134
|
if (!await pathExists(flowsRoot)) {
|
|
95855
96135
|
return null;
|
|
95856
96136
|
}
|
|
@@ -95862,7 +96142,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
95862
96142
|
}
|
|
95863
96143
|
const flows = [];
|
|
95864
96144
|
for (const dir of dirEntries) {
|
|
95865
|
-
const flowPath =
|
|
96145
|
+
const flowPath = path189.join(flowsRoot, dir, "flow.json");
|
|
95866
96146
|
if (!await pathExists(flowPath)) {
|
|
95867
96147
|
continue;
|
|
95868
96148
|
}
|
|
@@ -95870,7 +96150,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
95870
96150
|
const flow = JSON.parse(await readFile99(flowPath, "utf8"));
|
|
95871
96151
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
95872
96152
|
let acTotal = 0;
|
|
95873
|
-
const acPath =
|
|
96153
|
+
const acPath = path189.join(flowsRoot, dir, "acceptance-criteria.md");
|
|
95874
96154
|
if (await pathExists(acPath)) {
|
|
95875
96155
|
const acContent = await readFile99(acPath, "utf8");
|
|
95876
96156
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
@@ -95924,7 +96204,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
95924
96204
|
"data/testing/context.md"
|
|
95925
96205
|
];
|
|
95926
96206
|
for (const href of staticHrefs) {
|
|
95927
|
-
const filePath =
|
|
96207
|
+
const filePath = path189.join(metaprojectRoot, ...href.split("/"));
|
|
95928
96208
|
if (!await pathExists(filePath)) {
|
|
95929
96209
|
continue;
|
|
95930
96210
|
}
|
|
@@ -95941,7 +96221,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
95941
96221
|
return docs;
|
|
95942
96222
|
}
|
|
95943
96223
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
95944
|
-
const reportPath =
|
|
96224
|
+
const reportPath = path189.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
95945
96225
|
if (!await pathExists(reportPath)) {
|
|
95946
96226
|
return;
|
|
95947
96227
|
}
|
|
@@ -96050,8 +96330,8 @@ function metricToScope(metric) {
|
|
|
96050
96330
|
};
|
|
96051
96331
|
}
|
|
96052
96332
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
96053
|
-
const nodesPath =
|
|
96054
|
-
const edgesPath =
|
|
96333
|
+
const nodesPath = path189.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
96334
|
+
const edgesPath = path189.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
96055
96335
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
96056
96336
|
return;
|
|
96057
96337
|
}
|
|
@@ -96102,8 +96382,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
96102
96382
|
};
|
|
96103
96383
|
}
|
|
96104
96384
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
96105
|
-
const reportPath =
|
|
96106
|
-
const contextPath =
|
|
96385
|
+
const reportPath = path189.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
96386
|
+
const contextPath = path189.join(metaprojectRoot, "data", "testing", "context.md");
|
|
96107
96387
|
if (await pathExists(reportPath)) {
|
|
96108
96388
|
const report = JSON.parse(await readFile99(reportPath, "utf8"));
|
|
96109
96389
|
const totalTests = numberOrUndefined(report.total);
|
|
@@ -96132,7 +96412,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
96132
96412
|
const files = await listMarkdownFiles(root);
|
|
96133
96413
|
const pages = [];
|
|
96134
96414
|
for (const filePath of files.slice(0, 40)) {
|
|
96135
|
-
const relativePath =
|
|
96415
|
+
const relativePath = path189.relative(root, filePath).split(path189.sep).join("/");
|
|
96136
96416
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
96137
96417
|
continue;
|
|
96138
96418
|
}
|
|
@@ -96153,7 +96433,7 @@ async function listMarkdownFiles(root) {
|
|
|
96153
96433
|
const entries = await readdir35(root, { withFileTypes: true });
|
|
96154
96434
|
const files = [];
|
|
96155
96435
|
for (const entry of entries) {
|
|
96156
|
-
const fullPath =
|
|
96436
|
+
const fullPath = path189.join(root, entry.name);
|
|
96157
96437
|
if (entry.isDirectory()) {
|
|
96158
96438
|
files.push(...await listMarkdownFiles(fullPath));
|
|
96159
96439
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -96201,7 +96481,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
96201
96481
|
const manifest = {
|
|
96202
96482
|
schemaVersion: 1,
|
|
96203
96483
|
standardVersion: STANDARD_VERSION,
|
|
96204
|
-
name: `${
|
|
96484
|
+
name: `${path189.basename(path189.dirname(metaprojectRoot))}-metaproject`,
|
|
96205
96485
|
createdBy: "keryx",
|
|
96206
96486
|
profiles: computeProfiles(enabledModuleKeys),
|
|
96207
96487
|
paths: {
|
|
@@ -96291,11 +96571,11 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
96291
96571
|
metaproject: ".metaproject/index.md"
|
|
96292
96572
|
}
|
|
96293
96573
|
};
|
|
96294
|
-
await writeFile54(
|
|
96574
|
+
await writeFile54(path189.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
96295
96575
|
`, "utf8");
|
|
96296
96576
|
}
|
|
96297
96577
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
96298
|
-
const manifestPath =
|
|
96578
|
+
const manifestPath = path189.join(metaprojectRoot, "metaproject.json");
|
|
96299
96579
|
if (!await pathExists(manifestPath)) {
|
|
96300
96580
|
return;
|
|
96301
96581
|
}
|
|
@@ -96318,7 +96598,7 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
96318
96598
|
`, "utf8");
|
|
96319
96599
|
}
|
|
96320
96600
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
96321
|
-
const manifestPath =
|
|
96601
|
+
const manifestPath = path189.join(metaprojectRoot, "metaproject.json");
|
|
96322
96602
|
if (!await pathExists(manifestPath)) {
|
|
96323
96603
|
return;
|
|
96324
96604
|
}
|
|
@@ -96354,72 +96634,72 @@ async function updateRuntime(projectRoot) {
|
|
|
96354
96634
|
}
|
|
96355
96635
|
}
|
|
96356
96636
|
async function findRuntimeRoot(projectRoot) {
|
|
96357
|
-
const projectRuntime =
|
|
96358
|
-
if (await pathExists(
|
|
96637
|
+
const projectRuntime = path189.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
96638
|
+
if (await pathExists(path189.join(projectRuntime, ".git"))) {
|
|
96359
96639
|
return projectRuntime;
|
|
96360
96640
|
}
|
|
96361
96641
|
const home = process.env.HOME;
|
|
96362
96642
|
if (!home) {
|
|
96363
96643
|
return null;
|
|
96364
96644
|
}
|
|
96365
|
-
const globalRuntime =
|
|
96366
|
-
if (await pathExists(
|
|
96645
|
+
const globalRuntime = path189.join(home, ".keryx", "keryx");
|
|
96646
|
+
if (await pathExists(path189.join(globalRuntime, ".git"))) {
|
|
96367
96647
|
return globalRuntime;
|
|
96368
96648
|
}
|
|
96369
96649
|
return null;
|
|
96370
96650
|
}
|
|
96371
96651
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
96372
96652
|
const dirs = [
|
|
96373
|
-
|
|
96374
|
-
|
|
96375
|
-
|
|
96376
|
-
|
|
96377
|
-
|
|
96653
|
+
path189.join(metaprojectRoot, "core"),
|
|
96654
|
+
path189.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
96655
|
+
path189.join(metaprojectRoot, "modules"),
|
|
96656
|
+
path189.join(metaprojectRoot, "rules"),
|
|
96657
|
+
path189.join(metaprojectRoot, "skills", "project-rules"),
|
|
96378
96658
|
...modules.enableGdgraph ? [
|
|
96379
|
-
|
|
96380
|
-
|
|
96659
|
+
path189.join(metaprojectRoot, "core", "gdgraph"),
|
|
96660
|
+
path189.join(metaprojectRoot, "skills", "gdgraph")
|
|
96381
96661
|
] : [],
|
|
96382
96662
|
...modules.enableGdctx ? [
|
|
96383
|
-
|
|
96384
|
-
|
|
96663
|
+
path189.join(metaprojectRoot, "core", "gdctx"),
|
|
96664
|
+
path189.join(metaprojectRoot, "skills", "gdctx")
|
|
96385
96665
|
] : [],
|
|
96386
96666
|
...modules.enableGdwiki ? [
|
|
96387
|
-
|
|
96388
|
-
|
|
96667
|
+
path189.join(metaprojectRoot, "skills", "gdwiki"),
|
|
96668
|
+
path189.join(metaprojectRoot, "wiki", "templates")
|
|
96389
96669
|
] : [],
|
|
96390
96670
|
...modules.enableHealth ? [
|
|
96391
|
-
|
|
96392
|
-
|
|
96671
|
+
path189.join(metaprojectRoot, "core", "health"),
|
|
96672
|
+
path189.join(metaprojectRoot, "skills", "health")
|
|
96393
96673
|
] : [],
|
|
96394
96674
|
...modules.enableTesting ? [
|
|
96395
|
-
|
|
96396
|
-
|
|
96675
|
+
path189.join(metaprojectRoot, "core", "testing"),
|
|
96676
|
+
path189.join(metaprojectRoot, "skills", "testing")
|
|
96397
96677
|
] : [],
|
|
96398
96678
|
...modules.enableMemory ? [
|
|
96399
|
-
|
|
96400
|
-
|
|
96401
|
-
|
|
96679
|
+
path189.join(metaprojectRoot, "core", "memory"),
|
|
96680
|
+
path189.join(metaprojectRoot, "skills", "memory"),
|
|
96681
|
+
path189.join(metaprojectRoot, "memory", "templates")
|
|
96402
96682
|
] : [],
|
|
96403
96683
|
...modules.enableTasks ? [
|
|
96404
|
-
|
|
96405
|
-
|
|
96684
|
+
path189.join(metaprojectRoot, "flows"),
|
|
96685
|
+
path189.join(metaprojectRoot, "skills", "flow")
|
|
96406
96686
|
] : [],
|
|
96407
96687
|
...modules.enableSecurity ? [
|
|
96408
|
-
|
|
96688
|
+
path189.join(metaprojectRoot, "core", "security")
|
|
96409
96689
|
] : [],
|
|
96410
96690
|
...modules.enableSac ? [
|
|
96411
|
-
|
|
96691
|
+
path189.join(metaprojectRoot, "skills", "sac")
|
|
96412
96692
|
] : []
|
|
96413
96693
|
];
|
|
96414
96694
|
await Promise.all(dirs.map((dir) => mkdir62(dir, { recursive: true })));
|
|
96415
96695
|
}
|
|
96416
96696
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
96417
|
-
const gdgraphCoreRoot =
|
|
96697
|
+
const gdgraphCoreRoot = path189.join(metaprojectRoot, "core", "gdgraph");
|
|
96418
96698
|
await mkdir62(gdgraphCoreRoot, { recursive: true });
|
|
96419
96699
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
96420
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
96700
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path189.join(gdgraphCoreRoot, file));
|
|
96421
96701
|
}
|
|
96422
|
-
await writeTextIfChanged4(
|
|
96702
|
+
await writeTextIfChanged4(path189.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
96423
96703
|
}
|
|
96424
96704
|
async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
96425
96705
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
@@ -96427,7 +96707,7 @@ async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
|
96427
96707
|
return;
|
|
96428
96708
|
}
|
|
96429
96709
|
await mkdir62(hooksRoot, { recursive: true });
|
|
96430
|
-
const hookPath =
|
|
96710
|
+
const hookPath = path189.join(hooksRoot, hookName);
|
|
96431
96711
|
const blockStart = `# keryx:${blockId}:begin`;
|
|
96432
96712
|
const blockEnd = `# keryx:${blockId}:end`;
|
|
96433
96713
|
const managedBlock = `${blockStart}
|
|
@@ -96436,7 +96716,7 @@ ${blockEnd}`;
|
|
|
96436
96716
|
const existing = await pathExists(hookPath) ? await readFile99(hookPath, "utf8") : `#!/usr/bin/env sh
|
|
96437
96717
|
`;
|
|
96438
96718
|
const blockPattern = new RegExp(`${escapeRegExp7(blockStart)}[\\s\\S]*?${escapeRegExp7(blockEnd)}`);
|
|
96439
|
-
const next = blockPattern.test(existing) ? existing.replace(blockPattern, managedBlock) : `${existing.trimEnd()}
|
|
96719
|
+
const next = blockPattern.test(existing) ? existing.replace(blockPattern, () => managedBlock) : `${existing.trimEnd()}
|
|
96440
96720
|
|
|
96441
96721
|
${managedBlock}
|
|
96442
96722
|
`;
|
|
@@ -96448,7 +96728,7 @@ async function removeManagedHook2(projectRoot, hookName, blockId) {
|
|
|
96448
96728
|
if (!hooksRoot) {
|
|
96449
96729
|
return;
|
|
96450
96730
|
}
|
|
96451
|
-
const hookPath =
|
|
96731
|
+
const hookPath = path189.join(hooksRoot, hookName);
|
|
96452
96732
|
if (!await pathExists(hookPath)) {
|
|
96453
96733
|
return;
|
|
96454
96734
|
}
|
|
@@ -96470,7 +96750,7 @@ async function prePushHasSecurityBlock2(projectRoot) {
|
|
|
96470
96750
|
if (!hooksRoot) {
|
|
96471
96751
|
return false;
|
|
96472
96752
|
}
|
|
96473
|
-
const hookPath =
|
|
96753
|
+
const hookPath = path189.join(hooksRoot, "pre-push");
|
|
96474
96754
|
if (!await pathExists(hookPath)) {
|
|
96475
96755
|
return false;
|
|
96476
96756
|
}
|
|
@@ -96485,7 +96765,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
96485
96765
|
return (await readFile99(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
96486
96766
|
}
|
|
96487
96767
|
async function readManifest5(metaprojectRoot) {
|
|
96488
|
-
const manifestPath =
|
|
96768
|
+
const manifestPath = path189.join(metaprojectRoot, "metaproject.json");
|
|
96489
96769
|
if (!await pathExists(manifestPath)) {
|
|
96490
96770
|
return {
|
|
96491
96771
|
exists: false,
|
|
@@ -96554,7 +96834,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
96554
96834
|
}
|
|
96555
96835
|
async function anyPathExists(root, candidates) {
|
|
96556
96836
|
for (const candidate of candidates) {
|
|
96557
|
-
if (await pathExists(
|
|
96837
|
+
if (await pathExists(path189.join(root, candidate))) {
|
|
96558
96838
|
return true;
|
|
96559
96839
|
}
|
|
96560
96840
|
}
|
|
@@ -96577,13 +96857,13 @@ function parseUpdateArgs(args) {
|
|
|
96577
96857
|
};
|
|
96578
96858
|
}
|
|
96579
96859
|
async function runPostUpdateHooks(projectRoot) {
|
|
96580
|
-
const hooksDir =
|
|
96860
|
+
const hooksDir = path189.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
96581
96861
|
if (!await pathExists(hooksDir)) {
|
|
96582
96862
|
return;
|
|
96583
96863
|
}
|
|
96584
96864
|
const entries = (await readdir35(hooksDir)).sort();
|
|
96585
96865
|
for (const entry of entries) {
|
|
96586
|
-
const hookPath =
|
|
96866
|
+
const hookPath = path189.join(hooksDir, entry);
|
|
96587
96867
|
try {
|
|
96588
96868
|
await accessExecutable(hookPath);
|
|
96589
96869
|
} catch {
|
|
@@ -96624,14 +96904,14 @@ async function writeTextIfChanged4(filePath, content) {
|
|
|
96624
96904
|
if (await pathExists(filePath) && await readFile99(filePath, "utf8") === content) {
|
|
96625
96905
|
return;
|
|
96626
96906
|
}
|
|
96627
|
-
await mkdir62(
|
|
96907
|
+
await mkdir62(path189.dirname(filePath), { recursive: true });
|
|
96628
96908
|
await writeFile54(filePath, content, "utf8");
|
|
96629
96909
|
}
|
|
96630
96910
|
async function writeTextIfMissing4(filePath, content) {
|
|
96631
96911
|
if (await pathExists(filePath)) {
|
|
96632
96912
|
return;
|
|
96633
96913
|
}
|
|
96634
|
-
await mkdir62(
|
|
96914
|
+
await mkdir62(path189.dirname(filePath), { recursive: true });
|
|
96635
96915
|
await writeFile54(filePath, content, "utf8");
|
|
96636
96916
|
}
|
|
96637
96917
|
async function copyFileIfChanged2(from, to) {
|
|
@@ -96639,7 +96919,7 @@ async function copyFileIfChanged2(from, to) {
|
|
|
96639
96919
|
if (await pathExists(to) && await readFile99(to, "utf8") === next) {
|
|
96640
96920
|
return;
|
|
96641
96921
|
}
|
|
96642
|
-
await mkdir62(
|
|
96922
|
+
await mkdir62(path189.dirname(to), { recursive: true });
|
|
96643
96923
|
await writeFile54(to, next, "utf8");
|
|
96644
96924
|
}
|
|
96645
96925
|
function runtimeSourcePath2(relativePath) {
|
|
@@ -96648,7 +96928,7 @@ function runtimeSourcePath2(relativePath) {
|
|
|
96648
96928
|
return directPath;
|
|
96649
96929
|
}
|
|
96650
96930
|
if (relativePath.startsWith("../")) {
|
|
96651
|
-
const packagedSourcePath =
|
|
96931
|
+
const packagedSourcePath = path189.join(path189.dirname(fileURLToPath7(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
96652
96932
|
if (existsSync33(packagedSourcePath)) {
|
|
96653
96933
|
return packagedSourcePath;
|
|
96654
96934
|
}
|
|
@@ -96683,7 +96963,7 @@ function printHelp20() {
|
|
|
96683
96963
|
|
|
96684
96964
|
// src/commands/dashboard.ts
|
|
96685
96965
|
import { spawn as spawn7 } from "child_process";
|
|
96686
|
-
import
|
|
96966
|
+
import path190 from "path";
|
|
96687
96967
|
init_args();
|
|
96688
96968
|
async function dashboardCommand(args = []) {
|
|
96689
96969
|
const options = parseOptions(args);
|
|
@@ -96694,7 +96974,7 @@ async function dashboardCommand(args = []) {
|
|
|
96694
96974
|
}
|
|
96695
96975
|
if (subcommand === "build") {
|
|
96696
96976
|
const result = await buildDashboard();
|
|
96697
|
-
const rel =
|
|
96977
|
+
const rel = path190.relative(process.cwd(), result.path);
|
|
96698
96978
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
96699
96979
|
note(`Open it: keryx dashboard open`);
|
|
96700
96980
|
return;
|
|
@@ -96702,7 +96982,7 @@ async function dashboardCommand(args = []) {
|
|
|
96702
96982
|
if (subcommand === "open") {
|
|
96703
96983
|
const result = await buildDashboard();
|
|
96704
96984
|
await openFile(result.path);
|
|
96705
|
-
const rel =
|
|
96985
|
+
const rel = path190.relative(process.cwd(), result.path);
|
|
96706
96986
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
96707
96987
|
return;
|
|
96708
96988
|
}
|
|
@@ -96751,7 +97031,7 @@ import { readFileSync as readFileSync8 } from "fs";
|
|
|
96751
97031
|
// src/agents/bootstrap.ts
|
|
96752
97032
|
import { mkdir as mkdir63, readFile as readFile100, writeFile as writeFile55 } from "fs/promises";
|
|
96753
97033
|
import { homedir as homedir8 } from "os";
|
|
96754
|
-
import
|
|
97034
|
+
import path191 from "path";
|
|
96755
97035
|
init_fs();
|
|
96756
97036
|
var AGENT_BOOTSTRAP_START = "<!-- keryx:global-bootstrap -->";
|
|
96757
97037
|
var AGENT_BOOTSTRAP_END = "<!-- /keryx:global-bootstrap -->";
|
|
@@ -96761,35 +97041,35 @@ var AGENT_BOOTSTRAP_RUNTIMES = [
|
|
|
96761
97041
|
aliases: ["claude-code"],
|
|
96762
97042
|
label: "Claude Code",
|
|
96763
97043
|
fileName: "CLAUDE.md",
|
|
96764
|
-
filePath: (homeRoot) =>
|
|
97044
|
+
filePath: (homeRoot) => path191.join(homeRoot, ".claude", "CLAUDE.md")
|
|
96765
97045
|
},
|
|
96766
97046
|
{
|
|
96767
97047
|
id: "opencode",
|
|
96768
97048
|
aliases: ["open-code"],
|
|
96769
97049
|
label: "OpenCode",
|
|
96770
97050
|
fileName: "AGENTS.md",
|
|
96771
|
-
filePath: (homeRoot) =>
|
|
97051
|
+
filePath: (homeRoot) => path191.join(homeRoot, ".config", "opencode", "AGENTS.md")
|
|
96772
97052
|
},
|
|
96773
97053
|
{
|
|
96774
97054
|
id: "zcode",
|
|
96775
97055
|
aliases: ["zed", "zed-code"],
|
|
96776
97056
|
label: "ZCode",
|
|
96777
97057
|
fileName: "AGENTS.md",
|
|
96778
|
-
filePath: (homeRoot) =>
|
|
97058
|
+
filePath: (homeRoot) => path191.join(homeRoot, ".zcode", "AGENTS.md")
|
|
96779
97059
|
},
|
|
96780
97060
|
{
|
|
96781
97061
|
id: "codex",
|
|
96782
97062
|
aliases: [],
|
|
96783
97063
|
label: "Codex",
|
|
96784
97064
|
fileName: "AGENTS.md",
|
|
96785
|
-
filePath: (homeRoot) =>
|
|
97065
|
+
filePath: (homeRoot) => path191.join(homeRoot, ".codex", "AGENTS.md")
|
|
96786
97066
|
},
|
|
96787
97067
|
{
|
|
96788
97068
|
id: "antigravity",
|
|
96789
97069
|
aliases: ["antigravuty", "antigravity-code"],
|
|
96790
97070
|
label: "Antigravity",
|
|
96791
97071
|
fileName: "AGENTS.md",
|
|
96792
|
-
filePath: (homeRoot) =>
|
|
97072
|
+
filePath: (homeRoot) => path191.join(homeRoot, ".config", "antigravity", "AGENTS.md")
|
|
96793
97073
|
}
|
|
96794
97074
|
];
|
|
96795
97075
|
function agentBootstrapRuntimeIds() {
|
|
@@ -96837,7 +97117,7 @@ async function installAgentBootstrap(runtime, options = {}) {
|
|
|
96837
97117
|
const dryRun = options.dryRun === true;
|
|
96838
97118
|
const wrote = next !== current;
|
|
96839
97119
|
if (wrote && !dryRun) {
|
|
96840
|
-
await mkdir63(
|
|
97120
|
+
await mkdir63(path191.dirname(filePath), { recursive: true });
|
|
96841
97121
|
await writeFile55(filePath, next, "utf8");
|
|
96842
97122
|
}
|
|
96843
97123
|
const status = dryRun ? statusFromContent(runtime, filePath, exists, next) : await agentBootstrapStatus(runtime, homeRoot);
|
|
@@ -97199,7 +97479,7 @@ function reduceAgents(events) {
|
|
|
97199
97479
|
|
|
97200
97480
|
// src/commands/agents.ts
|
|
97201
97481
|
init_args();
|
|
97202
|
-
var
|
|
97482
|
+
var RUNTIME_USAGE = "<claude|opencode|zcode|codex|antigravity|all>";
|
|
97203
97483
|
async function agentsCommand(args = []) {
|
|
97204
97484
|
const subcommand = args[0];
|
|
97205
97485
|
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
@@ -97345,9 +97625,9 @@ async function bootstrapCommand(args) {
|
|
|
97345
97625
|
function printAgentsHelp() {
|
|
97346
97626
|
helpTitle("keryx agents", "manage agent bootstrap instructions and monitor a subagent fleet");
|
|
97347
97627
|
helpUsage([
|
|
97348
|
-
`keryx agents bootstrap status --runtime ${
|
|
97349
|
-
`keryx agents bootstrap install --runtime ${
|
|
97350
|
-
`keryx agents bootstrap uninstall --runtime ${
|
|
97628
|
+
`keryx agents bootstrap status --runtime ${RUNTIME_USAGE}`,
|
|
97629
|
+
`keryx agents bootstrap install --runtime ${RUNTIME_USAGE} [--dry-run]`,
|
|
97630
|
+
`keryx agents bootstrap uninstall --runtime ${RUNTIME_USAGE} [--dry-run]`,
|
|
97351
97631
|
"keryx agents bootstrap print",
|
|
97352
97632
|
"keryx agents monitor <events-file> [--json]",
|
|
97353
97633
|
"keryx agents external list [--json] [--no-probe]",
|
|
@@ -97357,9 +97637,9 @@ function printAgentsHelp() {
|
|
|
97357
97637
|
function printBootstrapHelp() {
|
|
97358
97638
|
helpTitle("keryx agents bootstrap", "install optional Metaproject routing into global agent entrypoints");
|
|
97359
97639
|
helpUsage([
|
|
97360
|
-
`keryx agents bootstrap status --runtime ${
|
|
97361
|
-
`keryx agents bootstrap install --runtime ${
|
|
97362
|
-
`keryx agents bootstrap uninstall --runtime ${
|
|
97640
|
+
`keryx agents bootstrap status --runtime ${RUNTIME_USAGE}`,
|
|
97641
|
+
`keryx agents bootstrap install --runtime ${RUNTIME_USAGE} [--dry-run]`,
|
|
97642
|
+
`keryx agents bootstrap uninstall --runtime ${RUNTIME_USAGE} [--dry-run]`,
|
|
97363
97643
|
"keryx agents bootstrap print"
|
|
97364
97644
|
]);
|
|
97365
97645
|
helpOptions([
|
|
@@ -97374,7 +97654,7 @@ function printBootstrapHelp() {
|
|
|
97374
97654
|
// src/commands/metrics.ts
|
|
97375
97655
|
init_args();
|
|
97376
97656
|
import { readFile as readFile101 } from "fs/promises";
|
|
97377
|
-
import
|
|
97657
|
+
import path193 from "path";
|
|
97378
97658
|
|
|
97379
97659
|
// src/metrics/benchmark.ts
|
|
97380
97660
|
var RELIABILITIES2 = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -98191,7 +98471,7 @@ function buildContainmentManifest(inputs, options = {}) {
|
|
|
98191
98471
|
|
|
98192
98472
|
// src/metrics/oracle-runner.ts
|
|
98193
98473
|
import { mkdir as mkdir64, writeFile as writeFile56 } from "fs/promises";
|
|
98194
|
-
import
|
|
98474
|
+
import path192 from "path";
|
|
98195
98475
|
|
|
98196
98476
|
// src/metrics/ir.ts
|
|
98197
98477
|
function toIdSet(ids) {
|
|
@@ -98637,9 +98917,9 @@ function buildEvidenceBundle(input, options = {}) {
|
|
|
98637
98917
|
async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
98638
98918
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
98639
98919
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
98640
|
-
const dir =
|
|
98920
|
+
const dir = path192.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
98641
98921
|
await mkdir64(dir, { recursive: true });
|
|
98642
|
-
const write = (name, value) => writeFile56(
|
|
98922
|
+
const write = (name, value) => writeFile56(path192.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
98643
98923
|
`, "utf8");
|
|
98644
98924
|
await Promise.all([
|
|
98645
98925
|
write("inputs.json", bundle.inputs),
|
|
@@ -98679,7 +98959,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98679
98959
|
console.log("# metrics status");
|
|
98680
98960
|
console.log("");
|
|
98681
98961
|
console.log(`root: ${root}`);
|
|
98682
|
-
console.log(`enabled: ${await Bun.file(
|
|
98962
|
+
console.log(`enabled: ${await Bun.file(path193.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
98683
98963
|
const latest = await readLatestPointer(root);
|
|
98684
98964
|
console.log(`latest: ${latest.status}`);
|
|
98685
98965
|
return;
|
|
@@ -98691,7 +98971,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98691
98971
|
process.exitCode = 1;
|
|
98692
98972
|
return;
|
|
98693
98973
|
}
|
|
98694
|
-
const record = JSON.parse(await readFile101(
|
|
98974
|
+
const record = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
98695
98975
|
const result = validateRunRecord(record);
|
|
98696
98976
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
98697
98977
|
for (const error of result.errors)
|
|
@@ -98716,7 +98996,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98716
98996
|
process.exitCode = 1;
|
|
98717
98997
|
return;
|
|
98718
98998
|
}
|
|
98719
|
-
const file =
|
|
98999
|
+
const file = path193.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
98720
99000
|
if (!await Bun.file(file).exists()) {
|
|
98721
99001
|
console.error(`Run not found: ${runId}`);
|
|
98722
99002
|
process.exitCode = 1;
|
|
@@ -98733,8 +99013,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98733
99013
|
process.exitCode = 1;
|
|
98734
99014
|
return;
|
|
98735
99015
|
}
|
|
98736
|
-
const a = JSON.parse(await readFile101(
|
|
98737
|
-
const b = JSON.parse(await readFile101(
|
|
99016
|
+
const a = JSON.parse(await readFile101(path193.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
99017
|
+
const b = JSON.parse(await readFile101(path193.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
98738
99018
|
const comparison = compareExecutionRuns(a, b);
|
|
98739
99019
|
console.log(stableJson(comparison));
|
|
98740
99020
|
return;
|
|
@@ -98768,8 +99048,8 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98768
99048
|
return;
|
|
98769
99049
|
}
|
|
98770
99050
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
98771
|
-
await Bun.write(
|
|
98772
|
-
console.log(`manifest: ${
|
|
99051
|
+
await Bun.write(path193.resolve(projectRoot, out), stableJson(template));
|
|
99052
|
+
console.log(`manifest: ${path193.relative(projectRoot, path193.resolve(projectRoot, out))}`);
|
|
98773
99053
|
return;
|
|
98774
99054
|
}
|
|
98775
99055
|
if (subcommand === "benchmark" && args[1] === "run") {
|
|
@@ -98783,7 +99063,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98783
99063
|
process.exitCode = 1;
|
|
98784
99064
|
return;
|
|
98785
99065
|
}
|
|
98786
|
-
const raw = JSON.parse(await readFile101(
|
|
99066
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
98787
99067
|
const input = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
98788
99068
|
const result = validatePairedBenchmark(input);
|
|
98789
99069
|
console.log(stableJson(result));
|
|
@@ -98795,7 +99075,7 @@ async function metricsCommand(args = [], projectRoot = process.cwd()) {
|
|
|
98795
99075
|
process.exitCode = 1;
|
|
98796
99076
|
}
|
|
98797
99077
|
async function loadAffectedSets(projectRoot, file) {
|
|
98798
|
-
const raw = JSON.parse(await readFile101(
|
|
99078
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
98799
99079
|
const map = new Map;
|
|
98800
99080
|
for (const entry of raw.targets ?? []) {
|
|
98801
99081
|
if (typeof entry.target === "string")
|
|
@@ -98866,7 +99146,7 @@ async function runHarnessLayer(projectRoot, args, ladder) {
|
|
|
98866
99146
|
let tasks;
|
|
98867
99147
|
let model;
|
|
98868
99148
|
try {
|
|
98869
|
-
const raw = JSON.parse(await readFile101(
|
|
99149
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, resultsPath), "utf8"));
|
|
98870
99150
|
tasks = raw.tasks ?? [];
|
|
98871
99151
|
model = raw.model;
|
|
98872
99152
|
} catch (error) {
|
|
@@ -98897,7 +99177,7 @@ async function runSafetyCompletionHonestyLayer(projectRoot, args, ladder) {
|
|
|
98897
99177
|
let cases;
|
|
98898
99178
|
let model;
|
|
98899
99179
|
try {
|
|
98900
|
-
const raw = JSON.parse(await readFile101(
|
|
99180
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, resultsPath), "utf8"));
|
|
98901
99181
|
cases = raw.cases ?? [];
|
|
98902
99182
|
model = raw.model;
|
|
98903
99183
|
} catch (error) {
|
|
@@ -98922,7 +99202,7 @@ async function runSafetyFalsePremiseLayer(projectRoot, args, ladder) {
|
|
|
98922
99202
|
let cases;
|
|
98923
99203
|
let model;
|
|
98924
99204
|
try {
|
|
98925
|
-
const raw = JSON.parse(await readFile101(
|
|
99205
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, resultsPath), "utf8"));
|
|
98926
99206
|
cases = raw.cases ?? [];
|
|
98927
99207
|
model = raw.model;
|
|
98928
99208
|
} catch (error) {
|
|
@@ -98947,7 +99227,7 @@ async function runSafetyContainmentLayer(projectRoot, args, ladder, caseClass) {
|
|
|
98947
99227
|
let cases;
|
|
98948
99228
|
let model;
|
|
98949
99229
|
try {
|
|
98950
|
-
const raw = JSON.parse(await readFile101(
|
|
99230
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, resultsPath), "utf8"));
|
|
98951
99231
|
cases = raw.cases ?? [];
|
|
98952
99232
|
model = raw.model;
|
|
98953
99233
|
} catch (error) {
|
|
@@ -99009,12 +99289,12 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
99009
99289
|
}
|
|
99010
99290
|
const manifests = buildOracleManifestsByGold(inputs, { ladder });
|
|
99011
99291
|
if (outDir) {
|
|
99012
|
-
const resolvedOut =
|
|
99292
|
+
const resolvedOut = path193.resolve(projectRoot, outDir);
|
|
99013
99293
|
for (const input of inputs) {
|
|
99014
99294
|
for (const named of input.golds) {
|
|
99015
99295
|
const bundle = buildEvidenceBundle({ target: input.target, system: input.system, gold: named.gold }, { ladder, goldReference: goldPathFor(named.kind), timestamp: new Date().toISOString() });
|
|
99016
|
-
const dir = await persistEvidenceBundle(
|
|
99017
|
-
console.error(`bundle[${named.kind}]: ${
|
|
99296
|
+
const dir = await persistEvidenceBundle(path193.join(resolvedOut, named.kind), bundle, ladder);
|
|
99297
|
+
console.error(`bundle[${named.kind}]: ${path193.relative(projectRoot, dir)}`);
|
|
99018
99298
|
}
|
|
99019
99299
|
}
|
|
99020
99300
|
}
|
|
@@ -99038,7 +99318,7 @@ async function runGdgraphLayer(projectRoot, args, ladder) {
|
|
|
99038
99318
|
return allValid;
|
|
99039
99319
|
}
|
|
99040
99320
|
async function loadCoverageMap2(projectRoot, file) {
|
|
99041
|
-
const raw = JSON.parse(await readFile101(
|
|
99321
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
99042
99322
|
return raw.coverageMap ?? {};
|
|
99043
99323
|
}
|
|
99044
99324
|
async function runTestingLayer(projectRoot, args, ladder) {
|
|
@@ -99075,7 +99355,7 @@ async function runTestingLayer(projectRoot, args, ladder) {
|
|
|
99075
99355
|
return result.valid;
|
|
99076
99356
|
}
|
|
99077
99357
|
async function loadMemoryGoldK(projectRoot, file) {
|
|
99078
|
-
const raw = JSON.parse(await readFile101(
|
|
99358
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
99079
99359
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 3;
|
|
99080
99360
|
}
|
|
99081
99361
|
async function runMemoryLayer(projectRoot, args, ladder) {
|
|
@@ -99112,11 +99392,11 @@ async function runMemoryLayer(projectRoot, args, ladder) {
|
|
|
99112
99392
|
return result.valid;
|
|
99113
99393
|
}
|
|
99114
99394
|
async function loadWikiGoldK(projectRoot, file) {
|
|
99115
|
-
const raw = JSON.parse(await readFile101(
|
|
99395
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
99116
99396
|
return typeof raw.k === "number" && raw.k > 0 ? raw.k : 5;
|
|
99117
99397
|
}
|
|
99118
99398
|
async function loadWikiGroundedness(projectRoot, file) {
|
|
99119
|
-
const raw = JSON.parse(await readFile101(
|
|
99399
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
99120
99400
|
const map = new Map;
|
|
99121
99401
|
for (const entry of raw.targets ?? []) {
|
|
99122
99402
|
if (typeof entry.target !== "string" || !Array.isArray(entry.scores) || entry.scores.length !== 3)
|
|
@@ -99172,7 +99452,7 @@ async function runWikiLayer(projectRoot, args, ladder) {
|
|
|
99172
99452
|
return result.valid;
|
|
99173
99453
|
}
|
|
99174
99454
|
async function loadGdctxFacts(projectRoot, file) {
|
|
99175
|
-
const raw = JSON.parse(await readFile101(
|
|
99455
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, file), "utf8"));
|
|
99176
99456
|
const inputs = [];
|
|
99177
99457
|
for (const entry of raw.inputs ?? []) {
|
|
99178
99458
|
if (typeof entry.input === "string") {
|
|
@@ -99210,7 +99490,7 @@ async function collect(projectRoot, args) {
|
|
|
99210
99490
|
process.exitCode = 1;
|
|
99211
99491
|
return;
|
|
99212
99492
|
}
|
|
99213
|
-
const raw = JSON.parse(await readFile101(
|
|
99493
|
+
const raw = JSON.parse(await readFile101(path193.resolve(projectRoot, eventFile), "utf8"));
|
|
99214
99494
|
const events = Array.isArray(raw) ? raw : raw.events;
|
|
99215
99495
|
const startedAt = optionValue(args, "--started-at") ?? events[0]?.timestamp_utc ?? new Date().toISOString();
|
|
99216
99496
|
const finishedAt = optionValue(args, "--finished-at") ?? events.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -99226,11 +99506,11 @@ async function collect(projectRoot, args) {
|
|
|
99226
99506
|
parentRunId: optionValue(args, "--parent-run-id") ?? null
|
|
99227
99507
|
});
|
|
99228
99508
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record, { cwd: projectRoot });
|
|
99229
|
-
console.log(`json: ${
|
|
99230
|
-
console.log(`markdown: ${
|
|
99509
|
+
console.log(`json: ${path193.relative(projectRoot, result.jsonPath)}`);
|
|
99510
|
+
console.log(`markdown: ${path193.relative(projectRoot, result.markdownPath)}`);
|
|
99231
99511
|
}
|
|
99232
99512
|
function metricsRoot(projectRoot) {
|
|
99233
|
-
return
|
|
99513
|
+
return path193.join(projectRoot, ".metaproject", "data", "metrics");
|
|
99234
99514
|
}
|
|
99235
99515
|
function printMetricsHelp() {
|
|
99236
99516
|
console.log(`keryx metrics
|
|
@@ -100122,6 +100402,8 @@ var CLI_ROUTES = {
|
|
|
100122
100402
|
commands: commandsCommand,
|
|
100123
100403
|
security: securityCommand,
|
|
100124
100404
|
sandbox: sandboxCommand,
|
|
100405
|
+
"serve-mcp": serveMcpCommand,
|
|
100406
|
+
integrate: integrateCommand,
|
|
100125
100407
|
mcp: mcpCommand,
|
|
100126
100408
|
harness: harnessCommand,
|
|
100127
100409
|
shell: shellCommand,
|
|
@@ -100260,10 +100542,12 @@ Usage:
|
|
|
100260
100542
|
keryx security incidents [--limit <n>]
|
|
100261
100543
|
keryx security hooks install --runtime <claude|cursor|windsurf|generic-mcp|all>
|
|
100262
100544
|
keryx security eval [--corpus <name|all>] [--with-model]
|
|
100263
|
-
keryx mcp
|
|
100545
|
+
keryx serve-mcp [--http] [--cwd <project-root>]
|
|
100546
|
+
keryx integrate [--remove] <cursor|claude|opencode|vscode|generic|all> [--dry-run]
|
|
100547
|
+
keryx mcp serve [--http] ... # retired: use keryx serve-mcp
|
|
100264
100548
|
keryx workspace create --title <title> [--component <workspace-relative-ref>]
|
|
100265
100549
|
keryx workspace list|show|add-resource
|
|
100266
|
-
keryx mcp install|uninstall --runtime
|
|
100550
|
+
keryx mcp install|uninstall --runtime ... # retired: use keryx integrate
|
|
100267
100551
|
keryx retention status [--json]
|
|
100268
100552
|
keryx retention sweep [--apply] [--target <id>]... [--max-age-days <n>] [--max-bytes <n>] [--json]
|
|
100269
100553
|
Bound gdctx raw/artifacts logs and owner write-conflict
|
|
@@ -100308,7 +100592,9 @@ Commands:
|
|
|
100308
100592
|
commands Agent-callable command registry (intents, args, output, model usage)
|
|
100309
100593
|
security Policy-based scanning, redaction, guardrails and audit reports
|
|
100310
100594
|
sandbox Report OS sandbox launcher availability and the per-capability containment matrix
|
|
100311
|
-
mcp
|
|
100595
|
+
serve-mcp Expose Metaproject services over the Model Context Protocol (opt-in)
|
|
100596
|
+
integrate Wire this project into an editor or agent as an MCP server
|
|
100597
|
+
mcp Retired spelling of serve-mcp / integrate; still works, names its replacement
|
|
100312
100598
|
metrics Provenance-aware execution observability: run records, baselines, benchmarks
|
|
100313
100599
|
workspace Shared Agent Context: workspaces, FWK reads, propose/review (module sac)
|
|
100314
100600
|
retention Bound stores that grow without bound (gdctx raw/artifacts, owner write-conflict sidecars)
|