@pleri/olam-cli 0.1.146 → 0.1.147
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/skills-migrate-hooks-back.d.ts +19 -0
- package/dist/commands/skills-migrate-hooks-back.d.ts.map +1 -0
- package/dist/commands/skills-migrate-hooks-back.js +83 -0
- package/dist/commands/skills-migrate-hooks-back.js.map +1 -0
- package/dist/commands/skills-migrate-hooks.d.ts +40 -0
- package/dist/commands/skills-migrate-hooks.d.ts.map +1 -0
- package/dist/commands/skills-migrate-hooks.js +178 -0
- package/dist/commands/skills-migrate-hooks.js.map +1 -0
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +49 -1
- package/dist/commands/skills.js.map +1 -1
- package/dist/image-digests.json +7 -7
- package/dist/index.js +1507 -553
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1196 -412
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -492,8 +492,8 @@ var init_parseUtil = __esm({
|
|
|
492
492
|
init_errors();
|
|
493
493
|
init_en();
|
|
494
494
|
makeIssue = (params) => {
|
|
495
|
-
const { data, path:
|
|
496
|
-
const fullPath = [...
|
|
495
|
+
const { data, path: path82, errorMaps, issueData } = params;
|
|
496
|
+
const fullPath = [...path82, ...issueData.path || []];
|
|
497
497
|
const fullIssue = {
|
|
498
498
|
...issueData,
|
|
499
499
|
path: fullPath
|
|
@@ -801,11 +801,11 @@ var init_types = __esm({
|
|
|
801
801
|
init_parseUtil();
|
|
802
802
|
init_util();
|
|
803
803
|
ParseInputLazyPath = class {
|
|
804
|
-
constructor(parent, value,
|
|
804
|
+
constructor(parent, value, path82, key) {
|
|
805
805
|
this._cachedPath = [];
|
|
806
806
|
this.parent = parent;
|
|
807
807
|
this.data = value;
|
|
808
|
-
this._path =
|
|
808
|
+
this._path = path82;
|
|
809
809
|
this._key = key;
|
|
810
810
|
}
|
|
811
811
|
get path() {
|
|
@@ -4286,7 +4286,7 @@ import YAML from "yaml";
|
|
|
4286
4286
|
function bootstrapStepCmd(entry) {
|
|
4287
4287
|
return typeof entry === "string" ? entry : entry.cmd;
|
|
4288
4288
|
}
|
|
4289
|
-
function refineForbiddenKeys(value,
|
|
4289
|
+
function refineForbiddenKeys(value, path82, ctx, rejectSource) {
|
|
4290
4290
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4291
4291
|
return;
|
|
4292
4292
|
}
|
|
@@ -4294,12 +4294,12 @@ function refineForbiddenKeys(value, path78, ctx, rejectSource) {
|
|
|
4294
4294
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4295
4295
|
ctx.addIssue({
|
|
4296
4296
|
code: external_exports.ZodIssueCode.custom,
|
|
4297
|
-
path: [...
|
|
4297
|
+
path: [...path82, key],
|
|
4298
4298
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
4299
4299
|
});
|
|
4300
4300
|
continue;
|
|
4301
4301
|
}
|
|
4302
|
-
if (rejectSource &&
|
|
4302
|
+
if (rejectSource && path82.length === 0 && key === "source") {
|
|
4303
4303
|
ctx.addIssue({
|
|
4304
4304
|
code: external_exports.ZodIssueCode.custom,
|
|
4305
4305
|
path: ["source"],
|
|
@@ -4307,21 +4307,21 @@ function refineForbiddenKeys(value, path78, ctx, rejectSource) {
|
|
|
4307
4307
|
});
|
|
4308
4308
|
continue;
|
|
4309
4309
|
}
|
|
4310
|
-
refineForbiddenKeys(value[key], [...
|
|
4310
|
+
refineForbiddenKeys(value[key], [...path82, key], ctx, false);
|
|
4311
4311
|
}
|
|
4312
4312
|
}
|
|
4313
|
-
function rejectForbiddenKeys(value,
|
|
4313
|
+
function rejectForbiddenKeys(value, path82, rejectSource) {
|
|
4314
4314
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4315
4315
|
return;
|
|
4316
4316
|
}
|
|
4317
4317
|
for (const key of Object.keys(value)) {
|
|
4318
4318
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4319
|
-
throw new Error(`[manifest] ${
|
|
4319
|
+
throw new Error(`[manifest] ${path82}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
4320
4320
|
}
|
|
4321
4321
|
if (rejectSource && key === "source") {
|
|
4322
|
-
throw new Error(`[manifest] ${
|
|
4322
|
+
throw new Error(`[manifest] ${path82}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
4323
4323
|
}
|
|
4324
|
-
rejectForbiddenKeys(value[key], `${
|
|
4324
|
+
rejectForbiddenKeys(value[key], `${path82}.${key}`, false);
|
|
4325
4325
|
}
|
|
4326
4326
|
}
|
|
4327
4327
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -5389,7 +5389,7 @@ async function safeText(res) {
|
|
|
5389
5389
|
}
|
|
5390
5390
|
}
|
|
5391
5391
|
function sleep(ms) {
|
|
5392
|
-
return new Promise((
|
|
5392
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
5393
5393
|
}
|
|
5394
5394
|
var DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, RETRY_COUNT, RETRY_BACKOFF_MS, AuthClient;
|
|
5395
5395
|
var init_client = __esm({
|
|
@@ -5500,8 +5500,8 @@ var init_client = __esm({
|
|
|
5500
5500
|
throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
|
|
5501
5501
|
}
|
|
5502
5502
|
}
|
|
5503
|
-
async request(method,
|
|
5504
|
-
const url2 = `${this.baseUrl}${
|
|
5503
|
+
async request(method, path82, body, attempt = 0) {
|
|
5504
|
+
const url2 = `${this.baseUrl}${path82}`;
|
|
5505
5505
|
const controller = new AbortController();
|
|
5506
5506
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
5507
5507
|
const headers = {};
|
|
@@ -5519,7 +5519,7 @@ var init_client = __esm({
|
|
|
5519
5519
|
} catch (err) {
|
|
5520
5520
|
if (attempt < RETRY_COUNT && isTransient(err)) {
|
|
5521
5521
|
await sleep(RETRY_BACKOFF_MS * (attempt + 1));
|
|
5522
|
-
return this.request(method,
|
|
5522
|
+
return this.request(method, path82, body, attempt + 1);
|
|
5523
5523
|
}
|
|
5524
5524
|
throw err;
|
|
5525
5525
|
} finally {
|
|
@@ -5541,7 +5541,7 @@ function resolveAuthServicePath() {
|
|
|
5541
5541
|
return path9.join(pkgsDir, "auth-service");
|
|
5542
5542
|
}
|
|
5543
5543
|
function sleep2(ms) {
|
|
5544
|
-
return new Promise((
|
|
5544
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
5545
5545
|
}
|
|
5546
5546
|
var DEFAULT_PORT, DEFAULT_VOLUME, DEFAULT_CONTAINER, DEFAULT_IMAGE, AuthContainerController;
|
|
5547
5547
|
var init_container = __esm({
|
|
@@ -5839,7 +5839,7 @@ var init_network = __esm({
|
|
|
5839
5839
|
// ../adapters/dist/docker/pull.js
|
|
5840
5840
|
import { spawn } from "node:child_process";
|
|
5841
5841
|
function spawnAsync(cmd, args, opts = {}) {
|
|
5842
|
-
return new Promise((
|
|
5842
|
+
return new Promise((resolve19) => {
|
|
5843
5843
|
const child = spawn(cmd, [...args], {
|
|
5844
5844
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5845
5845
|
signal: opts.signal
|
|
@@ -5853,10 +5853,10 @@ function spawnAsync(cmd, args, opts = {}) {
|
|
|
5853
5853
|
stderr += chunk.toString();
|
|
5854
5854
|
});
|
|
5855
5855
|
child.on("error", (err) => {
|
|
5856
|
-
|
|
5856
|
+
resolve19({ exitCode: -1, stdout, stderr: stderr + err.message });
|
|
5857
5857
|
});
|
|
5858
5858
|
child.on("close", (code) => {
|
|
5859
|
-
|
|
5859
|
+
resolve19({ exitCode: code ?? -1, stdout, stderr });
|
|
5860
5860
|
});
|
|
5861
5861
|
});
|
|
5862
5862
|
}
|
|
@@ -6330,7 +6330,7 @@ var demuxStream, execInContainer;
|
|
|
6330
6330
|
var init_exec = __esm({
|
|
6331
6331
|
"../adapters/dist/docker/exec.js"() {
|
|
6332
6332
|
"use strict";
|
|
6333
|
-
demuxStream = (stream) => new Promise((
|
|
6333
|
+
demuxStream = (stream) => new Promise((resolve19, reject) => {
|
|
6334
6334
|
const stdoutChunks = [];
|
|
6335
6335
|
const stderrChunks = [];
|
|
6336
6336
|
const stdout = new PassThrough();
|
|
@@ -6344,7 +6344,7 @@ var init_exec = __esm({
|
|
|
6344
6344
|
stream.pipe(stdout);
|
|
6345
6345
|
}
|
|
6346
6346
|
stream.on("end", () => {
|
|
6347
|
-
|
|
6347
|
+
resolve19({
|
|
6348
6348
|
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
6349
6349
|
stderr: Buffer.concat(stderrChunks).toString("utf-8")
|
|
6350
6350
|
});
|
|
@@ -6804,7 +6804,7 @@ var init_connection = __esm({
|
|
|
6804
6804
|
// -----------------------------------------------------------------------
|
|
6805
6805
|
async exec(host, command) {
|
|
6806
6806
|
const client = await this.getConnection(host);
|
|
6807
|
-
return new Promise((
|
|
6807
|
+
return new Promise((resolve19, reject) => {
|
|
6808
6808
|
client.exec(command, (err, stream) => {
|
|
6809
6809
|
if (err) {
|
|
6810
6810
|
reject(new Error(`SSH exec failed on ${host}: ${err.message}`));
|
|
@@ -6819,7 +6819,7 @@ var init_connection = __esm({
|
|
|
6819
6819
|
stderr += data.toString();
|
|
6820
6820
|
});
|
|
6821
6821
|
stream.on("close", (code) => {
|
|
6822
|
-
|
|
6822
|
+
resolve19({
|
|
6823
6823
|
exitCode: code ?? 0,
|
|
6824
6824
|
stdout: stdout.trimEnd(),
|
|
6825
6825
|
stderr: stderr.trimEnd()
|
|
@@ -6850,10 +6850,10 @@ var init_connection = __esm({
|
|
|
6850
6850
|
throw new Error(`No SSH configuration found for host: ${host}`);
|
|
6851
6851
|
}
|
|
6852
6852
|
const client = new SSHClient();
|
|
6853
|
-
return new Promise((
|
|
6853
|
+
return new Promise((resolve19, reject) => {
|
|
6854
6854
|
client.on("ready", () => {
|
|
6855
6855
|
this.connections.set(host, client);
|
|
6856
|
-
|
|
6856
|
+
resolve19(client);
|
|
6857
6857
|
}).on("error", (err) => {
|
|
6858
6858
|
this.connections.delete(host);
|
|
6859
6859
|
reject(new Error(`SSH connection to ${host} failed: ${err.message}`));
|
|
@@ -7292,8 +7292,8 @@ var init_provider3 = __esm({
|
|
|
7292
7292
|
// -----------------------------------------------------------------------
|
|
7293
7293
|
// Internal fetch helper
|
|
7294
7294
|
// -----------------------------------------------------------------------
|
|
7295
|
-
async request(
|
|
7296
|
-
const url2 = `${this.config.workerUrl}${
|
|
7295
|
+
async request(path82, method, body) {
|
|
7296
|
+
const url2 = `${this.config.workerUrl}${path82}`;
|
|
7297
7297
|
const bearer = await this.config.mintToken();
|
|
7298
7298
|
const headers = {
|
|
7299
7299
|
Authorization: `Bearer ${bearer}`
|
|
@@ -8640,17 +8640,17 @@ function kgRoot() {
|
|
|
8640
8640
|
function worldsRoot() {
|
|
8641
8641
|
return join16(olamHome(), "worlds");
|
|
8642
8642
|
}
|
|
8643
|
-
function assertWithinPrefix(
|
|
8644
|
-
if (!
|
|
8645
|
-
throw new Error(`${label} escape: ${
|
|
8643
|
+
function assertWithinPrefix(path82, prefix, label) {
|
|
8644
|
+
if (!path82.startsWith(prefix + "/")) {
|
|
8645
|
+
throw new Error(`${label} escape: ${path82} not under ${prefix}/`);
|
|
8646
8646
|
}
|
|
8647
8647
|
}
|
|
8648
8648
|
function kgPristinePath(workspace) {
|
|
8649
8649
|
validateWorkspaceName(workspace);
|
|
8650
8650
|
const root = kgRoot();
|
|
8651
|
-
const
|
|
8652
|
-
assertWithinPrefix(
|
|
8653
|
-
return
|
|
8651
|
+
const path82 = resolve5(join16(root, workspace));
|
|
8652
|
+
assertWithinPrefix(path82, root, "kgPristinePath");
|
|
8653
|
+
return path82;
|
|
8654
8654
|
}
|
|
8655
8655
|
var KG_PATHS_INTERNALS;
|
|
8656
8656
|
var init_storage_paths = __esm({
|
|
@@ -8765,8 +8765,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
|
|
|
8765
8765
|
import * as fs15 from "node:fs";
|
|
8766
8766
|
import * as os9 from "node:os";
|
|
8767
8767
|
import * as path16 from "node:path";
|
|
8768
|
-
function expandHome2(p,
|
|
8769
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
8768
|
+
function expandHome2(p, homedir47) {
|
|
8769
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir47());
|
|
8770
8770
|
}
|
|
8771
8771
|
function sanitizeRepoFilename(name) {
|
|
8772
8772
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -8789,7 +8789,7 @@ ${stderr}`;
|
|
|
8789
8789
|
}
|
|
8790
8790
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
8791
8791
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
|
|
8792
|
-
const
|
|
8792
|
+
const homedir47 = deps.homedir ?? (() => os9.homedir());
|
|
8793
8793
|
const baselineDir = path16.join(workspacePath, ".olam", "baseline");
|
|
8794
8794
|
try {
|
|
8795
8795
|
fs15.mkdirSync(baselineDir, { recursive: true });
|
|
@@ -8805,7 +8805,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8805
8805
|
continue;
|
|
8806
8806
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
8807
8807
|
const outPath = path16.join(baselineDir, filename);
|
|
8808
|
-
const repoPath = expandHome2(repo.path,
|
|
8808
|
+
const repoPath = expandHome2(repo.path, homedir47);
|
|
8809
8809
|
if (!fs15.existsSync(repoPath)) {
|
|
8810
8810
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
8811
8811
|
# (skipped: path ${repoPath} does not exist)
|
|
@@ -8925,21 +8925,21 @@ function extractStderr(err) {
|
|
|
8925
8925
|
}
|
|
8926
8926
|
function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
8927
8927
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
|
|
8928
|
-
const
|
|
8929
|
-
const
|
|
8928
|
+
const homedir47 = deps.homedir ?? (() => os9.homedir());
|
|
8929
|
+
const existsSync90 = deps.existsSync ?? ((p) => fs15.existsSync(p));
|
|
8930
8930
|
const copyFileSync12 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
|
|
8931
|
-
const
|
|
8931
|
+
const mkdirSync51 = deps.mkdirSync ?? ((dirPath, opts) => {
|
|
8932
8932
|
fs15.mkdirSync(dirPath, opts);
|
|
8933
8933
|
});
|
|
8934
8934
|
const plans = [];
|
|
8935
8935
|
for (const repo of repos) {
|
|
8936
8936
|
if (!repo.path)
|
|
8937
8937
|
continue;
|
|
8938
|
-
const repoPath = expandHome2(repo.path,
|
|
8938
|
+
const repoPath = expandHome2(repo.path, homedir47);
|
|
8939
8939
|
const worktreePath = path16.join(workspacePath, repo.name);
|
|
8940
|
-
if (!
|
|
8940
|
+
if (!existsSync90(repoPath))
|
|
8941
8941
|
continue;
|
|
8942
|
-
if (!
|
|
8942
|
+
if (!existsSync90(worktreePath)) {
|
|
8943
8943
|
console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
|
|
8944
8944
|
continue;
|
|
8945
8945
|
}
|
|
@@ -8999,10 +8999,10 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
|
8999
8999
|
for (const rel of plan.diff.untracked) {
|
|
9000
9000
|
const src = path16.join(plan.repoPath, rel);
|
|
9001
9001
|
const dest = path16.join(plan.worktreePath, rel);
|
|
9002
|
-
if (!
|
|
9002
|
+
if (!existsSync90(src))
|
|
9003
9003
|
continue;
|
|
9004
9004
|
try {
|
|
9005
|
-
|
|
9005
|
+
mkdirSync51(path16.dirname(dest), { recursive: true });
|
|
9006
9006
|
copyFileSync12(src, dest);
|
|
9007
9007
|
} catch (err) {
|
|
9008
9008
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -10515,7 +10515,7 @@ var init_loader2 = __esm({
|
|
|
10515
10515
|
});
|
|
10516
10516
|
|
|
10517
10517
|
// ../core/dist/world/auto-dispatch-task.js
|
|
10518
|
-
async function probeHealth(containerName, dockerExec, budgetMs,
|
|
10518
|
+
async function probeHealth(containerName, dockerExec, budgetMs, sleep8) {
|
|
10519
10519
|
const deadline = Date.now() + budgetMs;
|
|
10520
10520
|
const cadenceMs = 100;
|
|
10521
10521
|
let lastErr = "";
|
|
@@ -10528,7 +10528,7 @@ async function probeHealth(containerName, dockerExec, budgetMs, sleep7) {
|
|
|
10528
10528
|
} catch (err) {
|
|
10529
10529
|
lastErr = err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200);
|
|
10530
10530
|
}
|
|
10531
|
-
await
|
|
10531
|
+
await sleep8(cadenceMs);
|
|
10532
10532
|
}
|
|
10533
10533
|
throw new TaskDispatchError(`container-cp /health did not return 200 within ${budgetMs}ms`, "health-probe", lastErr || "no response");
|
|
10534
10534
|
}
|
|
@@ -10564,9 +10564,9 @@ function composeTaskPrompt(task, policies, formatPoliciesBrief2) {
|
|
|
10564
10564
|
${task}`;
|
|
10565
10565
|
}
|
|
10566
10566
|
async function autoDispatchTask(opts) {
|
|
10567
|
-
const { containerName, task, policies, dockerExec, healthBudgetMs = 15e3, sleep:
|
|
10567
|
+
const { containerName, task, policies, dockerExec, healthBudgetMs = 15e3, sleep: sleep8 = DEFAULT_SLEEP, logger = console, formatPoliciesBrief: formatPoliciesBrief2 } = opts;
|
|
10568
10568
|
const finalPrompt = composeTaskPrompt(task, policies, formatPoliciesBrief2);
|
|
10569
|
-
await probeHealth(containerName, dockerExec, healthBudgetMs,
|
|
10569
|
+
await probeHealth(containerName, dockerExec, healthBudgetMs, sleep8);
|
|
10570
10570
|
startAgent(containerName, dockerExec);
|
|
10571
10571
|
dispatch(containerName, finalPrompt, dockerExec);
|
|
10572
10572
|
logger.log(`[world] Task auto-dispatched (${finalPrompt.length} chars)`);
|
|
@@ -10585,7 +10585,7 @@ var init_auto_dispatch_task = __esm({
|
|
|
10585
10585
|
this.name = "TaskDispatchError";
|
|
10586
10586
|
}
|
|
10587
10587
|
};
|
|
10588
|
-
DEFAULT_SLEEP = (ms) => new Promise((
|
|
10588
|
+
DEFAULT_SLEEP = (ms) => new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
10589
10589
|
}
|
|
10590
10590
|
});
|
|
10591
10591
|
|
|
@@ -10616,7 +10616,7 @@ function isAbsoluteOrTilde(p) {
|
|
|
10616
10616
|
function hasNoTraversalComponents(p) {
|
|
10617
10617
|
return !p.split("/").some((seg) => seg === "..");
|
|
10618
10618
|
}
|
|
10619
|
-
var RepoEntrySchema, PortMapSchema, SeedSqlFileSchema, SeedCommandSchema, SeedFixtureCopySchema, SeedSchema, RunbookSchema, GlobalConfigSchema, DEFAULT_GLOBAL_CONFIG;
|
|
10619
|
+
var RepoEntrySchema, PortMapSchema, SeedSqlFileSchema, SeedCommandSchema, SeedFixtureCopySchema, SeedSchema, RunbookSchema, MetaHookBlockKindSchema, GlobalConfigSchema, DEFAULT_GLOBAL_CONFIG;
|
|
10620
10620
|
var init_schema4 = __esm({
|
|
10621
10621
|
"../core/dist/global-config/schema.js"() {
|
|
10622
10622
|
"use strict";
|
|
@@ -10666,11 +10666,19 @@ var init_schema4 = __esm({
|
|
|
10666
10666
|
env: external_exports.record(external_exports.string().min(1), external_exports.record(external_exports.string().min(1), external_exports.string())).optional(),
|
|
10667
10667
|
updatedAt: external_exports.number().int().nonnegative()
|
|
10668
10668
|
});
|
|
10669
|
+
MetaHookBlockKindSchema = external_exports.enum(["memory-recall", "memory-classify"]);
|
|
10669
10670
|
GlobalConfigSchema = external_exports.object({
|
|
10670
10671
|
schemaVersion: external_exports.literal(1),
|
|
10671
10672
|
repos: external_exports.array(RepoEntrySchema).optional().default([]),
|
|
10672
10673
|
runbooks: external_exports.array(RunbookSchema).optional().default([]),
|
|
10673
|
-
skillSources: external_exports.array(SkillSourceSchema).optional().default([])
|
|
10674
|
+
skillSources: external_exports.array(SkillSourceSchema).optional().default([]),
|
|
10675
|
+
/**
|
|
10676
|
+
* Phase B B4 — per-block disable list. Operator escape-hatch when a
|
|
10677
|
+
* specific meta-hook misbehaves; engine `injectMetaHooks` filters
|
|
10678
|
+
* these out regardless of services-status detection. CLI
|
|
10679
|
+
* `--meta-hooks-disabled <a,b>` flag (deferred) can override per-call.
|
|
10680
|
+
*/
|
|
10681
|
+
metaHooksDisabled: external_exports.array(MetaHookBlockKindSchema).optional().default([])
|
|
10674
10682
|
}).strip().superRefine((val, ctx) => {
|
|
10675
10683
|
const repoNames = val.repos.map((r) => r.name);
|
|
10676
10684
|
const repoDupes = repoNames.filter((n, i) => repoNames.indexOf(n) !== i);
|
|
@@ -10697,7 +10705,8 @@ var init_schema4 = __esm({
|
|
|
10697
10705
|
schemaVersion: 1,
|
|
10698
10706
|
repos: [],
|
|
10699
10707
|
runbooks: [],
|
|
10700
|
-
skillSources: []
|
|
10708
|
+
skillSources: [],
|
|
10709
|
+
metaHooksDisabled: []
|
|
10701
10710
|
};
|
|
10702
10711
|
}
|
|
10703
10712
|
});
|
|
@@ -11106,7 +11115,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
|
|
|
11106
11115
|
const probeTimeoutMs = options.probeTimeoutMs ?? 3e4;
|
|
11107
11116
|
const probeIntervalMs = options.probeIntervalMs ?? 1e3;
|
|
11108
11117
|
const clock = options.clock ?? Date.now;
|
|
11109
|
-
const
|
|
11118
|
+
const sleep8 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
11110
11119
|
for (const repo of repos) {
|
|
11111
11120
|
if (isPortBound(exec, containerName, repo.hostPort)) {
|
|
11112
11121
|
throw new PortInUseError(repo.hostPort, repo.name, repo.manifestPath);
|
|
@@ -11131,7 +11140,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
|
|
|
11131
11140
|
probeTimeoutMs,
|
|
11132
11141
|
probeIntervalMs,
|
|
11133
11142
|
clock,
|
|
11134
|
-
sleep:
|
|
11143
|
+
sleep: sleep8
|
|
11135
11144
|
})));
|
|
11136
11145
|
return {
|
|
11137
11146
|
sessionName,
|
|
@@ -14249,7 +14258,7 @@ function isCloudflaredAvailable() {
|
|
|
14249
14258
|
}
|
|
14250
14259
|
}
|
|
14251
14260
|
function startTunnel(port2) {
|
|
14252
|
-
return new Promise((
|
|
14261
|
+
return new Promise((resolve19, reject) => {
|
|
14253
14262
|
const child = spawn3("cloudflared", ["tunnel", "--url", `http://localhost:${port2}`], {
|
|
14254
14263
|
stdio: ["ignore", "pipe", "pipe"],
|
|
14255
14264
|
detached: false
|
|
@@ -14271,7 +14280,7 @@ function startTunnel(port2) {
|
|
|
14271
14280
|
if (match2) {
|
|
14272
14281
|
resolved = true;
|
|
14273
14282
|
clearTimeout(timeout);
|
|
14274
|
-
|
|
14283
|
+
resolve19(match2[0]);
|
|
14275
14284
|
}
|
|
14276
14285
|
}
|
|
14277
14286
|
child.stdout?.on("data", scan);
|
|
@@ -14358,8 +14367,8 @@ var init_dashboard = __esm({
|
|
|
14358
14367
|
}
|
|
14359
14368
|
throw err;
|
|
14360
14369
|
}
|
|
14361
|
-
await new Promise((
|
|
14362
|
-
this.server.on("listening",
|
|
14370
|
+
await new Promise((resolve19, reject) => {
|
|
14371
|
+
this.server.on("listening", resolve19);
|
|
14363
14372
|
this.server.on("error", reject);
|
|
14364
14373
|
});
|
|
14365
14374
|
this.info = { localUrl: `http://localhost:${port2}` };
|
|
@@ -14405,8 +14414,8 @@ var init_dashboard = __esm({
|
|
|
14405
14414
|
async stop() {
|
|
14406
14415
|
stopTunnel();
|
|
14407
14416
|
if (this.server) {
|
|
14408
|
-
await new Promise((
|
|
14409
|
-
this.server.close(() =>
|
|
14417
|
+
await new Promise((resolve19) => {
|
|
14418
|
+
this.server.close(() => resolve19());
|
|
14410
14419
|
});
|
|
14411
14420
|
this.server = null;
|
|
14412
14421
|
}
|
|
@@ -15095,10 +15104,10 @@ async function readHostCpToken2() {
|
|
|
15095
15104
|
if (!fs26.existsSync(tp)) return null;
|
|
15096
15105
|
return fs26.readFileSync(tp, "utf-8").trim();
|
|
15097
15106
|
}
|
|
15098
|
-
async function callHostCpProxy(method, worldId,
|
|
15107
|
+
async function callHostCpProxy(method, worldId, path82, body) {
|
|
15099
15108
|
const token = await readHostCpToken2();
|
|
15100
15109
|
if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
|
|
15101
|
-
const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${
|
|
15110
|
+
const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path82}`;
|
|
15102
15111
|
try {
|
|
15103
15112
|
const headers = {
|
|
15104
15113
|
Authorization: `Bearer ${token}`
|
|
@@ -15492,7 +15501,7 @@ async function ensureOlamPostgresSingleton(options = {}) {
|
|
|
15492
15501
|
};
|
|
15493
15502
|
}
|
|
15494
15503
|
function sleep3(ms) {
|
|
15495
|
-
return new Promise((
|
|
15504
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
15496
15505
|
}
|
|
15497
15506
|
var DEFAULT_POSTGRES_NETWORK, DEFAULT_POSTGRES_CONTAINER, DEFAULT_POSTGRES_HOST_PORT, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_READY_TIMEOUT_MS;
|
|
15498
15507
|
var init_postgres_init_helpers = __esm({
|
|
@@ -16135,9 +16144,9 @@ var UnknownArchetypeError = class extends Error {
|
|
|
16135
16144
|
};
|
|
16136
16145
|
var ArchetypeCycleError = class extends Error {
|
|
16137
16146
|
path;
|
|
16138
|
-
constructor(
|
|
16139
|
-
super(`Archetype inheritance cycle detected: ${
|
|
16140
|
-
this.path =
|
|
16147
|
+
constructor(path82) {
|
|
16148
|
+
super(`Archetype inheritance cycle detected: ${path82.join(" \u2192 ")} \u2192 ${path82[0] ?? "?"}`);
|
|
16149
|
+
this.path = path82;
|
|
16141
16150
|
this.name = "ArchetypeCycleError";
|
|
16142
16151
|
}
|
|
16143
16152
|
};
|
|
@@ -16765,10 +16774,10 @@ async function confirm(message) {
|
|
|
16765
16774
|
if (!process.stdin.isTTY) return true;
|
|
16766
16775
|
const { createInterface: createInterface9 } = await import("node:readline");
|
|
16767
16776
|
const rl = createInterface9({ input: process.stdin, output: process.stdout });
|
|
16768
|
-
return new Promise((
|
|
16777
|
+
return new Promise((resolve19) => {
|
|
16769
16778
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
16770
16779
|
rl.close();
|
|
16771
|
-
|
|
16780
|
+
resolve19(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
16772
16781
|
});
|
|
16773
16782
|
});
|
|
16774
16783
|
}
|
|
@@ -17219,7 +17228,7 @@ var KgServiceContainerController = class {
|
|
|
17219
17228
|
}
|
|
17220
17229
|
};
|
|
17221
17230
|
function sleep4(ms) {
|
|
17222
|
-
return new Promise((
|
|
17231
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
17223
17232
|
}
|
|
17224
17233
|
|
|
17225
17234
|
// src/commands/services.ts
|
|
@@ -17307,7 +17316,7 @@ var McpAuthContainerController = class {
|
|
|
17307
17316
|
}
|
|
17308
17317
|
};
|
|
17309
17318
|
function sleep5(ms) {
|
|
17310
|
-
return new Promise((
|
|
17319
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
17311
17320
|
}
|
|
17312
17321
|
function dumpContainerLogs(container, tail = 40) {
|
|
17313
17322
|
try {
|
|
@@ -17725,9 +17734,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
|
|
|
17725
17734
|
"These source files have changed since the image was built; the",
|
|
17726
17735
|
"changes will NOT take effect in fresh worlds until you rebuild:"
|
|
17727
17736
|
];
|
|
17728
|
-
for (const { path:
|
|
17737
|
+
for (const { path: path82, mtimeMs } of result.newerSources) {
|
|
17729
17738
|
const when = new Date(mtimeMs).toISOString();
|
|
17730
|
-
lines.push(` \u2022 ${
|
|
17739
|
+
lines.push(` \u2022 ${path82} (modified ${when})`);
|
|
17731
17740
|
}
|
|
17732
17741
|
lines.push("");
|
|
17733
17742
|
lines.push("Rebuild with:");
|
|
@@ -17895,56 +17904,56 @@ var SECRET_LEN_BYTES = 32;
|
|
|
17895
17904
|
function generateSecret() {
|
|
17896
17905
|
return randomBytes6(SECRET_LEN_BYTES).toString("hex");
|
|
17897
17906
|
}
|
|
17898
|
-
function writeSecretAtPath(
|
|
17899
|
-
mkdirSync18(dirname19(
|
|
17900
|
-
const tmp = `${
|
|
17907
|
+
function writeSecretAtPath(path82, value) {
|
|
17908
|
+
mkdirSync18(dirname19(path82), { recursive: true });
|
|
17909
|
+
const tmp = `${path82}.tmp.${process.pid}`;
|
|
17901
17910
|
writeFileSync13(tmp, value, { mode: 384 });
|
|
17902
17911
|
chmodSync3(tmp, 384);
|
|
17903
|
-
renameSync4(tmp,
|
|
17912
|
+
renameSync4(tmp, path82);
|
|
17904
17913
|
}
|
|
17905
|
-
function readSecretAtPathOrNull(
|
|
17906
|
-
if (!existsSync28(
|
|
17907
|
-
const mode = statSync7(
|
|
17914
|
+
function readSecretAtPathOrNull(path82) {
|
|
17915
|
+
if (!existsSync28(path82)) return null;
|
|
17916
|
+
const mode = statSync7(path82).mode & 511;
|
|
17908
17917
|
if (mode !== 384) {
|
|
17909
17918
|
process.stderr.write(
|
|
17910
|
-
`warn: ${
|
|
17919
|
+
`warn: ${path82} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
|
|
17911
17920
|
`
|
|
17912
17921
|
);
|
|
17913
17922
|
}
|
|
17914
|
-
return readFileSync20(
|
|
17923
|
+
return readFileSync20(path82, "utf8").trim();
|
|
17915
17924
|
}
|
|
17916
|
-
function readSecretAtPath(
|
|
17917
|
-
const v = readSecretAtPathOrNull(
|
|
17925
|
+
function readSecretAtPath(path82) {
|
|
17926
|
+
const v = readSecretAtPathOrNull(path82);
|
|
17918
17927
|
if (v === null) {
|
|
17919
17928
|
throw new Error(
|
|
17920
|
-
`Secret not found at ${
|
|
17929
|
+
`Secret not found at ${path82}. Run 'olam memory start' to generate it.`
|
|
17921
17930
|
);
|
|
17922
17931
|
}
|
|
17923
17932
|
return v;
|
|
17924
17933
|
}
|
|
17925
|
-
function ensureMemorySecret(
|
|
17926
|
-
const existing = readSecretAtPathOrNull(
|
|
17934
|
+
function ensureMemorySecret(path82 = MEMORY_SECRET_PATH) {
|
|
17935
|
+
const existing = readSecretAtPathOrNull(path82);
|
|
17927
17936
|
if (existing) return existing;
|
|
17928
17937
|
const fresh = generateSecret();
|
|
17929
|
-
writeSecretAtPath(
|
|
17938
|
+
writeSecretAtPath(path82, fresh);
|
|
17930
17939
|
return fresh;
|
|
17931
17940
|
}
|
|
17932
|
-
function readMemorySecretOrNull(
|
|
17933
|
-
return readSecretAtPathOrNull(
|
|
17941
|
+
function readMemorySecretOrNull(path82 = MEMORY_SECRET_PATH) {
|
|
17942
|
+
return readSecretAtPathOrNull(path82);
|
|
17934
17943
|
}
|
|
17935
|
-
function readMemorySecret(
|
|
17936
|
-
return readSecretAtPath(
|
|
17944
|
+
function readMemorySecret(path82 = MEMORY_SECRET_PATH) {
|
|
17945
|
+
return readSecretAtPath(path82);
|
|
17937
17946
|
}
|
|
17938
|
-
function rotateMemorySecret(
|
|
17947
|
+
function rotateMemorySecret(path82 = MEMORY_SECRET_PATH) {
|
|
17939
17948
|
const fresh = generateSecret();
|
|
17940
|
-
writeSecretAtPath(
|
|
17949
|
+
writeSecretAtPath(path82, fresh);
|
|
17941
17950
|
return fresh;
|
|
17942
17951
|
}
|
|
17943
|
-
function hasMemorySecret(
|
|
17944
|
-
return existsSync28(
|
|
17952
|
+
function hasMemorySecret(path82 = MEMORY_SECRET_PATH) {
|
|
17953
|
+
return existsSync28(path82);
|
|
17945
17954
|
}
|
|
17946
|
-
function writeCloudMemorySecret(value,
|
|
17947
|
-
writeSecretAtPath(
|
|
17955
|
+
function writeCloudMemorySecret(value, path82 = CLOUD_MEMORY_SECRET_PATH) {
|
|
17956
|
+
writeSecretAtPath(path82, value);
|
|
17948
17957
|
}
|
|
17949
17958
|
|
|
17950
17959
|
// src/lib/world-mcp-register.ts
|
|
@@ -18016,15 +18025,15 @@ var AGENTMEMORY_LOCAL_URL = "http://host.docker.internal:3111";
|
|
|
18016
18025
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
18017
18026
|
async function readHostCpTokenForCreate() {
|
|
18018
18027
|
try {
|
|
18019
|
-
const { default:
|
|
18020
|
-
const { default:
|
|
18021
|
-
const { default:
|
|
18022
|
-
const tp =
|
|
18023
|
-
process.env.OLAM_HOME ??
|
|
18028
|
+
const { default: fs82 } = await import("node:fs");
|
|
18029
|
+
const { default: os45 } = await import("node:os");
|
|
18030
|
+
const { default: path82 } = await import("node:path");
|
|
18031
|
+
const tp = path82.join(
|
|
18032
|
+
process.env.OLAM_HOME ?? path82.join(os45.homedir(), ".olam"),
|
|
18024
18033
|
"host-cp.token"
|
|
18025
18034
|
);
|
|
18026
|
-
if (!
|
|
18027
|
-
return
|
|
18035
|
+
if (!fs82.existsSync(tp)) return null;
|
|
18036
|
+
return fs82.readFileSync(tp, "utf-8").trim();
|
|
18028
18037
|
} catch {
|
|
18029
18038
|
return null;
|
|
18030
18039
|
}
|
|
@@ -18432,12 +18441,12 @@ function defaultNameFromPrompt(prompt) {
|
|
|
18432
18441
|
}
|
|
18433
18442
|
async function readHostCpToken3() {
|
|
18434
18443
|
try {
|
|
18435
|
-
const { default:
|
|
18436
|
-
const { default:
|
|
18437
|
-
const { default:
|
|
18438
|
-
const tp =
|
|
18439
|
-
if (!
|
|
18440
|
-
const raw =
|
|
18444
|
+
const { default: fs82 } = await import("node:fs");
|
|
18445
|
+
const { default: os45 } = await import("node:os");
|
|
18446
|
+
const { default: path82 } = await import("node:path");
|
|
18447
|
+
const tp = path82.join(os45.homedir(), ".olam", "host-cp.token");
|
|
18448
|
+
if (!fs82.existsSync(tp)) return null;
|
|
18449
|
+
const raw = fs82.readFileSync(tp, "utf-8").trim();
|
|
18441
18450
|
return raw.length > 0 ? raw : null;
|
|
18442
18451
|
} catch {
|
|
18443
18452
|
return null;
|
|
@@ -18680,7 +18689,7 @@ function parseRuntimeStatus(raw) {
|
|
|
18680
18689
|
last_event_age_seconds
|
|
18681
18690
|
};
|
|
18682
18691
|
}
|
|
18683
|
-
var fetchWorldRuntimeStatus = (worldId, token) => new Promise((
|
|
18692
|
+
var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve19) => {
|
|
18684
18693
|
const opts = {
|
|
18685
18694
|
host: "127.0.0.1",
|
|
18686
18695
|
port: HOST_CP_PORT2,
|
|
@@ -18692,7 +18701,7 @@ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve18) => {
|
|
|
18692
18701
|
const req = http3.request(opts, (res) => {
|
|
18693
18702
|
if (res.statusCode !== 200) {
|
|
18694
18703
|
res.resume();
|
|
18695
|
-
return
|
|
18704
|
+
return resolve19(null);
|
|
18696
18705
|
}
|
|
18697
18706
|
let body = "";
|
|
18698
18707
|
res.setEncoding("utf-8");
|
|
@@ -18702,17 +18711,17 @@ var fetchWorldRuntimeStatus = (worldId, token) => new Promise((resolve18) => {
|
|
|
18702
18711
|
res.on("end", () => {
|
|
18703
18712
|
try {
|
|
18704
18713
|
const parsed = parseRuntimeStatus(JSON.parse(body));
|
|
18705
|
-
|
|
18714
|
+
resolve19(parsed);
|
|
18706
18715
|
} catch {
|
|
18707
|
-
|
|
18716
|
+
resolve19(null);
|
|
18708
18717
|
}
|
|
18709
18718
|
});
|
|
18710
|
-
res.on("error", () =>
|
|
18719
|
+
res.on("error", () => resolve19(null));
|
|
18711
18720
|
});
|
|
18712
|
-
req.on("error", () =>
|
|
18721
|
+
req.on("error", () => resolve19(null));
|
|
18713
18722
|
req.on("timeout", () => {
|
|
18714
18723
|
req.destroy();
|
|
18715
|
-
|
|
18724
|
+
resolve19(null);
|
|
18716
18725
|
});
|
|
18717
18726
|
req.end();
|
|
18718
18727
|
});
|
|
@@ -19181,14 +19190,14 @@ function printTable(entries) {
|
|
|
19181
19190
|
async function confirmInteractive() {
|
|
19182
19191
|
process.stdout.write(" Type `yes` to proceed: ");
|
|
19183
19192
|
const buf = [];
|
|
19184
|
-
return new Promise((
|
|
19193
|
+
return new Promise((resolve19) => {
|
|
19185
19194
|
const onData = (chunk) => {
|
|
19186
19195
|
buf.push(chunk);
|
|
19187
19196
|
if (Buffer.concat(buf).toString("utf-8").includes("\n")) {
|
|
19188
19197
|
process.stdin.removeListener("data", onData);
|
|
19189
19198
|
process.stdin.pause();
|
|
19190
19199
|
const answer = Buffer.concat(buf).toString("utf-8").trim();
|
|
19191
|
-
|
|
19200
|
+
resolve19(answer.toLowerCase() === "yes");
|
|
19192
19201
|
}
|
|
19193
19202
|
};
|
|
19194
19203
|
process.stdin.resume();
|
|
@@ -22244,11 +22253,11 @@ function zodIssueToError(issue, doc, lineCounter) {
|
|
|
22244
22253
|
suggestion: deriveSuggestion(issue)
|
|
22245
22254
|
};
|
|
22246
22255
|
}
|
|
22247
|
-
function formatJsonPath(
|
|
22248
|
-
if (
|
|
22256
|
+
function formatJsonPath(path82) {
|
|
22257
|
+
if (path82.length === 0)
|
|
22249
22258
|
return "<root>";
|
|
22250
22259
|
let out = "";
|
|
22251
|
-
for (const seg of
|
|
22260
|
+
for (const seg of path82) {
|
|
22252
22261
|
if (typeof seg === "number") {
|
|
22253
22262
|
out += `[${seg}]`;
|
|
22254
22263
|
} else {
|
|
@@ -22257,11 +22266,11 @@ function formatJsonPath(path78) {
|
|
|
22257
22266
|
}
|
|
22258
22267
|
return out;
|
|
22259
22268
|
}
|
|
22260
|
-
function resolveYamlLocation(
|
|
22269
|
+
function resolveYamlLocation(path82, doc, lineCounter) {
|
|
22261
22270
|
let bestLine = 0;
|
|
22262
22271
|
let bestColumn = 0;
|
|
22263
|
-
for (let depth =
|
|
22264
|
-
const segment =
|
|
22272
|
+
for (let depth = path82.length; depth >= 0; depth -= 1) {
|
|
22273
|
+
const segment = path82.slice(0, depth);
|
|
22265
22274
|
try {
|
|
22266
22275
|
const node = doc.getIn(segment, true);
|
|
22267
22276
|
if (node && typeof node === "object" && "range" in node) {
|
|
@@ -22479,11 +22488,11 @@ function topoSort(nodes) {
|
|
|
22479
22488
|
}
|
|
22480
22489
|
function traceCycle(start, byId) {
|
|
22481
22490
|
const seen = /* @__PURE__ */ new Set();
|
|
22482
|
-
const
|
|
22491
|
+
const path82 = [];
|
|
22483
22492
|
let current = start;
|
|
22484
22493
|
while (current && !seen.has(current)) {
|
|
22485
22494
|
seen.add(current);
|
|
22486
|
-
|
|
22495
|
+
path82.push(current);
|
|
22487
22496
|
const node = byId.get(current);
|
|
22488
22497
|
const next = node?.dependsOn[0];
|
|
22489
22498
|
if (next === void 0)
|
|
@@ -22491,10 +22500,10 @@ function traceCycle(start, byId) {
|
|
|
22491
22500
|
current = next;
|
|
22492
22501
|
}
|
|
22493
22502
|
if (current && seen.has(current)) {
|
|
22494
|
-
const idx =
|
|
22495
|
-
return [...
|
|
22503
|
+
const idx = path82.indexOf(current);
|
|
22504
|
+
return [...path82.slice(idx), current];
|
|
22496
22505
|
}
|
|
22497
|
-
return
|
|
22506
|
+
return path82;
|
|
22498
22507
|
}
|
|
22499
22508
|
|
|
22500
22509
|
// ../core/dist/executor/types.js
|
|
@@ -24669,16 +24678,16 @@ function isValidConfig(value) {
|
|
|
24669
24678
|
if (typeof v.install_id !== "string" || v.install_id.length === 0) return false;
|
|
24670
24679
|
return true;
|
|
24671
24680
|
}
|
|
24672
|
-
function atomicWriteJSON(
|
|
24681
|
+
function atomicWriteJSON(path82, value, stderr = process.stderr) {
|
|
24673
24682
|
ensureStateDir();
|
|
24674
|
-
const dir = dirname24(
|
|
24683
|
+
const dir = dirname24(path82);
|
|
24675
24684
|
if (!existsSync39(dir)) {
|
|
24676
24685
|
mkdirSync24(dir, { recursive: true });
|
|
24677
24686
|
}
|
|
24678
|
-
const tmp = `${
|
|
24687
|
+
const tmp = `${path82}.tmp.${process.pid}`;
|
|
24679
24688
|
try {
|
|
24680
24689
|
writeFileSync18(tmp, JSON.stringify(value, null, 2) + "\n", { encoding: "utf8" });
|
|
24681
|
-
renameSync5(tmp,
|
|
24690
|
+
renameSync5(tmp, path82);
|
|
24682
24691
|
} catch (err) {
|
|
24683
24692
|
if (existsSync39(tmp)) {
|
|
24684
24693
|
try {
|
|
@@ -24756,7 +24765,7 @@ async function kubectlWrap(args, opts = {}) {
|
|
|
24756
24765
|
const spawnImpl = opts.spawnImpl ?? spawn5;
|
|
24757
24766
|
const stdout = [];
|
|
24758
24767
|
const stderr = [];
|
|
24759
|
-
return new Promise((
|
|
24768
|
+
return new Promise((resolve19) => {
|
|
24760
24769
|
let resolved = false;
|
|
24761
24770
|
let killTimer = null;
|
|
24762
24771
|
let sigkillTimer = null;
|
|
@@ -24771,7 +24780,7 @@ async function kubectlWrap(args, opts = {}) {
|
|
|
24771
24780
|
clearTimeout(sigkillTimer);
|
|
24772
24781
|
sigkillTimer = null;
|
|
24773
24782
|
}
|
|
24774
|
-
|
|
24783
|
+
resolve19(r);
|
|
24775
24784
|
}
|
|
24776
24785
|
let child;
|
|
24777
24786
|
try {
|
|
@@ -24780,7 +24789,7 @@ async function kubectlWrap(args, opts = {}) {
|
|
|
24780
24789
|
env: { ...process.env, ...opts.env ?? {} }
|
|
24781
24790
|
});
|
|
24782
24791
|
} catch (err) {
|
|
24783
|
-
|
|
24792
|
+
resolve19({
|
|
24784
24793
|
ok: false,
|
|
24785
24794
|
stdout: "",
|
|
24786
24795
|
stderr: err instanceof Error ? err.message : String(err),
|
|
@@ -24857,14 +24866,14 @@ async function probePortForwardLiveness(deps = {}) {
|
|
|
24857
24866
|
return probe2("127.0.0.1", PORT_FORWARD_PORT, TCP_PROBE_TIMEOUT_MS);
|
|
24858
24867
|
}
|
|
24859
24868
|
function realTcpProbe(host, port2, timeoutMs) {
|
|
24860
|
-
return new Promise((
|
|
24869
|
+
return new Promise((resolve19) => {
|
|
24861
24870
|
const socket = new net3.Socket();
|
|
24862
24871
|
let done = false;
|
|
24863
24872
|
function finish(result) {
|
|
24864
24873
|
if (done) return;
|
|
24865
24874
|
done = true;
|
|
24866
24875
|
socket.destroy();
|
|
24867
|
-
|
|
24876
|
+
resolve19(result);
|
|
24868
24877
|
}
|
|
24869
24878
|
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
24870
24879
|
socket.once("connect", () => {
|
|
@@ -25090,12 +25099,12 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
|
|
|
25090
25099
|
}
|
|
25091
25100
|
async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}) {
|
|
25092
25101
|
const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
|
|
25093
|
-
const
|
|
25094
|
-
const
|
|
25102
|
+
const readdirSync23 = deps.readdirSync ?? fs37.readdirSync;
|
|
25103
|
+
const readFileSync66 = deps.readFileSync ?? fs37.readFileSync;
|
|
25095
25104
|
const writeFileSyncImpl = deps.writeFileSync ?? fs37.writeFileSync;
|
|
25096
|
-
const
|
|
25105
|
+
const existsSync90 = deps.existsSync ?? fs37.existsSync;
|
|
25097
25106
|
const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
|
|
25098
|
-
if (!
|
|
25107
|
+
if (!existsSync90(manifestsDir)) {
|
|
25099
25108
|
return {
|
|
25100
25109
|
ok: false,
|
|
25101
25110
|
message: `manifests directory not found: ${manifestsDir}`
|
|
@@ -25103,7 +25112,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}) {
|
|
|
25103
25112
|
}
|
|
25104
25113
|
let files;
|
|
25105
25114
|
try {
|
|
25106
|
-
const entries =
|
|
25115
|
+
const entries = readdirSync23(manifestsDir, { withFileTypes: true });
|
|
25107
25116
|
files = entries.filter((e) => e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".json"))).map((e) => e.name);
|
|
25108
25117
|
} catch (err) {
|
|
25109
25118
|
return {
|
|
@@ -25116,7 +25125,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}) {
|
|
|
25116
25125
|
const filePath = path39.join(manifestsDir, file);
|
|
25117
25126
|
let content;
|
|
25118
25127
|
try {
|
|
25119
|
-
content =
|
|
25128
|
+
content = readFileSync66(filePath, "utf8");
|
|
25120
25129
|
} catch {
|
|
25121
25130
|
continue;
|
|
25122
25131
|
}
|
|
@@ -25697,10 +25706,10 @@ async function confirm2(message) {
|
|
|
25697
25706
|
if (!process.stdin.isTTY) return true;
|
|
25698
25707
|
const { createInterface: createInterface9 } = await import("node:readline");
|
|
25699
25708
|
const rl = createInterface9({ input: process.stdin, output: process.stdout });
|
|
25700
|
-
return new Promise((
|
|
25709
|
+
return new Promise((resolve19) => {
|
|
25701
25710
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
25702
25711
|
rl.close();
|
|
25703
|
-
|
|
25712
|
+
resolve19(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
25704
25713
|
});
|
|
25705
25714
|
});
|
|
25706
25715
|
}
|
|
@@ -28699,9 +28708,9 @@ function appendIdempotent(opts) {
|
|
|
28699
28708
|
}
|
|
28700
28709
|
function resolveShellRc(home, shellEnv) {
|
|
28701
28710
|
if (!shellEnv) return null;
|
|
28702
|
-
const
|
|
28703
|
-
if (
|
|
28704
|
-
if (
|
|
28711
|
+
const basename12 = path48.basename(shellEnv);
|
|
28712
|
+
if (basename12 === "zsh") return path48.join(home, ".zshrc");
|
|
28713
|
+
if (basename12 === "bash") return path48.join(home, ".bashrc");
|
|
28705
28714
|
return null;
|
|
28706
28715
|
}
|
|
28707
28716
|
|
|
@@ -28713,10 +28722,10 @@ var NEXT_STEPS_DOCS = [
|
|
|
28713
28722
|
"docs/architecture/manifest-spec.md \u2014 per-repo .adb.yaml schema",
|
|
28714
28723
|
"docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema"
|
|
28715
28724
|
];
|
|
28716
|
-
var defaultSpawn = (cmd, args) => new Promise((
|
|
28725
|
+
var defaultSpawn = (cmd, args) => new Promise((resolve19) => {
|
|
28717
28726
|
const child = spawn7(cmd, [...args], { stdio: "inherit" });
|
|
28718
|
-
child.on("exit", (code) =>
|
|
28719
|
-
child.on("error", () =>
|
|
28727
|
+
child.on("exit", (code) => resolve19({ status: code }));
|
|
28728
|
+
child.on("error", () => resolve19({ status: 1 }));
|
|
28720
28729
|
});
|
|
28721
28730
|
var defaultPrompt = (question, defaultYes) => {
|
|
28722
28731
|
if (!process.stdin.isTTY) {
|
|
@@ -28726,18 +28735,18 @@ var defaultPrompt = (question, defaultYes) => {
|
|
|
28726
28735
|
);
|
|
28727
28736
|
return Promise.resolve(defaultYes);
|
|
28728
28737
|
}
|
|
28729
|
-
return new Promise((
|
|
28738
|
+
return new Promise((resolve19) => {
|
|
28730
28739
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
28731
28740
|
const suffix = defaultYes ? " [Y/n]: " : " [y/N]: ";
|
|
28732
28741
|
rl.question(`${question}${suffix}`, (answer) => {
|
|
28733
28742
|
rl.close();
|
|
28734
28743
|
const t = answer.trim().toLowerCase();
|
|
28735
|
-
if (t === "")
|
|
28736
|
-
else if (t === "y" || t === "yes")
|
|
28737
|
-
else if (t === "n" || t === "no")
|
|
28738
|
-
else
|
|
28744
|
+
if (t === "") resolve19(defaultYes);
|
|
28745
|
+
else if (t === "y" || t === "yes") resolve19(true);
|
|
28746
|
+
else if (t === "n" || t === "no") resolve19(false);
|
|
28747
|
+
else resolve19(defaultYes);
|
|
28739
28748
|
});
|
|
28740
|
-
rl.on("close", () =>
|
|
28749
|
+
rl.on("close", () => resolve19(defaultYes));
|
|
28741
28750
|
});
|
|
28742
28751
|
};
|
|
28743
28752
|
async function phase1SystemCheck(deps) {
|
|
@@ -29290,7 +29299,7 @@ function registerBegin(program2) {
|
|
|
29290
29299
|
}
|
|
29291
29300
|
|
|
29292
29301
|
// src/commands/config.ts
|
|
29293
|
-
import * as
|
|
29302
|
+
import * as fs67 from "node:fs";
|
|
29294
29303
|
import { createRequire as createRequire4 } from "node:module";
|
|
29295
29304
|
|
|
29296
29305
|
// ../core/dist/global-config/index.js
|
|
@@ -29382,7 +29391,14 @@ import * as fs49 from "node:fs";
|
|
|
29382
29391
|
import * as path54 from "node:path";
|
|
29383
29392
|
import * as os29 from "node:os";
|
|
29384
29393
|
var SKILL_SOURCES_AUDIT_LOG_FILENAME = "skill-sources-audit.log";
|
|
29385
|
-
var TrustActionSchema = external_exports.enum([
|
|
29394
|
+
var TrustActionSchema = external_exports.enum([
|
|
29395
|
+
"added",
|
|
29396
|
+
"rejected",
|
|
29397
|
+
"auto-rejected",
|
|
29398
|
+
"failed",
|
|
29399
|
+
"removed",
|
|
29400
|
+
"meta-hook-stripped"
|
|
29401
|
+
]);
|
|
29386
29402
|
var TrustMethodSchema = external_exports.enum(["flag", "interactive", "auto-reject-tty", "none"]);
|
|
29387
29403
|
var TrustAuditEntrySchema = external_exports.object({
|
|
29388
29404
|
timestamp: external_exports.string().min(1),
|
|
@@ -29968,6 +29984,9 @@ function readMigrationSnapshotFromPath(p) {
|
|
|
29968
29984
|
return JSON.parse(fs54.readFileSync(p, "utf-8"));
|
|
29969
29985
|
}
|
|
29970
29986
|
|
|
29987
|
+
// ../core/dist/skill-sync/engine.js
|
|
29988
|
+
init_store2();
|
|
29989
|
+
|
|
29971
29990
|
// ../core/dist/skill-sync/artifact-resolver.js
|
|
29972
29991
|
import * as fs55 from "node:fs";
|
|
29973
29992
|
import * as path59 from "node:path";
|
|
@@ -30191,11 +30210,11 @@ function detectCollisions(artifacts) {
|
|
|
30191
30210
|
}
|
|
30192
30211
|
const collisions = [];
|
|
30193
30212
|
for (const [key, loserList] of losersByKey.entries()) {
|
|
30194
|
-
const [bucket,
|
|
30213
|
+
const [bucket, basename12] = key.split("\0");
|
|
30195
30214
|
const winner = seen.get(key);
|
|
30196
30215
|
collisions.push({
|
|
30197
30216
|
bucket,
|
|
30198
|
-
basename:
|
|
30217
|
+
basename: basename12,
|
|
30199
30218
|
winnerSourceId: winner.sourceId,
|
|
30200
30219
|
winnerSourcePath: winner.sourcePath,
|
|
30201
30220
|
loserSourceIds: loserList.map((l) => l.sourceId),
|
|
@@ -30271,11 +30290,161 @@ function deployArtifacts(artifacts) {
|
|
|
30271
30290
|
}
|
|
30272
30291
|
|
|
30273
30292
|
// ../core/dist/skill-sync/settings-merger.js
|
|
30274
|
-
import * as
|
|
30293
|
+
import * as fs59 from "node:fs";
|
|
30275
30294
|
import * as os34 from "node:os";
|
|
30276
30295
|
import * as path61 from "node:path";
|
|
30296
|
+
|
|
30297
|
+
// ../core/dist/meta-hooks/memory-recall.js
|
|
30298
|
+
import * as fs57 from "node:fs";
|
|
30299
|
+
var OLAM_META_MEMORY_RECALL_SENTINEL = "olam-meta-memory-recall-v1";
|
|
30300
|
+
var OLAM_META_MEMORY_RECALL_STAGE = "PreToolUse";
|
|
30301
|
+
var OLAM_META_MEMORY_RECALL_MATCHER = "Bash|Edit|MultiEdit|Write|Read|NotebookEdit";
|
|
30302
|
+
var OLAM_META_MEMORY_RECALL_TIMEOUT_MS = 5e3;
|
|
30303
|
+
var OLAM_META_MEMORY_RECALL_SCRIPT_PATH = "$HOME/.claude/scripts/agentmemory-classifier/agentmemory-recall-trigger.mjs";
|
|
30304
|
+
var OLAM_META_NOOP_GUARD = "command -v olam >/dev/null 2>&1 || exit 0;";
|
|
30305
|
+
function buildMemoryRecallHookEntry() {
|
|
30306
|
+
return {
|
|
30307
|
+
matcher: OLAM_META_MEMORY_RECALL_MATCHER,
|
|
30308
|
+
hooks: [
|
|
30309
|
+
{
|
|
30310
|
+
type: "command",
|
|
30311
|
+
command: `OLAM_META_SENTINEL=${OLAM_META_MEMORY_RECALL_SENTINEL}; ${OLAM_META_NOOP_GUARD} node "${OLAM_META_MEMORY_RECALL_SCRIPT_PATH}"`,
|
|
30312
|
+
timeout: OLAM_META_MEMORY_RECALL_TIMEOUT_MS
|
|
30313
|
+
}
|
|
30314
|
+
]
|
|
30315
|
+
};
|
|
30316
|
+
}
|
|
30317
|
+
function computeMemoryRecallUninstall(settings) {
|
|
30318
|
+
const matchers = settings.hooks?.PreToolUse;
|
|
30319
|
+
if (!Array.isArray(matchers) || matchers.length === 0) {
|
|
30320
|
+
return { status: "not-found" };
|
|
30321
|
+
}
|
|
30322
|
+
let changed = false;
|
|
30323
|
+
const filteredMatchers = [];
|
|
30324
|
+
for (const matcher of matchers) {
|
|
30325
|
+
const innerHooks = matcher.hooks ?? [];
|
|
30326
|
+
const keptInner = innerHooks.filter((h) => {
|
|
30327
|
+
if (typeof h.command === "string" && h.command.includes(OLAM_META_MEMORY_RECALL_SENTINEL)) {
|
|
30328
|
+
changed = true;
|
|
30329
|
+
return false;
|
|
30330
|
+
}
|
|
30331
|
+
return true;
|
|
30332
|
+
});
|
|
30333
|
+
if (keptInner.length === 0 && innerHooks.length > 0) {
|
|
30334
|
+
changed = true;
|
|
30335
|
+
continue;
|
|
30336
|
+
}
|
|
30337
|
+
if (keptInner.length === innerHooks.length) {
|
|
30338
|
+
filteredMatchers.push(matcher);
|
|
30339
|
+
} else {
|
|
30340
|
+
filteredMatchers.push({ ...matcher, hooks: keptInner });
|
|
30341
|
+
}
|
|
30342
|
+
}
|
|
30343
|
+
if (!changed)
|
|
30344
|
+
return { status: "not-found" };
|
|
30345
|
+
const next = {
|
|
30346
|
+
...settings,
|
|
30347
|
+
hooks: {
|
|
30348
|
+
...settings.hooks,
|
|
30349
|
+
PreToolUse: filteredMatchers
|
|
30350
|
+
}
|
|
30351
|
+
};
|
|
30352
|
+
if (filteredMatchers.length === 0) {
|
|
30353
|
+
const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== "PreToolUse");
|
|
30354
|
+
if (otherStages.length === 0) {
|
|
30355
|
+
delete next.hooks;
|
|
30356
|
+
} else {
|
|
30357
|
+
delete next.hooks.PreToolUse;
|
|
30358
|
+
}
|
|
30359
|
+
}
|
|
30360
|
+
return { status: "removed", settingsAfter: next };
|
|
30361
|
+
}
|
|
30362
|
+
function matchMemoryRecallSentinel(commandLine) {
|
|
30363
|
+
return commandLine.includes(OLAM_META_MEMORY_RECALL_SENTINEL);
|
|
30364
|
+
}
|
|
30365
|
+
|
|
30366
|
+
// ../core/dist/meta-hooks/memory-classify.js
|
|
30367
|
+
import * as fs58 from "node:fs";
|
|
30368
|
+
var OLAM_META_MEMORY_CLASSIFY_SENTINEL = "olam-meta-memory-classify-v1";
|
|
30369
|
+
var OLAM_META_MEMORY_CLASSIFY_STAGE = "PostToolUse";
|
|
30370
|
+
var OLAM_META_MEMORY_CLASSIFY_MATCHER = "Bash|Edit|MultiEdit|Write|Read|NotebookEdit";
|
|
30371
|
+
var OLAM_META_MEMORY_CLASSIFY_TIMEOUT_MS = 5e3;
|
|
30372
|
+
var OLAM_META_MEMORY_CLASSIFY_SCRIPT_PATH = "$HOME/.claude/scripts/agentmemory-classifier/agentmemory-classify-queue.mjs";
|
|
30373
|
+
var OLAM_META_NOOP_GUARD2 = "command -v olam >/dev/null 2>&1 || exit 0;";
|
|
30374
|
+
function buildMemoryClassifyHookEntry() {
|
|
30375
|
+
return {
|
|
30376
|
+
matcher: OLAM_META_MEMORY_CLASSIFY_MATCHER,
|
|
30377
|
+
hooks: [
|
|
30378
|
+
{
|
|
30379
|
+
type: "command",
|
|
30380
|
+
command: `OLAM_META_SENTINEL=${OLAM_META_MEMORY_CLASSIFY_SENTINEL}; ${OLAM_META_NOOP_GUARD2} node "${OLAM_META_MEMORY_CLASSIFY_SCRIPT_PATH}"`,
|
|
30381
|
+
timeout: OLAM_META_MEMORY_CLASSIFY_TIMEOUT_MS
|
|
30382
|
+
}
|
|
30383
|
+
]
|
|
30384
|
+
};
|
|
30385
|
+
}
|
|
30386
|
+
function computeMemoryClassifyUninstall(settings) {
|
|
30387
|
+
const matchers = settings.hooks?.PostToolUse;
|
|
30388
|
+
if (!Array.isArray(matchers) || matchers.length === 0) {
|
|
30389
|
+
return { status: "not-found" };
|
|
30390
|
+
}
|
|
30391
|
+
let changed = false;
|
|
30392
|
+
const filteredMatchers = [];
|
|
30393
|
+
for (const matcher of matchers) {
|
|
30394
|
+
const innerHooks = matcher.hooks ?? [];
|
|
30395
|
+
const keptInner = innerHooks.filter((h) => {
|
|
30396
|
+
if (typeof h.command === "string" && h.command.includes(OLAM_META_MEMORY_CLASSIFY_SENTINEL)) {
|
|
30397
|
+
changed = true;
|
|
30398
|
+
return false;
|
|
30399
|
+
}
|
|
30400
|
+
return true;
|
|
30401
|
+
});
|
|
30402
|
+
if (keptInner.length === 0 && innerHooks.length > 0) {
|
|
30403
|
+
changed = true;
|
|
30404
|
+
continue;
|
|
30405
|
+
}
|
|
30406
|
+
if (keptInner.length === innerHooks.length) {
|
|
30407
|
+
filteredMatchers.push(matcher);
|
|
30408
|
+
} else {
|
|
30409
|
+
filteredMatchers.push({ ...matcher, hooks: keptInner });
|
|
30410
|
+
}
|
|
30411
|
+
}
|
|
30412
|
+
if (!changed)
|
|
30413
|
+
return { status: "not-found" };
|
|
30414
|
+
const next = {
|
|
30415
|
+
...settings,
|
|
30416
|
+
hooks: {
|
|
30417
|
+
...settings.hooks,
|
|
30418
|
+
PostToolUse: filteredMatchers
|
|
30419
|
+
}
|
|
30420
|
+
};
|
|
30421
|
+
if (filteredMatchers.length === 0) {
|
|
30422
|
+
const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== "PostToolUse");
|
|
30423
|
+
if (otherStages.length === 0) {
|
|
30424
|
+
delete next.hooks;
|
|
30425
|
+
} else {
|
|
30426
|
+
delete next.hooks.PostToolUse;
|
|
30427
|
+
}
|
|
30428
|
+
}
|
|
30429
|
+
return { status: "removed", settingsAfter: next };
|
|
30430
|
+
}
|
|
30431
|
+
function matchMemoryClassifySentinel(commandLine) {
|
|
30432
|
+
return commandLine.includes(OLAM_META_MEMORY_CLASSIFY_SENTINEL);
|
|
30433
|
+
}
|
|
30434
|
+
|
|
30435
|
+
// ../core/dist/skill-sync/settings-merger.js
|
|
30277
30436
|
var OLAM_SKILLS_MARKER = "_olamSkillsManaged";
|
|
30278
30437
|
var BACKUP_RETENTION = 30;
|
|
30438
|
+
var DUAL_WRITE_DEDUP_RULES = [
|
|
30439
|
+
{
|
|
30440
|
+
preservedSentinel: OLAM_META_MEMORY_RECALL_SENTINEL,
|
|
30441
|
+
incomingCommandSubstring: "agentmemory-recall-trigger.mjs"
|
|
30442
|
+
},
|
|
30443
|
+
{
|
|
30444
|
+
preservedSentinel: OLAM_META_MEMORY_CLASSIFY_SENTINEL,
|
|
30445
|
+
incomingCommandSubstring: "agentmemory-classify-queue.mjs"
|
|
30446
|
+
}
|
|
30447
|
+
];
|
|
30279
30448
|
function claudeSettingsPath() {
|
|
30280
30449
|
const override = process.env["OLAM_CLAUDE_SETTINGS_PATH"];
|
|
30281
30450
|
if (override && override.length > 0)
|
|
@@ -30301,32 +30470,66 @@ function dedupeByMatcher(entries) {
|
|
|
30301
30470
|
}
|
|
30302
30471
|
return [...map.values()];
|
|
30303
30472
|
}
|
|
30473
|
+
function commandsInEntry(entry) {
|
|
30474
|
+
const cmds = [];
|
|
30475
|
+
const direct = entry["command"];
|
|
30476
|
+
if (typeof direct === "string")
|
|
30477
|
+
cmds.push(direct);
|
|
30478
|
+
const inner = entry["hooks"];
|
|
30479
|
+
if (Array.isArray(inner)) {
|
|
30480
|
+
for (const h of inner) {
|
|
30481
|
+
if (h && typeof h === "object" && typeof h.command === "string") {
|
|
30482
|
+
cmds.push(h.command);
|
|
30483
|
+
}
|
|
30484
|
+
}
|
|
30485
|
+
}
|
|
30486
|
+
return cmds;
|
|
30487
|
+
}
|
|
30488
|
+
function applyDualWriteDedup(incoming, preserved) {
|
|
30489
|
+
const preservedCommands = preserved.flatMap(commandsInEntry);
|
|
30490
|
+
const preservedHas = (sentinel) => preservedCommands.some((c) => c.includes(sentinel));
|
|
30491
|
+
let droppedCount = 0;
|
|
30492
|
+
const droppedCommands = [];
|
|
30493
|
+
const kept = incoming.filter((entry) => {
|
|
30494
|
+
const incomingCommands = commandsInEntry(entry);
|
|
30495
|
+
for (const rule of DUAL_WRITE_DEDUP_RULES) {
|
|
30496
|
+
const hasIncomingScript = incomingCommands.some((c) => c.includes(rule.incomingCommandSubstring));
|
|
30497
|
+
if (hasIncomingScript && preservedHas(rule.preservedSentinel)) {
|
|
30498
|
+
droppedCount += 1;
|
|
30499
|
+
droppedCommands.push(...incomingCommands.filter((c) => c.includes(rule.incomingCommandSubstring)));
|
|
30500
|
+
return false;
|
|
30501
|
+
}
|
|
30502
|
+
}
|
|
30503
|
+
return true;
|
|
30504
|
+
});
|
|
30505
|
+
return { kept, droppedCount, droppedCommands };
|
|
30506
|
+
}
|
|
30304
30507
|
function tagOlam(entry) {
|
|
30305
30508
|
return { ...entry, [OLAM_SKILLS_MARKER]: true };
|
|
30306
30509
|
}
|
|
30307
30510
|
function readJson(file) {
|
|
30308
|
-
return JSON.parse(
|
|
30511
|
+
return JSON.parse(fs59.readFileSync(file, "utf-8"));
|
|
30309
30512
|
}
|
|
30310
30513
|
function rotateBackups(backupDir) {
|
|
30311
|
-
if (!
|
|
30514
|
+
if (!fs59.existsSync(backupDir))
|
|
30312
30515
|
return;
|
|
30313
|
-
const files =
|
|
30516
|
+
const files = fs59.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path61.join(backupDir, f), mtime: fs59.statSync(path61.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
30314
30517
|
for (const f of files.slice(BACKUP_RETENTION)) {
|
|
30315
30518
|
try {
|
|
30316
|
-
|
|
30519
|
+
fs59.unlinkSync(f.full);
|
|
30317
30520
|
} catch {
|
|
30318
30521
|
}
|
|
30319
30522
|
}
|
|
30320
30523
|
}
|
|
30321
30524
|
function backupSettings() {
|
|
30322
30525
|
const src = claudeSettingsPath();
|
|
30323
|
-
if (!
|
|
30526
|
+
if (!fs59.existsSync(src))
|
|
30324
30527
|
return void 0;
|
|
30325
30528
|
const dir = settingsBackupDir();
|
|
30326
|
-
|
|
30529
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
30327
30530
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
30328
30531
|
const dest = path61.join(dir, `settings-${stamp}.json`);
|
|
30329
|
-
|
|
30532
|
+
fs59.copyFileSync(src, dest);
|
|
30330
30533
|
rotateBackups(dir);
|
|
30331
30534
|
return dest;
|
|
30332
30535
|
}
|
|
@@ -30334,7 +30537,7 @@ function mergeSettings(input) {
|
|
|
30334
30537
|
const settingsPath = claudeSettingsPath();
|
|
30335
30538
|
const backupPath = backupSettings();
|
|
30336
30539
|
let base = {};
|
|
30337
|
-
if (
|
|
30540
|
+
if (fs59.existsSync(settingsPath)) {
|
|
30338
30541
|
try {
|
|
30339
30542
|
base = readJson(settingsPath);
|
|
30340
30543
|
} catch {
|
|
@@ -30366,13 +30569,18 @@ function mergeSettings(input) {
|
|
|
30366
30569
|
...olamHooksByCategory.keys()
|
|
30367
30570
|
]);
|
|
30368
30571
|
let hooksAdded = 0;
|
|
30572
|
+
let dualWriteDeduped = 0;
|
|
30573
|
+
const dualWriteDroppedCommands = [];
|
|
30369
30574
|
for (const cat of categories) {
|
|
30370
30575
|
const existing = Array.isArray(existingHooks[cat]) ? existingHooks[cat] : [];
|
|
30371
30576
|
const preserved = existing.filter((e) => !e[OLAM_SKILLS_MARKER]);
|
|
30372
30577
|
const olam = olamHooksByCategory.get(cat) ?? [];
|
|
30373
30578
|
const olamDeduped = dedupeByMatcher(olam);
|
|
30374
|
-
|
|
30375
|
-
|
|
30579
|
+
const { kept: olamFinal, droppedCount, droppedCommands } = applyDualWriteDedup(olamDeduped, preserved);
|
|
30580
|
+
dualWriteDeduped += droppedCount;
|
|
30581
|
+
dualWriteDroppedCommands.push(...droppedCommands);
|
|
30582
|
+
mergedHooks[cat] = [...preserved, ...olamFinal];
|
|
30583
|
+
hooksAdded += olamFinal.length;
|
|
30376
30584
|
}
|
|
30377
30585
|
const permSet = /* @__PURE__ */ new Set();
|
|
30378
30586
|
for (const file of input.permissionFiles) {
|
|
@@ -30397,16 +30605,16 @@ function mergeSettings(input) {
|
|
|
30397
30605
|
...input.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
|
|
30398
30606
|
}
|
|
30399
30607
|
};
|
|
30400
|
-
|
|
30608
|
+
fs59.mkdirSync(path61.dirname(settingsPath), { recursive: true });
|
|
30401
30609
|
const tmp = `${settingsPath}.tmp-${process.pid}`;
|
|
30402
|
-
|
|
30403
|
-
|
|
30404
|
-
return { backupPath, hooksAdded, permissionsCount: permSet.size };
|
|
30610
|
+
fs59.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
|
|
30611
|
+
fs59.renameSync(tmp, settingsPath);
|
|
30612
|
+
return { backupPath, hooksAdded, permissionsCount: permSet.size, dualWriteDeduped, dualWriteDroppedCommands };
|
|
30405
30613
|
}
|
|
30406
30614
|
|
|
30407
30615
|
// ../core/dist/skill-sync/per-project-override.js
|
|
30408
30616
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
30409
|
-
import * as
|
|
30617
|
+
import * as fs60 from "node:fs";
|
|
30410
30618
|
import * as path62 from "node:path";
|
|
30411
30619
|
import { parse as parseYaml6 } from "yaml";
|
|
30412
30620
|
|
|
@@ -30443,8 +30651,8 @@ function findProjectOverride(startDir) {
|
|
|
30443
30651
|
const root = path62.parse(dir).root;
|
|
30444
30652
|
while (true) {
|
|
30445
30653
|
const candidate = path62.join(dir, PROJECT_OVERRIDE_RELATIVE_PATH);
|
|
30446
|
-
if (
|
|
30447
|
-
const raw =
|
|
30654
|
+
if (fs60.existsSync(candidate) && fs60.statSync(candidate).isFile()) {
|
|
30655
|
+
const raw = fs60.readFileSync(candidate, "utf-8");
|
|
30448
30656
|
let parsed;
|
|
30449
30657
|
try {
|
|
30450
30658
|
parsed = parseYaml6(raw);
|
|
@@ -30495,7 +30703,7 @@ function restoreCloneToBranchHead(opts) {
|
|
|
30495
30703
|
}
|
|
30496
30704
|
|
|
30497
30705
|
// ../core/dist/skill-sync/source-lock.js
|
|
30498
|
-
import * as
|
|
30706
|
+
import * as fs61 from "node:fs";
|
|
30499
30707
|
import * as os35 from "node:os";
|
|
30500
30708
|
import * as path63 from "node:path";
|
|
30501
30709
|
var SOURCE_LOCK_FILENAME = ".olam-sync.lock";
|
|
@@ -30517,11 +30725,11 @@ function defaultIsPidAlive(pid) {
|
|
|
30517
30725
|
}
|
|
30518
30726
|
}
|
|
30519
30727
|
function sleep6(ms) {
|
|
30520
|
-
return new Promise((
|
|
30728
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
30521
30729
|
}
|
|
30522
30730
|
function readLockMeta(lockPath) {
|
|
30523
30731
|
try {
|
|
30524
|
-
const raw =
|
|
30732
|
+
const raw = fs61.readFileSync(lockPath, "utf-8");
|
|
30525
30733
|
const parsed = JSON.parse(raw);
|
|
30526
30734
|
if (typeof parsed?.pid === "number" && typeof parsed?.hostname === "string" && typeof parsed?.timestamp === "number") {
|
|
30527
30735
|
return parsed;
|
|
@@ -30540,12 +30748,12 @@ function isLockStale(meta, opts) {
|
|
|
30540
30748
|
}
|
|
30541
30749
|
function tryAcquireOnce(lockPath, meta, opts) {
|
|
30542
30750
|
try {
|
|
30543
|
-
|
|
30544
|
-
const fd =
|
|
30751
|
+
fs61.mkdirSync(path63.dirname(lockPath), { recursive: true });
|
|
30752
|
+
const fd = fs61.openSync(lockPath, "wx", 384);
|
|
30545
30753
|
try {
|
|
30546
|
-
|
|
30754
|
+
fs61.writeSync(fd, JSON.stringify(meta));
|
|
30547
30755
|
} finally {
|
|
30548
|
-
|
|
30756
|
+
fs61.closeSync(fd);
|
|
30549
30757
|
}
|
|
30550
30758
|
return true;
|
|
30551
30759
|
} catch (err) {
|
|
@@ -30555,14 +30763,14 @@ function tryAcquireOnce(lockPath, meta, opts) {
|
|
|
30555
30763
|
const existing = readLockMeta(lockPath);
|
|
30556
30764
|
if (existing === void 0) {
|
|
30557
30765
|
try {
|
|
30558
|
-
|
|
30766
|
+
fs61.unlinkSync(lockPath);
|
|
30559
30767
|
} catch {
|
|
30560
30768
|
}
|
|
30561
30769
|
return tryAcquireOnce(lockPath, meta, opts);
|
|
30562
30770
|
}
|
|
30563
30771
|
if (isLockStale(existing, opts)) {
|
|
30564
30772
|
try {
|
|
30565
|
-
|
|
30773
|
+
fs61.unlinkSync(lockPath);
|
|
30566
30774
|
} catch {
|
|
30567
30775
|
}
|
|
30568
30776
|
return tryAcquireOnce(lockPath, meta, opts);
|
|
@@ -30591,7 +30799,7 @@ async function acquireSourceLock(clonePath, options = {}) {
|
|
|
30591
30799
|
lockPath,
|
|
30592
30800
|
release: () => {
|
|
30593
30801
|
try {
|
|
30594
|
-
|
|
30802
|
+
fs61.unlinkSync(lockPath);
|
|
30595
30803
|
} catch {
|
|
30596
30804
|
}
|
|
30597
30805
|
}
|
|
@@ -30615,17 +30823,464 @@ async function withSourceLock(clonePath, fn, options) {
|
|
|
30615
30823
|
}
|
|
30616
30824
|
}
|
|
30617
30825
|
|
|
30618
|
-
// ../core/dist/skill-sync/
|
|
30619
|
-
import * as
|
|
30826
|
+
// ../core/dist/skill-sync/settings-json-lock.js
|
|
30827
|
+
import * as fs62 from "node:fs";
|
|
30620
30828
|
import * as os36 from "node:os";
|
|
30621
30829
|
import * as path64 from "node:path";
|
|
30830
|
+
var SETTINGS_JSON_LOCK_FILENAME = ".settings-json.lock";
|
|
30831
|
+
var DEFAULT_ACQUIRE_TIMEOUT_MS2 = 1e4;
|
|
30832
|
+
var DEFAULT_STALE_LOCK_MS2 = 5 * 6e4;
|
|
30833
|
+
var SettingsJsonLockError = class extends Error {
|
|
30834
|
+
constructor(message) {
|
|
30835
|
+
super(message);
|
|
30836
|
+
this.name = "SettingsJsonLockError";
|
|
30837
|
+
}
|
|
30838
|
+
};
|
|
30839
|
+
function defaultSettingsJsonLockPath() {
|
|
30840
|
+
const stateDir = process.env["OLAM_STATE_DIR"] ?? path64.join(os36.homedir(), ".olam", "state");
|
|
30841
|
+
return path64.join(stateDir, SETTINGS_JSON_LOCK_FILENAME);
|
|
30842
|
+
}
|
|
30843
|
+
function defaultIsPidAlive2(pid) {
|
|
30844
|
+
try {
|
|
30845
|
+
process.kill(pid, 0);
|
|
30846
|
+
return true;
|
|
30847
|
+
} catch (err) {
|
|
30848
|
+
const code = err.code;
|
|
30849
|
+
return code === "EPERM";
|
|
30850
|
+
}
|
|
30851
|
+
}
|
|
30852
|
+
function sleep7(ms) {
|
|
30853
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
30854
|
+
}
|
|
30855
|
+
function readLockMeta2(lockPath) {
|
|
30856
|
+
try {
|
|
30857
|
+
const raw = fs62.readFileSync(lockPath, "utf-8");
|
|
30858
|
+
const parsed = JSON.parse(raw);
|
|
30859
|
+
if (typeof parsed?.pid === "number" && typeof parsed?.hostname === "string" && typeof parsed?.timestamp === "number") {
|
|
30860
|
+
return parsed;
|
|
30861
|
+
}
|
|
30862
|
+
} catch {
|
|
30863
|
+
}
|
|
30864
|
+
return void 0;
|
|
30865
|
+
}
|
|
30866
|
+
var MAX_STEAL_ATTEMPTS = 3;
|
|
30867
|
+
function isLockStale2(meta, opts) {
|
|
30868
|
+
const ageMs = opts.now - meta.timestamp;
|
|
30869
|
+
if (ageMs < opts.staleLockMs / 2)
|
|
30870
|
+
return false;
|
|
30871
|
+
if (meta.hostname !== os36.hostname()) {
|
|
30872
|
+
return ageMs > opts.staleLockMs * 2;
|
|
30873
|
+
}
|
|
30874
|
+
if (!opts.isPidAlive(meta.pid))
|
|
30875
|
+
return true;
|
|
30876
|
+
return ageMs > opts.staleLockMs;
|
|
30877
|
+
}
|
|
30878
|
+
function tryAcquireOnce2(lockPath, meta, opts) {
|
|
30879
|
+
for (let attempt = 0; attempt <= MAX_STEAL_ATTEMPTS; attempt += 1) {
|
|
30880
|
+
try {
|
|
30881
|
+
fs62.mkdirSync(path64.dirname(lockPath), { recursive: true });
|
|
30882
|
+
const fd = fs62.openSync(lockPath, "wx", 384);
|
|
30883
|
+
try {
|
|
30884
|
+
fs62.writeSync(fd, JSON.stringify(meta));
|
|
30885
|
+
} finally {
|
|
30886
|
+
fs62.closeSync(fd);
|
|
30887
|
+
}
|
|
30888
|
+
return true;
|
|
30889
|
+
} catch (err) {
|
|
30890
|
+
const code = err.code;
|
|
30891
|
+
if (code !== "EEXIST")
|
|
30892
|
+
throw err;
|
|
30893
|
+
}
|
|
30894
|
+
if (attempt >= MAX_STEAL_ATTEMPTS) {
|
|
30895
|
+
return false;
|
|
30896
|
+
}
|
|
30897
|
+
const existing = readLockMeta2(lockPath);
|
|
30898
|
+
const isStale = existing === void 0 || isLockStale2(existing, opts);
|
|
30899
|
+
if (!isStale) {
|
|
30900
|
+
return false;
|
|
30901
|
+
}
|
|
30902
|
+
const victimPath = `${lockPath}.victim-${process.pid}-${attempt}-${Date.now()}`;
|
|
30903
|
+
try {
|
|
30904
|
+
fs62.renameSync(lockPath, victimPath);
|
|
30905
|
+
try {
|
|
30906
|
+
fs62.unlinkSync(victimPath);
|
|
30907
|
+
} catch {
|
|
30908
|
+
}
|
|
30909
|
+
} catch (err) {
|
|
30910
|
+
const code = err.code;
|
|
30911
|
+
if (code !== "ENOENT")
|
|
30912
|
+
throw err;
|
|
30913
|
+
}
|
|
30914
|
+
}
|
|
30915
|
+
return false;
|
|
30916
|
+
}
|
|
30917
|
+
async function acquireSettingsJsonLock(options = {}) {
|
|
30918
|
+
const lockPath = options.lockPath ?? defaultSettingsJsonLockPath();
|
|
30919
|
+
const acquireTimeoutMs = options.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS2;
|
|
30920
|
+
const staleLockMs = options.staleLockMs ?? DEFAULT_STALE_LOCK_MS2;
|
|
30921
|
+
const now = options.now ?? Date.now;
|
|
30922
|
+
const isPidAlive4 = options.isPidAlive ?? defaultIsPidAlive2;
|
|
30923
|
+
const deadline = now() + acquireTimeoutMs;
|
|
30924
|
+
let backoffMs = 25;
|
|
30925
|
+
while (true) {
|
|
30926
|
+
const meta = {
|
|
30927
|
+
pid: process.pid,
|
|
30928
|
+
hostname: os36.hostname(),
|
|
30929
|
+
timestamp: now(),
|
|
30930
|
+
...options.reason ? { reason: options.reason } : {}
|
|
30931
|
+
};
|
|
30932
|
+
const acquired = tryAcquireOnce2(lockPath, meta, { now: now(), staleLockMs, isPidAlive: isPidAlive4 });
|
|
30933
|
+
if (acquired) {
|
|
30934
|
+
return {
|
|
30935
|
+
lockPath,
|
|
30936
|
+
release: () => {
|
|
30937
|
+
try {
|
|
30938
|
+
fs62.unlinkSync(lockPath);
|
|
30939
|
+
} catch {
|
|
30940
|
+
}
|
|
30941
|
+
}
|
|
30942
|
+
};
|
|
30943
|
+
}
|
|
30944
|
+
if (now() >= deadline) {
|
|
30945
|
+
const existing = readLockMeta2(lockPath);
|
|
30946
|
+
const held = existing ? `(held by pid ${existing.pid} on ${existing.hostname}, since ${new Date(existing.timestamp).toISOString()})` : "(holder unknown)";
|
|
30947
|
+
throw new SettingsJsonLockError(`failed to acquire settings.json lock at ${lockPath} within ${acquireTimeoutMs}ms ${held}`);
|
|
30948
|
+
}
|
|
30949
|
+
await sleep7(Math.min(backoffMs, 200));
|
|
30950
|
+
backoffMs = Math.min(backoffMs * 2, 200);
|
|
30951
|
+
}
|
|
30952
|
+
}
|
|
30953
|
+
async function withSettingsJsonLock(fn, options) {
|
|
30954
|
+
const { release: release2 } = await acquireSettingsJsonLock(options);
|
|
30955
|
+
try {
|
|
30956
|
+
return await fn();
|
|
30957
|
+
} finally {
|
|
30958
|
+
release2();
|
|
30959
|
+
}
|
|
30960
|
+
}
|
|
30961
|
+
|
|
30962
|
+
// ../core/dist/services-status/memory-probe.js
|
|
30963
|
+
var DEFAULT_TIMEOUT_MS4 = 2e3;
|
|
30964
|
+
var DEFAULT_MEMORY_PORT = 3111;
|
|
30965
|
+
var DEFAULT_HEALTH_PATH = "/agentmemory/livez";
|
|
30966
|
+
async function probeMemoryBridge(opts = {}) {
|
|
30967
|
+
const port2 = opts.port ?? DEFAULT_MEMORY_PORT;
|
|
30968
|
+
const healthPath = opts.healthPath ?? DEFAULT_HEALTH_PATH;
|
|
30969
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4;
|
|
30970
|
+
const url2 = `http://127.0.0.1:${port2}${healthPath}`;
|
|
30971
|
+
const t0 = Date.now();
|
|
30972
|
+
try {
|
|
30973
|
+
const res = await fetch(url2, {
|
|
30974
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
30975
|
+
// CP3 LOW fix: refuse to follow redirects. A local attacker
|
|
30976
|
+
// controlling the bridge port (or a misconfigured bridge
|
|
30977
|
+
// returning 3xx) could redirect to an external URL; default
|
|
30978
|
+
// `redirect: 'follow'` would leak timing + reachability.
|
|
30979
|
+
redirect: "error"
|
|
30980
|
+
});
|
|
30981
|
+
await res.text().catch(() => "");
|
|
30982
|
+
const latencyMs = Date.now() - t0;
|
|
30983
|
+
if (res.ok) {
|
|
30984
|
+
return { up: true, latencyMs };
|
|
30985
|
+
}
|
|
30986
|
+
return {
|
|
30987
|
+
up: false,
|
|
30988
|
+
latencyMs,
|
|
30989
|
+
detail: `http ${res.status}`
|
|
30990
|
+
};
|
|
30991
|
+
} catch (err) {
|
|
30992
|
+
const latencyMs = Date.now() - t0;
|
|
30993
|
+
const code = err?.code;
|
|
30994
|
+
const name = err?.name;
|
|
30995
|
+
if (name === "AbortError" || name === "TimeoutError") {
|
|
30996
|
+
return { up: false, latencyMs, detail: `timeout after ${timeoutMs}ms` };
|
|
30997
|
+
}
|
|
30998
|
+
if (code === "ECONNREFUSED") {
|
|
30999
|
+
return { up: false, latencyMs, detail: "connection refused (bridge not running)" };
|
|
31000
|
+
}
|
|
31001
|
+
return {
|
|
31002
|
+
up: false,
|
|
31003
|
+
latencyMs,
|
|
31004
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
31005
|
+
};
|
|
31006
|
+
}
|
|
31007
|
+
}
|
|
31008
|
+
|
|
31009
|
+
// ../core/dist/skill-sources/meta-hooks-migration-snapshot.js
|
|
31010
|
+
init_v3();
|
|
31011
|
+
import * as crypto9 from "node:crypto";
|
|
31012
|
+
import * as fs63 from "node:fs";
|
|
31013
|
+
import * as os37 from "node:os";
|
|
31014
|
+
import * as path65 from "node:path";
|
|
31015
|
+
var META_HOOKS_SNAPSHOT_SCHEMA_VERSION = 1;
|
|
31016
|
+
var META_HOOKS_SNAPSHOT_PREFIX = "meta-hooks-";
|
|
31017
|
+
var SettingsLooseSchema = external_exports.record(external_exports.unknown());
|
|
31018
|
+
var MetaHooksMigrationSnapshotSchema = external_exports.object({
|
|
31019
|
+
schemaVersion: external_exports.literal(META_HOOKS_SNAPSHOT_SCHEMA_VERSION),
|
|
31020
|
+
takenAt: external_exports.string().min(1),
|
|
31021
|
+
namespace: external_exports.literal("meta-hooks"),
|
|
31022
|
+
/**
|
|
31023
|
+
* Full settings.json content captured before injection. Reverting
|
|
31024
|
+
* writes this back verbatim. May be `null` when no settings.json
|
|
31025
|
+
* existed pre-injection (operator's first sync wrote a fresh one);
|
|
31026
|
+
* revert in that case deletes the file.
|
|
31027
|
+
*/
|
|
31028
|
+
originalSettings: external_exports.union([SettingsLooseSchema, external_exports.null()])
|
|
31029
|
+
});
|
|
31030
|
+
function migrationSnapshotsDir2() {
|
|
31031
|
+
const override = process.env["OLAM_MIGRATION_SNAPSHOTS_DIR"];
|
|
31032
|
+
if (override && override.length > 0)
|
|
31033
|
+
return override;
|
|
31034
|
+
return path65.join(os37.homedir(), ".olam", "state", "migration-snapshots");
|
|
31035
|
+
}
|
|
31036
|
+
function writeMetaHooksSnapshot(originalSettings) {
|
|
31037
|
+
const snapshot = {
|
|
31038
|
+
schemaVersion: META_HOOKS_SNAPSHOT_SCHEMA_VERSION,
|
|
31039
|
+
takenAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
31040
|
+
namespace: "meta-hooks",
|
|
31041
|
+
originalSettings
|
|
31042
|
+
};
|
|
31043
|
+
const validated = MetaHooksMigrationSnapshotSchema.parse(snapshot);
|
|
31044
|
+
const dir = migrationSnapshotsDir2();
|
|
31045
|
+
fs63.mkdirSync(dir, { recursive: true });
|
|
31046
|
+
const stamp = validated.takenAt.replace(/[:.]/g, "-");
|
|
31047
|
+
const rand = crypto9.randomBytes(3).toString("hex");
|
|
31048
|
+
const file = path65.join(dir, `${META_HOOKS_SNAPSHOT_PREFIX}${stamp}-${process.pid}-${rand}.json`);
|
|
31049
|
+
fs63.writeFileSync(file, JSON.stringify(validated, null, 2) + "\n", { mode: 384 });
|
|
31050
|
+
return file;
|
|
31051
|
+
}
|
|
31052
|
+
function readMetaHooksSnapshot(filePath) {
|
|
31053
|
+
if (!fs63.existsSync(filePath)) {
|
|
31054
|
+
throw new Error(`snapshot file not found: ${filePath}`);
|
|
31055
|
+
}
|
|
31056
|
+
const raw = fs63.readFileSync(filePath, "utf-8");
|
|
31057
|
+
const parsed = JSON.parse(raw);
|
|
31058
|
+
return MetaHooksMigrationSnapshotSchema.parse(parsed);
|
|
31059
|
+
}
|
|
31060
|
+
function findLatestMetaHooksSnapshot() {
|
|
31061
|
+
const dir = migrationSnapshotsDir2();
|
|
31062
|
+
if (!fs63.existsSync(dir))
|
|
31063
|
+
return void 0;
|
|
31064
|
+
const candidates2 = fs63.readdirSync(dir).filter((n) => n.startsWith(META_HOOKS_SNAPSHOT_PREFIX) && n.endsWith(".json")).sort().reverse();
|
|
31065
|
+
if (candidates2.length === 0)
|
|
31066
|
+
return void 0;
|
|
31067
|
+
return path65.join(dir, candidates2[0]);
|
|
31068
|
+
}
|
|
31069
|
+
function restoreSettingsFromSnapshot(snapshot, settingsPath) {
|
|
31070
|
+
if (snapshot.originalSettings === null) {
|
|
31071
|
+
if (fs63.existsSync(settingsPath)) {
|
|
31072
|
+
fs63.unlinkSync(settingsPath);
|
|
31073
|
+
}
|
|
31074
|
+
return;
|
|
31075
|
+
}
|
|
31076
|
+
fs63.mkdirSync(path65.dirname(settingsPath), { recursive: true });
|
|
31077
|
+
const tmp = `${settingsPath}.tmp-restore-${process.pid}-${Date.now()}`;
|
|
31078
|
+
fs63.writeFileSync(tmp, JSON.stringify(snapshot.originalSettings, null, 2) + "\n");
|
|
31079
|
+
fs63.renameSync(tmp, settingsPath);
|
|
31080
|
+
}
|
|
31081
|
+
|
|
31082
|
+
// ../core/dist/skill-sync/atlas-hook-strip.js
|
|
31083
|
+
var AGENTMEMORY_SCRIPT_PATTERNS = [
|
|
31084
|
+
"agentmemory-recall-trigger.mjs",
|
|
31085
|
+
"agentmemory-classify-queue.mjs"
|
|
31086
|
+
];
|
|
31087
|
+
var OLAM_META_SENTINELS_GUARDED = [
|
|
31088
|
+
OLAM_META_MEMORY_RECALL_SENTINEL,
|
|
31089
|
+
OLAM_META_MEMORY_CLASSIFY_SENTINEL
|
|
31090
|
+
];
|
|
31091
|
+
function isStripCommand(command) {
|
|
31092
|
+
for (const sentinel of OLAM_META_SENTINELS_GUARDED) {
|
|
31093
|
+
if (command.includes(sentinel))
|
|
31094
|
+
return { match: false };
|
|
31095
|
+
}
|
|
31096
|
+
for (const pattern of AGENTMEMORY_SCRIPT_PATTERNS) {
|
|
31097
|
+
if (command.includes(pattern))
|
|
31098
|
+
return { match: true, pattern };
|
|
31099
|
+
}
|
|
31100
|
+
return { match: false };
|
|
31101
|
+
}
|
|
31102
|
+
function findStripCandidates(settings) {
|
|
31103
|
+
const stages = ["PreToolUse", "PostToolUse"];
|
|
31104
|
+
const out = [];
|
|
31105
|
+
for (const stage of stages) {
|
|
31106
|
+
const matchers = settings.hooks?.[stage];
|
|
31107
|
+
if (!Array.isArray(matchers))
|
|
31108
|
+
continue;
|
|
31109
|
+
for (let mi = 0; mi < matchers.length; mi += 1) {
|
|
31110
|
+
const matcher = matchers[mi];
|
|
31111
|
+
const inner = Array.isArray(matcher.hooks) ? matcher.hooks : [];
|
|
31112
|
+
for (let ii = 0; ii < inner.length; ii += 1) {
|
|
31113
|
+
const cmd = inner[ii]?.command;
|
|
31114
|
+
if (typeof cmd !== "string")
|
|
31115
|
+
continue;
|
|
31116
|
+
const verdict = isStripCommand(cmd);
|
|
31117
|
+
if (verdict.match) {
|
|
31118
|
+
out.push({
|
|
31119
|
+
stage,
|
|
31120
|
+
matcherIndex: mi,
|
|
31121
|
+
innerIndex: ii,
|
|
31122
|
+
command: cmd,
|
|
31123
|
+
matcher: matcher.matcher,
|
|
31124
|
+
matchedPattern: verdict.pattern
|
|
31125
|
+
});
|
|
31126
|
+
}
|
|
31127
|
+
}
|
|
31128
|
+
}
|
|
31129
|
+
}
|
|
31130
|
+
return out;
|
|
31131
|
+
}
|
|
31132
|
+
function applyStrip(settings, candidates2) {
|
|
31133
|
+
if (candidates2.length === 0) {
|
|
31134
|
+
return { nextSettings: settings, removedCount: 0 };
|
|
31135
|
+
}
|
|
31136
|
+
const stripByStageMatcher = /* @__PURE__ */ new Map();
|
|
31137
|
+
for (const c of candidates2) {
|
|
31138
|
+
const key = `${c.stage}:${c.matcherIndex}`;
|
|
31139
|
+
if (!stripByStageMatcher.has(key))
|
|
31140
|
+
stripByStageMatcher.set(key, /* @__PURE__ */ new Set());
|
|
31141
|
+
stripByStageMatcher.get(key).add(c.innerIndex);
|
|
31142
|
+
}
|
|
31143
|
+
const nextHooks = { ...settings.hooks ?? {} };
|
|
31144
|
+
const stages = ["PreToolUse", "PostToolUse"];
|
|
31145
|
+
for (const stage of stages) {
|
|
31146
|
+
const matchers = settings.hooks?.[stage];
|
|
31147
|
+
if (!Array.isArray(matchers))
|
|
31148
|
+
continue;
|
|
31149
|
+
const nextMatchers = [];
|
|
31150
|
+
for (let mi = 0; mi < matchers.length; mi += 1) {
|
|
31151
|
+
const matcher = matchers[mi];
|
|
31152
|
+
const innerHooks = Array.isArray(matcher.hooks) ? matcher.hooks : [];
|
|
31153
|
+
const stripIdx = stripByStageMatcher.get(`${stage}:${mi}`);
|
|
31154
|
+
const keptInner = stripIdx === void 0 ? innerHooks : innerHooks.filter((_, ii) => !stripIdx.has(ii));
|
|
31155
|
+
if (keptInner.length === innerHooks.length) {
|
|
31156
|
+
nextMatchers.push(matcher);
|
|
31157
|
+
} else if (keptInner.length === 0) {
|
|
31158
|
+
} else {
|
|
31159
|
+
nextMatchers.push({ ...matcher, hooks: keptInner });
|
|
31160
|
+
}
|
|
31161
|
+
}
|
|
31162
|
+
if (nextMatchers.length === 0) {
|
|
31163
|
+
delete nextHooks[stage];
|
|
31164
|
+
} else {
|
|
31165
|
+
nextHooks[stage] = nextMatchers;
|
|
31166
|
+
}
|
|
31167
|
+
}
|
|
31168
|
+
const next = { ...settings };
|
|
31169
|
+
if (Object.keys(nextHooks).length === 0) {
|
|
31170
|
+
delete next.hooks;
|
|
31171
|
+
} else {
|
|
31172
|
+
next.hooks = nextHooks;
|
|
31173
|
+
}
|
|
31174
|
+
return { nextSettings: next, removedCount: candidates2.length };
|
|
31175
|
+
}
|
|
31176
|
+
|
|
31177
|
+
// ../core/dist/skill-sync/meta-hook-injector.js
|
|
31178
|
+
function decideTargetBlocks(opts) {
|
|
31179
|
+
const mode = opts.mode ?? "auto";
|
|
31180
|
+
const disabled = new Set(opts.disabledBlocks ?? []);
|
|
31181
|
+
if (mode === "never")
|
|
31182
|
+
return /* @__PURE__ */ new Set();
|
|
31183
|
+
const wantMemory = mode === "always" || opts.servicesStatus.memory;
|
|
31184
|
+
const target = /* @__PURE__ */ new Set();
|
|
31185
|
+
if (wantMemory && !disabled.has("memory-recall"))
|
|
31186
|
+
target.add("memory-recall");
|
|
31187
|
+
if (wantMemory && !disabled.has("memory-classify"))
|
|
31188
|
+
target.add("memory-classify");
|
|
31189
|
+
return target;
|
|
31190
|
+
}
|
|
31191
|
+
function injectMetaHooks(opts) {
|
|
31192
|
+
const target = decideTargetBlocks(opts);
|
|
31193
|
+
let working = JSON.parse(JSON.stringify(opts.currentSettings ?? {}));
|
|
31194
|
+
const blocksAdded = [];
|
|
31195
|
+
const blocksRemoved = [];
|
|
31196
|
+
const memoryRecallPresent = hasMemoryRecallBlock(working);
|
|
31197
|
+
if (target.has("memory-recall")) {
|
|
31198
|
+
if (!memoryRecallPresent) {
|
|
31199
|
+
working = appendBlock(working, OLAM_META_MEMORY_RECALL_STAGE, buildMemoryRecallHookEntry());
|
|
31200
|
+
blocksAdded.push("memory-recall");
|
|
31201
|
+
}
|
|
31202
|
+
} else {
|
|
31203
|
+
if (memoryRecallPresent) {
|
|
31204
|
+
const r = computeMemoryRecallUninstall(working);
|
|
31205
|
+
if (r.status === "removed" && r.settingsAfter) {
|
|
31206
|
+
working = r.settingsAfter;
|
|
31207
|
+
blocksRemoved.push("memory-recall");
|
|
31208
|
+
}
|
|
31209
|
+
}
|
|
31210
|
+
}
|
|
31211
|
+
const memoryClassifyPresent = hasMemoryClassifyBlock(working);
|
|
31212
|
+
if (target.has("memory-classify")) {
|
|
31213
|
+
if (!memoryClassifyPresent) {
|
|
31214
|
+
working = appendBlock(working, OLAM_META_MEMORY_CLASSIFY_STAGE, buildMemoryClassifyHookEntry());
|
|
31215
|
+
blocksAdded.push("memory-classify");
|
|
31216
|
+
}
|
|
31217
|
+
} else {
|
|
31218
|
+
if (memoryClassifyPresent) {
|
|
31219
|
+
const r = computeMemoryClassifyUninstall(working);
|
|
31220
|
+
if (r.status === "removed" && r.settingsAfter) {
|
|
31221
|
+
working = r.settingsAfter;
|
|
31222
|
+
blocksRemoved.push("memory-classify");
|
|
31223
|
+
}
|
|
31224
|
+
}
|
|
31225
|
+
}
|
|
31226
|
+
return {
|
|
31227
|
+
nextSettings: working,
|
|
31228
|
+
blocksAdded,
|
|
31229
|
+
blocksRemoved,
|
|
31230
|
+
mode: opts.mode ?? "auto"
|
|
31231
|
+
};
|
|
31232
|
+
}
|
|
31233
|
+
function hasMemoryRecallBlock(settings) {
|
|
31234
|
+
const entries = settings.hooks?.PreToolUse;
|
|
31235
|
+
if (!Array.isArray(entries))
|
|
31236
|
+
return false;
|
|
31237
|
+
for (const matcher of entries) {
|
|
31238
|
+
const inner = matcher?.hooks ?? [];
|
|
31239
|
+
if (!Array.isArray(inner))
|
|
31240
|
+
continue;
|
|
31241
|
+
for (const h of inner) {
|
|
31242
|
+
if (typeof h?.command === "string" && matchMemoryRecallSentinel(h.command))
|
|
31243
|
+
return true;
|
|
31244
|
+
}
|
|
31245
|
+
}
|
|
31246
|
+
return false;
|
|
31247
|
+
}
|
|
31248
|
+
function hasMemoryClassifyBlock(settings) {
|
|
31249
|
+
const entries = settings.hooks?.PostToolUse;
|
|
31250
|
+
if (!Array.isArray(entries))
|
|
31251
|
+
return false;
|
|
31252
|
+
for (const matcher of entries) {
|
|
31253
|
+
const inner = matcher?.hooks ?? [];
|
|
31254
|
+
if (!Array.isArray(inner))
|
|
31255
|
+
continue;
|
|
31256
|
+
for (const h of inner) {
|
|
31257
|
+
if (typeof h?.command === "string" && matchMemoryClassifySentinel(h.command))
|
|
31258
|
+
return true;
|
|
31259
|
+
}
|
|
31260
|
+
}
|
|
31261
|
+
return false;
|
|
31262
|
+
}
|
|
31263
|
+
function appendBlock(settings, stage, entry) {
|
|
31264
|
+
const next = { ...settings };
|
|
31265
|
+
const hooks = { ...settings.hooks ?? {} };
|
|
31266
|
+
const stageEntries = Array.isArray(hooks[stage]) ? [...hooks[stage]] : [];
|
|
31267
|
+
stageEntries.push(entry);
|
|
31268
|
+
hooks[stage] = stageEntries;
|
|
31269
|
+
next.hooks = hooks;
|
|
31270
|
+
return next;
|
|
31271
|
+
}
|
|
31272
|
+
|
|
31273
|
+
// ../core/dist/skill-sync/engine.js
|
|
31274
|
+
import * as fs64 from "node:fs";
|
|
31275
|
+
import * as os38 from "node:os";
|
|
31276
|
+
import * as path66 from "node:path";
|
|
30622
31277
|
function resolveAtlasUser(override) {
|
|
30623
31278
|
if (override)
|
|
30624
31279
|
return override;
|
|
30625
|
-
const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] ||
|
|
30626
|
-
const f =
|
|
30627
|
-
if (
|
|
30628
|
-
return
|
|
31280
|
+
const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path66.join(os38.homedir(), ".claude");
|
|
31281
|
+
const f = path66.join(claudeDir2, ".atlas-user");
|
|
31282
|
+
if (fs64.existsSync(f)) {
|
|
31283
|
+
return fs64.readFileSync(f, "utf-8").trim() || void 0;
|
|
30629
31284
|
}
|
|
30630
31285
|
return void 0;
|
|
30631
31286
|
}
|
|
@@ -30637,7 +31292,7 @@ async function syncSkills(opts = {}) {
|
|
|
30637
31292
|
const perSource = [];
|
|
30638
31293
|
for (const source of sources) {
|
|
30639
31294
|
const clonePath = skillSourceClonePath(source.id);
|
|
30640
|
-
if (!
|
|
31295
|
+
if (!fs64.existsSync(clonePath))
|
|
30641
31296
|
continue;
|
|
30642
31297
|
const { artifacts, subscription } = await withSourceLock(clonePath, () => {
|
|
30643
31298
|
const pinRef = projectOverride?.override.pin?.[source.id];
|
|
@@ -30673,6 +31328,7 @@ async function syncSkills(opts = {}) {
|
|
|
30673
31328
|
projectOverride,
|
|
30674
31329
|
deploy: void 0,
|
|
30675
31330
|
merge: void 0,
|
|
31331
|
+
metaHooks: void 0,
|
|
30676
31332
|
perSource
|
|
30677
31333
|
};
|
|
30678
31334
|
if (opts.dryRun) {
|
|
@@ -30682,12 +31338,105 @@ async function syncSkills(opts = {}) {
|
|
|
30682
31338
|
summary.deploy = deployArtifacts(projectFilteredArtifacts);
|
|
30683
31339
|
summary.collisions = summary.deploy.collisions;
|
|
30684
31340
|
summary.merge = mergeSettings({ hookFiles, permissionFiles });
|
|
31341
|
+
if (opts.metaHooks !== "never") {
|
|
31342
|
+
summary.metaHooks = await injectMetaHooksIntoSettings(opts);
|
|
31343
|
+
}
|
|
30685
31344
|
return summary;
|
|
30686
31345
|
}
|
|
31346
|
+
async function injectMetaHooksIntoSettings(opts) {
|
|
31347
|
+
const mode = opts.metaHooks ?? "auto";
|
|
31348
|
+
const memoryProbe = await probeMemoryBridge();
|
|
31349
|
+
const servicesStatus2 = {
|
|
31350
|
+
memory: memoryProbe.up,
|
|
31351
|
+
...memoryProbe.detail !== void 0 ? { memoryDetail: memoryProbe.detail } : {}
|
|
31352
|
+
};
|
|
31353
|
+
const settingsFile = claudeSettingsPath();
|
|
31354
|
+
let snapshotError;
|
|
31355
|
+
let stripCandidates = [];
|
|
31356
|
+
const result = await withSettingsJsonLock(() => {
|
|
31357
|
+
let currentSettings = {};
|
|
31358
|
+
let settingsExisted = false;
|
|
31359
|
+
if (fs64.existsSync(settingsFile)) {
|
|
31360
|
+
settingsExisted = true;
|
|
31361
|
+
try {
|
|
31362
|
+
const raw = fs64.readFileSync(settingsFile, "utf-8");
|
|
31363
|
+
currentSettings = raw.trim() ? JSON.parse(raw) : {};
|
|
31364
|
+
} catch {
|
|
31365
|
+
try {
|
|
31366
|
+
const raw = fs64.readFileSync(settingsFile);
|
|
31367
|
+
const bakDir = path66.join(path66.dirname(settingsFile), ".malformed-backups");
|
|
31368
|
+
fs64.mkdirSync(bakDir, { recursive: true });
|
|
31369
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31370
|
+
const bakFile = path66.join(bakDir, `settings.json.malformed.${stamp}.bak`);
|
|
31371
|
+
fs64.writeFileSync(bakFile, raw, { mode: 384 });
|
|
31372
|
+
snapshotError = `settings.json was malformed; original bytes preserved at ${bakFile}`;
|
|
31373
|
+
} catch (bakErr) {
|
|
31374
|
+
snapshotError = `settings.json malformed AND .bak write failed: ${bakErr instanceof Error ? bakErr.message : String(bakErr)}`;
|
|
31375
|
+
}
|
|
31376
|
+
currentSettings = {};
|
|
31377
|
+
settingsExisted = false;
|
|
31378
|
+
}
|
|
31379
|
+
}
|
|
31380
|
+
stripCandidates = findStripCandidates(currentSettings);
|
|
31381
|
+
const settingsForInject = stripCandidates.length > 0 ? applyStrip(currentSettings, stripCandidates).nextSettings : currentSettings;
|
|
31382
|
+
let configDisabled = [];
|
|
31383
|
+
try {
|
|
31384
|
+
const cfg = readGlobalConfig();
|
|
31385
|
+
configDisabled = cfg.metaHooksDisabled ?? [];
|
|
31386
|
+
} catch {
|
|
31387
|
+
}
|
|
31388
|
+
const disabledBlocks = Array.from(/* @__PURE__ */ new Set([
|
|
31389
|
+
...configDisabled,
|
|
31390
|
+
...opts.metaHooksDisabled ?? []
|
|
31391
|
+
]));
|
|
31392
|
+
const inject = injectMetaHooks({
|
|
31393
|
+
servicesStatus: servicesStatus2,
|
|
31394
|
+
currentSettings: settingsForInject,
|
|
31395
|
+
mode,
|
|
31396
|
+
...disabledBlocks.length > 0 ? { disabledBlocks } : {}
|
|
31397
|
+
});
|
|
31398
|
+
const noInjectDelta = inject.blocksAdded.length === 0 && inject.blocksRemoved.length === 0;
|
|
31399
|
+
const noStripDelta = stripCandidates.length === 0;
|
|
31400
|
+
if (noInjectDelta && noStripDelta) {
|
|
31401
|
+
return inject;
|
|
31402
|
+
}
|
|
31403
|
+
let snapshotPath;
|
|
31404
|
+
try {
|
|
31405
|
+
snapshotPath = writeMetaHooksSnapshot(settingsExisted ? currentSettings : null);
|
|
31406
|
+
} catch (err) {
|
|
31407
|
+
snapshotError = err instanceof Error ? err.message : String(err);
|
|
31408
|
+
}
|
|
31409
|
+
if (stripCandidates.length > 0) {
|
|
31410
|
+
try {
|
|
31411
|
+
appendTrustAudit({
|
|
31412
|
+
gitUrl: "internal:olam-meta-hooks",
|
|
31413
|
+
action: "meta-hook-stripped",
|
|
31414
|
+
trustMethod: "none",
|
|
31415
|
+
sourceId: "atlas-toolbox",
|
|
31416
|
+
note: `auto-migration during syncSkills stripped ${stripCandidates.length} agentmemory hook entry(ies)${snapshotPath ? `; snapshot at ${snapshotPath}` : ""}`
|
|
31417
|
+
});
|
|
31418
|
+
} catch {
|
|
31419
|
+
}
|
|
31420
|
+
}
|
|
31421
|
+
fs64.mkdirSync(path66.dirname(settingsFile), { recursive: true });
|
|
31422
|
+
const tmpPath = `${settingsFile}.tmp-${process.pid}-${Date.now()}`;
|
|
31423
|
+
fs64.writeFileSync(tmpPath, JSON.stringify(inject.nextSettings, null, 2) + "\n");
|
|
31424
|
+
fs64.renameSync(tmpPath, settingsFile);
|
|
31425
|
+
return inject;
|
|
31426
|
+
}, { reason: `syncSkills meta-hook injection (mode=${mode})` });
|
|
31427
|
+
return {
|
|
31428
|
+
mode: result.mode,
|
|
31429
|
+
servicesStatus: servicesStatus2,
|
|
31430
|
+
blocksAdded: result.blocksAdded,
|
|
31431
|
+
blocksRemoved: result.blocksRemoved,
|
|
31432
|
+
...snapshotError !== void 0 ? { snapshotError } : {},
|
|
31433
|
+
...stripCandidates.length > 0 ? { autoMigrated: { strippedCount: stripCandidates.length, stripCandidates } } : {}
|
|
31434
|
+
};
|
|
31435
|
+
}
|
|
30687
31436
|
|
|
30688
31437
|
// ../core/dist/skill-sync/shadow-backup-manager.js
|
|
30689
|
-
import * as
|
|
30690
|
-
import * as
|
|
31438
|
+
import * as fs65 from "node:fs";
|
|
31439
|
+
import * as path67 from "node:path";
|
|
30691
31440
|
var SHADOW_BACKUP_BUCKETS = ["commands", "agents", "skills", "scripts", "rules"];
|
|
30692
31441
|
var SHADOW_BACKUP_SUFFIX_RE = /\.shadow-backup-(\d+)$/;
|
|
30693
31442
|
function listShadowBackups(opts = {}) {
|
|
@@ -30695,12 +31444,12 @@ function listShadowBackups(opts = {}) {
|
|
|
30695
31444
|
const now = opts.now ?? Date.now();
|
|
30696
31445
|
const out = [];
|
|
30697
31446
|
for (const bucket of SHADOW_BACKUP_BUCKETS) {
|
|
30698
|
-
const bucketDir =
|
|
30699
|
-
if (!
|
|
31447
|
+
const bucketDir = path67.join(claude, bucket);
|
|
31448
|
+
if (!fs65.existsSync(bucketDir))
|
|
30700
31449
|
continue;
|
|
30701
31450
|
let entries;
|
|
30702
31451
|
try {
|
|
30703
|
-
entries =
|
|
31452
|
+
entries = fs65.readdirSync(bucketDir);
|
|
30704
31453
|
} catch {
|
|
30705
31454
|
continue;
|
|
30706
31455
|
}
|
|
@@ -30711,10 +31460,10 @@ function listShadowBackups(opts = {}) {
|
|
|
30711
31460
|
const epochSeconds = Number.parseInt(match2[1], 10);
|
|
30712
31461
|
if (!Number.isFinite(epochSeconds) || epochSeconds < 0)
|
|
30713
31462
|
continue;
|
|
30714
|
-
const full =
|
|
31463
|
+
const full = path67.join(bucketDir, name);
|
|
30715
31464
|
let sizeBytes = 0;
|
|
30716
31465
|
try {
|
|
30717
|
-
const st =
|
|
31466
|
+
const st = fs65.statSync(full);
|
|
30718
31467
|
if (st.isDirectory())
|
|
30719
31468
|
continue;
|
|
30720
31469
|
sizeBytes = st.size;
|
|
@@ -30727,7 +31476,7 @@ function listShadowBackups(opts = {}) {
|
|
|
30727
31476
|
bucket,
|
|
30728
31477
|
basename: name,
|
|
30729
31478
|
originalBasename,
|
|
30730
|
-
originalPath:
|
|
31479
|
+
originalPath: path67.join(bucketDir, originalBasename),
|
|
30731
31480
|
epochSeconds,
|
|
30732
31481
|
ageMs: now - epochSeconds * 1e3,
|
|
30733
31482
|
sizeBytes
|
|
@@ -30770,7 +31519,7 @@ function pruneShadowBackups(opts) {
|
|
|
30770
31519
|
}
|
|
30771
31520
|
if (!opts.dryRun) {
|
|
30772
31521
|
try {
|
|
30773
|
-
|
|
31522
|
+
fs65.unlinkSync(b.path);
|
|
30774
31523
|
} catch {
|
|
30775
31524
|
skipped.push(b);
|
|
30776
31525
|
continue;
|
|
@@ -30781,38 +31530,38 @@ function pruneShadowBackups(opts) {
|
|
|
30781
31530
|
return { deleted, skipped };
|
|
30782
31531
|
}
|
|
30783
31532
|
function restoreShadowBackup(opts) {
|
|
30784
|
-
const abs =
|
|
30785
|
-
if (!
|
|
31533
|
+
const abs = path67.resolve(opts.backupPath);
|
|
31534
|
+
if (!fs65.existsSync(abs)) {
|
|
30786
31535
|
throw new Error(`backup file not found: ${abs}`);
|
|
30787
31536
|
}
|
|
30788
|
-
const
|
|
30789
|
-
const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(
|
|
31537
|
+
const basename12 = path67.basename(abs);
|
|
31538
|
+
const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename12);
|
|
30790
31539
|
if (!match2) {
|
|
30791
|
-
throw new Error(`not a shadow-backup file (basename "${
|
|
31540
|
+
throw new Error(`not a shadow-backup file (basename "${basename12}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
|
|
30792
31541
|
}
|
|
30793
|
-
const originalBasename =
|
|
30794
|
-
const originalPath =
|
|
30795
|
-
if (
|
|
31542
|
+
const originalBasename = basename12.slice(0, basename12.length - match2[0].length);
|
|
31543
|
+
const originalPath = path67.join(path67.dirname(abs), originalBasename);
|
|
31544
|
+
if (fs65.existsSync(originalPath) && !opts.force) {
|
|
30796
31545
|
throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
|
|
30797
31546
|
}
|
|
30798
|
-
if (opts.force &&
|
|
30799
|
-
|
|
31547
|
+
if (opts.force && fs65.existsSync(originalPath)) {
|
|
31548
|
+
fs65.unlinkSync(originalPath);
|
|
30800
31549
|
}
|
|
30801
|
-
|
|
31550
|
+
fs65.renameSync(abs, originalPath);
|
|
30802
31551
|
return { restoredTo: originalPath };
|
|
30803
31552
|
}
|
|
30804
31553
|
|
|
30805
31554
|
// ../core/dist/skill-sources/doctor-checks.js
|
|
30806
31555
|
init_v3();
|
|
30807
|
-
import * as
|
|
30808
|
-
import * as
|
|
30809
|
-
import * as
|
|
31556
|
+
import * as fs66 from "node:fs";
|
|
31557
|
+
import * as path68 from "node:path";
|
|
31558
|
+
import * as os39 from "node:os";
|
|
30810
31559
|
init_schema4();
|
|
30811
31560
|
function claudeDirInternal3() {
|
|
30812
31561
|
const override = process.env["OLAM_CLAUDE_DIR"];
|
|
30813
31562
|
if (override && override.length > 0)
|
|
30814
31563
|
return override;
|
|
30815
|
-
return
|
|
31564
|
+
return path68.join(os39.homedir(), ".claude");
|
|
30816
31565
|
}
|
|
30817
31566
|
function checkStateFileParse() {
|
|
30818
31567
|
const filePath = globalConfigPath();
|
|
@@ -30821,11 +31570,11 @@ function checkStateFileParse() {
|
|
|
30821
31570
|
healthy: true,
|
|
30822
31571
|
description: `~/.olam state file (${filePath})`
|
|
30823
31572
|
};
|
|
30824
|
-
if (!
|
|
31573
|
+
if (!fs66.existsSync(filePath)) {
|
|
30825
31574
|
result.details = ["(file does not yet exist \u2014 will be created on first write)"];
|
|
30826
31575
|
return result;
|
|
30827
31576
|
}
|
|
30828
|
-
const raw =
|
|
31577
|
+
const raw = fs66.readFileSync(filePath, "utf-8");
|
|
30829
31578
|
let parsed;
|
|
30830
31579
|
try {
|
|
30831
31580
|
parsed = JSON.parse(raw);
|
|
@@ -30835,8 +31584,8 @@ function checkStateFileParse() {
|
|
|
30835
31584
|
result.details = [err instanceof Error ? err.message : String(err)];
|
|
30836
31585
|
result.repair = () => {
|
|
30837
31586
|
const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
|
|
30838
|
-
|
|
30839
|
-
|
|
31587
|
+
fs66.renameSync(filePath, aside);
|
|
31588
|
+
fs66.writeFileSync(filePath, JSON.stringify({ schemaVersion: 1, repos: [], runbooks: [], skillSources: [] }, null, 2));
|
|
30840
31589
|
};
|
|
30841
31590
|
return result;
|
|
30842
31591
|
}
|
|
@@ -30847,7 +31596,7 @@ function checkStateFileParse() {
|
|
|
30847
31596
|
result.details = validation.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`);
|
|
30848
31597
|
result.repair = () => {
|
|
30849
31598
|
const aside = `${filePath}.corrupt-${Math.floor(Date.now() / 1e3)}`;
|
|
30850
|
-
|
|
31599
|
+
fs66.copyFileSync(filePath, aside);
|
|
30851
31600
|
const base = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
30852
31601
|
const next = {
|
|
30853
31602
|
...base,
|
|
@@ -30856,7 +31605,7 @@ function checkStateFileParse() {
|
|
|
30856
31605
|
runbooks: [],
|
|
30857
31606
|
skillSources: []
|
|
30858
31607
|
};
|
|
30859
|
-
|
|
31608
|
+
fs66.writeFileSync(filePath, JSON.stringify(next, null, 2));
|
|
30860
31609
|
};
|
|
30861
31610
|
return result;
|
|
30862
31611
|
}
|
|
@@ -30867,16 +31616,16 @@ function checkDanglingSymlinks() {
|
|
|
30867
31616
|
const buckets = ["commands", "agents", "skills", "scripts", "rules"];
|
|
30868
31617
|
const dangling = [];
|
|
30869
31618
|
for (const bucket of buckets) {
|
|
30870
|
-
const dir =
|
|
30871
|
-
if (!
|
|
31619
|
+
const dir = path68.join(claude, bucket);
|
|
31620
|
+
if (!fs66.existsSync(dir))
|
|
30872
31621
|
continue;
|
|
30873
|
-
for (const name of
|
|
30874
|
-
const linkPath =
|
|
31622
|
+
for (const name of fs66.readdirSync(dir)) {
|
|
31623
|
+
const linkPath = path68.join(dir, name);
|
|
30875
31624
|
try {
|
|
30876
|
-
const lst =
|
|
31625
|
+
const lst = fs66.lstatSync(linkPath);
|
|
30877
31626
|
if (!lst.isSymbolicLink())
|
|
30878
31627
|
continue;
|
|
30879
|
-
if (!
|
|
31628
|
+
if (!fs66.existsSync(linkPath)) {
|
|
30880
31629
|
dangling.push(linkPath);
|
|
30881
31630
|
}
|
|
30882
31631
|
} catch {
|
|
@@ -30894,7 +31643,7 @@ function checkDanglingSymlinks() {
|
|
|
30894
31643
|
result.repair = () => {
|
|
30895
31644
|
for (const p of dangling) {
|
|
30896
31645
|
try {
|
|
30897
|
-
|
|
31646
|
+
fs66.unlinkSync(p);
|
|
30898
31647
|
} catch {
|
|
30899
31648
|
}
|
|
30900
31649
|
}
|
|
@@ -30913,19 +31662,19 @@ function checkOrphanedSnapshots() {
|
|
|
30913
31662
|
healthy: true,
|
|
30914
31663
|
description: `orphaned migration snapshots under ${dir}`
|
|
30915
31664
|
};
|
|
30916
|
-
if (!
|
|
31665
|
+
if (!fs66.existsSync(dir)) {
|
|
30917
31666
|
return result;
|
|
30918
31667
|
}
|
|
30919
31668
|
const orphans = [];
|
|
30920
|
-
for (const name of
|
|
31669
|
+
for (const name of fs66.readdirSync(dir)) {
|
|
30921
31670
|
if (!name.endsWith(".json"))
|
|
30922
31671
|
continue;
|
|
30923
|
-
const full =
|
|
31672
|
+
const full = path68.join(dir, name);
|
|
30924
31673
|
try {
|
|
30925
|
-
const stat =
|
|
31674
|
+
const stat = fs66.statSync(full);
|
|
30926
31675
|
if (!stat.isFile())
|
|
30927
31676
|
continue;
|
|
30928
|
-
const raw =
|
|
31677
|
+
const raw = fs66.readFileSync(full, "utf-8");
|
|
30929
31678
|
let parsed;
|
|
30930
31679
|
try {
|
|
30931
31680
|
parsed = JSON.parse(raw);
|
|
@@ -30950,7 +31699,7 @@ function checkOrphanedSnapshots() {
|
|
|
30950
31699
|
result.repair = () => {
|
|
30951
31700
|
for (const o of orphans) {
|
|
30952
31701
|
try {
|
|
30953
|
-
|
|
31702
|
+
fs66.unlinkSync(o.path);
|
|
30954
31703
|
} catch {
|
|
30955
31704
|
}
|
|
30956
31705
|
}
|
|
@@ -30965,12 +31714,12 @@ function checkSentinelDrift() {
|
|
|
30965
31714
|
healthy: true,
|
|
30966
31715
|
description: `olam-skills sentinel block in ${filePath}`
|
|
30967
31716
|
};
|
|
30968
|
-
if (!
|
|
31717
|
+
if (!fs66.existsSync(filePath)) {
|
|
30969
31718
|
return result;
|
|
30970
31719
|
}
|
|
30971
31720
|
let parsed;
|
|
30972
31721
|
try {
|
|
30973
|
-
parsed = JSON.parse(
|
|
31722
|
+
parsed = JSON.parse(fs66.readFileSync(filePath, "utf-8"));
|
|
30974
31723
|
} catch {
|
|
30975
31724
|
return result;
|
|
30976
31725
|
}
|
|
@@ -31011,7 +31760,7 @@ function checkSentinelDrift() {
|
|
|
31011
31760
|
backupSettings();
|
|
31012
31761
|
} catch {
|
|
31013
31762
|
}
|
|
31014
|
-
const next = JSON.parse(
|
|
31763
|
+
const next = JSON.parse(fs66.readFileSync(filePath, "utf-8"));
|
|
31015
31764
|
if (!next.hooks)
|
|
31016
31765
|
return;
|
|
31017
31766
|
for (const stage of Object.keys(next.hooks)) {
|
|
@@ -31034,7 +31783,7 @@ function checkSentinelDrift() {
|
|
|
31034
31783
|
return bad === void 0;
|
|
31035
31784
|
});
|
|
31036
31785
|
}
|
|
31037
|
-
|
|
31786
|
+
fs66.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
|
|
31038
31787
|
};
|
|
31039
31788
|
}
|
|
31040
31789
|
return result;
|
|
@@ -31056,14 +31805,14 @@ function registerConfig(program2) {
|
|
|
31056
31805
|
const config = program2.command("config").description("Manage global olam configuration");
|
|
31057
31806
|
config.command("validate [path]").description("Validate ~/.olam/config.json (or a custom path) against the schema").action((filePath) => {
|
|
31058
31807
|
const resolvedPath = filePath ?? globalConfigPath();
|
|
31059
|
-
if (!
|
|
31808
|
+
if (!fs67.existsSync(resolvedPath)) {
|
|
31060
31809
|
process.stderr.write(`config file not found: ${resolvedPath}
|
|
31061
31810
|
`);
|
|
31062
31811
|
process.exit(1);
|
|
31063
31812
|
}
|
|
31064
31813
|
let raw;
|
|
31065
31814
|
try {
|
|
31066
|
-
raw =
|
|
31815
|
+
raw = fs67.readFileSync(resolvedPath, "utf-8");
|
|
31067
31816
|
} catch (err) {
|
|
31068
31817
|
const msg = err instanceof Error ? err.message : String(err);
|
|
31069
31818
|
process.stderr.write(`cannot read ${resolvedPath}: ${msg}
|
|
@@ -31336,7 +32085,7 @@ async function decideTrust(opts) {
|
|
|
31336
32085
|
return { granted: yes, method: "interactive" };
|
|
31337
32086
|
}
|
|
31338
32087
|
function defaultTrustPrompt(gitUrl) {
|
|
31339
|
-
return new Promise((
|
|
32088
|
+
return new Promise((resolve19) => {
|
|
31340
32089
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
31341
32090
|
process.stdout.write(
|
|
31342
32091
|
`${pc30.yellow("Trust gate:")} register "${gitUrl}" as a skill source?
|
|
@@ -31346,12 +32095,12 @@ Type ${pc30.bold("y")} to add + trust, anything else to cancel: `
|
|
|
31346
32095
|
);
|
|
31347
32096
|
rl.question("", (a) => {
|
|
31348
32097
|
rl.close();
|
|
31349
|
-
|
|
32098
|
+
resolve19(a);
|
|
31350
32099
|
});
|
|
31351
32100
|
});
|
|
31352
32101
|
}
|
|
31353
32102
|
function defaultPostAddPrompt(input) {
|
|
31354
|
-
return new Promise((
|
|
32103
|
+
return new Promise((resolve19) => {
|
|
31355
32104
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
31356
32105
|
process.stdout.write(`
|
|
31357
32106
|
${pc30.bold("Sync now?")} ${pc30.dim("[Y/n] ")}`);
|
|
@@ -31359,7 +32108,7 @@ ${pc30.bold("Sync now?")} ${pc30.dim("[Y/n] ")}`);
|
|
|
31359
32108
|
const sync = !/^n(o)?$/i.test(syncAnswer.trim());
|
|
31360
32109
|
if (input.hookAlreadyInstalled) {
|
|
31361
32110
|
rl.close();
|
|
31362
|
-
|
|
32111
|
+
resolve19({ syncNow: sync, installHook: false });
|
|
31363
32112
|
return;
|
|
31364
32113
|
}
|
|
31365
32114
|
process.stdout.write(
|
|
@@ -31368,7 +32117,7 @@ ${pc30.bold("Sync now?")} ${pc30.dim("[Y/n] ")}`);
|
|
|
31368
32117
|
rl.question("", (hookAnswer) => {
|
|
31369
32118
|
rl.close();
|
|
31370
32119
|
const installHook = !/^n(o)?$/i.test(hookAnswer.trim());
|
|
31371
|
-
|
|
32120
|
+
resolve19({ syncNow: sync, installHook });
|
|
31372
32121
|
});
|
|
31373
32122
|
});
|
|
31374
32123
|
});
|
|
@@ -31642,8 +32391,8 @@ function registerSkillsSource(program2) {
|
|
|
31642
32391
|
}
|
|
31643
32392
|
|
|
31644
32393
|
// src/commands/skills.ts
|
|
31645
|
-
import * as
|
|
31646
|
-
import * as
|
|
32394
|
+
import * as fs68 from "node:fs";
|
|
32395
|
+
import * as path69 from "node:path";
|
|
31647
32396
|
import pc31 from "picocolors";
|
|
31648
32397
|
init_output();
|
|
31649
32398
|
function asMessage4(err) {
|
|
@@ -31657,14 +32406,14 @@ function listDeployed() {
|
|
|
31657
32406
|
);
|
|
31658
32407
|
const entries = [];
|
|
31659
32408
|
for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
|
|
31660
|
-
const bucketDir =
|
|
31661
|
-
if (!
|
|
31662
|
-
for (const name of
|
|
31663
|
-
const full =
|
|
32409
|
+
const bucketDir = path69.join(dir, bucket);
|
|
32410
|
+
if (!fs68.existsSync(bucketDir)) continue;
|
|
32411
|
+
for (const name of fs68.readdirSync(bucketDir)) {
|
|
32412
|
+
const full = path69.join(bucketDir, name);
|
|
31664
32413
|
try {
|
|
31665
|
-
const stat =
|
|
32414
|
+
const stat = fs68.lstatSync(full);
|
|
31666
32415
|
if (!stat.isSymbolicLink()) continue;
|
|
31667
|
-
const target =
|
|
32416
|
+
const target = fs68.readlinkSync(full);
|
|
31668
32417
|
let sourceId;
|
|
31669
32418
|
for (const [clonePath, id] of sourcePaths.entries()) {
|
|
31670
32419
|
if (target.startsWith(clonePath)) {
|
|
@@ -31712,6 +32461,32 @@ function printSyncSummary(summary, dryRun) {
|
|
|
31712
32461
|
if (summary.merge.backupPath) {
|
|
31713
32462
|
console.log(` settings backup: ${pc31.dim(summary.merge.backupPath)}`);
|
|
31714
32463
|
}
|
|
32464
|
+
if (summary.merge.dualWriteDeduped > 0) {
|
|
32465
|
+
console.log(` ${pc31.dim(`dual-write deduped: ${summary.merge.dualWriteDeduped} (atlas-shipped hook redundant with olam-meta block)`)}`);
|
|
32466
|
+
for (const cmd of summary.merge.dualWriteDroppedCommands) {
|
|
32467
|
+
console.log(` ${pc31.dim("(dropped)")} ${cmd.slice(0, 120)}${cmd.length > 120 ? "\u2026" : ""}`);
|
|
32468
|
+
}
|
|
32469
|
+
}
|
|
32470
|
+
}
|
|
32471
|
+
if (summary.metaHooks) {
|
|
32472
|
+
const mh = summary.metaHooks;
|
|
32473
|
+
const memLabel = mh.servicesStatus.memory ? pc31.green("up") : pc31.dim("down");
|
|
32474
|
+
console.log(` meta-hooks: mode=${mh.mode} \xB7 memory=${memLabel}${mh.servicesStatus.memoryDetail ? pc31.dim(` (${mh.servicesStatus.memoryDetail})`) : ""}`);
|
|
32475
|
+
if (mh.autoMigrated && mh.autoMigrated.strippedCount > 0) {
|
|
32476
|
+
console.log(
|
|
32477
|
+
` ${pc31.cyan("~ auto-migrated:")} stripped ${mh.autoMigrated.strippedCount} atlas-toolbox-shipped agentmemory hook entry(ies); replaced by olam-injected blocks`
|
|
32478
|
+
);
|
|
32479
|
+
}
|
|
32480
|
+
if (mh.blocksAdded.length > 0) {
|
|
32481
|
+
console.log(` ${pc31.green("+ injected:")} ${mh.blocksAdded.join(", ")}`);
|
|
32482
|
+
}
|
|
32483
|
+
if (mh.blocksRemoved.length > 0) {
|
|
32484
|
+
console.log(` ${pc31.yellow("- stripped:")} ${mh.blocksRemoved.join(", ")}`);
|
|
32485
|
+
}
|
|
32486
|
+
if (mh.snapshotError) {
|
|
32487
|
+
console.log(` ${pc31.red("! snapshot FAILED:")} ${mh.snapshotError}`);
|
|
32488
|
+
console.log(` ${pc31.red(" (migrate-hooks-back will not be able to undo this sync)")}`);
|
|
32489
|
+
}
|
|
31715
32490
|
}
|
|
31716
32491
|
console.log();
|
|
31717
32492
|
for (const s of summary.perSource) {
|
|
@@ -31721,9 +32496,23 @@ function printSyncSummary(summary, dryRun) {
|
|
|
31721
32496
|
}
|
|
31722
32497
|
function registerSkills(program2) {
|
|
31723
32498
|
const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
|
|
31724
|
-
skills.command("sync").description("Sync registered skill sources to ~/.claude/").option("--dry-run", "Resolve artifacts but do not deploy or merge").option("--atlas-user <user>", "Override atlas-user (defaults to ~/.claude/.atlas-user)").
|
|
32499
|
+
skills.command("sync").description("Sync registered skill sources to ~/.claude/").option("--dry-run", "Resolve artifacts but do not deploy or merge").option("--atlas-user <user>", "Override atlas-user (defaults to ~/.claude/.atlas-user)").option(
|
|
32500
|
+
"--meta-hooks <mode>",
|
|
32501
|
+
'olam-meta hook injection mode (B3): "auto" (default) \u2014 inject blocks for detected olam services; "always" \u2014 inject all blocks unconditionally; "never" \u2014 skip injection entirely',
|
|
32502
|
+
"auto"
|
|
32503
|
+
).action(async (opts) => {
|
|
31725
32504
|
try {
|
|
31726
|
-
const
|
|
32505
|
+
const validModes = ["auto", "always", "never"];
|
|
32506
|
+
if (opts.metaHooks && !validModes.includes(opts.metaHooks)) {
|
|
32507
|
+
printError(`--meta-hooks must be one of: ${validModes.join(", ")} (got "${opts.metaHooks}")`);
|
|
32508
|
+
process.exitCode = 1;
|
|
32509
|
+
return;
|
|
32510
|
+
}
|
|
32511
|
+
const summary = await syncSkills({
|
|
32512
|
+
dryRun: opts.dryRun,
|
|
32513
|
+
atlasUser: opts.atlasUser,
|
|
32514
|
+
metaHooks: opts.metaHooks ?? "auto"
|
|
32515
|
+
});
|
|
31727
32516
|
printSyncSummary(summary, !!opts.dryRun);
|
|
31728
32517
|
if (!opts.dryRun) {
|
|
31729
32518
|
printSuccess(`synced ${summary.sourceCount} source(s), ${summary.artifactCount} artifact(s)`);
|
|
@@ -31783,12 +32572,12 @@ function registerSkills(program2) {
|
|
|
31783
32572
|
|
|
31784
32573
|
// src/commands/skills-hook.ts
|
|
31785
32574
|
init_output();
|
|
31786
|
-
import * as
|
|
32575
|
+
import * as fs69 from "node:fs";
|
|
31787
32576
|
function backup(filePath) {
|
|
31788
|
-
if (!
|
|
32577
|
+
if (!fs69.existsSync(filePath)) return null;
|
|
31789
32578
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31790
32579
|
const backupPath = `${filePath}.olam-bak.${ts}`;
|
|
31791
|
-
|
|
32580
|
+
fs69.copyFileSync(filePath, backupPath);
|
|
31792
32581
|
return backupPath;
|
|
31793
32582
|
}
|
|
31794
32583
|
function registerSkillsHook(program2) {
|
|
@@ -31836,7 +32625,7 @@ function registerSkillsHook(program2) {
|
|
|
31836
32625
|
printInfo("olam-skills hook", `not found in ${filePath} \u2014 already uninstalled`);
|
|
31837
32626
|
if (backupPath) {
|
|
31838
32627
|
try {
|
|
31839
|
-
|
|
32628
|
+
fs69.unlinkSync(backupPath);
|
|
31840
32629
|
} catch {
|
|
31841
32630
|
}
|
|
31842
32631
|
}
|
|
@@ -32013,25 +32802,25 @@ function registerSkillsOnboard(program2) {
|
|
|
32013
32802
|
}
|
|
32014
32803
|
|
|
32015
32804
|
// src/commands/skills-migrate.ts
|
|
32016
|
-
import * as
|
|
32017
|
-
import * as
|
|
32805
|
+
import * as fs70 from "node:fs";
|
|
32806
|
+
import * as path70 from "node:path";
|
|
32018
32807
|
init_output();
|
|
32019
32808
|
var MIGRATE_FROM_TOOLBOX_COMMAND = "migrate-from-toolbox";
|
|
32020
32809
|
function asMessage6(err) {
|
|
32021
32810
|
return err instanceof Error ? err.message : String(err);
|
|
32022
32811
|
}
|
|
32023
32812
|
function isOlamSkillsHookPresent(filePath) {
|
|
32024
|
-
if (!
|
|
32813
|
+
if (!fs70.existsSync(filePath)) return false;
|
|
32025
32814
|
try {
|
|
32026
|
-
const raw =
|
|
32815
|
+
const raw = fs70.readFileSync(filePath, "utf-8");
|
|
32027
32816
|
return raw.includes(OLAM_SKILLS_HOOK_SENTINEL);
|
|
32028
32817
|
} catch {
|
|
32029
32818
|
return false;
|
|
32030
32819
|
}
|
|
32031
32820
|
}
|
|
32032
32821
|
function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
|
|
32033
|
-
if (!
|
|
32034
|
-
const raw =
|
|
32822
|
+
if (!fs70.existsSync(filePath)) return { removed: 0 };
|
|
32823
|
+
const raw = fs70.readFileSync(filePath, "utf-8");
|
|
32035
32824
|
const settings = raw.trim() ? JSON.parse(raw) : {};
|
|
32036
32825
|
const ss = settings?.hooks?.SessionStart;
|
|
32037
32826
|
if (!Array.isArray(ss)) return { removed: 0 };
|
|
@@ -32060,7 +32849,7 @@ function uninstallLegacyToolboxSessionStartHook(filePath, toolboxPath) {
|
|
|
32060
32849
|
if (otherStages.length === 0) delete next.hooks;
|
|
32061
32850
|
else delete next.hooks.SessionStart;
|
|
32062
32851
|
}
|
|
32063
|
-
|
|
32852
|
+
fs70.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
|
|
32064
32853
|
return { removed };
|
|
32065
32854
|
}
|
|
32066
32855
|
function registerSkillsMigrate(program2) {
|
|
@@ -32083,7 +32872,7 @@ function registerSkillsMigrate(program2) {
|
|
|
32083
32872
|
return;
|
|
32084
32873
|
}
|
|
32085
32874
|
const toolboxPath = opts.path;
|
|
32086
|
-
const namespace = opts.namespace ??
|
|
32875
|
+
const namespace = opts.namespace ?? path70.basename(toolboxPath);
|
|
32087
32876
|
const sourceName = opts.sourceName ?? namespace;
|
|
32088
32877
|
const snapshot = detectToolboxState({ toolboxPath, namespace });
|
|
32089
32878
|
if (!snapshot) {
|
|
@@ -32137,9 +32926,9 @@ function registerSkillsMigrate(program2) {
|
|
|
32137
32926
|
printWarning(`legacy hook removal failed: ${asMessage6(err)}; proceeding`);
|
|
32138
32927
|
}
|
|
32139
32928
|
const scope = opts.scope === "user" ? "user" : "project";
|
|
32140
|
-
const olamHookPath = scope === "user" ? settingsFile :
|
|
32929
|
+
const olamHookPath = scope === "user" ? settingsFile : path70.join(process.cwd(), ".claude", "settings.json");
|
|
32141
32930
|
try {
|
|
32142
|
-
|
|
32931
|
+
fs70.mkdirSync(path70.dirname(olamHookPath), { recursive: true });
|
|
32143
32932
|
const result = mergeHomeSettingsJson(olamHookPath, {
|
|
32144
32933
|
ensureHook: {
|
|
32145
32934
|
stage: OLAM_SKILLS_HOOK_STAGE,
|
|
@@ -32170,8 +32959,8 @@ function registerSkillsMigrate(program2) {
|
|
|
32170
32959
|
}
|
|
32171
32960
|
|
|
32172
32961
|
// src/commands/skills-migrate-back.ts
|
|
32173
|
-
import * as
|
|
32174
|
-
import * as
|
|
32962
|
+
import * as fs71 from "node:fs";
|
|
32963
|
+
import * as path71 from "node:path";
|
|
32175
32964
|
init_output();
|
|
32176
32965
|
var MIGRATE_BACK_TO_TOOLBOX_COMMAND = "migrate-back-to-toolbox";
|
|
32177
32966
|
function asMessage7(err) {
|
|
@@ -32180,16 +32969,16 @@ function asMessage7(err) {
|
|
|
32180
32969
|
function claudeDirInternal4() {
|
|
32181
32970
|
const override = process.env["OLAM_CLAUDE_DIR"];
|
|
32182
32971
|
if (override && override.length > 0) return override;
|
|
32183
|
-
return
|
|
32972
|
+
return path71.join(process.env["HOME"] ?? "", ".claude");
|
|
32184
32973
|
}
|
|
32185
32974
|
function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
|
|
32186
32975
|
if (!originalSessionStartHook || originalSessionStartHook.length === 0) {
|
|
32187
32976
|
return { restored: false };
|
|
32188
32977
|
}
|
|
32189
32978
|
let settings;
|
|
32190
|
-
if (
|
|
32979
|
+
if (fs71.existsSync(filePath)) {
|
|
32191
32980
|
try {
|
|
32192
|
-
const raw =
|
|
32981
|
+
const raw = fs71.readFileSync(filePath, "utf-8");
|
|
32193
32982
|
settings = raw.trim() ? JSON.parse(raw) : {};
|
|
32194
32983
|
} catch {
|
|
32195
32984
|
settings = {};
|
|
@@ -32205,8 +32994,8 @@ function restoreSessionStartFromSnapshot(filePath, originalSessionStartHook) {
|
|
|
32205
32994
|
SessionStart: originalSessionStartHook
|
|
32206
32995
|
}
|
|
32207
32996
|
};
|
|
32208
|
-
|
|
32209
|
-
|
|
32997
|
+
fs71.mkdirSync(path71.dirname(filePath), { recursive: true });
|
|
32998
|
+
fs71.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
|
|
32210
32999
|
return { restored: true };
|
|
32211
33000
|
}
|
|
32212
33001
|
function removeOlamManagedSymlinks() {
|
|
@@ -32215,16 +33004,16 @@ function removeOlamManagedSymlinks() {
|
|
|
32215
33004
|
const olamClonePaths = sources.map((s) => skillSourceClonePath(s.id));
|
|
32216
33005
|
let removed = 0;
|
|
32217
33006
|
for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
|
|
32218
|
-
const dir =
|
|
32219
|
-
if (!
|
|
32220
|
-
for (const name of
|
|
32221
|
-
const linkPath =
|
|
33007
|
+
const dir = path71.join(claude, bucket);
|
|
33008
|
+
if (!fs71.existsSync(dir)) continue;
|
|
33009
|
+
for (const name of fs71.readdirSync(dir)) {
|
|
33010
|
+
const linkPath = path71.join(dir, name);
|
|
32222
33011
|
try {
|
|
32223
|
-
const stat =
|
|
33012
|
+
const stat = fs71.lstatSync(linkPath);
|
|
32224
33013
|
if (!stat.isSymbolicLink()) continue;
|
|
32225
|
-
const target =
|
|
33014
|
+
const target = fs71.readlinkSync(linkPath);
|
|
32226
33015
|
if (olamClonePaths.some((cp) => target.startsWith(cp))) {
|
|
32227
|
-
|
|
33016
|
+
fs71.unlinkSync(linkPath);
|
|
32228
33017
|
removed += 1;
|
|
32229
33018
|
}
|
|
32230
33019
|
} catch {
|
|
@@ -32237,18 +33026,18 @@ function restoreToolboxSymlinks(symlinks) {
|
|
|
32237
33026
|
let restored = 0;
|
|
32238
33027
|
for (const { link, target } of symlinks) {
|
|
32239
33028
|
try {
|
|
32240
|
-
|
|
32241
|
-
if (
|
|
33029
|
+
fs71.mkdirSync(path71.dirname(link), { recursive: true });
|
|
33030
|
+
if (fs71.existsSync(link) || (() => {
|
|
32242
33031
|
try {
|
|
32243
|
-
|
|
33032
|
+
fs71.lstatSync(link);
|
|
32244
33033
|
return true;
|
|
32245
33034
|
} catch {
|
|
32246
33035
|
return false;
|
|
32247
33036
|
}
|
|
32248
33037
|
})()) {
|
|
32249
|
-
|
|
33038
|
+
fs71.unlinkSync(link);
|
|
32250
33039
|
}
|
|
32251
|
-
|
|
33040
|
+
fs71.symlinkSync(target, link);
|
|
32252
33041
|
restored += 1;
|
|
32253
33042
|
} catch {
|
|
32254
33043
|
}
|
|
@@ -32257,9 +33046,9 @@ function restoreToolboxSymlinks(symlinks) {
|
|
|
32257
33046
|
}
|
|
32258
33047
|
function restoreAtlasUserMarker(atlasUser) {
|
|
32259
33048
|
if (!atlasUser) return false;
|
|
32260
|
-
const file =
|
|
32261
|
-
|
|
32262
|
-
|
|
33049
|
+
const file = path71.join(claudeDirInternal4(), ".atlas-user");
|
|
33050
|
+
fs71.mkdirSync(path71.dirname(file), { recursive: true });
|
|
33051
|
+
fs71.writeFileSync(file, atlasUser);
|
|
32263
33052
|
return true;
|
|
32264
33053
|
}
|
|
32265
33054
|
function registerSkillsMigrateBack(program2) {
|
|
@@ -32272,15 +33061,15 @@ function registerSkillsMigrateBack(program2) {
|
|
|
32272
33061
|
let snapshot;
|
|
32273
33062
|
try {
|
|
32274
33063
|
if (opts.snapshot) {
|
|
32275
|
-
snapshotPath =
|
|
32276
|
-
if (!
|
|
33064
|
+
snapshotPath = path71.resolve(opts.snapshot);
|
|
33065
|
+
if (!fs71.existsSync(snapshotPath)) {
|
|
32277
33066
|
printError(`snapshot not found at ${snapshotPath}`);
|
|
32278
33067
|
process.exitCode = 1;
|
|
32279
33068
|
return;
|
|
32280
33069
|
}
|
|
32281
33070
|
snapshot = readMigrationSnapshotFromPath(snapshotPath);
|
|
32282
33071
|
} else {
|
|
32283
|
-
const filterNamespace = opts.namespace ?? (opts.path ?
|
|
33072
|
+
const filterNamespace = opts.namespace ?? (opts.path ? path71.basename(opts.path) : void 0);
|
|
32284
33073
|
const latest = readLatestMigrationSnapshot({ namespace: filterNamespace });
|
|
32285
33074
|
if (!latest) {
|
|
32286
33075
|
const where = filterNamespace ? ` for namespace "${filterNamespace}"` : "";
|
|
@@ -32350,13 +33139,176 @@ function registerSkillsMigrateBack(program2) {
|
|
|
32350
33139
|
});
|
|
32351
33140
|
}
|
|
32352
33141
|
|
|
32353
|
-
// src/commands/skills-
|
|
32354
|
-
import * as
|
|
33142
|
+
// src/commands/skills-migrate-hooks.ts
|
|
33143
|
+
import * as fs72 from "node:fs";
|
|
33144
|
+
import * as path72 from "node:path";
|
|
32355
33145
|
import pc33 from "picocolors";
|
|
32356
33146
|
init_output();
|
|
33147
|
+
var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
|
|
33148
|
+
function settingsHasOlamMetaSentinel(settings) {
|
|
33149
|
+
for (const stage of ["PreToolUse", "PostToolUse"]) {
|
|
33150
|
+
const matchers = settings.hooks?.[stage];
|
|
33151
|
+
if (!Array.isArray(matchers)) continue;
|
|
33152
|
+
for (const matcher of matchers) {
|
|
33153
|
+
const inner = Array.isArray(matcher.hooks) ? matcher.hooks : [];
|
|
33154
|
+
for (const h of inner) {
|
|
33155
|
+
const cmd = h?.command;
|
|
33156
|
+
if (typeof cmd !== "string") continue;
|
|
33157
|
+
for (const sentinel of OLAM_META_SENTINELS_GUARDED) {
|
|
33158
|
+
if (cmd.includes(sentinel)) return true;
|
|
33159
|
+
}
|
|
33160
|
+
}
|
|
33161
|
+
}
|
|
33162
|
+
}
|
|
33163
|
+
return false;
|
|
33164
|
+
}
|
|
33165
|
+
function readSettings2(filePath) {
|
|
33166
|
+
if (!fs72.existsSync(filePath)) return null;
|
|
33167
|
+
const raw = fs72.readFileSync(filePath, "utf-8");
|
|
33168
|
+
if (raw.trim().length === 0) return {};
|
|
33169
|
+
return JSON.parse(raw);
|
|
33170
|
+
}
|
|
33171
|
+
function writeSettings(filePath, settings) {
|
|
33172
|
+
fs72.mkdirSync(path72.dirname(filePath), { recursive: true });
|
|
33173
|
+
const tmp = `${filePath}.tmp-migrate-hooks-${process.pid}-${Date.now()}`;
|
|
33174
|
+
fs72.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
|
|
33175
|
+
fs72.renameSync(tmp, filePath);
|
|
33176
|
+
}
|
|
33177
|
+
function printSummary(candidates2, opts) {
|
|
33178
|
+
if (candidates2.length === 0) {
|
|
33179
|
+
printInfo(MIGRATE_HOOKS_COMMAND, "no atlas-toolbox-shipped agentmemory hooks found in settings.json \u2014 nothing to migrate");
|
|
33180
|
+
return;
|
|
33181
|
+
}
|
|
33182
|
+
const verb = opts.dryRun ? "would strip" : "stripped";
|
|
33183
|
+
console.log(pc33.bold(`${verb} ${candidates2.length} atlas-toolbox-shipped agentmemory hook entry(ies):`));
|
|
33184
|
+
for (const c of candidates2) {
|
|
33185
|
+
const matcher = c.matcher ?? "*";
|
|
33186
|
+
const cmdPreview = c.command.length > 120 ? `${c.command.slice(0, 117)}...` : c.command;
|
|
33187
|
+
console.log(` ${pc33.dim(`[${c.stage}]`)} matcher=${pc33.cyan(matcher)} pattern=${pc33.yellow(c.matchedPattern)}`);
|
|
33188
|
+
console.log(` ${pc33.dim(cmdPreview)}`);
|
|
33189
|
+
}
|
|
33190
|
+
if (opts.snapshotPath) {
|
|
33191
|
+
console.log();
|
|
33192
|
+
printInfo("snapshot", opts.snapshotPath);
|
|
33193
|
+
printInfo("reverse", `run \`olam skills migrate-hooks-back\` (or \`migrate-hooks-back --snapshot <path>\`) to restore the pre-strip settings.json`);
|
|
33194
|
+
}
|
|
33195
|
+
}
|
|
32357
33196
|
function asMessage8(err) {
|
|
32358
33197
|
return err instanceof Error ? err.message : String(err);
|
|
32359
33198
|
}
|
|
33199
|
+
function registerSkillsMigrateHooks(program2) {
|
|
33200
|
+
const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
|
|
33201
|
+
skills.command(MIGRATE_HOOKS_COMMAND).description("Strip atlas-toolbox-shipped agentmemory hook entries from ~/.claude/settings.json (forward migration; reverse via migrate-hooks-back)").option("--dry-run", "Show what would be stripped without mutating settings.json or writing a snapshot").action(async (opts) => {
|
|
33202
|
+
try {
|
|
33203
|
+
await withSettingsJsonLock(
|
|
33204
|
+
async () => {
|
|
33205
|
+
const settingsFile = claudeSettingsPath();
|
|
33206
|
+
const settings = readSettings2(settingsFile);
|
|
33207
|
+
if (settings === null) {
|
|
33208
|
+
printInfo(
|
|
33209
|
+
MIGRATE_HOOKS_COMMAND,
|
|
33210
|
+
`${settingsFile} does not exist \u2014 nothing to migrate`
|
|
33211
|
+
);
|
|
33212
|
+
return;
|
|
33213
|
+
}
|
|
33214
|
+
const candidates2 = findStripCandidates(settings);
|
|
33215
|
+
if (opts.dryRun) {
|
|
33216
|
+
printSummary(candidates2, { dryRun: true });
|
|
33217
|
+
return;
|
|
33218
|
+
}
|
|
33219
|
+
if (candidates2.length === 0) {
|
|
33220
|
+
printSummary(candidates2, { dryRun: false });
|
|
33221
|
+
return;
|
|
33222
|
+
}
|
|
33223
|
+
const hasOlamMetaSentinel = settingsHasOlamMetaSentinel(settings);
|
|
33224
|
+
if (!hasOlamMetaSentinel) {
|
|
33225
|
+
printWarning(
|
|
33226
|
+
`stripping ${candidates2.length} atlas-toolbox-shipped agentmemory entry(ies) WITHOUT any olam-meta sentinel-bound block present in settings.json. After the strip, agentmemory recall/classify will NOT fire from this settings.json. If unintended, reverse with \`olam skills migrate-hooks-back\` and re-sync with \`olam skills sync\` (default mode injects olam-meta blocks when memory-bridge is running).`
|
|
33227
|
+
);
|
|
33228
|
+
}
|
|
33229
|
+
const snapshotPath = writeMetaHooksSnapshot(settings);
|
|
33230
|
+
const { nextSettings, removedCount } = applyStrip(settings, candidates2);
|
|
33231
|
+
writeSettings(settingsFile, nextSettings);
|
|
33232
|
+
appendTrustAudit({
|
|
33233
|
+
gitUrl: "internal:olam-meta-hooks",
|
|
33234
|
+
action: "meta-hook-stripped",
|
|
33235
|
+
trustMethod: "none",
|
|
33236
|
+
sourceId: "atlas-toolbox",
|
|
33237
|
+
note: `removed ${removedCount} agentmemory hook entry(ies); snapshot at ${snapshotPath}`
|
|
33238
|
+
});
|
|
33239
|
+
printSummary(candidates2, { dryRun: false, snapshotPath });
|
|
33240
|
+
printSuccess(`stripped ${removedCount} atlas-toolbox-shipped agentmemory hook entry(ies) from ${settingsFile}`);
|
|
33241
|
+
},
|
|
33242
|
+
{ reason: `cli:${MIGRATE_HOOKS_COMMAND}` }
|
|
33243
|
+
);
|
|
33244
|
+
} catch (err) {
|
|
33245
|
+
printError(asMessage8(err));
|
|
33246
|
+
process.exitCode = 1;
|
|
33247
|
+
}
|
|
33248
|
+
});
|
|
33249
|
+
}
|
|
33250
|
+
|
|
33251
|
+
// src/commands/skills-migrate-hooks-back.ts
|
|
33252
|
+
import * as path73 from "node:path";
|
|
33253
|
+
init_output();
|
|
33254
|
+
function asMessage9(err) {
|
|
33255
|
+
return err instanceof Error ? err.message : String(err);
|
|
33256
|
+
}
|
|
33257
|
+
function registerSkillsMigrateHooksBack(program2) {
|
|
33258
|
+
const skills = program2.commands.find((c) => c.name() === "skills") ?? program2.command("skills").description("Manage skill sources and synchronization");
|
|
33259
|
+
skills.command("migrate-hooks-back").description("Reverse olam-meta hook injection by restoring ~/.claude/settings.json from a B5 snapshot").option("--snapshot <path>", "Use a specific snapshot file (default: most recent meta-hooks-*.json)").action((opts) => {
|
|
33260
|
+
try {
|
|
33261
|
+
const snapshotPath = opts.snapshot ?? findLatestMetaHooksSnapshot();
|
|
33262
|
+
if (!snapshotPath) {
|
|
33263
|
+
printError(
|
|
33264
|
+
"No meta-hooks-* snapshot found in ~/.olam/state/migration-snapshots/. Engine writes one before every injection that mutates settings.json; if none exist, no reversible injection has happened yet."
|
|
33265
|
+
);
|
|
33266
|
+
process.exitCode = 1;
|
|
33267
|
+
return;
|
|
33268
|
+
}
|
|
33269
|
+
if (opts.snapshot) {
|
|
33270
|
+
const resolved = path73.resolve(opts.snapshot);
|
|
33271
|
+
const allowedDir = path73.resolve(migrationSnapshotsDir2());
|
|
33272
|
+
if (!resolved.startsWith(allowedDir + path73.sep)) {
|
|
33273
|
+
printError(
|
|
33274
|
+
`--snapshot path must be inside ${allowedDir} (got "${resolved}"). Refusing to restore from an arbitrary path \u2014 settings.json would land operator-chosen content.`
|
|
33275
|
+
);
|
|
33276
|
+
process.exitCode = 1;
|
|
33277
|
+
return;
|
|
33278
|
+
}
|
|
33279
|
+
const basename12 = path73.basename(resolved);
|
|
33280
|
+
if (!basename12.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
|
|
33281
|
+
printError(
|
|
33282
|
+
`--snapshot filename must start with "${META_HOOKS_SNAPSHOT_PREFIX}" (got "${basename12}"). Cross-namespace snapshots (atlas-toolbox-*) are not valid restore targets for olam-meta hooks.`
|
|
33283
|
+
);
|
|
33284
|
+
process.exitCode = 1;
|
|
33285
|
+
return;
|
|
33286
|
+
}
|
|
33287
|
+
}
|
|
33288
|
+
printInfo("snapshot", snapshotPath);
|
|
33289
|
+
const snapshot = readMetaHooksSnapshot(snapshotPath);
|
|
33290
|
+
printInfo("takenAt", snapshot.takenAt);
|
|
33291
|
+
const settingsFile = claudeSettingsPath();
|
|
33292
|
+
restoreSettingsFromSnapshot(snapshot, settingsFile);
|
|
33293
|
+
if (snapshot.originalSettings === null) {
|
|
33294
|
+
printSuccess(`removed ${settingsFile} (no settings.json existed pre-injection)`);
|
|
33295
|
+
} else {
|
|
33296
|
+
printSuccess(`restored ${settingsFile} to pre-injection state`);
|
|
33297
|
+
}
|
|
33298
|
+
} catch (err) {
|
|
33299
|
+
printError(asMessage9(err));
|
|
33300
|
+
process.exitCode = 1;
|
|
33301
|
+
}
|
|
33302
|
+
});
|
|
33303
|
+
}
|
|
33304
|
+
|
|
33305
|
+
// src/commands/skills-shadow-backups.ts
|
|
33306
|
+
import * as fs73 from "node:fs";
|
|
33307
|
+
import pc34 from "picocolors";
|
|
33308
|
+
init_output();
|
|
33309
|
+
function asMessage10(err) {
|
|
33310
|
+
return err instanceof Error ? err.message : String(err);
|
|
33311
|
+
}
|
|
32360
33312
|
function formatAge3(ms) {
|
|
32361
33313
|
if (ms < 0) return "<future>";
|
|
32362
33314
|
const d = Math.floor(ms / 864e5);
|
|
@@ -32377,7 +33329,7 @@ function printBackupRows(backups) {
|
|
|
32377
33329
|
for (const b of backups) {
|
|
32378
33330
|
const when = new Date(b.epochSeconds * 1e3).toISOString().slice(0, 10);
|
|
32379
33331
|
console.log(
|
|
32380
|
-
` ${
|
|
33332
|
+
` ${pc34.dim(formatAge3(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc34.dim(when)} ${b.bucket}/${pc34.bold(b.basename)}`
|
|
32381
33333
|
);
|
|
32382
33334
|
}
|
|
32383
33335
|
}
|
|
@@ -32387,11 +33339,11 @@ function registerSkillsShadowBackups(program2) {
|
|
|
32387
33339
|
sb.command("list").description("List all shadow-backup files under ~/.claude/").action(() => {
|
|
32388
33340
|
const all = listShadowBackups();
|
|
32389
33341
|
if (all.length === 0) {
|
|
32390
|
-
console.log(
|
|
33342
|
+
console.log(pc34.dim("No shadow-backup files under ~/.claude/."));
|
|
32391
33343
|
return;
|
|
32392
33344
|
}
|
|
32393
33345
|
printHeader(`${all.length} shadow backup(s)`);
|
|
32394
|
-
console.log(
|
|
33346
|
+
console.log(pc34.dim(" age size created bucket/basename"));
|
|
32395
33347
|
printBackupRows(all);
|
|
32396
33348
|
});
|
|
32397
33349
|
sb.command("prune").description("Delete shadow-backup files older than a duration (e.g. 30d) OR all of them with --all --force").option("--older-than <duration>", "Delete backups older than this duration (e.g. 30d, 7d, 24h, 2w)", "30d").option("--all", "Delete every shadow-backup file (requires --force)").option("--force", "Confirm deletion when --all is used").option("--dry-run", "Show what would be deleted without deleting").action((opts) => {
|
|
@@ -32418,24 +33370,24 @@ function registerSkillsShadowBackups(program2) {
|
|
|
32418
33370
|
const result = pruneShadowBackups(pruneOpts);
|
|
32419
33371
|
const action = opts.dryRun ? "would delete" : "deleted";
|
|
32420
33372
|
if (result.deleted.length === 0) {
|
|
32421
|
-
console.log(
|
|
33373
|
+
console.log(pc34.dim(`No shadow-backups match \u2014 ${result.skipped.length} kept`));
|
|
32422
33374
|
return;
|
|
32423
33375
|
}
|
|
32424
33376
|
printHeader(`${action} ${result.deleted.length} shadow backup(s) (${result.skipped.length} kept)`);
|
|
32425
33377
|
printBackupRows(result.deleted);
|
|
32426
33378
|
if (opts.dryRun) {
|
|
32427
|
-
console.log(
|
|
33379
|
+
console.log(pc34.dim("\n(dry-run \u2014 re-run without --dry-run to delete)"));
|
|
32428
33380
|
} else {
|
|
32429
33381
|
printSuccess(`pruned ${result.deleted.length} backup(s)`);
|
|
32430
33382
|
}
|
|
32431
33383
|
} catch (err) {
|
|
32432
|
-
printError(
|
|
33384
|
+
printError(asMessage10(err));
|
|
32433
33385
|
process.exitCode = 1;
|
|
32434
33386
|
}
|
|
32435
33387
|
});
|
|
32436
33388
|
sb.command("restore").description("Move a shadow-backup file back to its original path").argument("<path>", "Absolute path to the .shadow-backup-<epoch> file").option("--force", "Overwrite the original path if it already exists").action((p, opts) => {
|
|
32437
33389
|
try {
|
|
32438
|
-
if (!
|
|
33390
|
+
if (!fs73.existsSync(p)) {
|
|
32439
33391
|
printError(`backup file not found: ${p}`);
|
|
32440
33392
|
process.exitCode = 1;
|
|
32441
33393
|
return;
|
|
@@ -32443,7 +33395,7 @@ function registerSkillsShadowBackups(program2) {
|
|
|
32443
33395
|
const result = restoreShadowBackup({ backupPath: p, force: opts.force });
|
|
32444
33396
|
printSuccess(`restored \u2192 ${result.restoredTo}`);
|
|
32445
33397
|
} catch (err) {
|
|
32446
|
-
printError(
|
|
33398
|
+
printError(asMessage10(err));
|
|
32447
33399
|
process.exitCode = 1;
|
|
32448
33400
|
}
|
|
32449
33401
|
});
|
|
@@ -32451,17 +33403,17 @@ function registerSkillsShadowBackups(program2) {
|
|
|
32451
33403
|
|
|
32452
33404
|
// src/commands/skills-doctor.ts
|
|
32453
33405
|
import * as readline3 from "node:readline";
|
|
32454
|
-
import
|
|
33406
|
+
import pc35 from "picocolors";
|
|
32455
33407
|
init_output();
|
|
32456
|
-
function
|
|
33408
|
+
function asMessage11(err) {
|
|
32457
33409
|
return err instanceof Error ? err.message : String(err);
|
|
32458
33410
|
}
|
|
32459
33411
|
function defaultDoctorPrompt(question) {
|
|
32460
|
-
return new Promise((
|
|
33412
|
+
return new Promise((resolve19) => {
|
|
32461
33413
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
32462
33414
|
rl.question(question, (a) => {
|
|
32463
33415
|
rl.close();
|
|
32464
|
-
|
|
33416
|
+
resolve19(a);
|
|
32465
33417
|
});
|
|
32466
33418
|
});
|
|
32467
33419
|
}
|
|
@@ -32475,16 +33427,16 @@ async function confirmRepair(check) {
|
|
|
32475
33427
|
}
|
|
32476
33428
|
function printCheck(check) {
|
|
32477
33429
|
if (check.healthy) {
|
|
32478
|
-
console.log(` ${
|
|
33430
|
+
console.log(` ${pc35.green("\u2713")} ${pc35.bold(check.name.padEnd(22))} ${pc35.dim(check.description)}`);
|
|
32479
33431
|
if (check.details && check.details.length > 0) {
|
|
32480
|
-
for (const d of check.details) console.log(` ${
|
|
33432
|
+
for (const d of check.details) console.log(` ${pc35.dim(d)}`);
|
|
32481
33433
|
}
|
|
32482
33434
|
} else {
|
|
32483
|
-
console.log(` ${
|
|
32484
|
-
console.log(` ${
|
|
33435
|
+
console.log(` ${pc35.red("\u2717")} ${pc35.bold(check.name.padEnd(22))} ${pc35.yellow(check.issue ?? "unhealthy")}`);
|
|
33436
|
+
console.log(` ${pc35.dim(check.description)}`);
|
|
32485
33437
|
if (check.details) {
|
|
32486
|
-
for (const d of check.details.slice(0, 10)) console.log(` ${
|
|
32487
|
-
if (check.details.length > 10) console.log(` ${
|
|
33438
|
+
for (const d of check.details.slice(0, 10)) console.log(` ${pc35.dim("\xB7 " + d)}`);
|
|
33439
|
+
if (check.details.length > 10) console.log(` ${pc35.dim(`\u2026 and ${check.details.length - 10} more`)}`);
|
|
32488
33440
|
}
|
|
32489
33441
|
}
|
|
32490
33442
|
}
|
|
@@ -32501,7 +33453,7 @@ function registerSkillsDoctor(program2) {
|
|
|
32501
33453
|
try {
|
|
32502
33454
|
checks = runAllDoctorChecks();
|
|
32503
33455
|
} catch (err) {
|
|
32504
|
-
printError(`doctor checks crashed: ${
|
|
33456
|
+
printError(`doctor checks crashed: ${asMessage11(err)}`);
|
|
32505
33457
|
process.exitCode = 1;
|
|
32506
33458
|
return;
|
|
32507
33459
|
}
|
|
@@ -32515,7 +33467,7 @@ function registerSkillsDoctor(program2) {
|
|
|
32515
33467
|
console.log();
|
|
32516
33468
|
printWarning(`${unhealthy.length} of ${checks.length} check(s) report issues`);
|
|
32517
33469
|
if (opts.checkOnly) {
|
|
32518
|
-
console.log(
|
|
33470
|
+
console.log(pc35.dim("(--check-only \u2014 exiting without repair)"));
|
|
32519
33471
|
process.exitCode = 1;
|
|
32520
33472
|
return;
|
|
32521
33473
|
}
|
|
@@ -32523,22 +33475,22 @@ function registerSkillsDoctor(program2) {
|
|
|
32523
33475
|
let skipped = 0;
|
|
32524
33476
|
for (const check of unhealthy) {
|
|
32525
33477
|
if (!check.repair) {
|
|
32526
|
-
console.log(
|
|
33478
|
+
console.log(pc35.dim(` (no auto-repair for ${check.name} \u2014 operator-attention required)`));
|
|
32527
33479
|
skipped += 1;
|
|
32528
33480
|
continue;
|
|
32529
33481
|
}
|
|
32530
33482
|
const shouldRepair = opts.autoFix ? true : await confirmRepair(check);
|
|
32531
33483
|
if (!shouldRepair) {
|
|
32532
|
-
console.log(
|
|
33484
|
+
console.log(pc35.dim(` skipped: ${check.name}`));
|
|
32533
33485
|
skipped += 1;
|
|
32534
33486
|
continue;
|
|
32535
33487
|
}
|
|
32536
33488
|
try {
|
|
32537
33489
|
await check.repair();
|
|
32538
|
-
console.log(
|
|
33490
|
+
console.log(pc35.green(` repaired: ${check.name}`));
|
|
32539
33491
|
repaired += 1;
|
|
32540
33492
|
} catch (err) {
|
|
32541
|
-
printError(` repair failed for ${check.name}: ${
|
|
33493
|
+
printError(` repair failed for ${check.name}: ${asMessage11(err)}`);
|
|
32542
33494
|
skipped += 1;
|
|
32543
33495
|
}
|
|
32544
33496
|
}
|
|
@@ -32626,17 +33578,17 @@ function registerWorldUpgrade(program2) {
|
|
|
32626
33578
|
|
|
32627
33579
|
// src/commands/mcp/serve.ts
|
|
32628
33580
|
init_output();
|
|
32629
|
-
import { existsSync as
|
|
32630
|
-
import { dirname as
|
|
33581
|
+
import { existsSync as existsSync78 } from "node:fs";
|
|
33582
|
+
import { dirname as dirname42, resolve as resolve17 } from "node:path";
|
|
32631
33583
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
32632
|
-
var here =
|
|
33584
|
+
var here = dirname42(fileURLToPath5(import.meta.url));
|
|
32633
33585
|
var BUNDLE_PATH_CANDIDATES = [
|
|
32634
33586
|
// bundled (`dist/index.js` after bundle-cli.mjs) — sibling
|
|
32635
|
-
|
|
33587
|
+
resolve17(here, "mcp-server.js"),
|
|
32636
33588
|
// dev / tsc-only (`dist/commands/mcp/serve.js`) — up two levels
|
|
32637
|
-
|
|
33589
|
+
resolve17(here, "..", "..", "mcp-server.js")
|
|
32638
33590
|
];
|
|
32639
|
-
function resolveBundlePath(candidates2 = BUNDLE_PATH_CANDIDATES, exists =
|
|
33591
|
+
function resolveBundlePath(candidates2 = BUNDLE_PATH_CANDIDATES, exists = existsSync78) {
|
|
32640
33592
|
return candidates2.find(exists) ?? null;
|
|
32641
33593
|
}
|
|
32642
33594
|
var MISSING_BUNDLE_REMEDY = "olam mcp server bundle missing. Searched: " + BUNDLE_PATH_CANDIDATES.join(", ") + ". For local dev, run: node packages/cli/scripts/bundle-mcp-server.mjs. A fresh `npm install -g @pleri/olam-cli@latest` should always include the bundle (see prepublishOnly in packages/cli/package.json); file an issue if it does not.";
|
|
@@ -32793,8 +33745,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
|
|
|
32793
33745
|
function authHeaders() {
|
|
32794
33746
|
return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
|
|
32795
33747
|
}
|
|
32796
|
-
async function apiFetch(
|
|
32797
|
-
const res = await fetch(`${BASE_URL}${
|
|
33748
|
+
async function apiFetch(path82, init = {}) {
|
|
33749
|
+
const res = await fetch(`${BASE_URL}${path82}`, {
|
|
32798
33750
|
...init,
|
|
32799
33751
|
headers: {
|
|
32800
33752
|
"Content-Type": "application/json",
|
|
@@ -32881,7 +33833,7 @@ function registerMcpLogin(cmd) {
|
|
|
32881
33833
|
init_output();
|
|
32882
33834
|
import * as readline4 from "node:readline";
|
|
32883
33835
|
async function readTokenSilent(prompt) {
|
|
32884
|
-
return new Promise((
|
|
33836
|
+
return new Promise((resolve19, reject) => {
|
|
32885
33837
|
const rl = readline4.createInterface({
|
|
32886
33838
|
input: process.stdin,
|
|
32887
33839
|
output: process.stdout,
|
|
@@ -32899,7 +33851,7 @@ async function readTokenSilent(prompt) {
|
|
|
32899
33851
|
process.stdin.removeListener("data", onData);
|
|
32900
33852
|
process.stdout.write("\n");
|
|
32901
33853
|
rl.close();
|
|
32902
|
-
|
|
33854
|
+
resolve19(token);
|
|
32903
33855
|
} else if (char === "") {
|
|
32904
33856
|
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
32905
33857
|
process.stdin.removeListener("data", onData);
|
|
@@ -32946,7 +33898,7 @@ function registerMcpAdd(cmd) {
|
|
|
32946
33898
|
|
|
32947
33899
|
// src/commands/mcp/list.ts
|
|
32948
33900
|
init_output();
|
|
32949
|
-
import
|
|
33901
|
+
import pc36 from "picocolors";
|
|
32950
33902
|
function registerMcpList(cmd) {
|
|
32951
33903
|
cmd.command("list").description("List all registered MCP credentials").action(async () => {
|
|
32952
33904
|
const client = getMcpAuthClient();
|
|
@@ -32961,8 +33913,8 @@ function registerMcpList(cmd) {
|
|
|
32961
33913
|
}
|
|
32962
33914
|
const mcps = data.mcps ?? [];
|
|
32963
33915
|
if (mcps.length === 0) {
|
|
32964
|
-
console.log(
|
|
32965
|
-
console.log(
|
|
33916
|
+
console.log(pc36.dim("No MCP credentials registered."));
|
|
33917
|
+
console.log(pc36.dim("Add one with: olam mcp add <service>"));
|
|
32966
33918
|
return;
|
|
32967
33919
|
}
|
|
32968
33920
|
const [c0, c1, c2, c3] = [16, 20, 10, 24];
|
|
@@ -32973,12 +33925,12 @@ function registerMcpList(cmd) {
|
|
|
32973
33925
|
"ENV VAR".padEnd(c3),
|
|
32974
33926
|
"STATUS"
|
|
32975
33927
|
].join(" ");
|
|
32976
|
-
console.log(
|
|
32977
|
-
console.log(
|
|
33928
|
+
console.log(pc36.dim(header));
|
|
33929
|
+
console.log(pc36.dim("\u2500".repeat(header.length)));
|
|
32978
33930
|
for (const m of mcps) {
|
|
32979
|
-
const status2 = !m.validated ?
|
|
33931
|
+
const status2 = !m.validated ? pc36.yellow("unvalidated") : m.expired ? pc36.red("expired") : pc36.green("active");
|
|
32980
33932
|
const row = [
|
|
32981
|
-
|
|
33933
|
+
pc36.cyan(m.service.padEnd(c0)),
|
|
32982
33934
|
m.label.padEnd(c1).slice(0, c1),
|
|
32983
33935
|
m.type.padEnd(c2),
|
|
32984
33936
|
(m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
|
|
@@ -33006,13 +33958,13 @@ function registerMcpRemove(cmd) {
|
|
|
33006
33958
|
|
|
33007
33959
|
// src/commands/mcp/status.ts
|
|
33008
33960
|
init_output();
|
|
33009
|
-
import
|
|
33961
|
+
import pc37 from "picocolors";
|
|
33010
33962
|
function formatExpiry(expiresAt) {
|
|
33011
33963
|
if (!expiresAt) return "\u2014";
|
|
33012
33964
|
const ms = expiresAt - Date.now();
|
|
33013
|
-
if (ms <= 0) return
|
|
33965
|
+
if (ms <= 0) return pc37.red("expired");
|
|
33014
33966
|
const hours = ms / (1e3 * 60 * 60);
|
|
33015
|
-
if (hours < 1) return
|
|
33967
|
+
if (hours < 1) return pc37.yellow(`${Math.ceil(ms / 6e4)}m`);
|
|
33016
33968
|
return `${hours.toFixed(1)}h`;
|
|
33017
33969
|
}
|
|
33018
33970
|
function registerMcpStatus(cmd) {
|
|
@@ -33029,14 +33981,14 @@ function registerMcpStatus(cmd) {
|
|
|
33029
33981
|
const mcps = data.mcps ?? [];
|
|
33030
33982
|
printHeader(`MCP Credentials (${mcps.length})`);
|
|
33031
33983
|
if (mcps.length === 0) {
|
|
33032
|
-
console.log(
|
|
33984
|
+
console.log(pc37.dim("No credentials registered."));
|
|
33033
33985
|
return;
|
|
33034
33986
|
}
|
|
33035
33987
|
for (const m of mcps) {
|
|
33036
|
-
const stateColor = !m.validated ?
|
|
33988
|
+
const stateColor = !m.validated ? pc37.yellow : m.expired ? pc37.red : pc37.green;
|
|
33037
33989
|
const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
|
|
33038
33990
|
console.log(`
|
|
33039
|
-
${
|
|
33991
|
+
${pc37.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
|
|
33040
33992
|
console.log(` label: ${m.label}`);
|
|
33041
33993
|
console.log(` type: ${m.type}`);
|
|
33042
33994
|
if (m.envName) console.log(` env var: ${m.envName}`);
|
|
@@ -33051,15 +34003,15 @@ function registerMcpStatus(cmd) {
|
|
|
33051
34003
|
// src/commands/mcp/import.ts
|
|
33052
34004
|
init_output();
|
|
33053
34005
|
import * as readline5 from "node:readline";
|
|
33054
|
-
import
|
|
34006
|
+
import pc38 from "picocolors";
|
|
33055
34007
|
|
|
33056
34008
|
// src/commands/mcp/import-discovery.ts
|
|
33057
|
-
import * as
|
|
33058
|
-
import * as
|
|
33059
|
-
import * as
|
|
34009
|
+
import * as fs74 from "node:fs";
|
|
34010
|
+
import * as os40 from "node:os";
|
|
34011
|
+
import * as path74 from "node:path";
|
|
33060
34012
|
function readJsonFile(filePath) {
|
|
33061
34013
|
try {
|
|
33062
|
-
const raw =
|
|
34014
|
+
const raw = fs74.readFileSync(filePath, "utf-8");
|
|
33063
34015
|
return JSON.parse(raw);
|
|
33064
34016
|
} catch {
|
|
33065
34017
|
return null;
|
|
@@ -33088,24 +34040,24 @@ function extractMcpServers(obj, source, sourceLabel) {
|
|
|
33088
34040
|
}
|
|
33089
34041
|
function getClaudeDesktopPath() {
|
|
33090
34042
|
if (process.platform === "darwin") {
|
|
33091
|
-
return
|
|
34043
|
+
return path74.join(os40.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
33092
34044
|
}
|
|
33093
34045
|
if (process.platform === "win32") {
|
|
33094
|
-
const appData = process.env["APPDATA"] ??
|
|
33095
|
-
return
|
|
34046
|
+
const appData = process.env["APPDATA"] ?? path74.join(os40.homedir(), "AppData", "Roaming");
|
|
34047
|
+
return path74.join(appData, "Claude", "claude_desktop_config.json");
|
|
33096
34048
|
}
|
|
33097
|
-
return
|
|
34049
|
+
return path74.join(os40.homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
33098
34050
|
}
|
|
33099
34051
|
function getOlamRepoPaths() {
|
|
33100
34052
|
const configPaths = [
|
|
33101
|
-
|
|
33102
|
-
|
|
34053
|
+
path74.join(os40.homedir(), ".olam", "config.yaml"),
|
|
34054
|
+
path74.join(process.cwd(), ".olam", "config.yaml")
|
|
33103
34055
|
];
|
|
33104
34056
|
const paths = [];
|
|
33105
34057
|
for (const configPath of configPaths) {
|
|
33106
|
-
if (!
|
|
34058
|
+
if (!fs74.existsSync(configPath)) continue;
|
|
33107
34059
|
try {
|
|
33108
|
-
const raw =
|
|
34060
|
+
const raw = fs74.readFileSync(configPath, "utf-8");
|
|
33109
34061
|
const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
|
|
33110
34062
|
for (const m of repoMatches) {
|
|
33111
34063
|
if (m[1]) paths.push(m[1]);
|
|
@@ -33121,7 +34073,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
33121
34073
|
const sources = [];
|
|
33122
34074
|
const sourceDefs = [
|
|
33123
34075
|
{
|
|
33124
|
-
path:
|
|
34076
|
+
path: path74.join(os40.homedir(), ".claude.json"),
|
|
33125
34077
|
label: "Claude Code (~/.claude.json)"
|
|
33126
34078
|
},
|
|
33127
34079
|
{
|
|
@@ -33129,19 +34081,19 @@ async function discoverMcpSources(repoPaths) {
|
|
|
33129
34081
|
label: "Claude Desktop"
|
|
33130
34082
|
},
|
|
33131
34083
|
{
|
|
33132
|
-
path:
|
|
34084
|
+
path: path74.join(os40.homedir(), ".cursor", "mcp.json"),
|
|
33133
34085
|
label: "Cursor (~/.cursor/mcp.json)"
|
|
33134
34086
|
},
|
|
33135
34087
|
{
|
|
33136
|
-
path:
|
|
34088
|
+
path: path74.join(os40.homedir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
33137
34089
|
label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
|
|
33138
34090
|
}
|
|
33139
34091
|
];
|
|
33140
34092
|
const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
|
|
33141
34093
|
for (const repoPath of resolvedRepoPaths) {
|
|
33142
34094
|
sourceDefs.push({
|
|
33143
|
-
path:
|
|
33144
|
-
label: `.mcp.json (${
|
|
34095
|
+
path: path74.join(repoPath, ".mcp.json"),
|
|
34096
|
+
label: `.mcp.json (${path74.basename(repoPath)})`
|
|
33145
34097
|
});
|
|
33146
34098
|
}
|
|
33147
34099
|
const reads = await Promise.all(
|
|
@@ -33174,7 +34126,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
33174
34126
|
import { spawn as spawn9 } from "node:child_process";
|
|
33175
34127
|
var VALIDATION_TIMEOUT_MS = 5e3;
|
|
33176
34128
|
async function validateMcpEntry(entry) {
|
|
33177
|
-
return new Promise((
|
|
34129
|
+
return new Promise((resolve19) => {
|
|
33178
34130
|
let stdout = "";
|
|
33179
34131
|
let timedOut = false;
|
|
33180
34132
|
let child;
|
|
@@ -33184,7 +34136,7 @@ async function validateMcpEntry(entry) {
|
|
|
33184
34136
|
env: { ...process.env, ...entry.env ?? {} }
|
|
33185
34137
|
});
|
|
33186
34138
|
} catch (err) {
|
|
33187
|
-
|
|
34139
|
+
resolve19({
|
|
33188
34140
|
name: entry.name,
|
|
33189
34141
|
validated: false,
|
|
33190
34142
|
reason: err instanceof Error ? err.message : "spawn failed"
|
|
@@ -33201,11 +34153,11 @@ async function validateMcpEntry(entry) {
|
|
|
33201
34153
|
child.on("close", (code) => {
|
|
33202
34154
|
clearTimeout(timer);
|
|
33203
34155
|
if (timedOut) {
|
|
33204
|
-
|
|
34156
|
+
resolve19({ name: entry.name, validated: false, reason: "timeout (5s)" });
|
|
33205
34157
|
return;
|
|
33206
34158
|
}
|
|
33207
34159
|
const validated = code === 0 && stdout.trim().length > 0;
|
|
33208
|
-
|
|
34160
|
+
resolve19({
|
|
33209
34161
|
name: entry.name,
|
|
33210
34162
|
validated,
|
|
33211
34163
|
reason: validated ? "ok" : `exit code ${code ?? "null"}`
|
|
@@ -33213,7 +34165,7 @@ async function validateMcpEntry(entry) {
|
|
|
33213
34165
|
});
|
|
33214
34166
|
child.on("error", (err) => {
|
|
33215
34167
|
clearTimeout(timer);
|
|
33216
|
-
|
|
34168
|
+
resolve19({ name: entry.name, validated: false, reason: err.message });
|
|
33217
34169
|
});
|
|
33218
34170
|
});
|
|
33219
34171
|
}
|
|
@@ -33221,18 +34173,18 @@ async function validateMcpEntry(entry) {
|
|
|
33221
34173
|
// src/commands/mcp/import.ts
|
|
33222
34174
|
async function multiSelectPicker(entries) {
|
|
33223
34175
|
if (entries.length === 0) return [];
|
|
33224
|
-
console.log("\n" +
|
|
34176
|
+
console.log("\n" + pc38.bold("Discovered MCP servers:"));
|
|
33225
34177
|
entries.forEach((e, i) => {
|
|
33226
34178
|
console.log(
|
|
33227
|
-
` ${
|
|
34179
|
+
` ${pc38.dim(`[${i + 1}]`)} ${pc38.cyan(e.name.padEnd(20))} ${pc38.dim(e.sourceLabel)}`
|
|
33228
34180
|
);
|
|
33229
34181
|
});
|
|
33230
|
-
console.log("\n" +
|
|
33231
|
-
const answer = await new Promise((
|
|
34182
|
+
console.log("\n" + pc38.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
34183
|
+
const answer = await new Promise((resolve19) => {
|
|
33232
34184
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
|
|
33233
34185
|
rl.question("> ", (ans) => {
|
|
33234
34186
|
rl.close();
|
|
33235
|
-
|
|
34187
|
+
resolve19(ans.trim());
|
|
33236
34188
|
});
|
|
33237
34189
|
});
|
|
33238
34190
|
if (!answer || answer === "") return [];
|
|
@@ -33254,7 +34206,7 @@ function registerMcpImport(cmd) {
|
|
|
33254
34206
|
const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
|
|
33255
34207
|
const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
|
|
33256
34208
|
if (entries.length === 0) {
|
|
33257
|
-
console.log(
|
|
34209
|
+
console.log(pc38.dim("No MCP servers found in any source path."));
|
|
33258
34210
|
return;
|
|
33259
34211
|
}
|
|
33260
34212
|
printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
|
|
@@ -33267,15 +34219,15 @@ function registerMcpImport(cmd) {
|
|
|
33267
34219
|
candidates2 = filtered;
|
|
33268
34220
|
}
|
|
33269
34221
|
if (skippedCount > 0) {
|
|
33270
|
-
console.log(
|
|
34222
|
+
console.log(pc38.dim(`skipped: ${skippedCount} already registered`));
|
|
33271
34223
|
}
|
|
33272
34224
|
if (candidates2.length === 0) {
|
|
33273
|
-
console.log(
|
|
34225
|
+
console.log(pc38.dim("Nothing new to import. Use --reimport to force."));
|
|
33274
34226
|
return;
|
|
33275
34227
|
}
|
|
33276
34228
|
const selected = await multiSelectPicker(candidates2);
|
|
33277
34229
|
if (selected.length === 0) {
|
|
33278
|
-
console.log(
|
|
34230
|
+
console.log(pc38.dim("No servers selected."));
|
|
33279
34231
|
return;
|
|
33280
34232
|
}
|
|
33281
34233
|
console.log(`
|
|
@@ -33286,16 +34238,16 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
33286
34238
|
let validated = false;
|
|
33287
34239
|
let validationReason = "skipped";
|
|
33288
34240
|
if (opts.validate !== false) {
|
|
33289
|
-
process.stdout.write(` ${
|
|
34241
|
+
process.stdout.write(` ${pc38.dim("\u2192")} ${entry.name} validating\u2026 `);
|
|
33290
34242
|
const vr = await validateMcpEntry(entry);
|
|
33291
34243
|
validated = vr.validated;
|
|
33292
34244
|
validationReason = vr.reason;
|
|
33293
34245
|
process.stdout.write(
|
|
33294
|
-
validated ?
|
|
34246
|
+
validated ? pc38.green("ok\n") : pc38.yellow(`unvalidated (${vr.reason})
|
|
33295
34247
|
`)
|
|
33296
34248
|
);
|
|
33297
34249
|
} else {
|
|
33298
|
-
console.log(` ${
|
|
34250
|
+
console.log(` ${pc38.dim("\u2192")} ${entry.name} ${pc38.dim("(validation skipped)")}`);
|
|
33299
34251
|
}
|
|
33300
34252
|
if (validated) validatedCount++;
|
|
33301
34253
|
const result = await client.staticAdd({
|
|
@@ -33310,21 +34262,21 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
33310
34262
|
}
|
|
33311
34263
|
}
|
|
33312
34264
|
console.log("");
|
|
33313
|
-
console.log(
|
|
34265
|
+
console.log(pc38.green(`\u2713 Imported ${importedCount}/${selected.length}`));
|
|
33314
34266
|
if (validatedCount > 0) {
|
|
33315
|
-
console.log(
|
|
34267
|
+
console.log(pc38.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
|
|
33316
34268
|
}
|
|
33317
34269
|
});
|
|
33318
34270
|
}
|
|
33319
34271
|
|
|
33320
34272
|
// src/commands/mcp/revoke.ts
|
|
33321
34273
|
init_output();
|
|
33322
|
-
import
|
|
34274
|
+
import pc39 from "picocolors";
|
|
33323
34275
|
function registerMcpRevoke(cmd) {
|
|
33324
34276
|
cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
|
|
33325
34277
|
const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
|
|
33326
34278
|
if (!multiTenant) {
|
|
33327
|
-
console.warn(
|
|
34279
|
+
console.warn(pc39.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
|
|
33328
34280
|
return;
|
|
33329
34281
|
}
|
|
33330
34282
|
const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
|
|
@@ -33353,8 +34305,8 @@ function registerMcpRevoke(cmd) {
|
|
|
33353
34305
|
process.exitCode = 1;
|
|
33354
34306
|
return;
|
|
33355
34307
|
}
|
|
33356
|
-
console.log(
|
|
33357
|
-
console.log(
|
|
34308
|
+
console.log(pc39.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
|
|
34309
|
+
console.log(pc39.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
|
|
33358
34310
|
});
|
|
33359
34311
|
}
|
|
33360
34312
|
|
|
@@ -33376,34 +34328,34 @@ function registerMcp(program2) {
|
|
|
33376
34328
|
// src/commands/memory/start.ts
|
|
33377
34329
|
init_output();
|
|
33378
34330
|
import { spawn as spawn10 } from "node:child_process";
|
|
33379
|
-
import { existsSync as
|
|
33380
|
-
import { join as
|
|
34331
|
+
import { existsSync as existsSync80, mkdirSync as mkdirSync47, openSync as openSync7, readFileSync as readFileSync60, writeFileSync as writeFileSync39 } from "node:fs";
|
|
34332
|
+
import { join as join73 } from "node:path";
|
|
33381
34333
|
import { pathToFileURL } from "node:url";
|
|
33382
34334
|
|
|
33383
34335
|
// src/commands/memory/_paths.ts
|
|
33384
|
-
import { homedir as
|
|
33385
|
-
import { join as
|
|
34336
|
+
import { homedir as homedir41 } from "node:os";
|
|
34337
|
+
import { join as join72, dirname as dirname43 } from "node:path";
|
|
33386
34338
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
33387
|
-
var OLAM_HOME2 =
|
|
33388
|
-
var OLAM_BIN_DIR =
|
|
33389
|
-
var III_BINARY_PATH =
|
|
33390
|
-
var MEMORY_PID_PATH =
|
|
33391
|
-
var MEMORY_LOG_PATH =
|
|
33392
|
-
var MEMORY_DATA_DIR =
|
|
34339
|
+
var OLAM_HOME2 = join72(homedir41(), ".olam");
|
|
34340
|
+
var OLAM_BIN_DIR = join72(OLAM_HOME2, "bin");
|
|
34341
|
+
var III_BINARY_PATH = join72(OLAM_BIN_DIR, "iii");
|
|
34342
|
+
var MEMORY_PID_PATH = join72(OLAM_HOME2, "memory.pid");
|
|
34343
|
+
var MEMORY_LOG_PATH = join72(OLAM_HOME2, "memory-service.log");
|
|
34344
|
+
var MEMORY_DATA_DIR = join72(OLAM_HOME2, "memory-data");
|
|
33393
34345
|
var MEMORY_REST_PORT = 3111;
|
|
33394
34346
|
var MEMORY_LIVEZ_URL = `http://localhost:${MEMORY_REST_PORT}/agentmemory/livez`;
|
|
33395
|
-
var here2 =
|
|
34347
|
+
var here2 = dirname43(fileURLToPath6(import.meta.url));
|
|
33396
34348
|
var candidates = [
|
|
33397
34349
|
// 1. Workspace dev (built): packages/cli/dist/commands/memory/_paths.js → packages/cli → packages/memory-service
|
|
33398
|
-
|
|
34350
|
+
join72(here2, "..", "..", "..", "..", "memory-service"),
|
|
33399
34351
|
// 2a. Workspace bundled: packages/cli/dist/index.js → packages/cli → packages/memory-service
|
|
33400
|
-
|
|
34352
|
+
join72(here2, "..", "..", "memory-service"),
|
|
33401
34353
|
// 2b. Published tarball: <prefix>/node_modules/@pleri/olam-cli/dist/index.js
|
|
33402
34354
|
// → <prefix>/node_modules/@pleri/olam-cli/memory-service-bundle
|
|
33403
34355
|
// (copied at publish time by bundle-cli.mjs)
|
|
33404
|
-
|
|
34356
|
+
join72(here2, "..", "memory-service-bundle"),
|
|
33405
34357
|
// 3. CWD fallback
|
|
33406
|
-
|
|
34358
|
+
join72(process.cwd(), "packages", "memory-service")
|
|
33407
34359
|
];
|
|
33408
34360
|
var MEMORY_SERVICE_CANDIDATES = candidates;
|
|
33409
34361
|
|
|
@@ -33412,7 +34364,7 @@ var READINESS_TIMEOUT_MS = 3e4;
|
|
|
33412
34364
|
var READINESS_POLL_MS = 500;
|
|
33413
34365
|
function resolveMemoryServiceDir() {
|
|
33414
34366
|
for (const c of MEMORY_SERVICE_CANDIDATES) {
|
|
33415
|
-
if (
|
|
34367
|
+
if (existsSync80(c)) return c;
|
|
33416
34368
|
}
|
|
33417
34369
|
throw new Error(
|
|
33418
34370
|
`Could not find packages/memory-service/. Searched: ${MEMORY_SERVICE_CANDIDATES.join(", ")}. If running from a published @pleri/olam-cli tarball, this is a packaging bug \u2014 please file an issue.`
|
|
@@ -33420,12 +34372,12 @@ function resolveMemoryServiceDir() {
|
|
|
33420
34372
|
}
|
|
33421
34373
|
function resolveAgentMemoryBin(serviceDir) {
|
|
33422
34374
|
const candidates2 = [
|
|
33423
|
-
|
|
33424
|
-
|
|
33425
|
-
|
|
34375
|
+
join73(serviceDir, "node_modules", ".bin", "agentmemory"),
|
|
34376
|
+
join73(serviceDir, "..", "..", "node_modules", ".bin", "agentmemory"),
|
|
34377
|
+
join73(serviceDir, "..", "..", "..", "node_modules", ".bin", "agentmemory")
|
|
33426
34378
|
];
|
|
33427
34379
|
for (const c of candidates2) {
|
|
33428
|
-
if (
|
|
34380
|
+
if (existsSync80(c)) return c;
|
|
33429
34381
|
}
|
|
33430
34382
|
throw new Error(
|
|
33431
34383
|
`Could not find agentmemory bin. Searched: ${candidates2.join(", ")}. Run 'npm install' from the repo root.`
|
|
@@ -33440,8 +34392,8 @@ function isProcessAlive(pid) {
|
|
|
33440
34392
|
}
|
|
33441
34393
|
}
|
|
33442
34394
|
function readPidFromFile() {
|
|
33443
|
-
if (!
|
|
33444
|
-
const raw =
|
|
34395
|
+
if (!existsSync80(MEMORY_PID_PATH)) return null;
|
|
34396
|
+
const raw = readFileSync60(MEMORY_PID_PATH, "utf8").trim();
|
|
33445
34397
|
const pid = parseInt(raw, 10);
|
|
33446
34398
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
33447
34399
|
return pid;
|
|
@@ -33468,7 +34420,7 @@ async function waitForReady(secret) {
|
|
|
33468
34420
|
return false;
|
|
33469
34421
|
}
|
|
33470
34422
|
async function autoEnsureIiiBinary(serviceDir) {
|
|
33471
|
-
const helperPath =
|
|
34423
|
+
const helperPath = join73(serviceDir, "scripts", "ensure-iii-engine.mjs");
|
|
33472
34424
|
const mod = await import(pathToFileURL(helperPath).href);
|
|
33473
34425
|
const result = await mod.ensureIiiEngine();
|
|
33474
34426
|
if (!result.ok) {
|
|
@@ -33484,7 +34436,7 @@ async function runMemoryStart() {
|
|
|
33484
34436
|
printError(err instanceof Error ? err.message : String(err));
|
|
33485
34437
|
return 1;
|
|
33486
34438
|
}
|
|
33487
|
-
if (!
|
|
34439
|
+
if (!existsSync80(III_BINARY_PATH)) {
|
|
33488
34440
|
printInfo("iii binary", `missing at ${III_BINARY_PATH} \u2014 auto-fetching v0.11.2`);
|
|
33489
34441
|
try {
|
|
33490
34442
|
await autoEnsureIiiBinary(serviceDir);
|
|
@@ -33512,9 +34464,9 @@ async function runMemoryStart() {
|
|
|
33512
34464
|
);
|
|
33513
34465
|
return 1;
|
|
33514
34466
|
}
|
|
33515
|
-
|
|
33516
|
-
|
|
33517
|
-
const logFd =
|
|
34467
|
+
mkdirSync47(OLAM_HOME2, { recursive: true });
|
|
34468
|
+
mkdirSync47(MEMORY_DATA_DIR, { recursive: true });
|
|
34469
|
+
const logFd = openSync7(MEMORY_LOG_PATH, "a");
|
|
33518
34470
|
const child = spawn10(agentmemoryBin, [], {
|
|
33519
34471
|
cwd: OLAM_HOME2,
|
|
33520
34472
|
env: {
|
|
@@ -33536,7 +34488,7 @@ async function runMemoryStart() {
|
|
|
33536
34488
|
printError("spawn returned no pid (process failed to start)");
|
|
33537
34489
|
return 1;
|
|
33538
34490
|
}
|
|
33539
|
-
|
|
34491
|
+
writeFileSync39(MEMORY_PID_PATH, `${child.pid}
|
|
33540
34492
|
`, { mode: 420 });
|
|
33541
34493
|
printInfo("pid", `${child.pid}`);
|
|
33542
34494
|
printInfo("readiness", `polling ${MEMORY_LIVEZ_URL}`);
|
|
@@ -33559,7 +34511,7 @@ function registerMemoryStart(cmd) {
|
|
|
33559
34511
|
|
|
33560
34512
|
// src/commands/memory/stop.ts
|
|
33561
34513
|
init_output();
|
|
33562
|
-
import { existsSync as
|
|
34514
|
+
import { existsSync as existsSync81, readFileSync as readFileSync61, unlinkSync as unlinkSync21 } from "node:fs";
|
|
33563
34515
|
var SIGTERM_GRACE_MS = 1e4;
|
|
33564
34516
|
var POLL_MS = 250;
|
|
33565
34517
|
function isAlive(pid) {
|
|
@@ -33572,19 +34524,19 @@ function isAlive(pid) {
|
|
|
33572
34524
|
}
|
|
33573
34525
|
async function runMemoryStop() {
|
|
33574
34526
|
printHeader("olam memory stop");
|
|
33575
|
-
if (!
|
|
34527
|
+
if (!existsSync81(MEMORY_PID_PATH)) {
|
|
33576
34528
|
printSuccess("no pidfile present (nothing to stop)");
|
|
33577
34529
|
return 0;
|
|
33578
34530
|
}
|
|
33579
|
-
const pid = parseInt(
|
|
34531
|
+
const pid = parseInt(readFileSync61(MEMORY_PID_PATH, "utf8").trim(), 10);
|
|
33580
34532
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
33581
34533
|
printWarning(`pidfile contained invalid value; removing`);
|
|
33582
|
-
|
|
34534
|
+
unlinkSync21(MEMORY_PID_PATH);
|
|
33583
34535
|
return 0;
|
|
33584
34536
|
}
|
|
33585
34537
|
if (!isAlive(pid)) {
|
|
33586
34538
|
printSuccess(`pid ${pid} is not running (stale pidfile); cleaned up`);
|
|
33587
|
-
|
|
34539
|
+
unlinkSync21(MEMORY_PID_PATH);
|
|
33588
34540
|
return 0;
|
|
33589
34541
|
}
|
|
33590
34542
|
printInfo("pid", `${pid}`);
|
|
@@ -33607,8 +34559,8 @@ async function runMemoryStop() {
|
|
|
33607
34559
|
}
|
|
33608
34560
|
await new Promise((r) => setTimeout(r, 500));
|
|
33609
34561
|
}
|
|
33610
|
-
if (
|
|
33611
|
-
|
|
34562
|
+
if (existsSync81(MEMORY_PID_PATH)) {
|
|
34563
|
+
unlinkSync21(MEMORY_PID_PATH);
|
|
33612
34564
|
}
|
|
33613
34565
|
printSuccess(`stopped (pid ${pid})`);
|
|
33614
34566
|
return 0;
|
|
@@ -33622,7 +34574,7 @@ function registerMemoryStop(cmd) {
|
|
|
33622
34574
|
|
|
33623
34575
|
// src/commands/memory/status.ts
|
|
33624
34576
|
init_output();
|
|
33625
|
-
import { existsSync as
|
|
34577
|
+
import { existsSync as existsSync82, readFileSync as readFileSync62 } from "node:fs";
|
|
33626
34578
|
function isAlive2(pid) {
|
|
33627
34579
|
try {
|
|
33628
34580
|
process.kill(pid, 0);
|
|
@@ -33646,8 +34598,8 @@ async function probe(secret) {
|
|
|
33646
34598
|
}
|
|
33647
34599
|
async function collectMemoryStatus() {
|
|
33648
34600
|
let pid = null;
|
|
33649
|
-
if (
|
|
33650
|
-
const raw =
|
|
34601
|
+
if (existsSync82(MEMORY_PID_PATH)) {
|
|
34602
|
+
const raw = readFileSync62(MEMORY_PID_PATH, "utf8").trim();
|
|
33651
34603
|
const parsed = parseInt(raw, 10);
|
|
33652
34604
|
pid = Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
33653
34605
|
}
|
|
@@ -33659,7 +34611,7 @@ async function collectMemoryStatus() {
|
|
|
33659
34611
|
alive,
|
|
33660
34612
|
livez,
|
|
33661
34613
|
secretSet: hasMemorySecret(),
|
|
33662
|
-
iiiBinary:
|
|
34614
|
+
iiiBinary: existsSync82(III_BINARY_PATH) ? III_BINARY_PATH : null,
|
|
33663
34615
|
port: MEMORY_REST_PORT
|
|
33664
34616
|
};
|
|
33665
34617
|
}
|
|
@@ -33702,10 +34654,10 @@ function registerMemoryStatus(cmd) {
|
|
|
33702
34654
|
|
|
33703
34655
|
// src/commands/memory/logs.ts
|
|
33704
34656
|
init_output();
|
|
33705
|
-
import { existsSync as
|
|
34657
|
+
import { existsSync as existsSync83 } from "node:fs";
|
|
33706
34658
|
import { spawn as spawn11 } from "node:child_process";
|
|
33707
34659
|
async function runMemoryLogs(opts) {
|
|
33708
|
-
if (!
|
|
34660
|
+
if (!existsSync83(MEMORY_LOG_PATH)) {
|
|
33709
34661
|
printWarning(`no log at ${MEMORY_LOG_PATH} (start the service first via 'olam memory start')`);
|
|
33710
34662
|
return 1;
|
|
33711
34663
|
}
|
|
@@ -33719,8 +34671,8 @@ async function runMemoryLogs(opts) {
|
|
|
33719
34671
|
args.push(MEMORY_LOG_PATH);
|
|
33720
34672
|
printHeader(`olam memory logs (${opts.follow ? "follow" : `tail -n ${tailN}`})`);
|
|
33721
34673
|
const child = spawn11("tail", args, { stdio: "inherit" });
|
|
33722
|
-
return new Promise((
|
|
33723
|
-
child.on("exit", (code) =>
|
|
34674
|
+
return new Promise((resolve19) => {
|
|
34675
|
+
child.on("exit", (code) => resolve19(code ?? 0));
|
|
33724
34676
|
});
|
|
33725
34677
|
}
|
|
33726
34678
|
function registerMemoryLogs(cmd) {
|
|
@@ -33731,7 +34683,7 @@ function registerMemoryLogs(cmd) {
|
|
|
33731
34683
|
}
|
|
33732
34684
|
|
|
33733
34685
|
// src/commands/memory/secret.ts
|
|
33734
|
-
import { existsSync as
|
|
34686
|
+
import { existsSync as existsSync84 } from "node:fs";
|
|
33735
34687
|
init_output();
|
|
33736
34688
|
async function runMemorySecretShow() {
|
|
33737
34689
|
if (!hasMemorySecret()) {
|
|
@@ -33746,7 +34698,7 @@ async function runMemorySecretShow() {
|
|
|
33746
34698
|
}
|
|
33747
34699
|
async function runMemorySecretRotate() {
|
|
33748
34700
|
printHeader("olam memory secret rotate");
|
|
33749
|
-
const wasRunning =
|
|
34701
|
+
const wasRunning = existsSync84(MEMORY_PID_PATH);
|
|
33750
34702
|
if (wasRunning) {
|
|
33751
34703
|
printInfo("current state", "service running; will restart with new secret");
|
|
33752
34704
|
const stopRc = await runMemoryStop();
|
|
@@ -33928,14 +34880,14 @@ function registerMemoryUninstall(cmd) {
|
|
|
33928
34880
|
// src/commands/memory/mode.ts
|
|
33929
34881
|
init_schema2();
|
|
33930
34882
|
init_output();
|
|
33931
|
-
import { existsSync as
|
|
33932
|
-
import { join as
|
|
34883
|
+
import { existsSync as existsSync85, readFileSync as readFileSync63, writeFileSync as writeFileSync40 } from "node:fs";
|
|
34884
|
+
import { join as join74 } from "node:path";
|
|
33933
34885
|
import * as readline6 from "node:readline/promises";
|
|
33934
34886
|
import { parse as parseYaml7, stringify as stringifyYaml6 } from "yaml";
|
|
33935
34887
|
var CONFIG_REL = ".olam/config.yaml";
|
|
33936
34888
|
function locateConfig(cwd) {
|
|
33937
|
-
const absPath =
|
|
33938
|
-
if (!
|
|
34889
|
+
const absPath = join74(cwd, CONFIG_REL);
|
|
34890
|
+
if (!existsSync85(absPath)) {
|
|
33939
34891
|
throw new Error(
|
|
33940
34892
|
`No ${CONFIG_REL} at ${cwd}. Run \`olam init\` in your workspace root first.`
|
|
33941
34893
|
);
|
|
@@ -33943,7 +34895,7 @@ function locateConfig(cwd) {
|
|
|
33943
34895
|
return { absPath };
|
|
33944
34896
|
}
|
|
33945
34897
|
function readConfigYaml(absPath) {
|
|
33946
|
-
const raw =
|
|
34898
|
+
const raw = readFileSync63(absPath, "utf-8");
|
|
33947
34899
|
const parsed = parseYaml7(raw) ?? {};
|
|
33948
34900
|
if (typeof parsed !== "object" || parsed === null) {
|
|
33949
34901
|
throw new Error(`${absPath} is not a YAML object`);
|
|
@@ -33952,7 +34904,7 @@ function readConfigYaml(absPath) {
|
|
|
33952
34904
|
}
|
|
33953
34905
|
function writeConfigYaml(absPath, parsed) {
|
|
33954
34906
|
const out = stringifyYaml6(parsed, { aliasDuplicateObjects: false });
|
|
33955
|
-
|
|
34907
|
+
writeFileSync40(absPath, out, "utf-8");
|
|
33956
34908
|
}
|
|
33957
34909
|
async function defaultPromptText(question) {
|
|
33958
34910
|
const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -34071,25 +35023,25 @@ function registerMemoryMode(cmd) {
|
|
|
34071
35023
|
// src/commands/memory/bridge.ts
|
|
34072
35024
|
init_output();
|
|
34073
35025
|
import { spawn as spawn12 } from "node:child_process";
|
|
34074
|
-
import { existsSync as
|
|
34075
|
-
import { join as
|
|
35026
|
+
import { existsSync as existsSync86 } from "node:fs";
|
|
35027
|
+
import { join as join75 } from "node:path";
|
|
34076
35028
|
var DEFAULT_PORT2 = 8788;
|
|
34077
35029
|
function resolveMemoryServiceDir2() {
|
|
34078
35030
|
for (const c of MEMORY_SERVICE_CANDIDATES) {
|
|
34079
|
-
if (
|
|
35031
|
+
if (existsSync86(c)) return c;
|
|
34080
35032
|
}
|
|
34081
35033
|
throw new Error(
|
|
34082
35034
|
`Could not find packages/memory-service/. Searched: ${MEMORY_SERVICE_CANDIDATES.join(", ")}. If running from a published @pleri/olam-cli tarball, this is a packaging bug \u2014 please file an issue.`
|
|
34083
35035
|
);
|
|
34084
35036
|
}
|
|
34085
35037
|
function resolveLocalBridgeScript(serviceDir) {
|
|
34086
|
-
const
|
|
34087
|
-
if (!
|
|
35038
|
+
const path82 = join75(serviceDir, "scripts", "local-bridge-server.mjs");
|
|
35039
|
+
if (!existsSync86(path82)) {
|
|
34088
35040
|
throw new Error(
|
|
34089
|
-
`Could not find local-bridge-server.mjs at ${
|
|
35041
|
+
`Could not find local-bridge-server.mjs at ${path82}. Verify packages/memory-service ships the scripts/ directory.`
|
|
34090
35042
|
);
|
|
34091
35043
|
}
|
|
34092
|
-
return
|
|
35044
|
+
return path82;
|
|
34093
35045
|
}
|
|
34094
35046
|
function validateBridgeOpts(opts) {
|
|
34095
35047
|
const local = opts.local ?? false;
|
|
@@ -34137,12 +35089,12 @@ async function runBridgeServe(opts, deps = {}) {
|
|
|
34137
35089
|
stdio: "inherit"
|
|
34138
35090
|
}));
|
|
34139
35091
|
const child = spawner(process.execPath, [scriptPath, ...args], env);
|
|
34140
|
-
return new Promise((
|
|
35092
|
+
return new Promise((resolve19) => {
|
|
34141
35093
|
let resolved = false;
|
|
34142
35094
|
const finish = (code) => {
|
|
34143
35095
|
if (resolved) return;
|
|
34144
35096
|
resolved = true;
|
|
34145
|
-
|
|
35097
|
+
resolve19(code);
|
|
34146
35098
|
};
|
|
34147
35099
|
const forward = (signal) => () => {
|
|
34148
35100
|
if (!child.killed) {
|
|
@@ -34450,9 +35402,9 @@ function registerMemory(program2) {
|
|
|
34450
35402
|
// src/commands/kg-build.ts
|
|
34451
35403
|
init_storage_paths();
|
|
34452
35404
|
init_workspace_name();
|
|
34453
|
-
import * as
|
|
34454
|
-
import * as
|
|
34455
|
-
import * as
|
|
35405
|
+
import * as fs79 from "node:fs";
|
|
35406
|
+
import * as os43 from "node:os";
|
|
35407
|
+
import * as path79 from "node:path";
|
|
34456
35408
|
|
|
34457
35409
|
// ../core/dist/kg/kg-service-client.js
|
|
34458
35410
|
var KG_SERVICE_PORT_DEFAULT = 9997;
|
|
@@ -34463,8 +35415,8 @@ function port() {
|
|
|
34463
35415
|
const n = Number.parseInt(env, 10);
|
|
34464
35416
|
return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
|
|
34465
35417
|
}
|
|
34466
|
-
function url(
|
|
34467
|
-
return `http://127.0.0.1:${port()}${
|
|
35418
|
+
function url(path82) {
|
|
35419
|
+
return `http://127.0.0.1:${port()}${path82}`;
|
|
34468
35420
|
}
|
|
34469
35421
|
function kgServiceHealthUrl() {
|
|
34470
35422
|
return url("/health");
|
|
@@ -34489,8 +35441,8 @@ var KgServiceUnreachableError = class extends Error {
|
|
|
34489
35441
|
this.name = "KgServiceUnreachableError";
|
|
34490
35442
|
}
|
|
34491
35443
|
};
|
|
34492
|
-
var
|
|
34493
|
-
async function postJson(endpointUrl, body, timeoutMs =
|
|
35444
|
+
var DEFAULT_TIMEOUT_MS5 = 5e3;
|
|
35445
|
+
async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS5) {
|
|
34494
35446
|
let res;
|
|
34495
35447
|
try {
|
|
34496
35448
|
res = await fetch(endpointUrl, {
|
|
@@ -34508,7 +35460,7 @@ async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS4) {
|
|
|
34508
35460
|
}
|
|
34509
35461
|
return await res.json();
|
|
34510
35462
|
}
|
|
34511
|
-
async function getJson(endpointUrl, timeoutMs =
|
|
35463
|
+
async function getJson(endpointUrl, timeoutMs = DEFAULT_TIMEOUT_MS5) {
|
|
34512
35464
|
let res;
|
|
34513
35465
|
try {
|
|
34514
35466
|
res = await fetch(endpointUrl, { signal: AbortSignal.timeout(timeoutMs) });
|
|
@@ -34542,40 +35494,40 @@ init_output();
|
|
|
34542
35494
|
// src/commands/kg-status.ts
|
|
34543
35495
|
init_storage_paths();
|
|
34544
35496
|
init_workspace_name();
|
|
34545
|
-
import
|
|
34546
|
-
import { homedir as
|
|
34547
|
-
import
|
|
35497
|
+
import fs75 from "node:fs";
|
|
35498
|
+
import { homedir as homedir42 } from "node:os";
|
|
35499
|
+
import path75 from "node:path";
|
|
34548
35500
|
init_output();
|
|
34549
35501
|
function olamHome4() {
|
|
34550
|
-
return process.env.OLAM_HOME ??
|
|
35502
|
+
return process.env.OLAM_HOME ?? path75.join(homedir42(), ".olam");
|
|
34551
35503
|
}
|
|
34552
35504
|
function kgRoot2() {
|
|
34553
|
-
return
|
|
35505
|
+
return path75.join(olamHome4(), "kg");
|
|
34554
35506
|
}
|
|
34555
35507
|
function worldsRoot2() {
|
|
34556
|
-
return
|
|
35508
|
+
return path75.join(olamHome4(), "worlds");
|
|
34557
35509
|
}
|
|
34558
35510
|
function dirSizeBytes2(dir) {
|
|
34559
|
-
if (!
|
|
35511
|
+
if (!fs75.existsSync(dir)) return 0;
|
|
34560
35512
|
let total = 0;
|
|
34561
35513
|
const stack = [dir];
|
|
34562
35514
|
while (stack.length > 0) {
|
|
34563
35515
|
const cur = stack.pop();
|
|
34564
35516
|
let entries;
|
|
34565
35517
|
try {
|
|
34566
|
-
entries =
|
|
35518
|
+
entries = fs75.readdirSync(cur, { withFileTypes: true });
|
|
34567
35519
|
} catch {
|
|
34568
35520
|
continue;
|
|
34569
35521
|
}
|
|
34570
35522
|
for (const entry of entries) {
|
|
34571
|
-
const full =
|
|
35523
|
+
const full = path75.join(cur, entry.name);
|
|
34572
35524
|
if (entry.isSymbolicLink()) continue;
|
|
34573
35525
|
if (entry.isDirectory()) {
|
|
34574
35526
|
stack.push(full);
|
|
34575
35527
|
continue;
|
|
34576
35528
|
}
|
|
34577
35529
|
try {
|
|
34578
|
-
total +=
|
|
35530
|
+
total += fs75.statSync(full).size;
|
|
34579
35531
|
} catch {
|
|
34580
35532
|
}
|
|
34581
35533
|
}
|
|
@@ -34589,10 +35541,10 @@ function formatBytes5(n) {
|
|
|
34589
35541
|
return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
34590
35542
|
}
|
|
34591
35543
|
function readFreshness(workspace) {
|
|
34592
|
-
const file =
|
|
34593
|
-
if (!
|
|
35544
|
+
const file = path75.join(kgPristinePath(workspace), "freshness.json");
|
|
35545
|
+
if (!fs75.existsSync(file)) return null;
|
|
34594
35546
|
try {
|
|
34595
|
-
const raw = JSON.parse(
|
|
35547
|
+
const raw = JSON.parse(fs75.readFileSync(file, "utf-8"));
|
|
34596
35548
|
if (raw && typeof raw === "object") return raw;
|
|
34597
35549
|
return null;
|
|
34598
35550
|
} catch {
|
|
@@ -34600,10 +35552,10 @@ function readFreshness(workspace) {
|
|
|
34600
35552
|
}
|
|
34601
35553
|
}
|
|
34602
35554
|
function readOverlayNodeCount(graphifyOutDir) {
|
|
34603
|
-
const graphPath =
|
|
34604
|
-
if (!
|
|
35555
|
+
const graphPath = path75.join(graphifyOutDir, "graph.json");
|
|
35556
|
+
if (!fs75.existsSync(graphPath)) return null;
|
|
34605
35557
|
try {
|
|
34606
|
-
const raw = JSON.parse(
|
|
35558
|
+
const raw = JSON.parse(fs75.readFileSync(graphPath, "utf-8"));
|
|
34607
35559
|
if (raw && typeof raw === "object") {
|
|
34608
35560
|
const nodes = raw.nodes;
|
|
34609
35561
|
if (Array.isArray(nodes)) return nodes.length;
|
|
@@ -34615,28 +35567,28 @@ function readOverlayNodeCount(graphifyOutDir) {
|
|
|
34615
35567
|
}
|
|
34616
35568
|
function listOverlays() {
|
|
34617
35569
|
const root = worldsRoot2();
|
|
34618
|
-
if (!
|
|
35570
|
+
if (!fs75.existsSync(root)) return [];
|
|
34619
35571
|
const records = [];
|
|
34620
35572
|
let worldDirs;
|
|
34621
35573
|
try {
|
|
34622
|
-
worldDirs =
|
|
35574
|
+
worldDirs = fs75.readdirSync(root, { withFileTypes: true });
|
|
34623
35575
|
} catch {
|
|
34624
35576
|
return [];
|
|
34625
35577
|
}
|
|
34626
35578
|
for (const worldEntry of worldDirs) {
|
|
34627
35579
|
if (!worldEntry.isDirectory()) continue;
|
|
34628
35580
|
const worldId = worldEntry.name;
|
|
34629
|
-
const worldDir =
|
|
35581
|
+
const worldDir = path75.join(root, worldId);
|
|
34630
35582
|
let cloneDirs;
|
|
34631
35583
|
try {
|
|
34632
|
-
cloneDirs =
|
|
35584
|
+
cloneDirs = fs75.readdirSync(worldDir, { withFileTypes: true });
|
|
34633
35585
|
} catch {
|
|
34634
35586
|
continue;
|
|
34635
35587
|
}
|
|
34636
35588
|
for (const cloneEntry of cloneDirs) {
|
|
34637
35589
|
if (!cloneEntry.isDirectory()) continue;
|
|
34638
|
-
const graphifyOut =
|
|
34639
|
-
if (!
|
|
35590
|
+
const graphifyOut = path75.join(worldDir, cloneEntry.name, "graphify-out");
|
|
35591
|
+
if (!fs75.existsSync(graphifyOut)) continue;
|
|
34640
35592
|
records.push({
|
|
34641
35593
|
world_id: worldId,
|
|
34642
35594
|
clone_dir: cloneEntry.name,
|
|
@@ -34650,11 +35602,11 @@ function listOverlays() {
|
|
|
34650
35602
|
}
|
|
34651
35603
|
function listPristines(overlays) {
|
|
34652
35604
|
const root = kgRoot2();
|
|
34653
|
-
if (!
|
|
35605
|
+
if (!fs75.existsSync(root)) return [];
|
|
34654
35606
|
const records = [];
|
|
34655
35607
|
let entries;
|
|
34656
35608
|
try {
|
|
34657
|
-
entries =
|
|
35609
|
+
entries = fs75.readdirSync(root, { withFileTypes: true });
|
|
34658
35610
|
} catch {
|
|
34659
35611
|
return [];
|
|
34660
35612
|
}
|
|
@@ -34667,7 +35619,7 @@ function listPristines(overlays) {
|
|
|
34667
35619
|
continue;
|
|
34668
35620
|
}
|
|
34669
35621
|
const fresh = readFreshness(workspace);
|
|
34670
|
-
const graphifyOut =
|
|
35622
|
+
const graphifyOut = path75.join(kgPristinePath(workspace), "graphify-out");
|
|
34671
35623
|
const size = dirSizeBytes2(graphifyOut);
|
|
34672
35624
|
const worldCount = overlays.filter((o) => o.clone_dir === workspace).length;
|
|
34673
35625
|
records.push({
|
|
@@ -34803,10 +35755,10 @@ init_storage_paths();
|
|
|
34803
35755
|
init_workspace_name();
|
|
34804
35756
|
init_output();
|
|
34805
35757
|
import { spawn as spawn13 } from "node:child_process";
|
|
34806
|
-
import
|
|
34807
|
-
import
|
|
35758
|
+
import fs76 from "node:fs";
|
|
35759
|
+
import path76 from "node:path";
|
|
34808
35760
|
function pidFilePath2(workspace) {
|
|
34809
|
-
return
|
|
35761
|
+
return path76.join(kgPristinePath(workspace), ".watch.pid");
|
|
34810
35762
|
}
|
|
34811
35763
|
function isPidAlive3(pid) {
|
|
34812
35764
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
@@ -34821,39 +35773,39 @@ function isPidAlive3(pid) {
|
|
|
34821
35773
|
}
|
|
34822
35774
|
function readAndClassifyPid(workspace) {
|
|
34823
35775
|
const file = pidFilePath2(workspace);
|
|
34824
|
-
if (!
|
|
35776
|
+
if (!fs76.existsSync(file)) return { status: "no-pidfile", pid: null };
|
|
34825
35777
|
let pid;
|
|
34826
35778
|
try {
|
|
34827
|
-
const raw =
|
|
35779
|
+
const raw = fs76.readFileSync(file, "utf-8").trim();
|
|
34828
35780
|
pid = Number.parseInt(raw, 10);
|
|
34829
35781
|
} catch {
|
|
34830
|
-
|
|
35782
|
+
fs76.rmSync(file, { force: true });
|
|
34831
35783
|
return { status: "stale-reclaimed", pid: null };
|
|
34832
35784
|
}
|
|
34833
35785
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
34834
|
-
|
|
35786
|
+
fs76.rmSync(file, { force: true });
|
|
34835
35787
|
return { status: "stale-reclaimed", pid: null };
|
|
34836
35788
|
}
|
|
34837
35789
|
if (isPidAlive3(pid)) return { status: "active", pid };
|
|
34838
|
-
|
|
35790
|
+
fs76.rmSync(file, { force: true });
|
|
34839
35791
|
return { status: "stale-reclaimed", pid: null };
|
|
34840
35792
|
}
|
|
34841
35793
|
function writePidFile2(workspace, pid) {
|
|
34842
35794
|
const file = pidFilePath2(workspace);
|
|
34843
|
-
const dir =
|
|
34844
|
-
|
|
34845
|
-
|
|
35795
|
+
const dir = path76.dirname(file);
|
|
35796
|
+
fs76.mkdirSync(dir, { recursive: true });
|
|
35797
|
+
fs76.writeFileSync(file, String(pid), { encoding: "utf-8" });
|
|
34846
35798
|
}
|
|
34847
35799
|
function removePidFile(workspace) {
|
|
34848
35800
|
const file = pidFilePath2(workspace);
|
|
34849
35801
|
try {
|
|
34850
|
-
|
|
35802
|
+
fs76.rmSync(file, { force: true });
|
|
34851
35803
|
} catch {
|
|
34852
35804
|
}
|
|
34853
35805
|
}
|
|
34854
35806
|
async function runKgWatch(workspaceArg, opts, deps = {}) {
|
|
34855
35807
|
const cwd = deps.cwd ?? opts.cwd ?? process.cwd();
|
|
34856
|
-
const name = workspaceArg ??
|
|
35808
|
+
const name = workspaceArg ?? path76.basename(cwd).toLowerCase();
|
|
34857
35809
|
try {
|
|
34858
35810
|
validateWorkspaceName(name);
|
|
34859
35811
|
} catch (err) {
|
|
@@ -34861,7 +35813,7 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
|
|
|
34861
35813
|
return { exitCode: 1, pidWritten: false };
|
|
34862
35814
|
}
|
|
34863
35815
|
const pristinePath = kgPristinePath(name);
|
|
34864
|
-
const graphPath =
|
|
35816
|
+
const graphPath = path76.join(pristinePath, "graphify-out", "graph.json");
|
|
34865
35817
|
const pidState = readAndClassifyPid(name);
|
|
34866
35818
|
if (pidState.status === "active") {
|
|
34867
35819
|
printError(
|
|
@@ -34901,16 +35853,16 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
|
|
|
34901
35853
|
process.on("SIGINT", () => forward("SIGINT"));
|
|
34902
35854
|
process.on("SIGTERM", () => forward("SIGTERM"));
|
|
34903
35855
|
}
|
|
34904
|
-
return new Promise((
|
|
35856
|
+
return new Promise((resolve19) => {
|
|
34905
35857
|
child.on("exit", (code, signal) => {
|
|
34906
35858
|
removePidFile(name);
|
|
34907
35859
|
const exitCode = typeof code === "number" ? code : signal === "SIGINT" || signal === "SIGTERM" ? 0 : 1;
|
|
34908
|
-
|
|
35860
|
+
resolve19({ exitCode, pidWritten: true });
|
|
34909
35861
|
});
|
|
34910
35862
|
child.on("error", (err) => {
|
|
34911
35863
|
removePidFile(name);
|
|
34912
35864
|
printError(`graphify subprocess error: ${err.message}`);
|
|
34913
|
-
|
|
35865
|
+
resolve19({ exitCode: 1, pidWritten: true });
|
|
34914
35866
|
});
|
|
34915
35867
|
});
|
|
34916
35868
|
}
|
|
@@ -34924,7 +35876,7 @@ function registerKgWatchCommand(kg) {
|
|
|
34924
35876
|
}
|
|
34925
35877
|
|
|
34926
35878
|
// src/commands/kg-classify.ts
|
|
34927
|
-
import
|
|
35879
|
+
import pc40 from "picocolors";
|
|
34928
35880
|
init_output();
|
|
34929
35881
|
function registerKgClassifyCommand(kg) {
|
|
34930
35882
|
kg.command("classify <question>").description("Route a question to kg | grep | both via the 4-layer classifier (kg-service required)").option("--workspace <name>", "Scope the L2 probe gate to a specific workspace graph").option("--json", "Emit raw JSON instead of the formatted summary").action(async (question, opts) => {
|
|
@@ -34934,7 +35886,7 @@ function registerKgClassifyCommand(kg) {
|
|
|
34934
35886
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
34935
35887
|
return;
|
|
34936
35888
|
}
|
|
34937
|
-
const routeStr = result.route === "kg" ?
|
|
35889
|
+
const routeStr = result.route === "kg" ? pc40.cyan("kg") : result.route === "grep" ? pc40.magenta("grep") : pc40.yellow("both");
|
|
34938
35890
|
printInfo("route", `${routeStr} (layer ${result.layer}, took ${result.took_ms}ms)`);
|
|
34939
35891
|
printInfo("confidence", String(result.confidence));
|
|
34940
35892
|
printInfo("reason", result.reason);
|
|
@@ -34956,7 +35908,7 @@ function registerKgClassifyCommand(kg) {
|
|
|
34956
35908
|
}
|
|
34957
35909
|
|
|
34958
35910
|
// src/commands/kg-doctor.ts
|
|
34959
|
-
import
|
|
35911
|
+
import pc41 from "picocolors";
|
|
34960
35912
|
init_output();
|
|
34961
35913
|
async function runProbes() {
|
|
34962
35914
|
const results = [];
|
|
@@ -35075,12 +36027,12 @@ function registerKgDoctorCommand(kg) {
|
|
|
35075
36027
|
} else {
|
|
35076
36028
|
printHeader("kg-service doctor");
|
|
35077
36029
|
for (const p of probes) {
|
|
35078
|
-
const badge = p.status === "ok" ?
|
|
36030
|
+
const badge = p.status === "ok" ? pc41.green("\u2713") : p.status === "warn" ? pc41.yellow("\u2298") : pc41.red("\u2717");
|
|
35079
36031
|
const label = `${badge} ${p.name}`;
|
|
35080
36032
|
const detail = p.detail ?? "";
|
|
35081
36033
|
printInfo(label, detail);
|
|
35082
36034
|
if (p.remedy) {
|
|
35083
|
-
process.stderr.write(` ${
|
|
36035
|
+
process.stderr.write(` ${pc41.dim("remedy:")} ${p.remedy}
|
|
35084
36036
|
`);
|
|
35085
36037
|
}
|
|
35086
36038
|
}
|
|
@@ -35098,9 +36050,9 @@ function registerKgDoctorCommand(kg) {
|
|
|
35098
36050
|
}
|
|
35099
36051
|
|
|
35100
36052
|
// src/commands/kg-install-hook.ts
|
|
35101
|
-
import * as
|
|
35102
|
-
import * as
|
|
35103
|
-
import * as
|
|
36053
|
+
import * as fs77 from "node:fs";
|
|
36054
|
+
import * as path77 from "node:path";
|
|
36055
|
+
import * as os41 from "node:os";
|
|
35104
36056
|
|
|
35105
36057
|
// ../core/dist/kg/hook-template.js
|
|
35106
36058
|
var KG_HOOK_SENTINEL = "kg-service-v2-classifier-hook";
|
|
@@ -35151,15 +36103,15 @@ function buildHookMatcherEntry(opts) {
|
|
|
35151
36103
|
init_output();
|
|
35152
36104
|
function settingsPathFor2(scope) {
|
|
35153
36105
|
if (scope === "user") {
|
|
35154
|
-
return
|
|
36106
|
+
return path77.join(os41.homedir(), ".claude", "settings.json");
|
|
35155
36107
|
}
|
|
35156
|
-
return
|
|
36108
|
+
return path77.join(process.cwd(), ".claude", "settings.json");
|
|
35157
36109
|
}
|
|
35158
36110
|
function backup2(filePath) {
|
|
35159
|
-
if (!
|
|
36111
|
+
if (!fs77.existsSync(filePath)) return null;
|
|
35160
36112
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
35161
36113
|
const backupPath = `${filePath}.olam-bak.${ts}`;
|
|
35162
|
-
|
|
36114
|
+
fs77.copyFileSync(filePath, backupPath);
|
|
35163
36115
|
return backupPath;
|
|
35164
36116
|
}
|
|
35165
36117
|
function registerKgInstallHookCommand(kg) {
|
|
@@ -35167,9 +36119,9 @@ function registerKgInstallHookCommand(kg) {
|
|
|
35167
36119
|
const scope = opts.scope === "user" ? "user" : "project";
|
|
35168
36120
|
const filePath = settingsPathFor2(scope);
|
|
35169
36121
|
try {
|
|
35170
|
-
|
|
36122
|
+
fs77.mkdirSync(path77.dirname(filePath), { recursive: true });
|
|
35171
36123
|
} catch (err) {
|
|
35172
|
-
printError(`could not create ${
|
|
36124
|
+
printError(`could not create ${path77.dirname(filePath)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
35173
36125
|
process.exitCode = 1;
|
|
35174
36126
|
return;
|
|
35175
36127
|
}
|
|
@@ -35193,7 +36145,7 @@ function registerKgInstallHookCommand(kg) {
|
|
|
35193
36145
|
printInfo("kg-service hook", `already installed at ${filePath}`);
|
|
35194
36146
|
if (backupPath) {
|
|
35195
36147
|
try {
|
|
35196
|
-
|
|
36148
|
+
fs77.unlinkSync(backupPath);
|
|
35197
36149
|
} catch {
|
|
35198
36150
|
}
|
|
35199
36151
|
}
|
|
@@ -35211,15 +36163,15 @@ function registerKgInstallHookCommand(kg) {
|
|
|
35211
36163
|
}
|
|
35212
36164
|
|
|
35213
36165
|
// src/commands/kg-uninstall-hook.ts
|
|
35214
|
-
import * as
|
|
35215
|
-
import * as
|
|
35216
|
-
import * as
|
|
36166
|
+
import * as fs78 from "node:fs";
|
|
36167
|
+
import * as path78 from "node:path";
|
|
36168
|
+
import * as os42 from "node:os";
|
|
35217
36169
|
init_output();
|
|
35218
36170
|
function settingsPathFor3(scope) {
|
|
35219
36171
|
if (scope === "user") {
|
|
35220
|
-
return
|
|
36172
|
+
return path78.join(os42.homedir(), ".claude", "settings.json");
|
|
35221
36173
|
}
|
|
35222
|
-
return
|
|
36174
|
+
return path78.join(process.cwd(), ".claude", "settings.json");
|
|
35223
36175
|
}
|
|
35224
36176
|
function dropSentinel(matchers) {
|
|
35225
36177
|
let changed = false;
|
|
@@ -35249,13 +36201,13 @@ function registerKgUninstallHookCommand(kg) {
|
|
|
35249
36201
|
kg.command("uninstall-hook").description("Remove kg-service PreToolUse hook from .claude/settings.json (sentinel-matched; surgical)").option("--scope <scope>", "project (default) or user", "project").action((opts) => {
|
|
35250
36202
|
const scope = opts.scope === "user" ? "user" : "project";
|
|
35251
36203
|
const filePath = settingsPathFor3(scope);
|
|
35252
|
-
if (!
|
|
36204
|
+
if (!fs78.existsSync(filePath)) {
|
|
35253
36205
|
printInfo("kg-service hook", `no settings.json at ${filePath} \u2014 nothing to remove`);
|
|
35254
36206
|
return;
|
|
35255
36207
|
}
|
|
35256
36208
|
let settings;
|
|
35257
36209
|
try {
|
|
35258
|
-
const raw =
|
|
36210
|
+
const raw = fs78.readFileSync(filePath, "utf-8");
|
|
35259
36211
|
settings = raw.trim() ? JSON.parse(raw) : {};
|
|
35260
36212
|
} catch (err) {
|
|
35261
36213
|
printError(`could not parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -35275,7 +36227,7 @@ function registerKgUninstallHookCommand(kg) {
|
|
|
35275
36227
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
35276
36228
|
const backupPath = `${filePath}.olam-bak.${ts}`;
|
|
35277
36229
|
try {
|
|
35278
|
-
|
|
36230
|
+
fs78.copyFileSync(filePath, backupPath);
|
|
35279
36231
|
} catch {
|
|
35280
36232
|
}
|
|
35281
36233
|
const next = {
|
|
@@ -35294,7 +36246,7 @@ function registerKgUninstallHookCommand(kg) {
|
|
|
35294
36246
|
}
|
|
35295
36247
|
}
|
|
35296
36248
|
try {
|
|
35297
|
-
|
|
36249
|
+
fs78.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
|
|
35298
36250
|
printSuccess(`kg-service hook removed from ${filePath}`);
|
|
35299
36251
|
printInfo("backup", backupPath);
|
|
35300
36252
|
} catch (err) {
|
|
@@ -35368,20 +36320,20 @@ function registerKgSavingsCommand(kg) {
|
|
|
35368
36320
|
// src/commands/kg-build.ts
|
|
35369
36321
|
function resolveWorkspace(arg) {
|
|
35370
36322
|
const cwd = process.cwd();
|
|
35371
|
-
const name = arg ??
|
|
36323
|
+
const name = arg ?? path79.basename(cwd).toLowerCase();
|
|
35372
36324
|
validateWorkspaceName(name);
|
|
35373
36325
|
return { name, sourcePath: cwd };
|
|
35374
36326
|
}
|
|
35375
36327
|
function toContainerPath(hostPath) {
|
|
35376
|
-
const home =
|
|
35377
|
-
const resolved =
|
|
35378
|
-
if (!resolved.startsWith(home +
|
|
36328
|
+
const home = os43.homedir();
|
|
36329
|
+
const resolved = path79.resolve(hostPath);
|
|
36330
|
+
if (!resolved.startsWith(home + path79.sep) && resolved !== home) {
|
|
35379
36331
|
throw new Error(
|
|
35380
36332
|
`source path "${resolved}" is not under $HOME (${home}). kg-service can only build repos that live under your home dir (it bind-mounts $HOME:/host-home:ro at start). Move the repo or set OLAM_HOME if you need a different root.`
|
|
35381
36333
|
);
|
|
35382
36334
|
}
|
|
35383
|
-
const rel =
|
|
35384
|
-
return rel === "" ? "/host-home" :
|
|
36335
|
+
const rel = path79.relative(home, resolved);
|
|
36336
|
+
return rel === "" ? "/host-home" : path79.posix.join("/host-home", rel.split(path79.sep).join("/"));
|
|
35385
36337
|
}
|
|
35386
36338
|
async function runKgBuild(workspaceArg, options = {}) {
|
|
35387
36339
|
let workspace;
|
|
@@ -35399,7 +36351,7 @@ async function runKgBuild(workspaceArg, options = {}) {
|
|
|
35399
36351
|
return { exitCode: 2 };
|
|
35400
36352
|
}
|
|
35401
36353
|
const outDir = kgPristinePath(workspace.name);
|
|
35402
|
-
|
|
36354
|
+
fs79.mkdirSync(outDir, { recursive: true });
|
|
35403
36355
|
const human = !options.json;
|
|
35404
36356
|
if (human) {
|
|
35405
36357
|
printInfo("kg build", `workspace=${workspace.name} source=${workspace.sourcePath}`);
|
|
@@ -35432,12 +36384,12 @@ async function runKgBuild(workspaceArg, options = {}) {
|
|
|
35432
36384
|
workspace: workspace.name,
|
|
35433
36385
|
graphify_path: "container"
|
|
35434
36386
|
};
|
|
35435
|
-
|
|
35436
|
-
|
|
36387
|
+
fs79.writeFileSync(
|
|
36388
|
+
path79.join(outDir, "freshness.json"),
|
|
35437
36389
|
JSON.stringify(freshness, null, 2) + "\n",
|
|
35438
36390
|
"utf-8"
|
|
35439
36391
|
);
|
|
35440
|
-
const finalOut =
|
|
36392
|
+
const finalOut = path79.join(outDir, "graphify-out");
|
|
35441
36393
|
if (options.json) {
|
|
35442
36394
|
process.stdout.write(JSON.stringify(freshness) + "\n");
|
|
35443
36395
|
} else {
|
|
@@ -35714,14 +36666,14 @@ init_manager();
|
|
|
35714
36666
|
init_context();
|
|
35715
36667
|
init_output();
|
|
35716
36668
|
import { spawnSync as defaultSpawnSync } from "node:child_process";
|
|
35717
|
-
import * as
|
|
35718
|
-
import * as
|
|
35719
|
-
import * as
|
|
36669
|
+
import * as fs80 from "node:fs";
|
|
36670
|
+
import * as os44 from "node:os";
|
|
36671
|
+
import * as path80 from "node:path";
|
|
35720
36672
|
function devboxContainerName(worldId) {
|
|
35721
36673
|
return `olam-${worldId}-devbox`;
|
|
35722
36674
|
}
|
|
35723
36675
|
function olamHomeDir() {
|
|
35724
|
-
return process.env["OLAM_HOME"] ??
|
|
36676
|
+
return process.env["OLAM_HOME"] ?? path80.join(os44.homedir(), ".olam");
|
|
35725
36677
|
}
|
|
35726
36678
|
function defaultRestartContainer(name, spawn14 = defaultSpawnSync) {
|
|
35727
36679
|
const r = spawn14("docker", ["restart", "--time", "30", name], {
|
|
@@ -35734,8 +36686,8 @@ function defaultRestartContainer(name, spawn14 = defaultSpawnSync) {
|
|
|
35734
36686
|
};
|
|
35735
36687
|
}
|
|
35736
36688
|
function defaultAppendAuditLog(homeDir, line) {
|
|
35737
|
-
|
|
35738
|
-
|
|
36689
|
+
fs80.mkdirSync(homeDir, { recursive: true });
|
|
36690
|
+
fs80.appendFileSync(path80.join(homeDir, "usage.log"), line.endsWith("\n") ? line : line + "\n", {
|
|
35739
36691
|
encoding: "utf-8"
|
|
35740
36692
|
});
|
|
35741
36693
|
}
|
|
@@ -35780,19 +36732,19 @@ async function doRekey(worldId, deps) {
|
|
|
35780
36732
|
);
|
|
35781
36733
|
const rotatedAt = deps.now().toISOString();
|
|
35782
36734
|
const homeDir = deps.olamHomeDir();
|
|
35783
|
-
const worldDir =
|
|
35784
|
-
|
|
35785
|
-
const credentialsPath =
|
|
36735
|
+
const worldDir = path80.join(homeDir, "worlds", worldId);
|
|
36736
|
+
fs80.mkdirSync(worldDir, { recursive: true });
|
|
36737
|
+
const credentialsPath = path80.join(worldDir, "credentials.json");
|
|
35786
36738
|
const payload = {
|
|
35787
36739
|
worldRoleName,
|
|
35788
36740
|
password,
|
|
35789
36741
|
rotatedAt
|
|
35790
36742
|
};
|
|
35791
|
-
|
|
36743
|
+
fs80.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + "\n", {
|
|
35792
36744
|
encoding: "utf-8",
|
|
35793
36745
|
mode: 384
|
|
35794
36746
|
});
|
|
35795
|
-
|
|
36747
|
+
fs80.chmodSync(credentialsPath, 384);
|
|
35796
36748
|
const restart = deps.restartContainer(devboxContainerName(worldId));
|
|
35797
36749
|
deps.appendAuditLog(`${rotatedAt} ${worldId} rekey`);
|
|
35798
36750
|
if (!restart.ok) {
|
|
@@ -35856,18 +36808,18 @@ function registerRekey(program2) {
|
|
|
35856
36808
|
}
|
|
35857
36809
|
|
|
35858
36810
|
// src/pleri-config.ts
|
|
35859
|
-
import * as
|
|
35860
|
-
import * as
|
|
36811
|
+
import * as fs81 from "node:fs";
|
|
36812
|
+
import * as path81 from "node:path";
|
|
35861
36813
|
function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
35862
36814
|
if (process.env.PLERI_BASE_URL) {
|
|
35863
36815
|
return true;
|
|
35864
36816
|
}
|
|
35865
|
-
const configPath =
|
|
35866
|
-
if (!
|
|
36817
|
+
const configPath = path81.join(configDir, "config.yaml");
|
|
36818
|
+
if (!fs81.existsSync(configPath)) {
|
|
35867
36819
|
return false;
|
|
35868
36820
|
}
|
|
35869
36821
|
try {
|
|
35870
|
-
const contents =
|
|
36822
|
+
const contents = fs81.readFileSync(configPath, "utf8");
|
|
35871
36823
|
return /^[^#\n]*\bpleri:/m.test(contents);
|
|
35872
36824
|
} catch {
|
|
35873
36825
|
return false;
|
|
@@ -35939,6 +36891,8 @@ registerSkillsHook(program);
|
|
|
35939
36891
|
registerSkillsOnboard(program);
|
|
35940
36892
|
registerSkillsMigrate(program);
|
|
35941
36893
|
registerSkillsMigrateBack(program);
|
|
36894
|
+
registerSkillsMigrateHooks(program);
|
|
36895
|
+
registerSkillsMigrateHooksBack(program);
|
|
35942
36896
|
registerSkillsShadowBackups(program);
|
|
35943
36897
|
registerSkillsDoctor(program);
|
|
35944
36898
|
program.parse();
|