@mrciphersmith/keryx 0.2.17 → 0.2.19
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/README.md +26 -0
- package/dist/cli.js +743 -293
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -55,9 +55,12 @@ import {
|
|
|
55
55
|
chmodSync,
|
|
56
56
|
mkdirSync,
|
|
57
57
|
readFileSync,
|
|
58
|
+
renameSync,
|
|
58
59
|
statSync,
|
|
60
|
+
unlinkSync,
|
|
59
61
|
writeFileSync
|
|
60
62
|
} from "fs";
|
|
63
|
+
import { randomUUID } from "crypto";
|
|
61
64
|
import { homedir } from "os";
|
|
62
65
|
import path from "path";
|
|
63
66
|
function keryxConfigDir(dir) {
|
|
@@ -146,6 +149,21 @@ function writeOwnerOnlyFile(file, body) {
|
|
|
146
149
|
chmodSync(file, 384);
|
|
147
150
|
} catch {}
|
|
148
151
|
}
|
|
152
|
+
function writeOwnerOnlyFileAtomic(file, body) {
|
|
153
|
+
const temporary = `${file}.${process.pid}.${randomUUID()}.tmp`;
|
|
154
|
+
try {
|
|
155
|
+
writeFileSync(temporary, body, { encoding: "utf8", mode: 384 });
|
|
156
|
+
if (process.platform !== "win32") {
|
|
157
|
+
chmodSync(temporary, 384);
|
|
158
|
+
}
|
|
159
|
+
renameSync(temporary, file);
|
|
160
|
+
} catch (cause) {
|
|
161
|
+
try {
|
|
162
|
+
unlinkSync(temporary);
|
|
163
|
+
} catch {}
|
|
164
|
+
throw cause;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
149
167
|
function ensureKeryxConfigDir(dir) {
|
|
150
168
|
const base = keryxConfigDir(dir);
|
|
151
169
|
try {
|
|
@@ -174,7 +192,7 @@ __export(exports_fs, {
|
|
|
174
192
|
pathExists: () => pathExists,
|
|
175
193
|
isPathInside: () => isPathInside
|
|
176
194
|
});
|
|
177
|
-
import { randomUUID as
|
|
195
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
178
196
|
import { access, mkdir, rename, rm, stat, writeFile } from "fs/promises";
|
|
179
197
|
import path5 from "path";
|
|
180
198
|
async function pathExists(filePath) {
|
|
@@ -195,7 +213,7 @@ function isPathInside(root, candidate) {
|
|
|
195
213
|
async function writeFileAtomic(filePath, content) {
|
|
196
214
|
const dir = path5.dirname(filePath);
|
|
197
215
|
await mkdir(dir, { recursive: true });
|
|
198
|
-
const tmp = path5.join(dir, `.${path5.basename(filePath)}.${process.pid}.${Date.now()}.${
|
|
216
|
+
const tmp = path5.join(dir, `.${path5.basename(filePath)}.${process.pid}.${Date.now()}.${randomUUID4()}.tmp`);
|
|
199
217
|
try {
|
|
200
218
|
await writeFile(tmp, content, "utf8");
|
|
201
219
|
await rename(tmp, filePath);
|
|
@@ -7819,6 +7837,12 @@ var init_gdgraph = __esm(() => {
|
|
|
7819
7837
|
});
|
|
7820
7838
|
|
|
7821
7839
|
// src/commands/providers.ts
|
|
7840
|
+
function isProviderPlatformSupported(provider, platform = process.platform) {
|
|
7841
|
+
if (provider.platforms === undefined || provider.platforms.length === 0) {
|
|
7842
|
+
return true;
|
|
7843
|
+
}
|
|
7844
|
+
return provider.platforms.includes(platform);
|
|
7845
|
+
}
|
|
7822
7846
|
function providerByName(name) {
|
|
7823
7847
|
return OPENAI_COMPAT_PROVIDERS.find((p) => p.name === name);
|
|
7824
7848
|
}
|
|
@@ -7863,7 +7887,7 @@ async function resolveModelsForPicker(fetchFn, provider, env = process.env, opts
|
|
|
7863
7887
|
return { models: [...provider.models], source: "fallback" };
|
|
7864
7888
|
}
|
|
7865
7889
|
const envKey = provider.envKey ?? compat.envKey;
|
|
7866
|
-
const raw = env[envKey];
|
|
7890
|
+
const raw = envKey === undefined ? undefined : env[envKey];
|
|
7867
7891
|
const apiKey = typeof raw === "string" && raw.length > 0 ? raw : undefined;
|
|
7868
7892
|
return fetchOpenAiCompatModelsDetailed(fetchFn, compat, apiKey, opts);
|
|
7869
7893
|
}
|
|
@@ -7938,6 +7962,16 @@ var init_providers = __esm(() => {
|
|
|
7938
7962
|
models: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant", "gpt-oss-120b"],
|
|
7939
7963
|
note: "free tier \xB7 fast"
|
|
7940
7964
|
},
|
|
7965
|
+
{
|
|
7966
|
+
name: "rapid-mlx",
|
|
7967
|
+
label: "Rapid-MLX (Local)",
|
|
7968
|
+
baseUrl: "http://127.0.0.1:8010",
|
|
7969
|
+
requiresApiKey: false,
|
|
7970
|
+
allowLoopback: true,
|
|
7971
|
+
platforms: ["darwin"],
|
|
7972
|
+
models: ["qwen3.5-9b-4bit"],
|
|
7973
|
+
note: "local \xB7 no key"
|
|
7974
|
+
},
|
|
7941
7975
|
{
|
|
7942
7976
|
name: "moonshot",
|
|
7943
7977
|
label: "Moonshot (Kimi)",
|
|
@@ -9624,18 +9658,21 @@ function makeProvider(name, _model, opts) {
|
|
|
9624
9658
|
}
|
|
9625
9659
|
const compat = providerByName(name);
|
|
9626
9660
|
if (compat !== undefined) {
|
|
9627
|
-
const
|
|
9628
|
-
|
|
9661
|
+
const needsKey = compat.requiresApiKey !== false;
|
|
9662
|
+
const apiKey = compat.envKey === undefined ? undefined : env[compat.envKey];
|
|
9663
|
+
if (needsKey && (apiKey === undefined || apiKey.length === 0)) {
|
|
9629
9664
|
return new FakeProvider([]);
|
|
9630
9665
|
}
|
|
9666
|
+
const grant = {
|
|
9667
|
+
network: true,
|
|
9668
|
+
baseUrl: opts.baseUrl ?? compat.baseUrl,
|
|
9669
|
+
...compat.allowLoopback === true ? { allowLoopback: true } : {},
|
|
9670
|
+
...compat.chatPath !== undefined ? { chatPath: compat.chatPath } : {},
|
|
9671
|
+
...apiKey !== undefined ? { apiKey } : {}
|
|
9672
|
+
};
|
|
9631
9673
|
return new OllamaProvider({
|
|
9632
9674
|
fetch: opts.fetch,
|
|
9633
|
-
grant
|
|
9634
|
-
network: true,
|
|
9635
|
-
baseUrl: opts.baseUrl ?? compat.baseUrl,
|
|
9636
|
-
apiKey,
|
|
9637
|
-
...compat.chatPath !== undefined ? { chatPath: compat.chatPath } : {}
|
|
9638
|
-
}
|
|
9675
|
+
grant
|
|
9639
9676
|
});
|
|
9640
9677
|
}
|
|
9641
9678
|
return new FakeProvider([]);
|
|
@@ -9752,13 +9789,22 @@ function hasCredential(provider, env) {
|
|
|
9752
9789
|
}
|
|
9753
9790
|
const compat = providerByName(provider);
|
|
9754
9791
|
if (compat) {
|
|
9792
|
+
if (compat.requiresApiKey === false) {
|
|
9793
|
+
return true;
|
|
9794
|
+
}
|
|
9795
|
+
if (compat.envKey === undefined) {
|
|
9796
|
+
return false;
|
|
9797
|
+
}
|
|
9755
9798
|
const key = env[compat.envKey];
|
|
9756
9799
|
return key !== undefined && key.length > 0;
|
|
9757
9800
|
}
|
|
9758
9801
|
return false;
|
|
9759
9802
|
}
|
|
9760
9803
|
function keyedProviderCandidates() {
|
|
9761
|
-
return [
|
|
9804
|
+
return [
|
|
9805
|
+
"anthropic",
|
|
9806
|
+
...OPENAI_COMPAT_PROVIDERS.filter((provider) => provider.requiresApiKey !== false).map((p) => p.name)
|
|
9807
|
+
];
|
|
9762
9808
|
}
|
|
9763
9809
|
function resolveAutoProvider(env, opts) {
|
|
9764
9810
|
if (opts?.preferSavedShell !== false) {
|
|
@@ -11146,7 +11192,7 @@ var init_search = __esm(() => {
|
|
|
11146
11192
|
});
|
|
11147
11193
|
|
|
11148
11194
|
// src/memory/report.ts
|
|
11149
|
-
import { randomUUID as
|
|
11195
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
11150
11196
|
import { access as access2, mkdir as mkdir27, readdir as readdir7, rename as rename3, rm as rm5, stat as stat4, writeFile as writeFile30 } from "fs/promises";
|
|
11151
11197
|
import path71 from "path";
|
|
11152
11198
|
function runtimeRoot(cwd) {
|
|
@@ -11306,7 +11352,7 @@ class MemoryReportStore {
|
|
|
11306
11352
|
nextRunId;
|
|
11307
11353
|
constructor(dependencies = {}) {
|
|
11308
11354
|
this.clock = dependencies.clock ?? (() => new Date);
|
|
11309
|
-
this.nextRunId = dependencies.runId ?? (() =>
|
|
11355
|
+
this.nextRunId = dependencies.runId ?? (() => randomUUID6());
|
|
11310
11356
|
}
|
|
11311
11357
|
async writeReport(input2) {
|
|
11312
11358
|
const runId = input2.runId ?? this.nextRunId();
|
|
@@ -11327,7 +11373,7 @@ class MemoryReportStore {
|
|
|
11327
11373
|
if ((await stat4(candidate)).mtimeMs <= staleBefore)
|
|
11328
11374
|
await rm5(candidate, { recursive: true, force: true });
|
|
11329
11375
|
}
|
|
11330
|
-
const staging = path71.join(tempRoot, `${runId}.${
|
|
11376
|
+
const staging = path71.join(tempRoot, `${runId}.${randomUUID6()}`);
|
|
11331
11377
|
try {
|
|
11332
11378
|
await mkdir27(staging);
|
|
11333
11379
|
await Promise.all([
|
|
@@ -12714,17 +12760,17 @@ import {
|
|
|
12714
12760
|
fsyncSync,
|
|
12715
12761
|
openSync as openSync2,
|
|
12716
12762
|
realpathSync,
|
|
12717
|
-
renameSync,
|
|
12763
|
+
renameSync as renameSync2,
|
|
12718
12764
|
statSync as statSync3,
|
|
12719
|
-
unlinkSync,
|
|
12765
|
+
unlinkSync as unlinkSync2,
|
|
12720
12766
|
writeFileSync as writeFileSync3
|
|
12721
12767
|
} from "fs";
|
|
12722
12768
|
import path3 from "path";
|
|
12723
|
-
import { randomUUID as
|
|
12769
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
12724
12770
|
|
|
12725
12771
|
// src/lib/file-lock.ts
|
|
12726
12772
|
import { closeSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync2, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
12727
|
-
import { randomUUID } from "crypto";
|
|
12773
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
12728
12774
|
import path2 from "path";
|
|
12729
12775
|
var LOCK_STALE_MS = 1e4;
|
|
12730
12776
|
var LOCK_TIMEOUT_MS = 15000;
|
|
@@ -12743,7 +12789,7 @@ function withFileLock(lockPath, fn, options = {}) {
|
|
|
12743
12789
|
} catch {
|
|
12744
12790
|
return null;
|
|
12745
12791
|
}
|
|
12746
|
-
const nonce =
|
|
12792
|
+
const nonce = randomUUID2();
|
|
12747
12793
|
const started = Date.now();
|
|
12748
12794
|
const deadline = started + LOCK_TIMEOUT_MS;
|
|
12749
12795
|
let handle = null;
|
|
@@ -12925,7 +12971,7 @@ function quarantineDamagedRegistry(dir, onWarn) {
|
|
|
12925
12971
|
}
|
|
12926
12972
|
function saveProjectRegistry(registry, dir, onWarn) {
|
|
12927
12973
|
const file = projectRegistryPath(dir);
|
|
12928
|
-
const temp = `${file}.${
|
|
12974
|
+
const temp = `${file}.${randomUUID3()}.tmp`;
|
|
12929
12975
|
try {
|
|
12930
12976
|
ensureKeryxConfigDir(dir);
|
|
12931
12977
|
const sorted = {
|
|
@@ -12940,11 +12986,11 @@ function saveProjectRegistry(registry, dir, onWarn) {
|
|
|
12940
12986
|
} finally {
|
|
12941
12987
|
closeSync2(handle);
|
|
12942
12988
|
}
|
|
12943
|
-
|
|
12989
|
+
renameSync2(temp, file);
|
|
12944
12990
|
return true;
|
|
12945
12991
|
} catch {
|
|
12946
12992
|
try {
|
|
12947
|
-
|
|
12993
|
+
unlinkSync2(temp);
|
|
12948
12994
|
} catch {}
|
|
12949
12995
|
return false;
|
|
12950
12996
|
}
|
|
@@ -12981,7 +13027,7 @@ function registerProject(projectPath, options = {}) {
|
|
|
12981
13027
|
return { ok: true, entry: existing, created: false };
|
|
12982
13028
|
}
|
|
12983
13029
|
const entry = {
|
|
12984
|
-
projectId:
|
|
13030
|
+
projectId: randomUUID3(),
|
|
12985
13031
|
path: absolute,
|
|
12986
13032
|
displayName: options.displayName ?? path3.basename(absolute),
|
|
12987
13033
|
state: "active",
|
|
@@ -13694,7 +13740,7 @@ function sessionDir(projectPath, sessionId, dataDir) {
|
|
|
13694
13740
|
|
|
13695
13741
|
// src/harness/process/sandbox/network-run.ts
|
|
13696
13742
|
import { Worker } from "worker_threads";
|
|
13697
|
-
import { randomUUID as
|
|
13743
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
13698
13744
|
import { existsSync as existsSync3 } from "fs";
|
|
13699
13745
|
import { rm as rm2, writeFile as writeFile3 } from "fs/promises";
|
|
13700
13746
|
import { fileURLToPath } from "url";
|
|
@@ -13789,7 +13835,7 @@ async function setupNetworkRun(profile, options = {}) {
|
|
|
13789
13835
|
for (const cred of options.masks ?? []) {
|
|
13790
13836
|
if (cred.realValue.length === 0)
|
|
13791
13837
|
continue;
|
|
13792
|
-
const sentinel = `keryx-sentinel-${
|
|
13838
|
+
const sentinel = `keryx-sentinel-${randomUUID5()}`;
|
|
13793
13839
|
maskedEnv[cred.name] = sentinel;
|
|
13794
13840
|
proxyMasks.push({ sentinel, realValue: cred.realValue, injectHosts: cred.injectHosts });
|
|
13795
13841
|
}
|
|
@@ -13799,7 +13845,7 @@ async function setupNetworkRun(profile, options = {}) {
|
|
|
13799
13845
|
const trustEnv = {};
|
|
13800
13846
|
let caPemPath;
|
|
13801
13847
|
if (tlsTerminate && caCertPem) {
|
|
13802
|
-
caPemPath = path9.join(tmpdir(), `keryx-run-ca-${
|
|
13848
|
+
caPemPath = path9.join(tmpdir(), `keryx-run-ca-${randomUUID5()}.pem`);
|
|
13803
13849
|
await writeFile3(caPemPath, caCertPem, { mode: 420 });
|
|
13804
13850
|
trustEnv.SSL_CERT_FILE = caPemPath;
|
|
13805
13851
|
trustEnv.CURL_CA_BUNDLE = caPemPath;
|
|
@@ -17192,7 +17238,8 @@ function renderIndexMarkdown({
|
|
|
17192
17238
|
"First choose the capability: graph/navigation, compact context, wiki/domain knowledge, memory, testing, health, security, skills/orchestration, or flow lifecycle.",
|
|
17193
17239
|
"If the same capability is available through MCP tools/resources, prefer MCP because it preserves structured inputs and outputs. If MCP is unavailable, use the module skill and `keryx` CLI fallback.",
|
|
17194
17240
|
"Load the narrowest relevant skill/rule before reading broad source files. Do not ask the user which internal command to run unless multiple user-level outcomes are genuinely possible.",
|
|
17195
|
-
"When reporting results, name the Metaproject sources used at a high level (for example: graph, wiki, memory, health), not every internal command."
|
|
17241
|
+
"When reporting results, name the Metaproject sources used at a high level (for example: graph, wiki, memory, health), not every internal command.",
|
|
17242
|
+
"Once per session, run `keryx version check --json`. Notify the user only when the result is `update-available`; this is an advisory and never installs anything. A timeout, offline registry, `unavailable`, or `unknown-command` result is non-blocking: never block project work on the check."
|
|
17196
17243
|
].map((item) => `- ${item}`).join(`
|
|
17197
17244
|
`);
|
|
17198
17245
|
const intentRows = [
|
|
@@ -32023,6 +32070,15 @@ var COMMAND_DESCRIPTORS = [
|
|
|
32023
32070
|
args: [{ name: "json", type: "bool", required: false, desc: "structured module state" }],
|
|
32024
32071
|
json: true,
|
|
32025
32072
|
read: true
|
|
32073
|
+
},
|
|
32074
|
+
{
|
|
32075
|
+
module: "core",
|
|
32076
|
+
command: "version check",
|
|
32077
|
+
summary: "Check the fixed npm latest endpoint for a newer Keryx release.",
|
|
32078
|
+
intent: ["check keryx version", "check for update", "\u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0432\u0435\u0440\u0441\u0438\u044E keryx"],
|
|
32079
|
+
args: [{ name: "json", type: "bool", required: false, desc: "typed structured result" }],
|
|
32080
|
+
json: true,
|
|
32081
|
+
read: true
|
|
32026
32082
|
}
|
|
32027
32083
|
];
|
|
32028
32084
|
function sortKey(descriptor) {
|
|
@@ -34743,7 +34799,7 @@ Reports the workspace root and one enabled/disabled line per module. Use
|
|
|
34743
34799
|
// src/commands/harness.ts
|
|
34744
34800
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
34745
34801
|
import path118 from "path";
|
|
34746
|
-
import { randomUUID as
|
|
34802
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
34747
34803
|
|
|
34748
34804
|
// src/security/harness-scan.ts
|
|
34749
34805
|
init_guard();
|
|
@@ -36427,6 +36483,9 @@ function projectPolicyTrusted(env) {
|
|
|
36427
36483
|
function buildDefaultMaskProviders(openaiCompat) {
|
|
36428
36484
|
const out = [];
|
|
36429
36485
|
for (const p of openaiCompat) {
|
|
36486
|
+
if (p.envKey === undefined) {
|
|
36487
|
+
continue;
|
|
36488
|
+
}
|
|
36430
36489
|
out.push({ envKey: p.envKey, baseUrl: p.baseUrl });
|
|
36431
36490
|
}
|
|
36432
36491
|
out.push({ envKey: "ANTHROPIC_API_KEY", baseUrl: "https://api.anthropic.com" });
|
|
@@ -37069,6 +37128,13 @@ function checkApproval(input2) {
|
|
|
37069
37128
|
}
|
|
37070
37129
|
|
|
37071
37130
|
// src/commands/harness.ts
|
|
37131
|
+
var HARNESS_PROVIDER_OPTIONS = [
|
|
37132
|
+
"fake",
|
|
37133
|
+
"anthropic",
|
|
37134
|
+
"ollama",
|
|
37135
|
+
...OPENAI_COMPAT_PROVIDERS.map((provider) => provider.name)
|
|
37136
|
+
];
|
|
37137
|
+
var HARNESS_PROVIDER_USAGE = `Usage: keryx harness run --provider <${HARNESS_PROVIDER_OPTIONS.join("|")}> --model <m> [--base-url <url>] "<prompt>"`;
|
|
37072
37138
|
function canonicalPath(p) {
|
|
37073
37139
|
try {
|
|
37074
37140
|
return realpathSync3(p);
|
|
@@ -37093,14 +37159,14 @@ function resolveRuntime(deps) {
|
|
|
37093
37159
|
const env = deps?.env ?? process.env;
|
|
37094
37160
|
const clock = deps?.clock ?? (() => new Date().toISOString());
|
|
37095
37161
|
let idCounter = 0;
|
|
37096
|
-
const idSeq = deps?.idSeq ?? (() => `${
|
|
37162
|
+
const idSeq = deps?.idSeq ?? (() => `${randomUUID7()}-${idCounter++}`);
|
|
37097
37163
|
return { env, clock, idSeq };
|
|
37098
37164
|
}
|
|
37099
37165
|
function shellAllowProfile() {
|
|
37100
37166
|
return resolveLocalProfile("monitored-trusted-local");
|
|
37101
37167
|
}
|
|
37102
37168
|
var USAGE = [
|
|
37103
|
-
|
|
37169
|
+
HARNESS_PROVIDER_USAGE,
|
|
37104
37170
|
" keryx harness exec [--allow-env KEY]... [--max-runtime-ms N] [--allow-real-subprocess]",
|
|
37105
37171
|
" [--allowed-domains a,b] [--mask-env NAME@host] [--tls-terminate] [--mask-mode auto|manual|off] [--auto-mask]",
|
|
37106
37172
|
" -- <path> [args...]",
|
|
@@ -37176,7 +37242,7 @@ async function harnessCommand(args, deps) {
|
|
|
37176
37242
|
return;
|
|
37177
37243
|
}
|
|
37178
37244
|
const { provider, model, baseUrl, prompt, record } = parseArgs2(args);
|
|
37179
|
-
const validProviders = new Set(
|
|
37245
|
+
const validProviders = new Set(HARNESS_PROVIDER_OPTIONS);
|
|
37180
37246
|
if (!validProviders.has(provider) || prompt.length === 0) {
|
|
37181
37247
|
console.log(USAGE);
|
|
37182
37248
|
return;
|
|
@@ -37184,7 +37250,7 @@ async function harnessCommand(args, deps) {
|
|
|
37184
37250
|
const env = deps?.env ?? process.env;
|
|
37185
37251
|
const clock = deps?.clock ?? (() => new Date().toISOString());
|
|
37186
37252
|
let idCounter = 0;
|
|
37187
|
-
const idSeq = deps?.idSeq ?? (() => `${
|
|
37253
|
+
const idSeq = deps?.idSeq ?? (() => `${randomUUID7()}-${idCounter++}`);
|
|
37188
37254
|
const fetchImpl = deps?.fetch ?? globalThis.fetch;
|
|
37189
37255
|
if (provider === "anthropic") {
|
|
37190
37256
|
const apiKey = env.ANTHROPIC_API_KEY;
|
|
@@ -37301,7 +37367,7 @@ function harnessReplay(args, deps) {
|
|
|
37301
37367
|
}
|
|
37302
37368
|
const clock = deps?.clock ?? (() => new Date().toISOString());
|
|
37303
37369
|
let idCounter = 0;
|
|
37304
|
-
const idSeq = deps?.idSeq ?? (() => `${
|
|
37370
|
+
const idSeq = deps?.idSeq ?? (() => `${randomUUID7()}-${idCounter++}`);
|
|
37305
37371
|
const fixture = (() => {
|
|
37306
37372
|
if (parsed.fixture === undefined || parsed.fixture.length === 0) {
|
|
37307
37373
|
return { ok: true, value: buildReplayFixture(run, { idSeq }), built: true };
|
|
@@ -37741,7 +37807,7 @@ function harnessWave(args, deps) {
|
|
|
37741
37807
|
// src/commands/shell.ts
|
|
37742
37808
|
init_make_provider();
|
|
37743
37809
|
init_orient();
|
|
37744
|
-
import { randomUUID as
|
|
37810
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
37745
37811
|
import * as readline2 from "readline";
|
|
37746
37812
|
|
|
37747
37813
|
// src/harness/tool/builtin/ask-user-tool.ts
|
|
@@ -38385,7 +38451,7 @@ function shellExecTool(root, run = makeCommandRunner(root)) {
|
|
|
38385
38451
|
}
|
|
38386
38452
|
|
|
38387
38453
|
// src/harness/tool/builtin/spawn-subagent-tool.ts
|
|
38388
|
-
import { createHash as createHash17, randomUUID as
|
|
38454
|
+
import { createHash as createHash17, randomUUID as randomUUID8 } from "crypto";
|
|
38389
38455
|
|
|
38390
38456
|
// src/harness/child/ledger.ts
|
|
38391
38457
|
function decrement(remaining, reservation) {
|
|
@@ -39501,7 +39567,7 @@ function sha2565(text) {
|
|
|
39501
39567
|
var parentShellPolicy = shellParentProfile;
|
|
39502
39568
|
var childReadOnlyPolicy = shellChildReadOnlyProfile;
|
|
39503
39569
|
function createSpawnSubagentTool(deps) {
|
|
39504
|
-
const idSeq = deps.idSeq ?? (() =>
|
|
39570
|
+
const idSeq = deps.idSeq ?? (() => randomUUID8());
|
|
39505
39571
|
const clock = deps.clock ?? (() => new Date().toISOString());
|
|
39506
39572
|
const parentRunId = deps.parentRunId ?? idSeq();
|
|
39507
39573
|
const parentSessionId = deps.parentSessionId ?? idSeq();
|
|
@@ -40350,11 +40416,11 @@ import {
|
|
|
40350
40416
|
existsSync as existsSync23,
|
|
40351
40417
|
mkdirSync as mkdirSync6,
|
|
40352
40418
|
readdirSync,
|
|
40353
|
-
renameSync as
|
|
40419
|
+
renameSync as renameSync3,
|
|
40354
40420
|
writeFileSync as writeFileSync7
|
|
40355
40421
|
} from "fs";
|
|
40356
40422
|
import path120 from "path";
|
|
40357
|
-
import { randomUUID as
|
|
40423
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
40358
40424
|
var SESSION_SCHEMA_VERSION = 1;
|
|
40359
40425
|
function nowIso() {
|
|
40360
40426
|
return new Date().toISOString();
|
|
@@ -40393,7 +40459,7 @@ function tighten(target) {
|
|
|
40393
40459
|
function atomicWriteText(file, body) {
|
|
40394
40460
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
40395
40461
|
writeFileSync7(tmp, body, { encoding: "utf8", mode: 384 });
|
|
40396
|
-
|
|
40462
|
+
renameSync3(tmp, file);
|
|
40397
40463
|
}
|
|
40398
40464
|
function atomicWriteJson(file, value) {
|
|
40399
40465
|
atomicWriteText(file, `${JSON.stringify(value, null, 2)}
|
|
@@ -40501,7 +40567,7 @@ function readJsonl2(file) {
|
|
|
40501
40567
|
function createSession(opts) {
|
|
40502
40568
|
const projectPath = resolveProjectRoot(opts.cwd);
|
|
40503
40569
|
const projectKey2 = projectKeyFromPath(projectPath);
|
|
40504
|
-
const id = opts.id ??
|
|
40570
|
+
const id = opts.id ?? randomUUID9();
|
|
40505
40571
|
const dir = sessionDir(projectPath, id, opts.dataDir);
|
|
40506
40572
|
ensureDir(dir, opts.dataDir);
|
|
40507
40573
|
const ts = nowIso();
|
|
@@ -40944,6 +41010,279 @@ function showComposerChoice(otui, r, dock, request) {
|
|
|
40944
41010
|
});
|
|
40945
41011
|
}
|
|
40946
41012
|
|
|
41013
|
+
// src/lib/version-check.ts
|
|
41014
|
+
init_config_dir();
|
|
41015
|
+
init_fs();
|
|
41016
|
+
import path121 from "path";
|
|
41017
|
+
var REGISTRY_URL = "https://registry.npmjs.org/@mrciphersmith%2Fkeryx/latest";
|
|
41018
|
+
var FIXED_INSTALL_COMMAND = "npm install -g @mrciphersmith/keryx@latest";
|
|
41019
|
+
var RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
|
|
41020
|
+
var VERSION_STRING_LIMIT_CHARS = 64;
|
|
41021
|
+
var REQUEST_TIMEOUT_MS = 2000;
|
|
41022
|
+
var SUCCESS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
41023
|
+
var FAILURE_BACKOFF_MS = 15 * 60 * 1000;
|
|
41024
|
+
var CACHE_LOCK_TIMEOUT_MS = 250;
|
|
41025
|
+
var CACHE_LOCK_RETRY_MS = 10;
|
|
41026
|
+
var CACHE_LOCK_STALE_MS = 5000;
|
|
41027
|
+
var SYSTEM_TIMER = {
|
|
41028
|
+
schedule: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
41029
|
+
cancel: (handle) => clearTimeout(handle)
|
|
41030
|
+
};
|
|
41031
|
+
function formatVersionUpdateAdvisory(result) {
|
|
41032
|
+
if (result.status !== "update-available")
|
|
41033
|
+
return;
|
|
41034
|
+
return `Keryx update ${result.currentVersion} \u2192 ${result.latestVersion}
|
|
41035
|
+
${result.installCommand}`;
|
|
41036
|
+
}
|
|
41037
|
+
var STRICT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
41038
|
+
function parseSemVer(value) {
|
|
41039
|
+
if (value.length > VERSION_STRING_LIMIT_CHARS)
|
|
41040
|
+
return;
|
|
41041
|
+
const match = STRICT_SEMVER.exec(value);
|
|
41042
|
+
if (match === null)
|
|
41043
|
+
return;
|
|
41044
|
+
const prereleaseText = match[4];
|
|
41045
|
+
const prerelease = [];
|
|
41046
|
+
if (prereleaseText !== undefined) {
|
|
41047
|
+
for (const identifier of prereleaseText.split(".")) {
|
|
41048
|
+
if (/^\d+$/.test(identifier)) {
|
|
41049
|
+
if (identifier.length > 1 && identifier.startsWith("0"))
|
|
41050
|
+
return;
|
|
41051
|
+
prerelease.push(BigInt(identifier));
|
|
41052
|
+
} else {
|
|
41053
|
+
prerelease.push(identifier);
|
|
41054
|
+
}
|
|
41055
|
+
}
|
|
41056
|
+
}
|
|
41057
|
+
return {
|
|
41058
|
+
major: BigInt(match[1]),
|
|
41059
|
+
minor: BigInt(match[2]),
|
|
41060
|
+
patch: BigInt(match[3]),
|
|
41061
|
+
prerelease
|
|
41062
|
+
};
|
|
41063
|
+
}
|
|
41064
|
+
function compareSemVer(left, right) {
|
|
41065
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
41066
|
+
if (left[key] < right[key])
|
|
41067
|
+
return -1;
|
|
41068
|
+
if (left[key] > right[key])
|
|
41069
|
+
return 1;
|
|
41070
|
+
}
|
|
41071
|
+
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
41072
|
+
if (left.prerelease.length === right.prerelease.length)
|
|
41073
|
+
return 0;
|
|
41074
|
+
return left.prerelease.length === 0 ? 1 : -1;
|
|
41075
|
+
}
|
|
41076
|
+
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
41077
|
+
for (let index = 0;index < length; index += 1) {
|
|
41078
|
+
const a = left.prerelease[index];
|
|
41079
|
+
const b = right.prerelease[index];
|
|
41080
|
+
if (a === undefined || b === undefined) {
|
|
41081
|
+
if (a === b)
|
|
41082
|
+
return 0;
|
|
41083
|
+
return a === undefined ? -1 : 1;
|
|
41084
|
+
}
|
|
41085
|
+
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
41086
|
+
if (a < b)
|
|
41087
|
+
return -1;
|
|
41088
|
+
if (a > b)
|
|
41089
|
+
return 1;
|
|
41090
|
+
} else if (typeof a === "bigint") {
|
|
41091
|
+
return -1;
|
|
41092
|
+
} else if (typeof b === "bigint") {
|
|
41093
|
+
return 1;
|
|
41094
|
+
} else if (a !== b) {
|
|
41095
|
+
return a < b ? -1 : 1;
|
|
41096
|
+
}
|
|
41097
|
+
}
|
|
41098
|
+
return 0;
|
|
41099
|
+
}
|
|
41100
|
+
function parseCache(file) {
|
|
41101
|
+
const read = readConfigFile(file);
|
|
41102
|
+
if (!read.ok)
|
|
41103
|
+
return;
|
|
41104
|
+
try {
|
|
41105
|
+
const value = JSON.parse(read.text);
|
|
41106
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
41107
|
+
return;
|
|
41108
|
+
const record = value;
|
|
41109
|
+
const cache = {};
|
|
41110
|
+
if (typeof record.latestVersion === "string" && parseSemVer(record.latestVersion) !== undefined) {
|
|
41111
|
+
cache.latestVersion = record.latestVersion;
|
|
41112
|
+
}
|
|
41113
|
+
if (typeof record.successAt === "number" && Number.isFinite(record.successAt))
|
|
41114
|
+
cache.successAt = record.successAt;
|
|
41115
|
+
if (typeof record.failureAt === "number" && Number.isFinite(record.failureAt))
|
|
41116
|
+
cache.failureAt = record.failureAt;
|
|
41117
|
+
return cache;
|
|
41118
|
+
} catch {
|
|
41119
|
+
return;
|
|
41120
|
+
}
|
|
41121
|
+
}
|
|
41122
|
+
function resultFor(currentVersion, current, latestVersion, source) {
|
|
41123
|
+
const latest2 = parseSemVer(latestVersion);
|
|
41124
|
+
return compareSemVer(current, latest2) < 0 ? { status: "update-available", currentVersion, latestVersion, installCommand: FIXED_INSTALL_COMMAND, source } : { status: "up-to-date", currentVersion, latestVersion, source };
|
|
41125
|
+
}
|
|
41126
|
+
function cancelWithoutWaiting(cancel) {
|
|
41127
|
+
try {
|
|
41128
|
+
cancel().catch(() => {});
|
|
41129
|
+
} catch {}
|
|
41130
|
+
}
|
|
41131
|
+
async function boundedResponseText(response) {
|
|
41132
|
+
const declared = response.headers.get("content-length");
|
|
41133
|
+
if (declared !== null && /^\d+$/.test(declared) && BigInt(declared) > BigInt(RESPONSE_BODY_LIMIT_BYTES)) {
|
|
41134
|
+
if (response.body !== null) {
|
|
41135
|
+
cancelWithoutWaiting(() => response.body.cancel());
|
|
41136
|
+
}
|
|
41137
|
+
return;
|
|
41138
|
+
}
|
|
41139
|
+
if (response.body === null)
|
|
41140
|
+
return "";
|
|
41141
|
+
const reader = response.body.getReader();
|
|
41142
|
+
const decoder = new TextDecoder;
|
|
41143
|
+
let size = 0;
|
|
41144
|
+
let text = "";
|
|
41145
|
+
try {
|
|
41146
|
+
for (;; ) {
|
|
41147
|
+
const chunk = await reader.read();
|
|
41148
|
+
if (chunk.done)
|
|
41149
|
+
break;
|
|
41150
|
+
size += chunk.value.byteLength;
|
|
41151
|
+
if (size > RESPONSE_BODY_LIMIT_BYTES) {
|
|
41152
|
+
cancelWithoutWaiting(() => reader.cancel());
|
|
41153
|
+
return;
|
|
41154
|
+
}
|
|
41155
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
41156
|
+
}
|
|
41157
|
+
return text + decoder.decode();
|
|
41158
|
+
} finally {
|
|
41159
|
+
reader.releaseLock();
|
|
41160
|
+
}
|
|
41161
|
+
}
|
|
41162
|
+
function unavailable(currentVersion, reason, cache) {
|
|
41163
|
+
return {
|
|
41164
|
+
status: "unavailable",
|
|
41165
|
+
currentVersion,
|
|
41166
|
+
reason,
|
|
41167
|
+
...cache?.latestVersion !== undefined ? { cachedLatestVersion: cache.latestVersion } : {}
|
|
41168
|
+
};
|
|
41169
|
+
}
|
|
41170
|
+
function saveCache(file, cache) {
|
|
41171
|
+
try {
|
|
41172
|
+
writeOwnerOnlyFileAtomic(file, `${JSON.stringify(cache, null, 2)}
|
|
41173
|
+
`);
|
|
41174
|
+
return true;
|
|
41175
|
+
} catch {
|
|
41176
|
+
return false;
|
|
41177
|
+
}
|
|
41178
|
+
}
|
|
41179
|
+
function mergeSuccessfulCache(committed, latestVersion, successAt) {
|
|
41180
|
+
if (committed.latestVersion === undefined || committed.successAt === undefined) {
|
|
41181
|
+
return { latestVersion, successAt };
|
|
41182
|
+
}
|
|
41183
|
+
if (committed.successAt > successAt)
|
|
41184
|
+
return committed;
|
|
41185
|
+
if (committed.successAt < successAt)
|
|
41186
|
+
return { latestVersion, successAt };
|
|
41187
|
+
const committedVersion = parseSemVer(committed.latestVersion);
|
|
41188
|
+
const candidateVersion = parseSemVer(latestVersion);
|
|
41189
|
+
if (committedVersion !== undefined && candidateVersion !== undefined) {
|
|
41190
|
+
const precedence = compareSemVer(committedVersion, candidateVersion);
|
|
41191
|
+
if (precedence > 0)
|
|
41192
|
+
return committed;
|
|
41193
|
+
if (precedence < 0)
|
|
41194
|
+
return { latestVersion, successAt };
|
|
41195
|
+
if (committed.latestVersion >= latestVersion)
|
|
41196
|
+
return committed;
|
|
41197
|
+
}
|
|
41198
|
+
return { latestVersion, successAt };
|
|
41199
|
+
}
|
|
41200
|
+
async function updateCache(file, update) {
|
|
41201
|
+
try {
|
|
41202
|
+
return await withFileLock2(`${file}.lock`, async () => saveCache(file, update(parseCache(file) ?? {})), {
|
|
41203
|
+
timeoutMs: CACHE_LOCK_TIMEOUT_MS,
|
|
41204
|
+
retryMs: CACHE_LOCK_RETRY_MS,
|
|
41205
|
+
staleMs: CACHE_LOCK_STALE_MS
|
|
41206
|
+
});
|
|
41207
|
+
} catch {
|
|
41208
|
+
return false;
|
|
41209
|
+
}
|
|
41210
|
+
}
|
|
41211
|
+
async function checkVersion(options) {
|
|
41212
|
+
const current = parseSemVer(options.currentVersion);
|
|
41213
|
+
if (current === undefined)
|
|
41214
|
+
return unavailable(options.currentVersion, "invalid-current-version");
|
|
41215
|
+
const now = options.now ?? Date.now;
|
|
41216
|
+
const timestamp = now();
|
|
41217
|
+
const configDir = ensureKeryxConfigDir(options.cacheDir);
|
|
41218
|
+
const cacheFile = path121.join(configDir, "version-check.json");
|
|
41219
|
+
const cache = parseCache(cacheFile);
|
|
41220
|
+
if (cache?.latestVersion !== undefined && cache.successAt !== undefined && timestamp - cache.successAt >= 0 && timestamp - cache.successAt < SUCCESS_CACHE_TTL_MS) {
|
|
41221
|
+
return resultFor(options.currentVersion, current, cache.latestVersion, "cache");
|
|
41222
|
+
}
|
|
41223
|
+
if (cache?.failureAt !== undefined && timestamp - cache.failureAt >= 0 && timestamp - cache.failureAt < FAILURE_BACKOFF_MS) {
|
|
41224
|
+
return unavailable(options.currentVersion, "suppressed", cache);
|
|
41225
|
+
}
|
|
41226
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
41227
|
+
const controller = new AbortController;
|
|
41228
|
+
const timer = options.timer ?? SYSTEM_TIMER;
|
|
41229
|
+
let timeout;
|
|
41230
|
+
let timeoutScheduled = false;
|
|
41231
|
+
let failure;
|
|
41232
|
+
let latestVersion;
|
|
41233
|
+
try {
|
|
41234
|
+
timeout = timer.schedule(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
41235
|
+
timeoutScheduled = true;
|
|
41236
|
+
const response = await fetchImpl(REGISTRY_URL, {
|
|
41237
|
+
method: "GET",
|
|
41238
|
+
headers: { accept: "application/json" },
|
|
41239
|
+
signal: controller.signal,
|
|
41240
|
+
credentials: "omit"
|
|
41241
|
+
});
|
|
41242
|
+
if (!response.ok) {
|
|
41243
|
+
failure = "http";
|
|
41244
|
+
} else {
|
|
41245
|
+
const body = await boundedResponseText(response);
|
|
41246
|
+
if (body === undefined) {
|
|
41247
|
+
failure = "response-too-large";
|
|
41248
|
+
} else {
|
|
41249
|
+
let parsed;
|
|
41250
|
+
try {
|
|
41251
|
+
parsed = JSON.parse(body);
|
|
41252
|
+
} catch {
|
|
41253
|
+
parsed = undefined;
|
|
41254
|
+
}
|
|
41255
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
41256
|
+
failure = "malformed-response";
|
|
41257
|
+
} else {
|
|
41258
|
+
const record = parsed;
|
|
41259
|
+
if (record.name !== "@mrciphersmith/keryx" || typeof record.version !== "string") {
|
|
41260
|
+
failure = "malformed-response";
|
|
41261
|
+
} else if (parseSemVer(record.version) === undefined) {
|
|
41262
|
+
failure = "invalid-latest-version";
|
|
41263
|
+
} else {
|
|
41264
|
+
latestVersion = record.version;
|
|
41265
|
+
}
|
|
41266
|
+
}
|
|
41267
|
+
}
|
|
41268
|
+
}
|
|
41269
|
+
} catch {
|
|
41270
|
+
failure = controller.signal.aborted ? "timeout" : "network";
|
|
41271
|
+
} finally {
|
|
41272
|
+
if (timeoutScheduled) {
|
|
41273
|
+
try {
|
|
41274
|
+
timer.cancel(timeout);
|
|
41275
|
+
} catch {}
|
|
41276
|
+
}
|
|
41277
|
+
}
|
|
41278
|
+
if (latestVersion === undefined) {
|
|
41279
|
+
await updateCache(cacheFile, (committed) => ({ ...committed, failureAt: timestamp }));
|
|
41280
|
+
return unavailable(options.currentVersion, failure ?? "network", cache);
|
|
41281
|
+
}
|
|
41282
|
+
await updateCache(cacheFile, (committed) => mergeSuccessfulCache(committed, latestVersion, timestamp));
|
|
41283
|
+
return resultFor(options.currentVersion, current, latestVersion, "registry");
|
|
41284
|
+
}
|
|
41285
|
+
|
|
40947
41286
|
// src/tui/shell-chrome.ts
|
|
40948
41287
|
function onKeypress2(r, handler) {
|
|
40949
41288
|
r._internalKeyInput.onInternal("keypress", handler);
|
|
@@ -40957,6 +41296,14 @@ var SIDEBAR_BORDER_LEFT = 1;
|
|
|
40957
41296
|
var SIDEBAR_PADDING_LEFT = 2;
|
|
40958
41297
|
var SIDEBAR_PADDING_RIGHT = 1;
|
|
40959
41298
|
var SIDEBAR_TEXT_WIDTH = SIDEBAR_WIDTH - SIDEBAR_BORDER_LEFT - SIDEBAR_PADDING_LEFT - SIDEBAR_PADDING_RIGHT;
|
|
41299
|
+
function formatSidebarVersionUpdateAdvisory(result) {
|
|
41300
|
+
const advisory = formatVersionUpdateAdvisory(result);
|
|
41301
|
+
if (advisory === undefined || result.status !== "update-available")
|
|
41302
|
+
return;
|
|
41303
|
+
const split = Math.ceil(result.installCommand.length / 2);
|
|
41304
|
+
return advisory.replace(result.installCommand, `${result.installCommand.slice(0, split)}
|
|
41305
|
+
${result.installCommand.slice(split)}`);
|
|
41306
|
+
}
|
|
40960
41307
|
var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
40961
41308
|
var SPINNER_MS = 120;
|
|
40962
41309
|
var TOAST_MS = 5000;
|
|
@@ -40986,6 +41333,7 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
40986
41333
|
const toastMs = opts.toastMs ?? TOAST_MS;
|
|
40987
41334
|
const filter = opts.filterCommands ?? ((query) => prefixFilter(opts.commands, query));
|
|
40988
41335
|
let uid = 0;
|
|
41336
|
+
let alive = true;
|
|
40989
41337
|
const rootRow = new otui.BoxRenderable(r, { id: "root-row", flexGrow: 1, flexDirection: "row" });
|
|
40990
41338
|
r.root.add(rootRow);
|
|
40991
41339
|
const main = new otui.BoxRenderable(r, { id: "main", flexGrow: 1, minWidth: 0, flexDirection: "column" });
|
|
@@ -41004,6 +41352,21 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
41004
41352
|
rootRow.add(sidebar);
|
|
41005
41353
|
const sidebarTop = new otui.BoxRenderable(r, { id: "sb-top", flexShrink: 0, flexDirection: "column" });
|
|
41006
41354
|
sidebar.add(sidebarTop);
|
|
41355
|
+
if (opts.versionCheck !== undefined) {
|
|
41356
|
+
const versionNotice = new otui.TextRenderable(r, {
|
|
41357
|
+
id: `sb-version-${uid++}`,
|
|
41358
|
+
content: ""
|
|
41359
|
+
});
|
|
41360
|
+
sidebarTop.add(versionNotice);
|
|
41361
|
+
opts.versionCheck.then((result) => {
|
|
41362
|
+
const advisory = formatSidebarVersionUpdateAdvisory(result);
|
|
41363
|
+
if (!alive || advisory === undefined)
|
|
41364
|
+
return;
|
|
41365
|
+
try {
|
|
41366
|
+
versionNotice.content = otui.t`${otui.yellow(advisory)}`;
|
|
41367
|
+
} catch {}
|
|
41368
|
+
}, () => {});
|
|
41369
|
+
}
|
|
41007
41370
|
const sidebarSpacer = new otui.BoxRenderable(r, { id: "sb-spacer", flexGrow: 1 });
|
|
41008
41371
|
sidebar.add(sidebarSpacer);
|
|
41009
41372
|
const toastText = new otui.TextRenderable(r, { id: "sb-toast", content: "" });
|
|
@@ -41384,6 +41747,7 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
41384
41747
|
};
|
|
41385
41748
|
},
|
|
41386
41749
|
destroy: () => {
|
|
41750
|
+
alive = false;
|
|
41387
41751
|
clearBusyTimer();
|
|
41388
41752
|
clearToastTimer();
|
|
41389
41753
|
unsubscribeMenuKeys();
|
|
@@ -42847,7 +43211,8 @@ async function launchTuiAgentShell(opts) {
|
|
|
42847
43211
|
placeholder: "type a task or / for commands \xB7 Enter send \xB7 Shift+Enter newline",
|
|
42848
43212
|
commands: commandsForMode("agent"),
|
|
42849
43213
|
headerMeta: "\u21910 \u21930",
|
|
42850
|
-
filterCommands: (query) => filterCommands(query, "agent")
|
|
43214
|
+
filterCommands: (query) => filterCommands(query, "agent"),
|
|
43215
|
+
...opts.versionCheck !== undefined ? { versionCheck: opts.versionCheck } : {}
|
|
42851
43216
|
});
|
|
42852
43217
|
mountedChrome = chrome;
|
|
42853
43218
|
const transcript = chrome.transcript;
|
|
@@ -43905,7 +44270,8 @@ async function mountChatShell(otui, renderer, opts) {
|
|
|
43905
44270
|
placeholder: "type a message or / for commands \xB7 Enter send \xB7 Shift+Enter newline",
|
|
43906
44271
|
commands: commandsForMode("chat"),
|
|
43907
44272
|
headerMeta: "~0",
|
|
43908
|
-
filterCommands: (query) => filterCommands(query, "chat")
|
|
44273
|
+
filterCommands: (query) => filterCommands(query, "chat"),
|
|
44274
|
+
...opts.versionCheck !== undefined ? { versionCheck: opts.versionCheck } : {}
|
|
43909
44275
|
});
|
|
43910
44276
|
let uid = 0;
|
|
43911
44277
|
const transcript = chrome.transcript;
|
|
@@ -44057,7 +44423,8 @@ async function launchTuiChatShell(opts) {
|
|
|
44057
44423
|
},
|
|
44058
44424
|
onExit: () => {
|
|
44059
44425
|
r.destroy();
|
|
44060
|
-
}
|
|
44426
|
+
},
|
|
44427
|
+
...opts.versionCheck !== undefined ? { versionCheck: opts.versionCheck } : {}
|
|
44061
44428
|
});
|
|
44062
44429
|
await Promise.race([exited, handle.done]);
|
|
44063
44430
|
return true;
|
|
@@ -44072,6 +44439,76 @@ async function launchTuiChatShell(opts) {
|
|
|
44072
44439
|
|
|
44073
44440
|
// src/commands/shell.ts
|
|
44074
44441
|
init_shell_config();
|
|
44442
|
+
// package.json
|
|
44443
|
+
var package_default = {
|
|
44444
|
+
name: "@mrciphersmith/keryx",
|
|
44445
|
+
version: "0.2.19",
|
|
44446
|
+
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
44447
|
+
private: false,
|
|
44448
|
+
publishConfig: {
|
|
44449
|
+
access: "public"
|
|
44450
|
+
},
|
|
44451
|
+
license: "MIT",
|
|
44452
|
+
type: "module",
|
|
44453
|
+
repository: {
|
|
44454
|
+
type: "git",
|
|
44455
|
+
url: "git+ssh://git@github.com/MrCipherSmith/keryx.git"
|
|
44456
|
+
},
|
|
44457
|
+
keywords: [
|
|
44458
|
+
"ai-agents",
|
|
44459
|
+
"coding-agents",
|
|
44460
|
+
"agent-harness",
|
|
44461
|
+
"agent-context",
|
|
44462
|
+
"repository-context",
|
|
44463
|
+
"code-graph",
|
|
44464
|
+
"project-memory",
|
|
44465
|
+
"test-impact-analysis",
|
|
44466
|
+
"developer-tools",
|
|
44467
|
+
"model-context-protocol",
|
|
44468
|
+
"mcp",
|
|
44469
|
+
"claude-code",
|
|
44470
|
+
"cursor",
|
|
44471
|
+
"codex",
|
|
44472
|
+
"cli",
|
|
44473
|
+
"bun"
|
|
44474
|
+
],
|
|
44475
|
+
bin: {
|
|
44476
|
+
keryx: "./dist/cli.js"
|
|
44477
|
+
},
|
|
44478
|
+
scripts: {
|
|
44479
|
+
keryx: "bun ./src/cli.ts",
|
|
44480
|
+
build: "bun build ./src/cli.ts --outdir ./dist --target bun --external @modelcontextprotocol/sdk --external web-tree-sitter --external @opentui/core && bun build ./src/harness/process/sandbox/proxy-worker.ts --outdir ./dist --target bun --external @modelcontextprotocol/sdk --external web-tree-sitter --external @opentui/core",
|
|
44481
|
+
prepare: "bun run build",
|
|
44482
|
+
typecheck: "tsc --noEmit",
|
|
44483
|
+
test: "bun test",
|
|
44484
|
+
check: "tsc --noEmit && bun test",
|
|
44485
|
+
"check:doc-links": "bun scripts/check-doc-links.ts",
|
|
44486
|
+
"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"
|
|
44487
|
+
},
|
|
44488
|
+
files: [
|
|
44489
|
+
"dist",
|
|
44490
|
+
"src/gdgraph",
|
|
44491
|
+
"src/gdskills/bundled",
|
|
44492
|
+
"src/gdskills/contracts",
|
|
44493
|
+
"LICENSE",
|
|
44494
|
+
"README.md",
|
|
44495
|
+
"package.json"
|
|
44496
|
+
],
|
|
44497
|
+
dependencies: {},
|
|
44498
|
+
optionalDependencies: {
|
|
44499
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
44500
|
+
"@opentui/core": "^0.4.5",
|
|
44501
|
+
"web-tree-sitter": "^0.22.0"
|
|
44502
|
+
},
|
|
44503
|
+
devDependencies: {
|
|
44504
|
+
"@types/bun": "latest",
|
|
44505
|
+
"bun-types": "latest",
|
|
44506
|
+
typescript: "^5"
|
|
44507
|
+
},
|
|
44508
|
+
engines: {
|
|
44509
|
+
bun: ">=1.1.0"
|
|
44510
|
+
}
|
|
44511
|
+
};
|
|
44075
44512
|
|
|
44076
44513
|
// src/commands/select.ts
|
|
44077
44514
|
init_guard2();
|
|
@@ -44128,6 +44565,7 @@ async function probeOllamaModels(deps, baseUrl) {
|
|
|
44128
44565
|
}
|
|
44129
44566
|
async function detectProviders(deps) {
|
|
44130
44567
|
const baseUrl = deps.baseUrl ?? DEFAULT_OLLAMA_BASE_URL;
|
|
44568
|
+
const platform = deps.platform ?? process.platform;
|
|
44131
44569
|
const detected = [];
|
|
44132
44570
|
const ollamaModels = await probeOllamaModels(deps, baseUrl);
|
|
44133
44571
|
if (ollamaModels !== undefined) {
|
|
@@ -44138,15 +44576,18 @@ async function detectProviders(deps) {
|
|
|
44138
44576
|
detected.push({ name: "anthropic", models: [...ANTHROPIC_MODELS] });
|
|
44139
44577
|
}
|
|
44140
44578
|
for (const p of OPENAI_COMPAT_PROVIDERS) {
|
|
44579
|
+
if (!isProviderPlatformSupported(p, platform)) {
|
|
44580
|
+
continue;
|
|
44581
|
+
}
|
|
44141
44582
|
detected.push({
|
|
44142
44583
|
name: p.name,
|
|
44143
44584
|
models: [...p.models],
|
|
44144
44585
|
baseUrl: p.baseUrl,
|
|
44145
|
-
envKey: p.envKey,
|
|
44146
44586
|
label: p.label,
|
|
44147
44587
|
...p.chatPath !== undefined ? { chatPath: p.chatPath } : {},
|
|
44148
44588
|
...p.modelsPath !== undefined ? { modelsPath: p.modelsPath } : {},
|
|
44149
|
-
...p.note !== undefined ? { note: p.note } : {}
|
|
44589
|
+
...p.note !== undefined ? { note: p.note } : {},
|
|
44590
|
+
...p.envKey !== undefined ? { envKey: p.envKey } : {}
|
|
44150
44591
|
});
|
|
44151
44592
|
}
|
|
44152
44593
|
detected.push({ name: "fake", models: [...FAKE_MODELS] });
|
|
@@ -44380,6 +44821,7 @@ Starting a new session.
|
|
|
44380
44821
|
provider = makeActive();
|
|
44381
44822
|
};
|
|
44382
44823
|
for await (const line of io.lines) {
|
|
44824
|
+
io.onSafeBoundary?.();
|
|
44383
44825
|
if (line.startsWith("/")) {
|
|
44384
44826
|
const parts = line.trim().split(/\s+/);
|
|
44385
44827
|
const command = parts[0] ?? "";
|
|
@@ -44528,6 +44970,7 @@ Starting a new session.
|
|
|
44528
44970
|
} else {
|
|
44529
44971
|
history.pop();
|
|
44530
44972
|
}
|
|
44973
|
+
io.onSafeBoundary?.();
|
|
44531
44974
|
io.write(`
|
|
44532
44975
|
|
|
44533
44976
|
`);
|
|
@@ -44560,6 +45003,7 @@ function realSelectProviderModel(baseUrl) {
|
|
|
44560
45003
|
const detected = await detectProviders({
|
|
44561
45004
|
fetch: globalThis.fetch,
|
|
44562
45005
|
env: process.env,
|
|
45006
|
+
platform: process.platform,
|
|
44563
45007
|
...baseUrl !== undefined ? { baseUrl } : {}
|
|
44564
45008
|
});
|
|
44565
45009
|
const filtered = opts?.onlyProvider !== undefined ? detected.filter((d) => d.name === opts.onlyProvider) : detected;
|
|
@@ -44609,7 +45053,32 @@ function countRows(text, columns) {
|
|
|
44609
45053
|
}
|
|
44610
45054
|
return rows;
|
|
44611
45055
|
}
|
|
44612
|
-
function
|
|
45056
|
+
function createVersionAdvisoryBoundary(versionCheck) {
|
|
45057
|
+
let active = true;
|
|
45058
|
+
let pending;
|
|
45059
|
+
let shown = false;
|
|
45060
|
+
versionCheck.then((result) => {
|
|
45061
|
+
if (active)
|
|
45062
|
+
pending = formatVersionUpdateAdvisory(result);
|
|
45063
|
+
}, () => {});
|
|
45064
|
+
return {
|
|
45065
|
+
flush: (write) => {
|
|
45066
|
+
if (!active || shown || pending === undefined)
|
|
45067
|
+
return;
|
|
45068
|
+
shown = true;
|
|
45069
|
+
const advisory = pending;
|
|
45070
|
+
pending = undefined;
|
|
45071
|
+
write(`
|
|
45072
|
+
${advisory}
|
|
45073
|
+
`);
|
|
45074
|
+
},
|
|
45075
|
+
destroy: () => {
|
|
45076
|
+
active = false;
|
|
45077
|
+
pending = undefined;
|
|
45078
|
+
}
|
|
45079
|
+
};
|
|
45080
|
+
}
|
|
45081
|
+
function createRichIo(lines, versionCheck) {
|
|
44613
45082
|
const stdout2 = process.stdout;
|
|
44614
45083
|
const rich = colorEnabled() && Boolean(stdout2.isTTY);
|
|
44615
45084
|
const out = (s) => {
|
|
@@ -44619,6 +45088,7 @@ function createRichIo(lines) {
|
|
|
44619
45088
|
let frame = 0;
|
|
44620
45089
|
let awaitingFirstToken = false;
|
|
44621
45090
|
let raw = "";
|
|
45091
|
+
const advisory = createVersionAdvisoryBoundary(versionCheck);
|
|
44622
45092
|
const stopSpinner = () => {
|
|
44623
45093
|
if (spinner !== undefined) {
|
|
44624
45094
|
clearInterval(spinner);
|
|
@@ -44702,10 +45172,18 @@ ${GUTTER}${style.cyan("\u25C6")} ${style.bold(title)} ${style.dim(subtitle)}
|
|
|
44702
45172
|
|
|
44703
45173
|
`);
|
|
44704
45174
|
}
|
|
45175
|
+
advisory.flush(emitSystem);
|
|
44705
45176
|
printPrompt();
|
|
44706
45177
|
};
|
|
44707
|
-
const io = {
|
|
44708
|
-
|
|
45178
|
+
const io = {
|
|
45179
|
+
lines,
|
|
45180
|
+
write,
|
|
45181
|
+
onTurnStart,
|
|
45182
|
+
onTurnEnd,
|
|
45183
|
+
onSystem: emitSystem,
|
|
45184
|
+
onSafeBoundary: () => advisory.flush(emitSystem)
|
|
45185
|
+
};
|
|
45186
|
+
return { io, emitSystem, printHeader, printPrompt, destroy: advisory.destroy };
|
|
44709
45187
|
}
|
|
44710
45188
|
function turnSeparator() {
|
|
44711
45189
|
return style.dim("\u2500".repeat(24));
|
|
@@ -44926,6 +45404,7 @@ New session ${shortSessionId(live.summary.id)}.
|
|
|
44926
45404
|
if (line === undefined) {
|
|
44927
45405
|
return;
|
|
44928
45406
|
}
|
|
45407
|
+
rich.safeBoundary?.();
|
|
44929
45408
|
if (line.startsWith("/")) {
|
|
44930
45409
|
const parts = line.trim().split(/\s+/);
|
|
44931
45410
|
const command = parts[0] ?? "";
|
|
@@ -45022,6 +45501,7 @@ ${GUTTER}${usageLine}
|
|
|
45022
45501
|
${GUTTER}${turnSeparator()}
|
|
45023
45502
|
|
|
45024
45503
|
`);
|
|
45504
|
+
rich.safeBoundary?.();
|
|
45025
45505
|
rich.printPrompt();
|
|
45026
45506
|
}
|
|
45027
45507
|
}
|
|
@@ -45100,13 +45580,17 @@ function chooseShellSurface(flags, isTty) {
|
|
|
45100
45580
|
}
|
|
45101
45581
|
return flags.modeFlag === false ? "tui-chat" : "tui-agent";
|
|
45102
45582
|
}
|
|
45103
|
-
async function shellCommand(args2) {
|
|
45583
|
+
async function shellCommand(args2, runtime = {}) {
|
|
45584
|
+
const versionCheck = (runtime.checkVersion ?? (() => checkVersion({
|
|
45585
|
+
currentVersion: package_default.version,
|
|
45586
|
+
...runtime.cacheDir !== undefined ? { cacheDir: runtime.cacheDir } : {}
|
|
45587
|
+
})))();
|
|
45104
45588
|
const flags = parseShellCliFlags(args2);
|
|
45105
45589
|
let providerArg = flags.providerArg;
|
|
45106
45590
|
let modelArg = flags.modelArg;
|
|
45107
45591
|
let baseUrl = flags.baseUrl;
|
|
45108
45592
|
let modeFlag = flags.modeFlag;
|
|
45109
|
-
const surface = chooseShellSurface(flags, process.stdout.isTTY === true);
|
|
45593
|
+
const surface = chooseShellSurface(flags, runtime.isTty ?? process.stdout.isTTY === true);
|
|
45110
45594
|
if (surface !== "readline") {
|
|
45111
45595
|
const cwd = process.cwd();
|
|
45112
45596
|
const tuiProviderFactory = realMakeProvider(() => {});
|
|
@@ -45151,7 +45635,7 @@ async function shellCommand(args2) {
|
|
|
45151
45635
|
modelId: sel.model
|
|
45152
45636
|
}),
|
|
45153
45637
|
maxToolCalls: resolveAgentMaxToolCalls(),
|
|
45154
|
-
idSeq: () =>
|
|
45638
|
+
idSeq: () => randomUUID10()
|
|
45155
45639
|
};
|
|
45156
45640
|
};
|
|
45157
45641
|
const redetect = () => detectProviders({
|
|
@@ -45163,7 +45647,8 @@ async function shellCommand(args2) {
|
|
|
45163
45647
|
providerArg,
|
|
45164
45648
|
modelArg,
|
|
45165
45649
|
baseUrl,
|
|
45166
|
-
detect: redetect
|
|
45650
|
+
detect: redetect,
|
|
45651
|
+
...runtime.cacheDir !== undefined ? { configDir: runtime.cacheDir } : {}
|
|
45167
45652
|
});
|
|
45168
45653
|
const tuiInitial = startup.initial;
|
|
45169
45654
|
const tuiDetected = startup.detected;
|
|
@@ -45173,7 +45658,7 @@ async function shellCommand(args2) {
|
|
|
45173
45658
|
if (flags.resumePick === true && chatResumeId === undefined) {
|
|
45174
45659
|
chatResumeId = latestSession(cwd)?.id;
|
|
45175
45660
|
}
|
|
45176
|
-
if (await launchTuiChatShell({
|
|
45661
|
+
if (await (runtime.launchChat ?? launchTuiChatShell)({
|
|
45177
45662
|
detected: tuiDetected,
|
|
45178
45663
|
redetect,
|
|
45179
45664
|
...tuiInitial !== undefined ? { initial: tuiInitial } : {},
|
|
@@ -45181,18 +45666,19 @@ async function shellCommand(args2) {
|
|
|
45181
45666
|
makeShellDeps: (sel) => ({
|
|
45182
45667
|
makeProvider: chatFactory,
|
|
45183
45668
|
clock: () => new Date().toISOString(),
|
|
45184
|
-
idSeq: () =>
|
|
45669
|
+
idSeq: () => randomUUID10(),
|
|
45185
45670
|
initial: sel,
|
|
45186
45671
|
session: {
|
|
45187
45672
|
cwd,
|
|
45188
45673
|
...flags.continueLast === true ? { continueLast: true } : {},
|
|
45189
45674
|
...chatResumeId !== undefined ? { resumeId: chatResumeId } : {}
|
|
45190
45675
|
}
|
|
45191
|
-
})
|
|
45676
|
+
}),
|
|
45677
|
+
versionCheck
|
|
45192
45678
|
})) {
|
|
45193
45679
|
return;
|
|
45194
45680
|
}
|
|
45195
|
-
} else if (await launchTuiAgentShell({
|
|
45681
|
+
} else if (await (runtime.launchAgent ?? launchTuiAgentShell)({
|
|
45196
45682
|
detected: tuiDetected,
|
|
45197
45683
|
makeAgentDeps,
|
|
45198
45684
|
redetect,
|
|
@@ -45202,7 +45688,8 @@ async function shellCommand(args2) {
|
|
|
45202
45688
|
...flags.continueLast === true ? { continueLast: true } : {},
|
|
45203
45689
|
...flags.resumeId !== undefined ? { resumeId: flags.resumeId } : {},
|
|
45204
45690
|
...flags.resumePick === true ? { pickOnStart: true } : {}
|
|
45205
|
-
}
|
|
45691
|
+
},
|
|
45692
|
+
versionCheck
|
|
45206
45693
|
})) {
|
|
45207
45694
|
return;
|
|
45208
45695
|
}
|
|
@@ -45210,7 +45697,7 @@ async function shellCommand(args2) {
|
|
|
45210
45697
|
const rl = readline2.createInterface({ input: process.stdin });
|
|
45211
45698
|
const lineIterator = rl[Symbol.asyncIterator]();
|
|
45212
45699
|
const sharedLines = { [Symbol.asyncIterator]: () => lineIterator };
|
|
45213
|
-
const { io, emitSystem, printHeader, printPrompt } = createRichIo(sharedLines);
|
|
45700
|
+
const { io, emitSystem, printHeader, printPrompt, destroy } = createRichIo(sharedLines, versionCheck);
|
|
45214
45701
|
let provider;
|
|
45215
45702
|
let model;
|
|
45216
45703
|
try {
|
|
@@ -45249,7 +45736,7 @@ async function shellCommand(args2) {
|
|
|
45249
45736
|
const deps = {
|
|
45250
45737
|
makeProvider: baseFactory,
|
|
45251
45738
|
clock: () => new Date().toISOString(),
|
|
45252
|
-
idSeq: () =>
|
|
45739
|
+
idSeq: () => randomUUID10(),
|
|
45253
45740
|
initial: baseUrl === undefined ? { provider, model } : { provider, model, baseUrl },
|
|
45254
45741
|
selectProviderModel: realSelectProviderModel(baseUrl)
|
|
45255
45742
|
};
|
|
@@ -45293,13 +45780,13 @@ async function shellCommand(args2) {
|
|
|
45293
45780
|
modelId: model
|
|
45294
45781
|
}),
|
|
45295
45782
|
maxToolCalls: resolveAgentMaxToolCalls(),
|
|
45296
|
-
idSeq: () =>
|
|
45783
|
+
idSeq: () => randomUUID10()
|
|
45297
45784
|
};
|
|
45298
45785
|
let resumeId = flags.resumeId;
|
|
45299
45786
|
if (flags.resumePick === true && resumeId === undefined) {
|
|
45300
45787
|
resumeId = latestSession(process.cwd())?.id;
|
|
45301
45788
|
}
|
|
45302
|
-
await runAgentRepl(sharedLines, { printPrompt }, agentDeps, metaprojectPort, {
|
|
45789
|
+
await runAgentRepl(sharedLines, { printPrompt, safeBoundary: io.onSafeBoundary }, agentDeps, metaprojectPort, {
|
|
45303
45790
|
cwd: process.cwd(),
|
|
45304
45791
|
...flags.continueLast === true ? { continueLast: true } : {},
|
|
45305
45792
|
...resumeId !== undefined ? { resumeId } : {}
|
|
@@ -45319,6 +45806,7 @@ async function shellCommand(args2) {
|
|
|
45319
45806
|
});
|
|
45320
45807
|
}
|
|
45321
45808
|
} finally {
|
|
45809
|
+
destroy();
|
|
45322
45810
|
rl.close();
|
|
45323
45811
|
}
|
|
45324
45812
|
}
|
|
@@ -45463,7 +45951,7 @@ Shell:
|
|
|
45463
45951
|
init_fs();
|
|
45464
45952
|
import { readFile as readFile63 } from "fs/promises";
|
|
45465
45953
|
import { stdin } from "process";
|
|
45466
|
-
import
|
|
45954
|
+
import path122 from "path";
|
|
45467
45955
|
var MODULES = [
|
|
45468
45956
|
{ name: "gdgraph", flag: "--no-gdgraph", desc: "code graph, symbols, affected context", defaultEnabled: true },
|
|
45469
45957
|
{ name: "gdctx", flag: "--no-gdctx", desc: "token-aware command/read output", defaultEnabled: true },
|
|
@@ -45502,8 +45990,8 @@ async function modulesCommand(args2 = []) {
|
|
|
45502
45990
|
return;
|
|
45503
45991
|
}
|
|
45504
45992
|
const wantsJson = args2.includes("--json") && (sub === undefined || sub === "status" || sub === "list" || sub === "--json");
|
|
45505
|
-
const metaprojectRoot =
|
|
45506
|
-
const manifestPath =
|
|
45993
|
+
const metaprojectRoot = path122.join(process.cwd(), ".metaproject");
|
|
45994
|
+
const manifestPath = path122.join(metaprojectRoot, "metaproject.json");
|
|
45507
45995
|
if (!await pathExists(manifestPath)) {
|
|
45508
45996
|
if (wantsJson) {
|
|
45509
45997
|
console.log(JSON.stringify({ schemaVersion: 1, error: "not-initialized", modules: [] }, null, 2));
|
|
@@ -45617,18 +46105,18 @@ function printHelp16() {
|
|
|
45617
46105
|
}
|
|
45618
46106
|
|
|
45619
46107
|
// src/commands/serve.ts
|
|
45620
|
-
import { randomUUID as
|
|
46108
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
45621
46109
|
|
|
45622
46110
|
// src/lib/serve-config.ts
|
|
45623
46111
|
init_config_dir();
|
|
45624
46112
|
import { existsSync as existsSync24 } from "fs";
|
|
45625
|
-
import
|
|
46113
|
+
import path123 from "path";
|
|
45626
46114
|
var SERVE_CONFIG_SCHEMA_VERSION = "1.0.0";
|
|
45627
46115
|
var DEFAULT_SERVE_BIND_ADDRESS = "127.0.0.1";
|
|
45628
46116
|
var DEFAULT_SERVE_PORT = 7377;
|
|
45629
46117
|
var DEFAULT_SERVE_PROFILE = "remote-restricted";
|
|
45630
46118
|
function serveConfigPath(dir) {
|
|
45631
|
-
return
|
|
46119
|
+
return path123.join(keryxConfigDir(dir), "serve.json");
|
|
45632
46120
|
}
|
|
45633
46121
|
function parseIpv4(value) {
|
|
45634
46122
|
const parts = value.split(".");
|
|
@@ -45944,21 +46432,21 @@ function saveServeConfig(config, dir, onWarn) {
|
|
|
45944
46432
|
|
|
45945
46433
|
// src/lib/serve-credential.ts
|
|
45946
46434
|
init_config_dir();
|
|
45947
|
-
import { createHash as createHash19, randomBytes as randomBytes2, randomUUID as
|
|
46435
|
+
import { createHash as createHash19, randomBytes as randomBytes2, randomUUID as randomUUID11 } from "crypto";
|
|
45948
46436
|
import {
|
|
45949
46437
|
chmodSync as chmodSync4,
|
|
45950
46438
|
closeSync as closeSync3,
|
|
45951
46439
|
existsSync as existsSync25,
|
|
45952
46440
|
fsyncSync as fsyncSync2,
|
|
45953
46441
|
openSync as openSync3,
|
|
45954
|
-
renameSync as
|
|
46442
|
+
renameSync as renameSync4,
|
|
45955
46443
|
statSync as statSync5,
|
|
45956
|
-
unlinkSync as
|
|
46444
|
+
unlinkSync as unlinkSync3,
|
|
45957
46445
|
writeFileSync as writeFileSync8
|
|
45958
46446
|
} from "fs";
|
|
45959
|
-
import
|
|
46447
|
+
import path124 from "path";
|
|
45960
46448
|
function serveCredentialPath(dir) {
|
|
45961
|
-
return
|
|
46449
|
+
return path124.join(keryxConfigDir(dir), "serve-credentials.json");
|
|
45962
46450
|
}
|
|
45963
46451
|
function constantTimeEqual(a, b) {
|
|
45964
46452
|
const width = Math.max(a.length, b.length);
|
|
@@ -46028,7 +46516,7 @@ function readServeCredential(dir) {
|
|
|
46028
46516
|
}
|
|
46029
46517
|
function writeStore(store, dir) {
|
|
46030
46518
|
const file = serveCredentialPath(dir);
|
|
46031
|
-
const temp = `${file}.${
|
|
46519
|
+
const temp = `${file}.${randomUUID11()}.tmp`;
|
|
46032
46520
|
try {
|
|
46033
46521
|
ensureKeryxConfigDir(dir);
|
|
46034
46522
|
const handle = openSync3(temp, "wx", 384);
|
|
@@ -46039,12 +46527,12 @@ function writeStore(store, dir) {
|
|
|
46039
46527
|
} finally {
|
|
46040
46528
|
closeSync3(handle);
|
|
46041
46529
|
}
|
|
46042
|
-
|
|
46530
|
+
renameSync4(temp, file);
|
|
46043
46531
|
tighten2(file, 384);
|
|
46044
46532
|
return true;
|
|
46045
46533
|
} catch {
|
|
46046
46534
|
try {
|
|
46047
|
-
|
|
46535
|
+
unlinkSync3(temp);
|
|
46048
46536
|
} catch {}
|
|
46049
46537
|
return false;
|
|
46050
46538
|
}
|
|
@@ -46068,7 +46556,7 @@ function mintRecord(now) {
|
|
|
46068
46556
|
const salt = randomBytes2(32).toString("hex");
|
|
46069
46557
|
return {
|
|
46070
46558
|
token,
|
|
46071
|
-
record: { id:
|
|
46559
|
+
record: { id: randomUUID11(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
|
|
46072
46560
|
};
|
|
46073
46561
|
}
|
|
46074
46562
|
function issueServeToken(dir, now = () => new Date().toISOString(), onWaiting) {
|
|
@@ -46189,22 +46677,22 @@ class AuthFailureThrottle {
|
|
|
46189
46677
|
init_config_dir();
|
|
46190
46678
|
import { createHash as createHash20 } from "crypto";
|
|
46191
46679
|
import { existsSync as existsSync26, readdirSync as readdirSync2, rmSync as rmSync2 } from "fs";
|
|
46192
|
-
import
|
|
46680
|
+
import path125 from "path";
|
|
46193
46681
|
var MAX_TURN_EVENTS = 1e4;
|
|
46194
46682
|
function turnsRoot(dir) {
|
|
46195
|
-
return
|
|
46683
|
+
return path125.join(keryxConfigDir(dir), "turns");
|
|
46196
46684
|
}
|
|
46197
46685
|
function turnDir(turnId, dir) {
|
|
46198
|
-
return
|
|
46686
|
+
return path125.join(turnsRoot(dir), turnId);
|
|
46199
46687
|
}
|
|
46200
46688
|
function keyPath(project, idempotencyKey, dir) {
|
|
46201
46689
|
const projectBytes = Buffer.byteLength(project, "utf8");
|
|
46202
46690
|
const digest = createHash20("sha256").update(`${projectBytes}:${project}\x00${idempotencyKey}`, "utf8").digest("hex");
|
|
46203
|
-
return
|
|
46691
|
+
return path125.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
46204
46692
|
}
|
|
46205
46693
|
function legacyKeyPath(idempotencyKey, dir) {
|
|
46206
46694
|
const digest = createHash20("sha256").update(idempotencyKey, "utf8").digest("hex");
|
|
46207
|
-
return
|
|
46695
|
+
return path125.join(turnsRoot(dir), "keys", `${digest}.json`);
|
|
46208
46696
|
}
|
|
46209
46697
|
function adoptLegacyClaim(project, idempotencyKey, dir) {
|
|
46210
46698
|
const legacy = legacyKeyPath(idempotencyKey, dir);
|
|
@@ -46268,7 +46756,7 @@ function ensureTurnDir(turnId, dir) {
|
|
|
46268
46756
|
}
|
|
46269
46757
|
function createTurnRecord(record, dir) {
|
|
46270
46758
|
ensureTurnDir(record.turnId, dir);
|
|
46271
|
-
writeOwnerOnlyFile(
|
|
46759
|
+
writeOwnerOnlyFile(path125.join(turnDir(record.turnId, dir), "turn.json"), `${JSON.stringify(record, null, 2)}
|
|
46272
46760
|
`);
|
|
46273
46761
|
}
|
|
46274
46762
|
function appendTurnEvent(event, dir, opts) {
|
|
@@ -46277,12 +46765,12 @@ function appendTurnEvent(event, dir, opts) {
|
|
|
46277
46765
|
}
|
|
46278
46766
|
const line = JSON.stringify(event);
|
|
46279
46767
|
try {
|
|
46280
|
-
appendOwnerOnlyLine(
|
|
46768
|
+
appendOwnerOnlyLine(path125.join(turnDir(event.turnId, dir), "events.jsonl"), line);
|
|
46281
46769
|
} catch (error) {
|
|
46282
46770
|
if (error?.code !== "ENOENT") {
|
|
46283
46771
|
throw error;
|
|
46284
46772
|
}
|
|
46285
|
-
appendOwnerOnlyLine(
|
|
46773
|
+
appendOwnerOnlyLine(path125.join(ensureTurnDir(event.turnId, dir), "events.jsonl"), line);
|
|
46286
46774
|
}
|
|
46287
46775
|
return true;
|
|
46288
46776
|
}
|
|
@@ -46290,7 +46778,7 @@ function readTurnEvents(turnId, after = -1, dir) {
|
|
|
46290
46778
|
if (!isTurnId(turnId)) {
|
|
46291
46779
|
return { ok: false, reason: "not-a-turn-id" };
|
|
46292
46780
|
}
|
|
46293
|
-
const read = readTurnFile(
|
|
46781
|
+
const read = readTurnFile(path125.join(turnDir(turnId, dir), "events.jsonl"));
|
|
46294
46782
|
if (!read.ok) {
|
|
46295
46783
|
if (isDefiniteAbsence2(read.reason)) {
|
|
46296
46784
|
return { ok: true, value: [] };
|
|
@@ -46318,7 +46806,7 @@ function readTurnRecord(turnId, dir) {
|
|
|
46318
46806
|
if (!isTurnId(turnId)) {
|
|
46319
46807
|
return { ok: false, reason: "not-a-turn-id" };
|
|
46320
46808
|
}
|
|
46321
|
-
const read = readTurnFile(
|
|
46809
|
+
const read = readTurnFile(path125.join(turnDir(turnId, dir), "turn.json"));
|
|
46322
46810
|
if (!read.ok) {
|
|
46323
46811
|
return { ok: false, reason: read.reason };
|
|
46324
46812
|
}
|
|
@@ -46337,7 +46825,7 @@ function finishTurn(turnId, result, dir) {
|
|
|
46337
46825
|
if (!record.ok) {
|
|
46338
46826
|
return false;
|
|
46339
46827
|
}
|
|
46340
|
-
writeOwnerOnlyFile(
|
|
46828
|
+
writeOwnerOnlyFile(path125.join(turnDir(turnId, dir), "turn.json"), `${JSON.stringify({ ...record.value, result }, null, 2)}
|
|
46341
46829
|
`);
|
|
46342
46830
|
return true;
|
|
46343
46831
|
}
|
|
@@ -46382,8 +46870,8 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
|
|
|
46382
46870
|
}
|
|
46383
46871
|
|
|
46384
46872
|
// src/lib/serve-turn.ts
|
|
46385
|
-
import { randomUUID as
|
|
46386
|
-
import
|
|
46873
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
46874
|
+
import path126 from "path";
|
|
46387
46875
|
init_service();
|
|
46388
46876
|
var REMOTE_ORIGIN = "remote:http";
|
|
46389
46877
|
var MAX_PROMPT_CHARS = 32000;
|
|
@@ -46452,9 +46940,9 @@ function isUuid(value) {
|
|
|
46452
46940
|
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);
|
|
46453
46941
|
}
|
|
46454
46942
|
function resolveProject(declared, dir) {
|
|
46455
|
-
const wanted =
|
|
46943
|
+
const wanted = path126.resolve(declared);
|
|
46456
46944
|
for (const entry of listProjects(dir, () => {})) {
|
|
46457
|
-
if (
|
|
46945
|
+
if (path126.resolve(entry.path) === wanted) {
|
|
46458
46946
|
return { ok: true, project: entry.path };
|
|
46459
46947
|
}
|
|
46460
46948
|
}
|
|
@@ -46501,7 +46989,7 @@ async function redactOut(security, text) {
|
|
|
46501
46989
|
async function runRemoteTurn(input2) {
|
|
46502
46990
|
const scanRoot = input2.scanRoot;
|
|
46503
46991
|
const security = createSecurityService(scanRoot);
|
|
46504
|
-
const newId = input2.newId ?? (() =>
|
|
46992
|
+
const newId = input2.newId ?? (() => randomUUID12());
|
|
46505
46993
|
const clock = input2.clock ?? (() => new Date().toISOString());
|
|
46506
46994
|
const turnId = input2.turnId ?? newId();
|
|
46507
46995
|
const sessionId = input2.request.sessionId ?? newId();
|
|
@@ -46644,7 +47132,7 @@ function outcomeOf(status, gate, unresolvedBlockerIds) {
|
|
|
46644
47132
|
}
|
|
46645
47133
|
function createSubmitTurn(deps) {
|
|
46646
47134
|
return async (request, project) => {
|
|
46647
|
-
const turnId = (deps.newId ?? (() =>
|
|
47135
|
+
const turnId = (deps.newId ?? (() => randomUUID12()))();
|
|
46648
47136
|
const scanned = await scanPrompt(deps.dir, request.prompt);
|
|
46649
47137
|
if (scanned.rejected) {
|
|
46650
47138
|
return { kind: "rejected" };
|
|
@@ -47331,7 +47819,7 @@ function runConfig(args2) {
|
|
|
47331
47819
|
return;
|
|
47332
47820
|
}
|
|
47333
47821
|
const credential = readServeCredential();
|
|
47334
|
-
const credentialId = credential.status === "ok" ? credential.record.id :
|
|
47822
|
+
const credentialId = credential.status === "ok" ? credential.record.id : randomUUID13();
|
|
47335
47823
|
const config = defaultServeConfig(credentialId, {
|
|
47336
47824
|
address: parsed.parsed.values.get("--bind") ?? DEFAULT_SERVE_BIND_ADDRESS,
|
|
47337
47825
|
port: port ?? DEFAULT_SERVE_PORT,
|
|
@@ -47489,7 +47977,7 @@ function printHelp17() {
|
|
|
47489
47977
|
import { spawn as spawn5 } from "child_process";
|
|
47490
47978
|
import { chmod as chmod4, mkdir as mkdir45, readFile as readFile64, readdir as readdir20, writeFile as writeFile42 } from "fs/promises";
|
|
47491
47979
|
import { access as access3, constants, existsSync as existsSync27 } from "fs";
|
|
47492
|
-
import
|
|
47980
|
+
import path127 from "path";
|
|
47493
47981
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
47494
47982
|
init_config();
|
|
47495
47983
|
init_config2();
|
|
@@ -47504,8 +47992,8 @@ async function updateCommand(args2 = []) {
|
|
|
47504
47992
|
return;
|
|
47505
47993
|
}
|
|
47506
47994
|
const projectRoot = process.cwd();
|
|
47507
|
-
const metaprojectRoot =
|
|
47508
|
-
banner("keryx update", `Refreshing the .metaproject workspace in ${
|
|
47995
|
+
const metaprojectRoot = path127.join(projectRoot, ".metaproject");
|
|
47996
|
+
banner("keryx update", `Refreshing the .metaproject workspace in ${path127.basename(projectRoot)}/`);
|
|
47509
47997
|
if (!await pathExists(metaprojectRoot)) {
|
|
47510
47998
|
console.log(` ${style.red(symbols.cross)} Metaproject is not initialized.`);
|
|
47511
47999
|
console.log(` ${style.cyan(symbols.arrow)} Run ${style.cyan("keryx init")} first.`);
|
|
@@ -47548,12 +48036,12 @@ async function updateCommand(args2 = []) {
|
|
|
47548
48036
|
nextSteps(steps);
|
|
47549
48037
|
}
|
|
47550
48038
|
async function refreshServiceFiles(projectRoot, options) {
|
|
47551
|
-
const metaprojectRoot =
|
|
48039
|
+
const metaprojectRoot = path127.join(projectRoot, ".metaproject");
|
|
47552
48040
|
const manifestState = await readManifest5(metaprojectRoot);
|
|
47553
48041
|
const manifest = manifestState.manifest;
|
|
47554
48042
|
const recoveredManifest = !manifestState.exists || !manifestState.valid;
|
|
47555
48043
|
if (manifestState.migrated) {
|
|
47556
|
-
await writeFile42(
|
|
48044
|
+
await writeFile42(path127.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
47557
48045
|
`, "utf8");
|
|
47558
48046
|
}
|
|
47559
48047
|
const enableGdgraph = moduleEnabled2(manifest, "gdgraph");
|
|
@@ -47588,11 +48076,11 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47588
48076
|
enableTasks,
|
|
47589
48077
|
enableSecurity
|
|
47590
48078
|
});
|
|
47591
|
-
await writeTextIfChanged4(
|
|
47592
|
-
await writeTextIfChanged4(
|
|
47593
|
-
await writeTextIfChanged4(
|
|
47594
|
-
await writeTextIfChanged4(
|
|
47595
|
-
await writeTextIfChanged4(
|
|
48079
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "README.md"), renderMetaprojectCoreReadme());
|
|
48080
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "hooks", "README.md"), renderHooksReadme());
|
|
48081
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "rules", "README.md"), renderProjectRulesReadme());
|
|
48082
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "project-rules", "README.md"), renderProjectRulesSkillReadme({ sources: ruleSources }));
|
|
48083
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "index.md"), renderIndexMarkdown({
|
|
47596
48084
|
enableGdgraph,
|
|
47597
48085
|
enableGdctx,
|
|
47598
48086
|
enableGdwiki,
|
|
@@ -47605,7 +48093,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47605
48093
|
ruleSources,
|
|
47606
48094
|
hasDistilledEntrypoints: await hasDistilledEntrypoints(metaprojectRoot)
|
|
47607
48095
|
}));
|
|
47608
|
-
await writeTextIfChanged4(
|
|
48096
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "keryx-dashboard.html"), renderMetaprojectDashboardHtml({
|
|
47609
48097
|
enableGdgraph,
|
|
47610
48098
|
enableGdctx,
|
|
47611
48099
|
enableGdwiki,
|
|
@@ -47617,7 +48105,7 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47617
48105
|
enableSecurity,
|
|
47618
48106
|
data: dashboardData
|
|
47619
48107
|
}));
|
|
47620
|
-
await writeTextIfMissing4(
|
|
48108
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "README.md"), renderMetaprojectReadme({
|
|
47621
48109
|
enableGdgraph,
|
|
47622
48110
|
enableGdctx,
|
|
47623
48111
|
enableGdwiki,
|
|
@@ -47630,24 +48118,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47630
48118
|
}));
|
|
47631
48119
|
if (enableGdgraph) {
|
|
47632
48120
|
await installGdgraphCoreScripts2(metaprojectRoot);
|
|
47633
|
-
await writeTextIfChanged4(
|
|
47634
|
-
await writeTextIfChanged4(
|
|
47635
|
-
await writeTextIfChanged4(
|
|
48121
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "gdgraph.md"), renderGdgraphManifest());
|
|
48122
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "gdgraph", "README.md"), renderGdgraphCoreReadme());
|
|
48123
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "gdgraph", "SKILL.md"), renderGdgraphSkillReadme());
|
|
47636
48124
|
await seedAssetsLock(metaprojectRoot);
|
|
47637
48125
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
47638
48126
|
await installManagedHook2(projectRoot, "post-commit", "gdgraph-post-commit", renderGdgraphPostCommitHook());
|
|
47639
48127
|
}
|
|
47640
48128
|
}
|
|
47641
48129
|
if (enableGdctx) {
|
|
47642
|
-
await writeTextIfMissing4(
|
|
47643
|
-
await writeTextIfChanged4(
|
|
47644
|
-
await writeTextIfChanged4(
|
|
47645
|
-
await writeTextIfChanged4(
|
|
48130
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "gdctx.config.json"), renderGdctxConfig());
|
|
48131
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "gdctx.md"), renderGdctxManifest());
|
|
48132
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "gdctx", "README.md"), renderGdctxCoreReadme());
|
|
48133
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "gdctx", "SKILL.md"), renderGdctxSkillReadme());
|
|
47646
48134
|
}
|
|
47647
48135
|
if (enableGdwiki) {
|
|
47648
|
-
await writeTextIfMissing4(
|
|
47649
|
-
await writeTextIfChanged4(
|
|
47650
|
-
await writeTextIfChanged4(
|
|
48136
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "wiki", "templates", "page.md"), renderWikiPageTemplate());
|
|
48137
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "gdwiki.md"), renderGdwikiManifest());
|
|
48138
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "gdwiki", "SKILL.md"), renderGdwikiSkillReadme());
|
|
47651
48139
|
if (manifest.modules?.gdgraph?.hooks?.gitPostCommit) {
|
|
47652
48140
|
await installManagedHook2(projectRoot, "post-commit", "gdwiki-post-commit", renderGdwikiPostCommitHook());
|
|
47653
48141
|
}
|
|
@@ -47659,25 +48147,25 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47659
48147
|
}
|
|
47660
48148
|
}
|
|
47661
48149
|
if (enableHealth) {
|
|
47662
|
-
await writeTextIfMissing4(
|
|
47663
|
-
await writeTextIfChanged4(
|
|
47664
|
-
await writeTextIfChanged4(
|
|
47665
|
-
await writeTextIfChanged4(
|
|
48150
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "health.config.json"), renderHealthConfig());
|
|
48151
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "health.md"), renderHealthManifest());
|
|
48152
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "health", "README.md"), renderHealthCoreReadme());
|
|
48153
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "health", "SKILL.md"), renderHealthSkillReadme());
|
|
47666
48154
|
if (manifest.modules?.health?.hooks?.gitPostCommit) {
|
|
47667
48155
|
await installManagedHook2(projectRoot, "post-commit", "health-post-commit", renderHealthPostCommitHook());
|
|
47668
48156
|
}
|
|
47669
48157
|
}
|
|
47670
48158
|
if (enableTesting) {
|
|
47671
|
-
await writeTextIfMissing4(
|
|
48159
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "testing.config.json"), renderTestingConfig({
|
|
47672
48160
|
postCommitRefresh: Boolean(manifest.modules?.testing?.hooks?.gitPostCommit),
|
|
47673
48161
|
prePushGate: Boolean(manifest.modules?.testing?.hooks?.prePush)
|
|
47674
48162
|
}));
|
|
47675
|
-
await writeTextIfChanged4(
|
|
47676
|
-
await writeTextIfChanged4(
|
|
47677
|
-
await writeTextIfChanged4(
|
|
48163
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "testing.md"), renderTestingManifest());
|
|
48164
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "testing", "README.md"), renderTestingCoreReadme());
|
|
48165
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "testing", "SKILL.md"), renderTestingSkillReadme());
|
|
47678
48166
|
if (enableGdwiki) {
|
|
47679
|
-
await writeTextIfMissing4(
|
|
47680
|
-
await writeTextIfMissing4(
|
|
48167
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "wiki", "testing", "README.md"), renderTestingWikiReadme());
|
|
48168
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "wiki", "testing", "conventions.md"), renderTestingWikiConventions());
|
|
47681
48169
|
}
|
|
47682
48170
|
if (manifest.modules?.testing?.hooks?.gitPostCommit) {
|
|
47683
48171
|
await installManagedHook2(projectRoot, "post-commit", "testing-post-commit", renderTestingPostCommitHook());
|
|
@@ -47690,24 +48178,24 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47690
48178
|
await installManagedHook2(projectRoot, "post-commit", "metaproject-dashboard-post-commit", renderMetaprojectDashboardPostCommitHook());
|
|
47691
48179
|
}
|
|
47692
48180
|
if (enableMemory) {
|
|
47693
|
-
await writeTextIfMissing4(
|
|
47694
|
-
await writeTextIfMissing4(
|
|
47695
|
-
await writeTextIfChanged4(
|
|
47696
|
-
await writeTextIfChanged4(
|
|
47697
|
-
await writeTextIfChanged4(
|
|
48181
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "memory.config.json"), renderMemoryConfig());
|
|
48182
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "memory", "templates", "entry.md"), renderMemoryEntryTemplate());
|
|
48183
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "memory.md"), renderMemoryManifest());
|
|
48184
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "memory", "README.md"), renderMemoryCoreReadme());
|
|
48185
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "memory", "SKILL.md"), renderMemorySkillReadme());
|
|
47698
48186
|
}
|
|
47699
48187
|
if (enableTasks) {
|
|
47700
|
-
await writeTextIfChanged4(
|
|
47701
|
-
await writeTextIfChanged4(
|
|
47702
|
-
await writeTextIfChanged4(
|
|
47703
|
-
await writeTextIfChanged4(
|
|
47704
|
-
await writeTextIfChanged4(
|
|
47705
|
-
await writeTextIfChanged4(
|
|
48188
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "flows", "README.md"), renderFlowsReadme());
|
|
48189
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "tasks.md"), renderTasksManifest());
|
|
48190
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "flow", "SKILL.md"), renderFlowSkillRouter());
|
|
48191
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "flow", "init.md"), renderFlowInitSkill());
|
|
48192
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "flow", "manage.md"), renderFlowManageSkill());
|
|
48193
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "skills", "flow", "complete.md"), renderFlowCompleteSkill());
|
|
47706
48194
|
}
|
|
47707
48195
|
if (enableSecurity) {
|
|
47708
|
-
await writeTextIfMissing4(
|
|
47709
|
-
await writeTextIfChanged4(
|
|
47710
|
-
await writeTextIfChanged4(
|
|
48196
|
+
await writeTextIfMissing4(path127.join(metaprojectRoot, "security.config.json"), renderSecurityConfig());
|
|
48197
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "modules", "security.md"), renderSecurityManifest());
|
|
48198
|
+
await writeTextIfChanged4(path127.join(metaprojectRoot, "core", "security", "README.md"), renderSecurityCoreReadme());
|
|
47711
48199
|
if (manifest.modules?.security?.hooks?.prePush) {
|
|
47712
48200
|
await installManagedHook2(projectRoot, "pre-push", "security-pre-push", renderSecurityPrePushHook());
|
|
47713
48201
|
}
|
|
@@ -47756,13 +48244,13 @@ async function refreshServiceFiles(projectRoot, options) {
|
|
|
47756
48244
|
};
|
|
47757
48245
|
}
|
|
47758
48246
|
async function buildDashboard(projectRoot = process.cwd()) {
|
|
47759
|
-
const metaprojectRoot =
|
|
48247
|
+
const metaprojectRoot = path127.join(projectRoot, ".metaproject");
|
|
47760
48248
|
if (!await pathExists(metaprojectRoot)) {
|
|
47761
48249
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
47762
48250
|
}
|
|
47763
48251
|
const manifest = (await readManifest5(metaprojectRoot)).manifest;
|
|
47764
48252
|
const data = await collectDashboardData(metaprojectRoot);
|
|
47765
|
-
const dashboardPath =
|
|
48253
|
+
const dashboardPath = path127.join(metaprojectRoot, "keryx-dashboard.html");
|
|
47766
48254
|
await writeTextIfChanged4(dashboardPath, renderMetaprojectDashboardHtml({
|
|
47767
48255
|
enableGdgraph: moduleEnabled2(manifest, "gdgraph"),
|
|
47768
48256
|
enableGdctx: moduleEnabled2(manifest, "gdctx"),
|
|
@@ -47782,7 +48270,7 @@ async function shouldInstallDashboardPostCommitHook(projectRoot, manifest) {
|
|
|
47782
48270
|
if (Object.values(modules).some((module) => Boolean(module.hooks?.gitPostCommit))) {
|
|
47783
48271
|
return true;
|
|
47784
48272
|
}
|
|
47785
|
-
const hookPath =
|
|
48273
|
+
const hookPath = path127.join(projectRoot, ".git", "hooks", "post-commit");
|
|
47786
48274
|
if (!await pathExists(hookPath)) {
|
|
47787
48275
|
return false;
|
|
47788
48276
|
}
|
|
@@ -47802,11 +48290,11 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
47802
48290
|
if (testing) {
|
|
47803
48291
|
data.testing = testing;
|
|
47804
48292
|
}
|
|
47805
|
-
const wiki = await collectMarkdownPages(
|
|
48293
|
+
const wiki = await collectMarkdownPages(path127.join(metaprojectRoot, "wiki"), "wiki");
|
|
47806
48294
|
if (wiki.length > 0) {
|
|
47807
48295
|
data.wiki = { pages: wiki };
|
|
47808
48296
|
}
|
|
47809
|
-
const memory = await collectMarkdownPages(
|
|
48297
|
+
const memory = await collectMarkdownPages(path127.join(metaprojectRoot, "memory"), "memory");
|
|
47810
48298
|
if (memory.length > 0) {
|
|
47811
48299
|
data.memory = { entries: memory };
|
|
47812
48300
|
}
|
|
@@ -47821,7 +48309,7 @@ async function collectDashboardData(metaprojectRoot) {
|
|
|
47821
48309
|
return data;
|
|
47822
48310
|
}
|
|
47823
48311
|
async function collectTasksDashboardData(metaprojectRoot) {
|
|
47824
|
-
const flowsRoot2 =
|
|
48312
|
+
const flowsRoot2 = path127.join(metaprojectRoot, "flows");
|
|
47825
48313
|
if (!await pathExists(flowsRoot2)) {
|
|
47826
48314
|
return null;
|
|
47827
48315
|
}
|
|
@@ -47833,7 +48321,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
47833
48321
|
}
|
|
47834
48322
|
const flows = [];
|
|
47835
48323
|
for (const dir of dirEntries) {
|
|
47836
|
-
const flowPath =
|
|
48324
|
+
const flowPath = path127.join(flowsRoot2, dir, "flow.json");
|
|
47837
48325
|
if (!await pathExists(flowPath)) {
|
|
47838
48326
|
continue;
|
|
47839
48327
|
}
|
|
@@ -47841,7 +48329,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
47841
48329
|
const flow = JSON.parse(await readFile64(flowPath, "utf8"));
|
|
47842
48330
|
const tasks = Array.isArray(flow.tasks) ? flow.tasks : [];
|
|
47843
48331
|
let acTotal = 0;
|
|
47844
|
-
const acPath2 =
|
|
48332
|
+
const acPath2 = path127.join(flowsRoot2, dir, "acceptance-criteria.md");
|
|
47845
48333
|
if (await pathExists(acPath2)) {
|
|
47846
48334
|
const acContent = await readFile64(acPath2, "utf8");
|
|
47847
48335
|
acTotal = (acContent.match(/^- AC\d+:/gm) ?? []).length;
|
|
@@ -47894,7 +48382,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
47894
48382
|
"data/testing/context.md"
|
|
47895
48383
|
];
|
|
47896
48384
|
for (const href of staticHrefs) {
|
|
47897
|
-
const filePath =
|
|
48385
|
+
const filePath = path127.join(metaprojectRoot, ...href.split("/"));
|
|
47898
48386
|
if (!await pathExists(filePath)) {
|
|
47899
48387
|
continue;
|
|
47900
48388
|
}
|
|
@@ -47911,7 +48399,7 @@ async function collectDashboardDocs(metaprojectRoot, wiki, memory) {
|
|
|
47911
48399
|
return docs;
|
|
47912
48400
|
}
|
|
47913
48401
|
async function collectHealthDashboardData(metaprojectRoot) {
|
|
47914
|
-
const reportPath2 =
|
|
48402
|
+
const reportPath2 = path127.join(metaprojectRoot, "data", "health", "artifacts", "latest.json");
|
|
47915
48403
|
if (!await pathExists(reportPath2)) {
|
|
47916
48404
|
return;
|
|
47917
48405
|
}
|
|
@@ -48020,8 +48508,8 @@ function metricToScope(metric) {
|
|
|
48020
48508
|
};
|
|
48021
48509
|
}
|
|
48022
48510
|
async function collectGraphDashboardData(metaprojectRoot) {
|
|
48023
|
-
const nodesPath =
|
|
48024
|
-
const edgesPath =
|
|
48511
|
+
const nodesPath = path127.join(metaprojectRoot, "data", "gdgraph", "storage", "nodes.jsonl");
|
|
48512
|
+
const edgesPath = path127.join(metaprojectRoot, "data", "gdgraph", "storage", "edges.jsonl");
|
|
48025
48513
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
48026
48514
|
return;
|
|
48027
48515
|
}
|
|
@@ -48072,8 +48560,8 @@ async function collectGraphDashboardData(metaprojectRoot) {
|
|
|
48072
48560
|
};
|
|
48073
48561
|
}
|
|
48074
48562
|
async function collectTestingDashboardData(metaprojectRoot) {
|
|
48075
|
-
const reportPath2 =
|
|
48076
|
-
const contextPath =
|
|
48563
|
+
const reportPath2 = path127.join(metaprojectRoot, "data", "testing", "artifacts", "latest.json");
|
|
48564
|
+
const contextPath = path127.join(metaprojectRoot, "data", "testing", "context.md");
|
|
48077
48565
|
if (await pathExists(reportPath2)) {
|
|
48078
48566
|
const report = JSON.parse(await readFile64(reportPath2, "utf8"));
|
|
48079
48567
|
const totalTests = numberOrUndefined(report.total);
|
|
@@ -48102,7 +48590,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
48102
48590
|
const files = await listMarkdownFiles(root);
|
|
48103
48591
|
const pages = [];
|
|
48104
48592
|
for (const filePath of files.slice(0, 40)) {
|
|
48105
|
-
const relativePath =
|
|
48593
|
+
const relativePath = path127.relative(root, filePath).split(path127.sep).join("/");
|
|
48106
48594
|
if (relativePath === "index.md" || relativePath.startsWith("templates/")) {
|
|
48107
48595
|
continue;
|
|
48108
48596
|
}
|
|
@@ -48123,7 +48611,7 @@ async function listMarkdownFiles(root) {
|
|
|
48123
48611
|
const entries = await readdir20(root, { withFileTypes: true });
|
|
48124
48612
|
const files = [];
|
|
48125
48613
|
for (const entry of entries) {
|
|
48126
|
-
const fullPath =
|
|
48614
|
+
const fullPath = path127.join(root, entry.name);
|
|
48127
48615
|
if (entry.isDirectory()) {
|
|
48128
48616
|
files.push(...await listMarkdownFiles(fullPath));
|
|
48129
48617
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -48171,7 +48659,7 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
48171
48659
|
const manifest = {
|
|
48172
48660
|
schemaVersion: 1,
|
|
48173
48661
|
standardVersion: STANDARD_VERSION,
|
|
48174
|
-
name: `${
|
|
48662
|
+
name: `${path127.basename(path127.dirname(metaprojectRoot))}-metaproject`,
|
|
48175
48663
|
createdBy: "keryx",
|
|
48176
48664
|
profiles: computeProfiles(enabledModuleKeys2),
|
|
48177
48665
|
paths: {
|
|
@@ -48254,11 +48742,11 @@ async function writeRecoveredManifest(metaprojectRoot, modules) {
|
|
|
48254
48742
|
metaproject: ".metaproject/index.md"
|
|
48255
48743
|
}
|
|
48256
48744
|
};
|
|
48257
|
-
await writeFile42(
|
|
48745
|
+
await writeFile42(path127.join(metaprojectRoot, "metaproject.json"), `${JSON.stringify(manifest, null, 2)}
|
|
48258
48746
|
`, "utf8");
|
|
48259
48747
|
}
|
|
48260
48748
|
async function enableTasksInManifest(metaprojectRoot) {
|
|
48261
|
-
const manifestPath =
|
|
48749
|
+
const manifestPath = path127.join(metaprojectRoot, "metaproject.json");
|
|
48262
48750
|
if (!await pathExists(manifestPath)) {
|
|
48263
48751
|
return;
|
|
48264
48752
|
}
|
|
@@ -48281,7 +48769,7 @@ async function enableTasksInManifest(metaprojectRoot) {
|
|
|
48281
48769
|
`, "utf8");
|
|
48282
48770
|
}
|
|
48283
48771
|
async function updateManifestAgentEntrypoints(metaprojectRoot, ruleSources) {
|
|
48284
|
-
const manifestPath =
|
|
48772
|
+
const manifestPath = path127.join(metaprojectRoot, "metaproject.json");
|
|
48285
48773
|
if (!await pathExists(manifestPath)) {
|
|
48286
48774
|
return;
|
|
48287
48775
|
}
|
|
@@ -48317,69 +48805,69 @@ async function updateRuntime(projectRoot) {
|
|
|
48317
48805
|
}
|
|
48318
48806
|
}
|
|
48319
48807
|
async function findRuntimeRoot(projectRoot) {
|
|
48320
|
-
const projectRuntime =
|
|
48321
|
-
if (await pathExists(
|
|
48808
|
+
const projectRuntime = path127.join(projectRoot, ".metaproject", "runtime", "keryx");
|
|
48809
|
+
if (await pathExists(path127.join(projectRuntime, ".git"))) {
|
|
48322
48810
|
return projectRuntime;
|
|
48323
48811
|
}
|
|
48324
48812
|
const home = process.env.HOME;
|
|
48325
48813
|
if (!home) {
|
|
48326
48814
|
return null;
|
|
48327
48815
|
}
|
|
48328
|
-
const globalRuntime =
|
|
48329
|
-
if (await pathExists(
|
|
48816
|
+
const globalRuntime = path127.join(home, ".keryx", "keryx");
|
|
48817
|
+
if (await pathExists(path127.join(globalRuntime, ".git"))) {
|
|
48330
48818
|
return globalRuntime;
|
|
48331
48819
|
}
|
|
48332
48820
|
return null;
|
|
48333
48821
|
}
|
|
48334
48822
|
async function createServiceDirs(metaprojectRoot, modules) {
|
|
48335
48823
|
const dirs = [
|
|
48336
|
-
|
|
48337
|
-
|
|
48338
|
-
|
|
48339
|
-
|
|
48340
|
-
|
|
48824
|
+
path127.join(metaprojectRoot, "core"),
|
|
48825
|
+
path127.join(metaprojectRoot, "hooks", "post-update.d"),
|
|
48826
|
+
path127.join(metaprojectRoot, "modules"),
|
|
48827
|
+
path127.join(metaprojectRoot, "rules"),
|
|
48828
|
+
path127.join(metaprojectRoot, "skills", "project-rules"),
|
|
48341
48829
|
...modules.enableGdgraph ? [
|
|
48342
|
-
|
|
48343
|
-
|
|
48830
|
+
path127.join(metaprojectRoot, "core", "gdgraph"),
|
|
48831
|
+
path127.join(metaprojectRoot, "skills", "gdgraph")
|
|
48344
48832
|
] : [],
|
|
48345
48833
|
...modules.enableGdctx ? [
|
|
48346
|
-
|
|
48347
|
-
|
|
48834
|
+
path127.join(metaprojectRoot, "core", "gdctx"),
|
|
48835
|
+
path127.join(metaprojectRoot, "skills", "gdctx")
|
|
48348
48836
|
] : [],
|
|
48349
48837
|
...modules.enableGdwiki ? [
|
|
48350
|
-
|
|
48351
|
-
|
|
48838
|
+
path127.join(metaprojectRoot, "skills", "gdwiki"),
|
|
48839
|
+
path127.join(metaprojectRoot, "wiki", "templates")
|
|
48352
48840
|
] : [],
|
|
48353
48841
|
...modules.enableHealth ? [
|
|
48354
|
-
|
|
48355
|
-
|
|
48842
|
+
path127.join(metaprojectRoot, "core", "health"),
|
|
48843
|
+
path127.join(metaprojectRoot, "skills", "health")
|
|
48356
48844
|
] : [],
|
|
48357
48845
|
...modules.enableTesting ? [
|
|
48358
|
-
|
|
48359
|
-
|
|
48846
|
+
path127.join(metaprojectRoot, "core", "testing"),
|
|
48847
|
+
path127.join(metaprojectRoot, "skills", "testing")
|
|
48360
48848
|
] : [],
|
|
48361
48849
|
...modules.enableMemory ? [
|
|
48362
|
-
|
|
48363
|
-
|
|
48364
|
-
|
|
48850
|
+
path127.join(metaprojectRoot, "core", "memory"),
|
|
48851
|
+
path127.join(metaprojectRoot, "skills", "memory"),
|
|
48852
|
+
path127.join(metaprojectRoot, "memory", "templates")
|
|
48365
48853
|
] : [],
|
|
48366
48854
|
...modules.enableTasks ? [
|
|
48367
|
-
|
|
48368
|
-
|
|
48855
|
+
path127.join(metaprojectRoot, "flows"),
|
|
48856
|
+
path127.join(metaprojectRoot, "skills", "flow")
|
|
48369
48857
|
] : [],
|
|
48370
48858
|
...modules.enableSecurity ? [
|
|
48371
|
-
|
|
48859
|
+
path127.join(metaprojectRoot, "core", "security")
|
|
48372
48860
|
] : []
|
|
48373
48861
|
];
|
|
48374
48862
|
await Promise.all(dirs.map((dir) => mkdir45(dir, { recursive: true })));
|
|
48375
48863
|
}
|
|
48376
48864
|
async function installGdgraphCoreScripts2(metaprojectRoot) {
|
|
48377
|
-
const gdgraphCoreRoot =
|
|
48865
|
+
const gdgraphCoreRoot = path127.join(metaprojectRoot, "core", "gdgraph");
|
|
48378
48866
|
await mkdir45(gdgraphCoreRoot, { recursive: true });
|
|
48379
48867
|
for (const file of GDGRAPH_CORE_SOURCES) {
|
|
48380
|
-
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`),
|
|
48868
|
+
await copyFileIfChanged2(runtimeSourcePath2(`../gdgraph/${file}`), path127.join(gdgraphCoreRoot, file));
|
|
48381
48869
|
}
|
|
48382
|
-
await writeTextIfChanged4(
|
|
48870
|
+
await writeTextIfChanged4(path127.join(gdgraphCoreRoot, "cli.ts"), renderGdgraphCoreCli());
|
|
48383
48871
|
}
|
|
48384
48872
|
async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
48385
48873
|
const hooksRoot = await resolveGitHooksRoot(projectRoot);
|
|
@@ -48387,7 +48875,7 @@ async function installManagedHook2(projectRoot, hookName, blockId, content) {
|
|
|
48387
48875
|
return;
|
|
48388
48876
|
}
|
|
48389
48877
|
await mkdir45(hooksRoot, { recursive: true });
|
|
48390
|
-
const hookPath =
|
|
48878
|
+
const hookPath = path127.join(hooksRoot, hookName);
|
|
48391
48879
|
const blockStart = `# keryx:${blockId}:begin`;
|
|
48392
48880
|
const blockEnd = `# keryx:${blockId}:end`;
|
|
48393
48881
|
const managedBlock = `${blockStart}
|
|
@@ -48408,7 +48896,7 @@ async function removeManagedHook2(projectRoot, hookName, blockId) {
|
|
|
48408
48896
|
if (!hooksRoot) {
|
|
48409
48897
|
return;
|
|
48410
48898
|
}
|
|
48411
|
-
const hookPath =
|
|
48899
|
+
const hookPath = path127.join(hooksRoot, hookName);
|
|
48412
48900
|
if (!await pathExists(hookPath)) {
|
|
48413
48901
|
return;
|
|
48414
48902
|
}
|
|
@@ -48430,7 +48918,7 @@ async function prePushHasSecurityBlock2(projectRoot) {
|
|
|
48430
48918
|
if (!hooksRoot) {
|
|
48431
48919
|
return false;
|
|
48432
48920
|
}
|
|
48433
|
-
const hookPath =
|
|
48921
|
+
const hookPath = path127.join(hooksRoot, "pre-push");
|
|
48434
48922
|
if (!await pathExists(hookPath)) {
|
|
48435
48923
|
return false;
|
|
48436
48924
|
}
|
|
@@ -48445,7 +48933,7 @@ async function agentSettingsHasSecuritySentinel2(projectRoot) {
|
|
|
48445
48933
|
return (await readFile64(file, "utf8")).includes(AGENT_HOOKS_SENTINEL);
|
|
48446
48934
|
}
|
|
48447
48935
|
async function readManifest5(metaprojectRoot) {
|
|
48448
|
-
const manifestPath =
|
|
48936
|
+
const manifestPath = path127.join(metaprojectRoot, "metaproject.json");
|
|
48449
48937
|
if (!await pathExists(manifestPath)) {
|
|
48450
48938
|
return {
|
|
48451
48939
|
exists: false,
|
|
@@ -48513,7 +49001,7 @@ async function inferManifestFromExistingMetaproject(metaprojectRoot) {
|
|
|
48513
49001
|
}
|
|
48514
49002
|
async function anyPathExists(root, candidates) {
|
|
48515
49003
|
for (const candidate of candidates) {
|
|
48516
|
-
if (await pathExists(
|
|
49004
|
+
if (await pathExists(path127.join(root, candidate))) {
|
|
48517
49005
|
return true;
|
|
48518
49006
|
}
|
|
48519
49007
|
}
|
|
@@ -48534,13 +49022,13 @@ function parseUpdateArgs(args2) {
|
|
|
48534
49022
|
};
|
|
48535
49023
|
}
|
|
48536
49024
|
async function runPostUpdateHooks(projectRoot) {
|
|
48537
|
-
const hooksDir =
|
|
49025
|
+
const hooksDir = path127.join(projectRoot, ".metaproject", "hooks", "post-update.d");
|
|
48538
49026
|
if (!await pathExists(hooksDir)) {
|
|
48539
49027
|
return;
|
|
48540
49028
|
}
|
|
48541
49029
|
const entries = (await readdir20(hooksDir)).sort();
|
|
48542
49030
|
for (const entry of entries) {
|
|
48543
|
-
const hookPath =
|
|
49031
|
+
const hookPath = path127.join(hooksDir, entry);
|
|
48544
49032
|
try {
|
|
48545
49033
|
await accessExecutable(hookPath);
|
|
48546
49034
|
} catch {
|
|
@@ -48581,14 +49069,14 @@ async function writeTextIfChanged4(filePath, content) {
|
|
|
48581
49069
|
if (await pathExists(filePath) && await readFile64(filePath, "utf8") === content) {
|
|
48582
49070
|
return;
|
|
48583
49071
|
}
|
|
48584
|
-
await mkdir45(
|
|
49072
|
+
await mkdir45(path127.dirname(filePath), { recursive: true });
|
|
48585
49073
|
await writeFile42(filePath, content, "utf8");
|
|
48586
49074
|
}
|
|
48587
49075
|
async function writeTextIfMissing4(filePath, content) {
|
|
48588
49076
|
if (await pathExists(filePath)) {
|
|
48589
49077
|
return;
|
|
48590
49078
|
}
|
|
48591
|
-
await mkdir45(
|
|
49079
|
+
await mkdir45(path127.dirname(filePath), { recursive: true });
|
|
48592
49080
|
await writeFile42(filePath, content, "utf8");
|
|
48593
49081
|
}
|
|
48594
49082
|
async function copyFileIfChanged2(from, to) {
|
|
@@ -48596,7 +49084,7 @@ async function copyFileIfChanged2(from, to) {
|
|
|
48596
49084
|
if (await pathExists(to) && await readFile64(to, "utf8") === next) {
|
|
48597
49085
|
return;
|
|
48598
49086
|
}
|
|
48599
|
-
await mkdir45(
|
|
49087
|
+
await mkdir45(path127.dirname(to), { recursive: true });
|
|
48600
49088
|
await writeFile42(to, next, "utf8");
|
|
48601
49089
|
}
|
|
48602
49090
|
function runtimeSourcePath2(relativePath) {
|
|
@@ -48605,7 +49093,7 @@ function runtimeSourcePath2(relativePath) {
|
|
|
48605
49093
|
return directPath;
|
|
48606
49094
|
}
|
|
48607
49095
|
if (relativePath.startsWith("../")) {
|
|
48608
|
-
const packagedSourcePath =
|
|
49096
|
+
const packagedSourcePath = path127.join(path127.dirname(fileURLToPath6(import.meta.url)), "..", "src", relativePath.slice(3));
|
|
48609
49097
|
if (existsSync27(packagedSourcePath)) {
|
|
48610
49098
|
return packagedSourcePath;
|
|
48611
49099
|
}
|
|
@@ -48637,7 +49125,7 @@ function printHelp18() {
|
|
|
48637
49125
|
|
|
48638
49126
|
// src/commands/dashboard.ts
|
|
48639
49127
|
import { spawn as spawn6 } from "child_process";
|
|
48640
|
-
import
|
|
49128
|
+
import path128 from "path";
|
|
48641
49129
|
init_args();
|
|
48642
49130
|
async function dashboardCommand(args2 = []) {
|
|
48643
49131
|
const options = parseOptions(args2);
|
|
@@ -48648,7 +49136,7 @@ async function dashboardCommand(args2 = []) {
|
|
|
48648
49136
|
}
|
|
48649
49137
|
if (subcommand === "build") {
|
|
48650
49138
|
const result = await buildDashboard();
|
|
48651
|
-
const rel =
|
|
49139
|
+
const rel = path128.relative(process.cwd(), result.path);
|
|
48652
49140
|
console.log(` ${style.green(symbols.ok)} Dashboard built ${style.cyan(symbols.arrow)} ${style.cyan(rel)}`);
|
|
48653
49141
|
note(`Open it: keryx dashboard open`);
|
|
48654
49142
|
return;
|
|
@@ -48656,7 +49144,7 @@ async function dashboardCommand(args2 = []) {
|
|
|
48656
49144
|
if (subcommand === "open") {
|
|
48657
49145
|
const result = await buildDashboard();
|
|
48658
49146
|
await openFile(result.path);
|
|
48659
|
-
const rel =
|
|
49147
|
+
const rel = path128.relative(process.cwd(), result.path);
|
|
48660
49148
|
console.log(` ${style.green(symbols.ok)} Opened ${style.cyan(rel)}`);
|
|
48661
49149
|
return;
|
|
48662
49150
|
}
|
|
@@ -48705,7 +49193,7 @@ import { readFileSync as readFileSync10 } from "fs";
|
|
|
48705
49193
|
// src/agents/bootstrap.ts
|
|
48706
49194
|
import { mkdir as mkdir46, readFile as readFile65, writeFile as writeFile43 } from "fs/promises";
|
|
48707
49195
|
import { homedir as homedir6 } from "os";
|
|
48708
|
-
import
|
|
49196
|
+
import path129 from "path";
|
|
48709
49197
|
init_fs();
|
|
48710
49198
|
var AGENT_BOOTSTRAP_START = "<!-- keryx:global-bootstrap -->";
|
|
48711
49199
|
var AGENT_BOOTSTRAP_END = "<!-- /keryx:global-bootstrap -->";
|
|
@@ -48715,35 +49203,35 @@ var AGENT_BOOTSTRAP_RUNTIMES = [
|
|
|
48715
49203
|
aliases: ["claude-code"],
|
|
48716
49204
|
label: "Claude Code",
|
|
48717
49205
|
fileName: "CLAUDE.md",
|
|
48718
|
-
filePath: (homeRoot) =>
|
|
49206
|
+
filePath: (homeRoot) => path129.join(homeRoot, ".claude", "CLAUDE.md")
|
|
48719
49207
|
},
|
|
48720
49208
|
{
|
|
48721
49209
|
id: "opencode",
|
|
48722
49210
|
aliases: ["open-code"],
|
|
48723
49211
|
label: "OpenCode",
|
|
48724
49212
|
fileName: "AGENTS.md",
|
|
48725
|
-
filePath: (homeRoot) =>
|
|
49213
|
+
filePath: (homeRoot) => path129.join(homeRoot, ".config", "opencode", "AGENTS.md")
|
|
48726
49214
|
},
|
|
48727
49215
|
{
|
|
48728
49216
|
id: "zcode",
|
|
48729
49217
|
aliases: ["zed", "zed-code"],
|
|
48730
49218
|
label: "ZCode",
|
|
48731
49219
|
fileName: "AGENTS.md",
|
|
48732
|
-
filePath: (homeRoot) =>
|
|
49220
|
+
filePath: (homeRoot) => path129.join(homeRoot, ".zcode", "AGENTS.md")
|
|
48733
49221
|
},
|
|
48734
49222
|
{
|
|
48735
49223
|
id: "codex",
|
|
48736
49224
|
aliases: [],
|
|
48737
49225
|
label: "Codex",
|
|
48738
49226
|
fileName: "AGENTS.md",
|
|
48739
|
-
filePath: (homeRoot) =>
|
|
49227
|
+
filePath: (homeRoot) => path129.join(homeRoot, ".codex", "AGENTS.md")
|
|
48740
49228
|
},
|
|
48741
49229
|
{
|
|
48742
49230
|
id: "antigravity",
|
|
48743
49231
|
aliases: ["antigravuty", "antigravity-code"],
|
|
48744
49232
|
label: "Antigravity",
|
|
48745
49233
|
fileName: "AGENTS.md",
|
|
48746
|
-
filePath: (homeRoot) =>
|
|
49234
|
+
filePath: (homeRoot) => path129.join(homeRoot, ".config", "antigravity", "AGENTS.md")
|
|
48747
49235
|
}
|
|
48748
49236
|
];
|
|
48749
49237
|
function agentBootstrapRuntimeIds() {
|
|
@@ -48791,7 +49279,7 @@ async function installAgentBootstrap(runtime, options = {}) {
|
|
|
48791
49279
|
const dryRun = options.dryRun === true;
|
|
48792
49280
|
const wrote = next !== current;
|
|
48793
49281
|
if (wrote && !dryRun) {
|
|
48794
|
-
await mkdir46(
|
|
49282
|
+
await mkdir46(path129.dirname(filePath), { recursive: true });
|
|
48795
49283
|
await writeFile43(filePath, next, "utf8");
|
|
48796
49284
|
}
|
|
48797
49285
|
const status = dryRun ? statusFromContent(runtime, filePath, exists2, next) : await agentBootstrapStatus(runtime, homeRoot);
|
|
@@ -49139,7 +49627,7 @@ function printBootstrapHelp() {
|
|
|
49139
49627
|
// src/commands/metrics.ts
|
|
49140
49628
|
init_args();
|
|
49141
49629
|
import { readFile as readFile66 } from "fs/promises";
|
|
49142
|
-
import
|
|
49630
|
+
import path130 from "path";
|
|
49143
49631
|
|
|
49144
49632
|
// src/metrics/benchmark.ts
|
|
49145
49633
|
function createPairedBenchmarkTemplate(taskIds) {
|
|
@@ -49367,7 +49855,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
49367
49855
|
console.log("# metrics status");
|
|
49368
49856
|
console.log("");
|
|
49369
49857
|
console.log(`root: ${root}`);
|
|
49370
|
-
console.log(`enabled: ${await Bun.file(
|
|
49858
|
+
console.log(`enabled: ${await Bun.file(path130.join(projectRoot, ".metaproject", "metaproject.json")).exists() ? "yes" : "no"}`);
|
|
49371
49859
|
const latest2 = await readLatestPointer(root);
|
|
49372
49860
|
console.log(`latest: ${latest2.status}`);
|
|
49373
49861
|
return;
|
|
@@ -49379,7 +49867,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
49379
49867
|
process.exitCode = 1;
|
|
49380
49868
|
return;
|
|
49381
49869
|
}
|
|
49382
|
-
const record2 = JSON.parse(await readFile66(
|
|
49870
|
+
const record2 = JSON.parse(await readFile66(path130.resolve(projectRoot, file), "utf8"));
|
|
49383
49871
|
const result = validateRunRecord(record2);
|
|
49384
49872
|
console.log(result.valid ? "valid: yes" : "valid: no");
|
|
49385
49873
|
for (const error of result.errors)
|
|
@@ -49404,7 +49892,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
49404
49892
|
process.exitCode = 1;
|
|
49405
49893
|
return;
|
|
49406
49894
|
}
|
|
49407
|
-
const file =
|
|
49895
|
+
const file = path130.join(metricsRoot(projectRoot), "runs", `${runId}.json`);
|
|
49408
49896
|
if (!await Bun.file(file).exists()) {
|
|
49409
49897
|
console.error(`Run not found: ${runId}`);
|
|
49410
49898
|
process.exitCode = 1;
|
|
@@ -49421,8 +49909,8 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
49421
49909
|
process.exitCode = 1;
|
|
49422
49910
|
return;
|
|
49423
49911
|
}
|
|
49424
|
-
const a = JSON.parse(await readFile66(
|
|
49425
|
-
const b = JSON.parse(await readFile66(
|
|
49912
|
+
const a = JSON.parse(await readFile66(path130.join(metricsRoot(projectRoot), "runs", `${runA}.json`), "utf8"));
|
|
49913
|
+
const b = JSON.parse(await readFile66(path130.join(metricsRoot(projectRoot), "runs", `${runB}.json`), "utf8"));
|
|
49426
49914
|
const comparison = compareExecutionRuns(a, b);
|
|
49427
49915
|
console.log(stableJson(comparison));
|
|
49428
49916
|
return;
|
|
@@ -49456,8 +49944,8 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
49456
49944
|
return;
|
|
49457
49945
|
}
|
|
49458
49946
|
const template = createPairedBenchmarkTemplate(taskIds);
|
|
49459
|
-
await Bun.write(
|
|
49460
|
-
console.log(`manifest: ${
|
|
49947
|
+
await Bun.write(path130.resolve(projectRoot, out), stableJson(template));
|
|
49948
|
+
console.log(`manifest: ${path130.relative(projectRoot, path130.resolve(projectRoot, out))}`);
|
|
49461
49949
|
return;
|
|
49462
49950
|
}
|
|
49463
49951
|
if (subcommand === "benchmark" && args2[1] === "validate") {
|
|
@@ -49467,7 +49955,7 @@ async function metricsCommand(args2 = [], projectRoot = process.cwd()) {
|
|
|
49467
49955
|
process.exitCode = 1;
|
|
49468
49956
|
return;
|
|
49469
49957
|
}
|
|
49470
|
-
const raw = JSON.parse(await readFile66(
|
|
49958
|
+
const raw = JSON.parse(await readFile66(path130.resolve(projectRoot, file), "utf8"));
|
|
49471
49959
|
const input2 = Array.isArray(raw) ? raw : raw.runs ?? [];
|
|
49472
49960
|
const result = validatePairedBenchmark(input2);
|
|
49473
49961
|
console.log(stableJson(result));
|
|
@@ -49485,7 +49973,7 @@ async function collect(projectRoot, args2) {
|
|
|
49485
49973
|
process.exitCode = 1;
|
|
49486
49974
|
return;
|
|
49487
49975
|
}
|
|
49488
|
-
const raw = JSON.parse(await readFile66(
|
|
49976
|
+
const raw = JSON.parse(await readFile66(path130.resolve(projectRoot, eventFile), "utf8"));
|
|
49489
49977
|
const events2 = Array.isArray(raw) ? raw : raw.events;
|
|
49490
49978
|
const startedAt = optionValue(args2, "--started-at") ?? events2[0]?.timestamp_utc ?? new Date().toISOString();
|
|
49491
49979
|
const finishedAt = optionValue(args2, "--finished-at") ?? events2.at(-1)?.timestamp_utc ?? startedAt;
|
|
@@ -49501,11 +49989,11 @@ async function collect(projectRoot, args2) {
|
|
|
49501
49989
|
parentRunId: optionValue(args2, "--parent-run-id") ?? null
|
|
49502
49990
|
});
|
|
49503
49991
|
const result = await writeRunArtifacts(metricsRoot(projectRoot), record2, { cwd: projectRoot });
|
|
49504
|
-
console.log(`json: ${
|
|
49505
|
-
console.log(`markdown: ${
|
|
49992
|
+
console.log(`json: ${path130.relative(projectRoot, result.jsonPath)}`);
|
|
49993
|
+
console.log(`markdown: ${path130.relative(projectRoot, result.markdownPath)}`);
|
|
49506
49994
|
}
|
|
49507
49995
|
function metricsRoot(projectRoot) {
|
|
49508
|
-
return
|
|
49996
|
+
return path130.join(projectRoot, ".metaproject", "data", "metrics");
|
|
49509
49997
|
}
|
|
49510
49998
|
function printMetricsHelp() {
|
|
49511
49999
|
console.log(`keryx metrics
|
|
@@ -49523,76 +50011,35 @@ Usage:
|
|
|
49523
50011
|
keryx metrics benchmark validate <manifest.json>
|
|
49524
50012
|
`);
|
|
49525
50013
|
}
|
|
49526
|
-
|
|
49527
|
-
|
|
49528
|
-
|
|
49529
|
-
|
|
49530
|
-
|
|
49531
|
-
|
|
49532
|
-
|
|
49533
|
-
|
|
49534
|
-
},
|
|
49535
|
-
license: "MIT",
|
|
49536
|
-
type: "module",
|
|
49537
|
-
repository: {
|
|
49538
|
-
type: "git",
|
|
49539
|
-
url: "git+ssh://git@github.com/MrCipherSmith/keryx.git"
|
|
49540
|
-
},
|
|
49541
|
-
keywords: [
|
|
49542
|
-
"ai-agents",
|
|
49543
|
-
"coding-agents",
|
|
49544
|
-
"agent-harness",
|
|
49545
|
-
"agent-context",
|
|
49546
|
-
"repository-context",
|
|
49547
|
-
"code-graph",
|
|
49548
|
-
"project-memory",
|
|
49549
|
-
"test-impact-analysis",
|
|
49550
|
-
"developer-tools",
|
|
49551
|
-
"model-context-protocol",
|
|
49552
|
-
"mcp",
|
|
49553
|
-
"claude-code",
|
|
49554
|
-
"cursor",
|
|
49555
|
-
"codex",
|
|
49556
|
-
"cli",
|
|
49557
|
-
"bun"
|
|
49558
|
-
],
|
|
49559
|
-
bin: {
|
|
49560
|
-
keryx: "./dist/cli.js"
|
|
49561
|
-
},
|
|
49562
|
-
scripts: {
|
|
49563
|
-
keryx: "bun ./src/cli.ts",
|
|
49564
|
-
build: "bun build ./src/cli.ts --outdir ./dist --target bun --external @modelcontextprotocol/sdk --external web-tree-sitter --external @opentui/core && bun build ./src/harness/process/sandbox/proxy-worker.ts --outdir ./dist --target bun --external @modelcontextprotocol/sdk --external web-tree-sitter --external @opentui/core",
|
|
49565
|
-
prepare: "bun run build",
|
|
49566
|
-
typecheck: "tsc --noEmit",
|
|
49567
|
-
test: "bun test",
|
|
49568
|
-
check: "tsc --noEmit && bun test",
|
|
49569
|
-
"check:doc-links": "bun scripts/check-doc-links.ts",
|
|
49570
|
-
"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"
|
|
49571
|
-
},
|
|
49572
|
-
files: [
|
|
49573
|
-
"dist",
|
|
49574
|
-
"src/gdgraph",
|
|
49575
|
-
"src/gdskills/bundled",
|
|
49576
|
-
"src/gdskills/contracts",
|
|
49577
|
-
"LICENSE",
|
|
49578
|
-
"README.md",
|
|
49579
|
-
"package.json"
|
|
49580
|
-
],
|
|
49581
|
-
dependencies: {},
|
|
49582
|
-
optionalDependencies: {
|
|
49583
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
49584
|
-
"@opentui/core": "^0.4.5",
|
|
49585
|
-
"web-tree-sitter": "^0.22.0"
|
|
49586
|
-
},
|
|
49587
|
-
devDependencies: {
|
|
49588
|
-
"@types/bun": "latest",
|
|
49589
|
-
"bun-types": "latest",
|
|
49590
|
-
typescript: "^5"
|
|
49591
|
-
},
|
|
49592
|
-
engines: {
|
|
49593
|
-
bun: ">=1.1.0"
|
|
50014
|
+
|
|
50015
|
+
// src/commands/version.ts
|
|
50016
|
+
async function versionCommand(args2, deps = {}) {
|
|
50017
|
+
const json = args2.length === 2 && args2[1] === "--json";
|
|
50018
|
+
if (args2[0] !== "check" || args2.length !== 1 && !json) {
|
|
50019
|
+
console.error("Usage: keryx version check [--json]");
|
|
50020
|
+
process.exitCode = 1;
|
|
50021
|
+
return;
|
|
49594
50022
|
}
|
|
49595
|
-
|
|
50023
|
+
const options = {
|
|
50024
|
+
currentVersion: deps.currentVersion ?? package_default.version,
|
|
50025
|
+
...deps.fetch !== undefined ? { fetch: deps.fetch } : {},
|
|
50026
|
+
...deps.cacheDir !== undefined ? { cacheDir: deps.cacheDir } : {},
|
|
50027
|
+
...deps.now !== undefined ? { now: deps.now } : {}
|
|
50028
|
+
};
|
|
50029
|
+
const result = await (deps.check ?? checkVersion)(options);
|
|
50030
|
+
if (json) {
|
|
50031
|
+
console.log(JSON.stringify(result));
|
|
50032
|
+
return;
|
|
50033
|
+
}
|
|
50034
|
+
if (result.status === "update-available") {
|
|
50035
|
+
console.log(`Keryx ${result.currentVersion} \u2192 ${result.latestVersion}`);
|
|
50036
|
+
console.log(result.installCommand);
|
|
50037
|
+
} else if (result.status === "up-to-date") {
|
|
50038
|
+
console.log(`Keryx ${result.currentVersion} is up to date.`);
|
|
50039
|
+
} else {
|
|
50040
|
+
console.log(`Keryx version check unavailable (${result.reason}).`);
|
|
50041
|
+
}
|
|
50042
|
+
}
|
|
49596
50043
|
|
|
49597
50044
|
// src/cli.ts
|
|
49598
50045
|
var VERSION2 = package_default.version;
|
|
@@ -49627,7 +50074,8 @@ var CLI_ROUTES = {
|
|
|
49627
50074
|
harness: harnessCommand,
|
|
49628
50075
|
shell: shellCommand,
|
|
49629
50076
|
sessions: sessionsCommand,
|
|
49630
|
-
session: sessionsCommand
|
|
50077
|
+
session: sessionsCommand,
|
|
50078
|
+
version: versionCommand
|
|
49631
50079
|
};
|
|
49632
50080
|
async function main() {
|
|
49633
50081
|
const args2 = process.argv.slice(2);
|
|
@@ -49658,6 +50106,7 @@ Usage:
|
|
|
49658
50106
|
Start TUI agent shell (sessions are per-project)
|
|
49659
50107
|
keryx sessions list|fork <id>|export <id>|path
|
|
49660
50108
|
List / branch / export sessions for the current project
|
|
50109
|
+
keryx version check [--json] Check npm latest (advisory; never installs)
|
|
49661
50110
|
keryx harness run --provider <fake|anthropic|ollama> --model <m> [--base-url <url>] [--record <path>] "<prompt>"
|
|
49662
50111
|
keryx harness exec [--allow-env KEY]... [--max-runtime-ms N] [--allow-real-subprocess]
|
|
49663
50112
|
[--allowed-domains a,b] [--mask-env NAME@host] [--tls-terminate] [--mask-mode auto|manual|off] [--auto-mask] -- <path> [args...]
|
|
@@ -49741,6 +50190,7 @@ Commands:
|
|
|
49741
50190
|
shell Start the interactive TUI agent harness. Use --no-tui or --chat to opt out.
|
|
49742
50191
|
Sessions: -c continue last in this project, -r [id] resume (per-project).
|
|
49743
50192
|
sessions List or export per-project shell sessions
|
|
50193
|
+
version Check whether a newer npm release is available
|
|
49744
50194
|
harness Run a single provider turn (harness run) and print structured events
|
|
49745
50195
|
init Initialize .metaproject in the current project
|
|
49746
50196
|
status Show local Metaproject status
|