threadnote 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/mcp_server.cjs +246 -95
- package/dist/threadnote.cjs +328 -155
- package/docs/agent-instructions.md +8 -0
- package/docs/index.html +185 -106
- package/package.json +1 -1
package/dist/threadnote.cjs
CHANGED
|
@@ -3522,8 +3522,8 @@ var DEFAULT_SEED_PATTERNS = [
|
|
|
3522
3522
|
];
|
|
3523
3523
|
|
|
3524
3524
|
// src/hooks.ts
|
|
3525
|
-
var
|
|
3526
|
-
var
|
|
3525
|
+
var import_promises6 = require("node:fs/promises");
|
|
3526
|
+
var import_node_path7 = require("node:path");
|
|
3527
3527
|
|
|
3528
3528
|
// src/mcp.ts
|
|
3529
3529
|
var import_node_fs2 = require("node:fs");
|
|
@@ -7118,6 +7118,15 @@ function uriSegment(value) {
|
|
|
7118
7118
|
const normalized = value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7119
7119
|
return normalized.length > 0 ? normalized : "unknown";
|
|
7120
7120
|
}
|
|
7121
|
+
async function inferProjectFromQuery(manifestPath, query) {
|
|
7122
|
+
try {
|
|
7123
|
+
const manifest = await readSeedManifest(manifestPath);
|
|
7124
|
+
const normalized = query.toLowerCase();
|
|
7125
|
+
return manifest.projects.find((project) => normalized.includes(project.name.toLowerCase()));
|
|
7126
|
+
} catch {
|
|
7127
|
+
return void 0;
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7121
7130
|
async function readSeedManifest(path) {
|
|
7122
7131
|
const raw = await (0, import_promises3.readFile)(path, "utf8");
|
|
7123
7132
|
const loaded = jsYaml.load(raw);
|
|
@@ -7388,11 +7397,32 @@ async function runRecall(config, options) {
|
|
|
7388
7397
|
args.push("--node-limit", String(parsePositiveInteger(options.nodeLimit, "node limit")));
|
|
7389
7398
|
}
|
|
7390
7399
|
await maybeRun(options.dryRun === true, ov, withIdentity(config, args));
|
|
7400
|
+
await augmentRecallWithSeededResources(config, ov, options, inferredUri);
|
|
7391
7401
|
await printExactMemoryMatches(config, ov, options.query, {
|
|
7392
7402
|
dryRun: options.dryRun === true,
|
|
7393
7403
|
includeArchived: options.includeArchived === true
|
|
7394
7404
|
});
|
|
7395
7405
|
}
|
|
7406
|
+
async function augmentRecallWithSeededResources(config, ov, options, inferredUri) {
|
|
7407
|
+
if (options.uri || options.inferScope === false) {
|
|
7408
|
+
return;
|
|
7409
|
+
}
|
|
7410
|
+
const project = await inferProjectFromQuery(config.manifestPath, options.query);
|
|
7411
|
+
if (!project) {
|
|
7412
|
+
return;
|
|
7413
|
+
}
|
|
7414
|
+
const projectResourceUri = trimTrailingSlash(project.uri);
|
|
7415
|
+
if (!projectResourceUri.startsWith("viking://") || projectResourceUri === inferredUri) {
|
|
7416
|
+
return;
|
|
7417
|
+
}
|
|
7418
|
+
const args = ["search", options.query, "--uri", projectResourceUri];
|
|
7419
|
+
if (options.nodeLimit) {
|
|
7420
|
+
args.push("--node-limit", String(parsePositiveInteger(options.nodeLimit, "node limit")));
|
|
7421
|
+
}
|
|
7422
|
+
console.log(`
|
|
7423
|
+
Also searching seeded resources: ${projectResourceUri}`);
|
|
7424
|
+
await maybeRun(options.dryRun === true, ov, withIdentity(config, args));
|
|
7425
|
+
}
|
|
7396
7426
|
async function runRead(config, uri, options) {
|
|
7397
7427
|
assertVikingUri(uri);
|
|
7398
7428
|
const ov = await openVikingCliForMode(options.dryRun === true);
|
|
@@ -7511,21 +7541,11 @@ async function runImportPack(config, options) {
|
|
|
7511
7541
|
);
|
|
7512
7542
|
}
|
|
7513
7543
|
async function inferRecallUri(config, query) {
|
|
7514
|
-
|
|
7515
|
-
if (/\bskills?\b/.test(normalizedQuery)) {
|
|
7516
|
-
const project2 = await inferProjectFromQuery(config, normalizedQuery);
|
|
7517
|
-
return project2 ? `viking://resources/agent-skills/repo-local-${uriSegment(project2.name)}` : "viking://resources/agent-skills";
|
|
7518
|
-
}
|
|
7519
|
-
const project = await inferProjectFromQuery(config, normalizedQuery);
|
|
7520
|
-
return project ? trimTrailingSlash(project.uri) : void 0;
|
|
7521
|
-
}
|
|
7522
|
-
async function inferProjectFromQuery(config, normalizedQuery) {
|
|
7523
|
-
try {
|
|
7524
|
-
const manifest = await readSeedManifest(config.manifestPath);
|
|
7525
|
-
return manifest.projects.find((project) => normalizedQuery.includes(project.name.toLowerCase()));
|
|
7526
|
-
} catch (_err) {
|
|
7544
|
+
if (!/\bskills?\b/.test(query.toLowerCase())) {
|
|
7527
7545
|
return void 0;
|
|
7528
7546
|
}
|
|
7547
|
+
const project = await inferProjectFromQuery(config.manifestPath, query);
|
|
7548
|
+
return project ? `viking://resources/agent-skills/repo-local-${uriSegment(project.name)}` : "viking://resources/agent-skills";
|
|
7529
7549
|
}
|
|
7530
7550
|
async function printExactMemoryMatches(config, ov, query, options) {
|
|
7531
7551
|
const terms = exactRecallTerms(query);
|
|
@@ -7755,7 +7775,11 @@ function exactMemoryScopes(config, includeArchived) {
|
|
|
7755
7775
|
`${userBase}/incidents/active`,
|
|
7756
7776
|
`${userBase}/events`,
|
|
7757
7777
|
`${userBase}/shared`,
|
|
7758
|
-
`viking://agent/${uriSegment(config.agentId)}/memories
|
|
7778
|
+
`viking://agent/${uriSegment(config.agentId)}/memories`,
|
|
7779
|
+
// Seeded project resources (READMEs, AGENTS.md, SKILL.md, docs/**) live
|
|
7780
|
+
// under viking://resources/repos/<project>. Include them so an exact-term
|
|
7781
|
+
// grep in a recall surfaces matches in seeded guidance, not only memories.
|
|
7782
|
+
"viking://resources/repos"
|
|
7759
7783
|
];
|
|
7760
7784
|
return includeArchived ? [...scopes, `${userBase}/durable/archived`, `${userBase}/handoffs/archived`, `${userBase}/incidents/archived`] : scopes;
|
|
7761
7785
|
}
|
|
@@ -8109,6 +8133,128 @@ function formatBlock(value, emptyValue) {
|
|
|
8109
8133
|
return trimmed.split("\n").map((line) => `- ${line}`).join("\n");
|
|
8110
8134
|
}
|
|
8111
8135
|
|
|
8136
|
+
// src/update-check.ts
|
|
8137
|
+
var import_node_child_process2 = require("node:child_process");
|
|
8138
|
+
var import_promises5 = require("node:fs/promises");
|
|
8139
|
+
var import_node_path5 = require("node:path");
|
|
8140
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8141
|
+
var NPM_LATEST_URL = "https://registry.npmjs.org/threadnote/latest";
|
|
8142
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
8143
|
+
async function checkForThreadnoteUpdate(args) {
|
|
8144
|
+
if (args.currentVersion === "unknown") {
|
|
8145
|
+
return void 0;
|
|
8146
|
+
}
|
|
8147
|
+
const cached = await readUpdateCache(args.cachePath);
|
|
8148
|
+
if (cached && isCacheFresh(cached)) {
|
|
8149
|
+
return compareVersions(args.currentVersion, cached.latestVersion);
|
|
8150
|
+
}
|
|
8151
|
+
const fresh = await fetchLatestVersion();
|
|
8152
|
+
if (fresh) {
|
|
8153
|
+
await writeUpdateCache(args.cachePath, {
|
|
8154
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8155
|
+
latestVersion: fresh,
|
|
8156
|
+
version: 1
|
|
8157
|
+
});
|
|
8158
|
+
return compareVersions(args.currentVersion, fresh);
|
|
8159
|
+
}
|
|
8160
|
+
if (cached) {
|
|
8161
|
+
return compareVersions(args.currentVersion, cached.latestVersion);
|
|
8162
|
+
}
|
|
8163
|
+
return void 0;
|
|
8164
|
+
}
|
|
8165
|
+
function spawnDetachedAutoUpdate() {
|
|
8166
|
+
try {
|
|
8167
|
+
const entry = process.argv[1];
|
|
8168
|
+
if (typeof entry !== "string" || entry.length === 0) {
|
|
8169
|
+
return;
|
|
8170
|
+
}
|
|
8171
|
+
const child = (0, import_node_child_process2.spawn)(process.execPath, [entry, "update", "--yes"], {
|
|
8172
|
+
detached: true,
|
|
8173
|
+
stdio: "ignore"
|
|
8174
|
+
});
|
|
8175
|
+
child.unref();
|
|
8176
|
+
} catch {
|
|
8177
|
+
}
|
|
8178
|
+
}
|
|
8179
|
+
function compareVersions(currentVersion, latestVersion) {
|
|
8180
|
+
return {
|
|
8181
|
+
currentVersion,
|
|
8182
|
+
latestVersion,
|
|
8183
|
+
outdated: isNewerVersion(latestVersion, currentVersion)
|
|
8184
|
+
};
|
|
8185
|
+
}
|
|
8186
|
+
function isNewerVersion(candidate, baseline) {
|
|
8187
|
+
const candidateParts = parseVersion(candidate);
|
|
8188
|
+
const baselineParts = parseVersion(baseline);
|
|
8189
|
+
for (let index = 0; index < 3; index += 1) {
|
|
8190
|
+
if (candidateParts[index] !== baselineParts[index]) {
|
|
8191
|
+
return candidateParts[index] > baselineParts[index];
|
|
8192
|
+
}
|
|
8193
|
+
}
|
|
8194
|
+
return false;
|
|
8195
|
+
}
|
|
8196
|
+
function parseVersion(value) {
|
|
8197
|
+
const parts = value.split(".").map((part) => parseInt(part, 10));
|
|
8198
|
+
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
8199
|
+
}
|
|
8200
|
+
function isCacheFresh(cache) {
|
|
8201
|
+
const checkedAt = new Date(cache.checkedAt).getTime();
|
|
8202
|
+
return Number.isFinite(checkedAt) && Date.now() - checkedAt < CACHE_TTL_MS;
|
|
8203
|
+
}
|
|
8204
|
+
async function readUpdateCache(cachePath) {
|
|
8205
|
+
try {
|
|
8206
|
+
const raw = await (0, import_promises5.readFile)(cachePath, "utf8");
|
|
8207
|
+
const parsed = JSON.parse(raw);
|
|
8208
|
+
if (parsed.version !== 1 || typeof parsed.latestVersion !== "string" || typeof parsed.checkedAt !== "string") {
|
|
8209
|
+
return void 0;
|
|
8210
|
+
}
|
|
8211
|
+
return { checkedAt: parsed.checkedAt, latestVersion: parsed.latestVersion, version: 1 };
|
|
8212
|
+
} catch {
|
|
8213
|
+
return void 0;
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
8216
|
+
async function writeUpdateCache(cachePath, contents) {
|
|
8217
|
+
try {
|
|
8218
|
+
await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(cachePath), { recursive: true });
|
|
8219
|
+
await (0, import_promises5.writeFile)(cachePath, `${JSON.stringify(contents)}
|
|
8220
|
+
`, { encoding: "utf8", mode: 384 });
|
|
8221
|
+
} catch {
|
|
8222
|
+
}
|
|
8223
|
+
}
|
|
8224
|
+
async function fetchLatestVersion() {
|
|
8225
|
+
try {
|
|
8226
|
+
const response = await fetch(NPM_LATEST_URL, {
|
|
8227
|
+
headers: { accept: "application/json" },
|
|
8228
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
8229
|
+
});
|
|
8230
|
+
if (!response.ok) {
|
|
8231
|
+
return void 0;
|
|
8232
|
+
}
|
|
8233
|
+
const data = await response.json();
|
|
8234
|
+
return typeof data.version === "string" && data.version.length > 0 ? data.version : void 0;
|
|
8235
|
+
} catch {
|
|
8236
|
+
return void 0;
|
|
8237
|
+
}
|
|
8238
|
+
}
|
|
8239
|
+
|
|
8240
|
+
// src/version.ts
|
|
8241
|
+
var import_node_fs4 = require("node:fs");
|
|
8242
|
+
var import_node_path6 = require("node:path");
|
|
8243
|
+
var cachedVersion;
|
|
8244
|
+
function getThreadnoteVersion() {
|
|
8245
|
+
if (cachedVersion !== void 0) {
|
|
8246
|
+
return cachedVersion;
|
|
8247
|
+
}
|
|
8248
|
+
try {
|
|
8249
|
+
const packageJsonPath = (0, import_node_path6.join)(__dirname, "..", "package.json");
|
|
8250
|
+
const parsed = JSON.parse((0, import_node_fs4.readFileSync)(packageJsonPath, "utf8"));
|
|
8251
|
+
cachedVersion = typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : "unknown";
|
|
8252
|
+
} catch {
|
|
8253
|
+
cachedVersion = "unknown";
|
|
8254
|
+
}
|
|
8255
|
+
return cachedVersion;
|
|
8256
|
+
}
|
|
8257
|
+
|
|
8112
8258
|
// src/hooks.ts
|
|
8113
8259
|
var MANAGED_HOOKS = [
|
|
8114
8260
|
{
|
|
@@ -8142,7 +8288,7 @@ async function runHooksInstall(config, agent, options) {
|
|
|
8142
8288
|
}
|
|
8143
8289
|
async function runClaudeHooksInstall(options) {
|
|
8144
8290
|
const path = expandPath(CLAUDE_SETTINGS_PATH);
|
|
8145
|
-
const existingRaw = await exists(path) ? await (0,
|
|
8291
|
+
const existingRaw = await exists(path) ? await (0, import_promises6.readFile)(path, "utf8") : "{}";
|
|
8146
8292
|
const parsed = parseJsonConfigObject(existingRaw) ?? {};
|
|
8147
8293
|
const next = options.remove ? withoutThreadnoteHooks(parsed) : withThreadnoteHooks(parsed);
|
|
8148
8294
|
const before = JSON.stringify(parsed);
|
|
@@ -8159,11 +8305,11 @@ async function runClaudeHooksInstall(options) {
|
|
|
8159
8305
|
console.log("\nRe-run with --apply to actually modify the file.");
|
|
8160
8306
|
return;
|
|
8161
8307
|
}
|
|
8162
|
-
await (0,
|
|
8308
|
+
await (0, import_promises6.mkdir)((0, import_node_path7.dirname)(path), { recursive: true });
|
|
8163
8309
|
const serialized = `${JSON.stringify(next, void 0, 2)}
|
|
8164
8310
|
`;
|
|
8165
|
-
await (0,
|
|
8166
|
-
await (0,
|
|
8311
|
+
await (0, import_promises6.writeFile)(path, serialized, { encoding: "utf8", mode: 384 });
|
|
8312
|
+
await (0, import_promises6.chmod)(path, 384);
|
|
8167
8313
|
console.log(`${options.remove ? "Removed" : "Installed"} threadnote-managed Claude hooks.`);
|
|
8168
8314
|
}
|
|
8169
8315
|
function withThreadnoteHooks(input2) {
|
|
@@ -8241,7 +8387,7 @@ async function hasManagedClaudeHooks() {
|
|
|
8241
8387
|
if (!await exists(path)) {
|
|
8242
8388
|
return false;
|
|
8243
8389
|
}
|
|
8244
|
-
const raw = await (0,
|
|
8390
|
+
const raw = await (0, import_promises6.readFile)(path, "utf8");
|
|
8245
8391
|
const parsed = parseJsonConfigObject(raw);
|
|
8246
8392
|
if (!parsed || !isJsonObject(parsed.hooks)) {
|
|
8247
8393
|
return false;
|
|
@@ -8259,7 +8405,7 @@ async function hasManagedClaudeHooks() {
|
|
|
8259
8405
|
async function runPreCompactHook(config, options = {}) {
|
|
8260
8406
|
try {
|
|
8261
8407
|
const repoRoot = await gitValue(["rev-parse", "--show-toplevel"]);
|
|
8262
|
-
const project = repoRoot ? (0,
|
|
8408
|
+
const project = repoRoot ? (0, import_node_path7.basename)(repoRoot) : "general";
|
|
8263
8409
|
await runHandoff(config, {
|
|
8264
8410
|
blockers: "- none recorded",
|
|
8265
8411
|
dryRun: options.dryRun === true,
|
|
@@ -8283,7 +8429,8 @@ async function runSessionStartHook(config, options = {}) {
|
|
|
8283
8429
|
if (!repoRoot) {
|
|
8284
8430
|
return;
|
|
8285
8431
|
}
|
|
8286
|
-
const project = (0,
|
|
8432
|
+
const project = (0, import_node_path7.basename)(repoRoot);
|
|
8433
|
+
await emitUpdateBannerIfOutdated(config);
|
|
8287
8434
|
process.stdout.write(`## Threadnote \u2014 latest context for ${project}
|
|
8288
8435
|
|
|
8289
8436
|
`);
|
|
@@ -8300,10 +8447,36 @@ async function runSessionStartHook(config, options = {}) {
|
|
|
8300
8447
|
);
|
|
8301
8448
|
}
|
|
8302
8449
|
}
|
|
8450
|
+
async function emitUpdateBannerIfOutdated(config) {
|
|
8451
|
+
try {
|
|
8452
|
+
const result = await checkForThreadnoteUpdate({
|
|
8453
|
+
cachePath: (0, import_node_path7.join)(config.agentContextHome, ".update-state.json"),
|
|
8454
|
+
currentVersion: getThreadnoteVersion()
|
|
8455
|
+
});
|
|
8456
|
+
if (!result || !result.outdated) {
|
|
8457
|
+
return;
|
|
8458
|
+
}
|
|
8459
|
+
if (process.env.THREADNOTE_AUTO_UPDATE === "1") {
|
|
8460
|
+
process.stdout.write(
|
|
8461
|
+
`[threadnote] v${result.latestVersion} available (current v${result.currentVersion}). Auto-updating in the background; the new version takes effect next session.
|
|
8462
|
+
|
|
8463
|
+
`
|
|
8464
|
+
);
|
|
8465
|
+
spawnDetachedAutoUpdate();
|
|
8466
|
+
return;
|
|
8467
|
+
}
|
|
8468
|
+
process.stdout.write(
|
|
8469
|
+
`[threadnote] v${result.latestVersion} available (current v${result.currentVersion}). Run: threadnote update
|
|
8470
|
+
|
|
8471
|
+
`
|
|
8472
|
+
);
|
|
8473
|
+
} catch {
|
|
8474
|
+
}
|
|
8475
|
+
}
|
|
8303
8476
|
|
|
8304
8477
|
// src/seeding.ts
|
|
8305
|
-
var
|
|
8306
|
-
var
|
|
8478
|
+
var import_promises7 = require("node:fs/promises");
|
|
8479
|
+
var import_node_path8 = require("node:path");
|
|
8307
8480
|
async function runSeed(config, options) {
|
|
8308
8481
|
const manifest = await readSeedManifest(config.manifestPath);
|
|
8309
8482
|
const ignorePatterns = await loadIgnorePatterns();
|
|
@@ -8332,7 +8505,7 @@ async function runSeed(config, options) {
|
|
|
8332
8505
|
}
|
|
8333
8506
|
async function runInitManifest(config, options) {
|
|
8334
8507
|
const manifestPath = expandPath(
|
|
8335
|
-
options.path ?? process.env.THREADNOTE_MANIFEST ?? (0,
|
|
8508
|
+
options.path ?? process.env.THREADNOTE_MANIFEST ?? (0, import_node_path8.join)(config.agentContextHome, USER_MANIFEST_NAME)
|
|
8336
8509
|
);
|
|
8337
8510
|
const repoInputs = options.repo && options.repo.length > 0 ? options.repo : [getInvocationCwd()];
|
|
8338
8511
|
const existingManifest = options.replace === true || !await exists(manifestPath) ? void 0 : await readSeedManifest(manifestPath);
|
|
@@ -8375,9 +8548,9 @@ async function runInitManifest(config, options) {
|
|
|
8375
8548
|
console.log(output2.trimEnd());
|
|
8376
8549
|
return;
|
|
8377
8550
|
}
|
|
8378
|
-
await ensureDirectory((0,
|
|
8379
|
-
await (0,
|
|
8380
|
-
await (0,
|
|
8551
|
+
await ensureDirectory((0, import_node_path8.dirname)(manifestPath), false);
|
|
8552
|
+
await (0, import_promises7.writeFile)(manifestPath, output2, { encoding: "utf8", mode: 384 });
|
|
8553
|
+
await (0, import_promises7.chmod)(manifestPath, 384);
|
|
8381
8554
|
console.log(`Wrote manifest: ${manifestPath}`);
|
|
8382
8555
|
console.log("Seed with:");
|
|
8383
8556
|
console.log(" threadnote seed --dry-run");
|
|
@@ -8407,13 +8580,13 @@ async function resolveRepoRoot(repoInput) {
|
|
|
8407
8580
|
async function projectIdentity(path) {
|
|
8408
8581
|
const expanded = expandPath(path);
|
|
8409
8582
|
try {
|
|
8410
|
-
return await (0,
|
|
8583
|
+
return await (0, import_promises7.realpath)(expanded);
|
|
8411
8584
|
} catch (_err) {
|
|
8412
8585
|
return expanded;
|
|
8413
8586
|
}
|
|
8414
8587
|
}
|
|
8415
8588
|
function projectManifestForRepo(repoRoot, existingProjects) {
|
|
8416
|
-
const baseName = uriSegment((0,
|
|
8589
|
+
const baseName = uriSegment((0, import_node_path8.basename)(repoRoot));
|
|
8417
8590
|
const usedNames = new Set(existingProjects.map((project) => project.name));
|
|
8418
8591
|
const usedUris = new Set(existingProjects.map((project) => project.uri));
|
|
8419
8592
|
let name = baseName;
|
|
@@ -8435,7 +8608,7 @@ async function collectSeedCandidates(project, projectRoot, ignorePatterns) {
|
|
|
8435
8608
|
for (const pattern of project.seed) {
|
|
8436
8609
|
const files = await resolveProjectPattern(projectRoot, pattern);
|
|
8437
8610
|
for (const filePath of files) {
|
|
8438
|
-
const relativePath = toPosixPath((0,
|
|
8611
|
+
const relativePath = toPosixPath((0, import_node_path8.relative)(projectRoot, filePath));
|
|
8439
8612
|
if (seen.has(relativePath) || matchesIgnore(relativePath, ignorePatterns)) {
|
|
8440
8613
|
continue;
|
|
8441
8614
|
}
|
|
@@ -8453,20 +8626,20 @@ async function collectSeedCandidates(project, projectRoot, ignorePatterns) {
|
|
|
8453
8626
|
async function resolveProjectPattern(projectRoot, pattern) {
|
|
8454
8627
|
const normalizedPattern = toPosixPath(pattern);
|
|
8455
8628
|
if (!hasGlob(normalizedPattern)) {
|
|
8456
|
-
const filePath = (0,
|
|
8629
|
+
const filePath = (0, import_node_path8.join)(projectRoot, normalizedPattern);
|
|
8457
8630
|
return await isFile(filePath) ? [filePath] : [];
|
|
8458
8631
|
}
|
|
8459
8632
|
const globBase = getGlobBase(normalizedPattern);
|
|
8460
|
-
const basePath = (0,
|
|
8633
|
+
const basePath = (0, import_node_path8.join)(projectRoot, globBase);
|
|
8461
8634
|
if (!await exists(basePath)) {
|
|
8462
8635
|
return [];
|
|
8463
8636
|
}
|
|
8464
8637
|
const regex = globToRegExp(normalizedPattern);
|
|
8465
8638
|
const files = await walkFiles(basePath);
|
|
8466
|
-
return files.filter((filePath) => regex.test(toPosixPath((0,
|
|
8639
|
+
return files.filter((filePath) => regex.test(toPosixPath((0, import_node_path8.relative)(projectRoot, filePath))));
|
|
8467
8640
|
}
|
|
8468
8641
|
async function prepareSeedFile(config, candidate, dryRun) {
|
|
8469
|
-
const content = await (0,
|
|
8642
|
+
const content = await (0, import_promises7.readFile)(candidate.filePath, "utf8");
|
|
8470
8643
|
const redactedContent = shouldRedactPath(candidate.relativePath) ? redactContent(candidate.relativePath, content) : content;
|
|
8471
8644
|
const secretMatches = detectSecretMatches(redactedContent);
|
|
8472
8645
|
if (secretMatches.length > 0) {
|
|
@@ -8478,14 +8651,14 @@ async function prepareSeedFile(config, candidate, dryRun) {
|
|
|
8478
8651
|
if (redactedContent === content) {
|
|
8479
8652
|
return candidate.filePath;
|
|
8480
8653
|
}
|
|
8481
|
-
const redactedPath = (0,
|
|
8654
|
+
const redactedPath = (0, import_node_path8.join)(config.agentContextHome, "redacted", candidate.projectName, candidate.relativePath);
|
|
8482
8655
|
if (dryRun) {
|
|
8483
8656
|
console.log(`Would write redacted copy: ${redactedPath}`);
|
|
8484
8657
|
return redactedPath;
|
|
8485
8658
|
}
|
|
8486
|
-
await ensureDirectory((0,
|
|
8487
|
-
await (0,
|
|
8488
|
-
await (0,
|
|
8659
|
+
await ensureDirectory((0, import_node_path8.dirname)(redactedPath), false);
|
|
8660
|
+
await (0, import_promises7.writeFile)(redactedPath, redactedContent, { encoding: "utf8", mode: 384 });
|
|
8661
|
+
await (0, import_promises7.chmod)(redactedPath, 384);
|
|
8489
8662
|
return redactedPath;
|
|
8490
8663
|
}
|
|
8491
8664
|
async function collectSkillCandidates(config) {
|
|
@@ -8510,7 +8683,7 @@ async function collectSkillCandidates(config) {
|
|
|
8510
8683
|
for (const source of sources) {
|
|
8511
8684
|
const files = await resolveAbsolutePattern(expandPath(source.pattern));
|
|
8512
8685
|
for (const filePath of files) {
|
|
8513
|
-
const content = await (0,
|
|
8686
|
+
const content = await (0, import_promises7.readFile)(filePath, "utf8");
|
|
8514
8687
|
const matches = detectSecretMatches(content);
|
|
8515
8688
|
if (matches.length > 0) {
|
|
8516
8689
|
console.log(`SKIP skill with possible secret: ${filePath}`);
|
|
@@ -8541,10 +8714,10 @@ async function resolveAbsolutePattern(pattern) {
|
|
|
8541
8714
|
return files.filter((filePath) => regex.test(toPosixPath(filePath)));
|
|
8542
8715
|
}
|
|
8543
8716
|
function skillResourceUri(skill) {
|
|
8544
|
-
return `viking://resources/agent-skills/${uriSegment(skill.source)}/${uriSegment((0,
|
|
8717
|
+
return `viking://resources/agent-skills/${uriSegment(skill.source)}/${uriSegment((0, import_node_path8.basename)((0, import_node_path8.dirname)(skill.filePath)))}-${skill.hash.slice(0, 12)}.md`;
|
|
8545
8718
|
}
|
|
8546
8719
|
async function loadIgnorePatterns() {
|
|
8547
|
-
const raw = await (0,
|
|
8720
|
+
const raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(toolRoot(), ".threadnoteignore"), "utf8");
|
|
8548
8721
|
return raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8549
8722
|
}
|
|
8550
8723
|
function matchesIgnore(relativePath, patterns) {
|
|
@@ -8615,9 +8788,9 @@ function detectSecretMatches(content) {
|
|
|
8615
8788
|
}
|
|
8616
8789
|
|
|
8617
8790
|
// src/share.ts
|
|
8618
|
-
var
|
|
8791
|
+
var import_promises8 = require("node:fs/promises");
|
|
8619
8792
|
var import_node_os4 = require("node:os");
|
|
8620
|
-
var
|
|
8793
|
+
var import_node_path9 = require("node:path");
|
|
8621
8794
|
var TEAMS_FILE_VERSION = 1;
|
|
8622
8795
|
var SHARED_SEGMENT = "shared";
|
|
8623
8796
|
var SHAREABLE_MEMORY_KIND_DIRS = ["durable"];
|
|
@@ -8684,8 +8857,8 @@ async function runShareInit(config, remoteUrl, options) {
|
|
|
8684
8857
|
if (await exists(gitdir)) {
|
|
8685
8858
|
throw new Error(`Gitdir already exists at ${gitdir}; remove it or pick a different team name.`);
|
|
8686
8859
|
}
|
|
8687
|
-
await ensureDirectory((0,
|
|
8688
|
-
await ensureDirectory((0,
|
|
8860
|
+
await ensureDirectory((0, import_node_path9.dirname)(worktree), dryRun);
|
|
8861
|
+
await ensureDirectory((0, import_node_path9.dirname)(gitdir), dryRun);
|
|
8689
8862
|
const git = await requiredExecutable("git");
|
|
8690
8863
|
await maybeRun(dryRun, git, ["clone", `--separate-git-dir=${gitdir}`, "--", remoteUrl, worktree]);
|
|
8691
8864
|
const newConfig = {
|
|
@@ -8716,7 +8889,7 @@ async function runShareInit(config, remoteUrl, options) {
|
|
|
8716
8889
|
var SHARED_GITIGNORE_PATTERNS = ["**/.abstract.md", "**/.overview.md"];
|
|
8717
8890
|
var SHARED_GITIGNORE_HEADER = "# Threadnote: ignore OpenViking-generated directory summaries.";
|
|
8718
8891
|
async function ensureSharedGitignore(worktree, git, push) {
|
|
8719
|
-
const gitignorePath = (0,
|
|
8892
|
+
const gitignorePath = (0, import_node_path9.join)(worktree, ".gitignore");
|
|
8720
8893
|
const existing = await readFileIfExists(gitignorePath) ?? "";
|
|
8721
8894
|
const lines = existing.split("\n").map((line) => line.trim());
|
|
8722
8895
|
const missingPatterns = SHARED_GITIGNORE_PATTERNS.filter((pattern) => !lines.includes(pattern));
|
|
@@ -8735,7 +8908,7 @@ async function ensureSharedGitignore(worktree, git, push) {
|
|
|
8735
8908
|
segments.push(SHARED_GITIGNORE_HEADER, "\n");
|
|
8736
8909
|
}
|
|
8737
8910
|
segments.push(missingPatterns.join("\n"), "\n");
|
|
8738
|
-
await (0,
|
|
8911
|
+
await (0, import_promises8.writeFile)(gitignorePath, `${existing}${segments.join("")}`, { encoding: "utf8" });
|
|
8739
8912
|
console.log(`Added ${missingPatterns.join(", ")} to ${portablePath(gitignorePath)}`);
|
|
8740
8913
|
await maybeRun(false, git, ["-C", worktree, "add", ".gitignore"]);
|
|
8741
8914
|
const commitResult = await runCommand(
|
|
@@ -8800,7 +8973,7 @@ async function runShareSync(config, options) {
|
|
|
8800
8973
|
if (dryRun) {
|
|
8801
8974
|
console.log(`Would run: ${formatShellCommand(git, ["-C", worktree, "pull", "--rebase", DEFAULT_GIT_REMOTE_NAME])}`);
|
|
8802
8975
|
} else if (pullResult && pullResult.exitCode !== 0) {
|
|
8803
|
-
if (await exists((0,
|
|
8976
|
+
if (await exists((0, import_node_path9.join)(team.config.gitdir, "rebase-merge")) || await exists((0, import_node_path9.join)(team.config.gitdir, "rebase-apply"))) {
|
|
8804
8977
|
throw new Error(
|
|
8805
8978
|
`git pull --rebase reported conflicts in ${worktree}. The worktree is in a rebase-in-progress state.
|
|
8806
8979
|
Resolve the conflicts in-place, run \`git -C ${worktree} rebase --continue\` (or --abort), then re-run \`threadnote share sync\`.`
|
|
@@ -8976,10 +9149,10 @@ function normalizeTeamName(input2) {
|
|
|
8976
9149
|
return candidate;
|
|
8977
9150
|
}
|
|
8978
9151
|
function teamsFilePath(config) {
|
|
8979
|
-
return (0,
|
|
9152
|
+
return (0, import_node_path9.join)(config.agentContextHome, "share", "teams.json");
|
|
8980
9153
|
}
|
|
8981
9154
|
function teamWorktreePath(config, team) {
|
|
8982
|
-
return (0,
|
|
9155
|
+
return (0, import_node_path9.join)(
|
|
8983
9156
|
config.agentContextHome,
|
|
8984
9157
|
"data",
|
|
8985
9158
|
"viking",
|
|
@@ -8992,7 +9165,7 @@ function teamWorktreePath(config, team) {
|
|
|
8992
9165
|
);
|
|
8993
9166
|
}
|
|
8994
9167
|
function teamGitdirPath(config, team) {
|
|
8995
|
-
return (0,
|
|
9168
|
+
return (0, import_node_path9.join)(config.agentContextHome, "share", "teams", `${team}.gitdir`);
|
|
8996
9169
|
}
|
|
8997
9170
|
async function readTeamsFile(config) {
|
|
8998
9171
|
const path = teamsFilePath(config);
|
|
@@ -9035,13 +9208,13 @@ async function readTeamsFile(config) {
|
|
|
9035
9208
|
}
|
|
9036
9209
|
async function writeTeamsFile(config, contents) {
|
|
9037
9210
|
const path = teamsFilePath(config);
|
|
9038
|
-
await (0,
|
|
9211
|
+
await (0, import_promises8.mkdir)((0, import_node_path9.dirname)(path), { recursive: true });
|
|
9039
9212
|
const serializable = {
|
|
9040
9213
|
defaultTeam: contents.defaultTeam,
|
|
9041
9214
|
teams: contents.teams,
|
|
9042
9215
|
version: contents.version
|
|
9043
9216
|
};
|
|
9044
|
-
await (0,
|
|
9217
|
+
await (0, import_promises8.writeFile)(path, `${JSON.stringify(serializable, void 0, 2)}
|
|
9045
9218
|
`, { encoding: "utf8", mode: 384 });
|
|
9046
9219
|
}
|
|
9047
9220
|
async function resolveTeam(config, requested) {
|
|
@@ -9071,7 +9244,7 @@ async function assertWorktreeUsable(worktree) {
|
|
|
9071
9244
|
if (!await isDirectory(worktree)) {
|
|
9072
9245
|
throw new Error(`Cannot use ${worktree} as a worktree: not a directory.`);
|
|
9073
9246
|
}
|
|
9074
|
-
const entries = await (0,
|
|
9247
|
+
const entries = await (0, import_promises8.readdir)(worktree);
|
|
9075
9248
|
if (entries.length > 0) {
|
|
9076
9249
|
const preview = entries.slice(0, 5).join(", ");
|
|
9077
9250
|
const suffix = entries.length > 5 ? `, +${entries.length - 5} more` : "";
|
|
@@ -9095,7 +9268,7 @@ async function walkMemoryFiles(root) {
|
|
|
9095
9268
|
async function visit(path, depth) {
|
|
9096
9269
|
let entries;
|
|
9097
9270
|
try {
|
|
9098
|
-
entries = await (0,
|
|
9271
|
+
entries = await (0, import_promises8.readdir)(path, { withFileTypes: true });
|
|
9099
9272
|
} catch (err) {
|
|
9100
9273
|
console.warn(`Skipping ${path} during shared-tree walk: ${err instanceof Error ? err.message : String(err)}`);
|
|
9101
9274
|
return;
|
|
@@ -9104,7 +9277,7 @@ async function walkMemoryFiles(root) {
|
|
|
9104
9277
|
if (entry.name === ".git") {
|
|
9105
9278
|
continue;
|
|
9106
9279
|
}
|
|
9107
|
-
const full = (0,
|
|
9280
|
+
const full = (0, import_node_path9.join)(path, entry.name);
|
|
9108
9281
|
if (entry.isDirectory()) {
|
|
9109
9282
|
if (depth === 0 && !SHAREABLE_MEMORY_KIND_DIRS.includes(entry.name)) {
|
|
9110
9283
|
continue;
|
|
@@ -9128,7 +9301,7 @@ async function walkMemoryFiles(root) {
|
|
|
9128
9301
|
return out;
|
|
9129
9302
|
}
|
|
9130
9303
|
function workfileToVikingUri(config, team, filePath) {
|
|
9131
|
-
const rel = (0,
|
|
9304
|
+
const rel = (0, import_node_path9.relative)(team.worktree, filePath).split(import_node_path9.sep).join("/");
|
|
9132
9305
|
return `viking://user/${uriSegment(config.user)}/memories/${SHARED_SEGMENT}/${team.name}/${rel}`;
|
|
9133
9306
|
}
|
|
9134
9307
|
function isInSharedNamespace(config, uri) {
|
|
@@ -9240,13 +9413,13 @@ async function writeMemoryFile(config, ov, uri, content, initialMode, dryRun) {
|
|
|
9240
9413
|
console.log(`Would run: ${formatShellCommand(ov, args)}`);
|
|
9241
9414
|
return;
|
|
9242
9415
|
}
|
|
9243
|
-
const stagingDir = await (0,
|
|
9244
|
-
const tempPath = (0,
|
|
9416
|
+
const stagingDir = await (0, import_promises8.mkdtemp)((0, import_node_path9.join)((0, import_node_os4.tmpdir)(), "threadnote-share-"));
|
|
9417
|
+
const tempPath = (0, import_node_path9.join)(stagingDir, "body.txt");
|
|
9245
9418
|
try {
|
|
9246
|
-
await (0,
|
|
9419
|
+
await (0, import_promises8.writeFile)(tempPath, content, { encoding: "utf8", mode: 384 });
|
|
9247
9420
|
await writeOvFileWithRetry(config, ov, uri, tempPath, initialMode);
|
|
9248
9421
|
} finally {
|
|
9249
|
-
await (0,
|
|
9422
|
+
await (0, import_promises8.rm)(stagingDir, { force: true, recursive: true });
|
|
9250
9423
|
}
|
|
9251
9424
|
}
|
|
9252
9425
|
async function writeOvFileWithRetry(config, ov, uri, fromFile, initialMode) {
|
|
@@ -9304,7 +9477,7 @@ ${stdout}`.toLowerCase();
|
|
|
9304
9477
|
return output2.includes("resource is busy") || output2.includes("resource is being processed") || output2.includes("network error") || output2.includes("error sending request") || output2.includes("http request failed") || output2.includes("connection refused") || output2.includes("connection reset") || output2.includes("timed out");
|
|
9305
9478
|
}
|
|
9306
9479
|
async function ingestSingleFile(ov, config, uri, filePath, initialMode) {
|
|
9307
|
-
const content = await (0,
|
|
9480
|
+
const content = await (0, import_promises8.readFile)(filePath, "utf8");
|
|
9308
9481
|
await writeMemoryFile(config, ov, uri, content, initialMode, false);
|
|
9309
9482
|
}
|
|
9310
9483
|
async function removeWithRollback(config, ov, sourceUri, rollbackUri, worktree, dryRun, label) {
|
|
@@ -9346,7 +9519,7 @@ async function bestEffortRemoveWorktreeFile(rollbackUri, worktree, label) {
|
|
|
9346
9519
|
if (!relative3) {
|
|
9347
9520
|
return;
|
|
9348
9521
|
}
|
|
9349
|
-
await (0,
|
|
9522
|
+
await (0, import_promises8.rm)((0, import_node_path9.join)(worktree, relative3), { force: true });
|
|
9350
9523
|
}
|
|
9351
9524
|
async function removeMemoryUri(config, ov, uri, dryRun) {
|
|
9352
9525
|
const args = withIdentity(config, ["rm", uri]);
|
|
@@ -9403,8 +9576,8 @@ async function listChangedFiles(worktree, beforeRev, afterRev) {
|
|
|
9403
9576
|
const oldRel = entries[index + 1];
|
|
9404
9577
|
const newRel = entries[index + 2];
|
|
9405
9578
|
if (oldRel && newRel) {
|
|
9406
|
-
changes.push({ path: (0,
|
|
9407
|
-
changes.push({ path: (0,
|
|
9579
|
+
changes.push({ path: (0, import_node_path9.join)(worktree, oldRel), relativePath: oldRel, status: "removed" });
|
|
9580
|
+
changes.push({ path: (0, import_node_path9.join)(worktree, newRel), relativePath: newRel, status: "added" });
|
|
9408
9581
|
}
|
|
9409
9582
|
index += 3;
|
|
9410
9583
|
continue;
|
|
@@ -9412,7 +9585,7 @@ async function listChangedFiles(worktree, beforeRev, afterRev) {
|
|
|
9412
9585
|
const rel = entries[index + 1];
|
|
9413
9586
|
if (rel) {
|
|
9414
9587
|
const status = head === "A" ? "added" : head === "D" ? "removed" : "modified";
|
|
9415
|
-
changes.push({ path: (0,
|
|
9588
|
+
changes.push({ path: (0, import_node_path9.join)(worktree, rel), relativePath: rel, status });
|
|
9416
9589
|
}
|
|
9417
9590
|
index += 2;
|
|
9418
9591
|
}
|
|
@@ -9436,32 +9609,32 @@ async function applyChangesToOpenViking(config, team, changes) {
|
|
|
9436
9609
|
if (!await isFile(change.path)) {
|
|
9437
9610
|
continue;
|
|
9438
9611
|
}
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
);
|
|
9612
|
+
const ovHasResource = await vikingResourceExists2(ov, config, uri);
|
|
9613
|
+
if (ovHasResource) {
|
|
9614
|
+
const reason = change.status === "modified" ? "overwriting local with upstream (local edits to the shared subtree are not preserved across sync)" : "aligning OV to upstream (resource pre-existed in OV, likely from an earlier local publish or sync)";
|
|
9615
|
+
console.warn(`share sync: ${uri}: ${reason}.`);
|
|
9443
9616
|
}
|
|
9444
9617
|
await ensureSharedDirectoryChain(config, ov, uri, false);
|
|
9445
|
-
const writeMode =
|
|
9618
|
+
const writeMode = ovHasResource ? "replace" : "create";
|
|
9446
9619
|
await ingestSingleFile(ov, config, uri, change.path, writeMode);
|
|
9447
9620
|
}
|
|
9448
9621
|
}
|
|
9449
9622
|
|
|
9450
9623
|
// src/lifecycle.ts
|
|
9451
|
-
var
|
|
9452
|
-
var
|
|
9453
|
-
var
|
|
9624
|
+
var import_node_child_process3 = require("node:child_process");
|
|
9625
|
+
var import_node_fs6 = require("node:fs");
|
|
9626
|
+
var import_promises11 = require("node:fs/promises");
|
|
9454
9627
|
var import_node_os6 = require("node:os");
|
|
9455
|
-
var
|
|
9628
|
+
var import_node_path11 = require("node:path");
|
|
9456
9629
|
var import_node_process2 = require("node:process");
|
|
9457
|
-
var
|
|
9630
|
+
var import_promises12 = require("node:readline/promises");
|
|
9458
9631
|
|
|
9459
9632
|
// src/update.ts
|
|
9460
|
-
var
|
|
9461
|
-
var
|
|
9633
|
+
var import_node_fs5 = require("node:fs");
|
|
9634
|
+
var import_promises9 = require("node:fs/promises");
|
|
9462
9635
|
var import_node_os5 = require("node:os");
|
|
9463
|
-
var
|
|
9464
|
-
var
|
|
9636
|
+
var import_node_path10 = require("node:path");
|
|
9637
|
+
var import_promises10 = require("node:readline/promises");
|
|
9465
9638
|
var import_node_process = require("node:process");
|
|
9466
9639
|
var NPM_PACKAGE_NAME = "threadnote";
|
|
9467
9640
|
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
@@ -9509,7 +9682,7 @@ async function runUpdate(config, options) {
|
|
|
9509
9682
|
console.log(`Update available. Run: threadnote update`);
|
|
9510
9683
|
} else {
|
|
9511
9684
|
console.log(
|
|
9512
|
-
|
|
9685
|
+
compareVersions2(info.currentVersion, info.latestVersion) > 0 ? "Current version is newer than npm latest." : "Threadnote is up to date."
|
|
9513
9686
|
);
|
|
9514
9687
|
}
|
|
9515
9688
|
return;
|
|
@@ -9597,26 +9770,26 @@ async function maybeRunPostUpdateAfterRepair(config, options) {
|
|
|
9597
9770
|
async function getUpdateInfo(config, options) {
|
|
9598
9771
|
const currentVersion = await currentPackageVersion();
|
|
9599
9772
|
const cached = options.preferFresh ? void 0 : await readFreshCache(config, options.registry);
|
|
9600
|
-
const latestVersion = cached?.latestVersion ?? await
|
|
9773
|
+
const latestVersion = cached?.latestVersion ?? await fetchLatestVersion2(options.registry);
|
|
9601
9774
|
if (!cached && options.allowCacheWrite) {
|
|
9602
|
-
await
|
|
9775
|
+
await writeUpdateCache2(config, { checkedAt: (/* @__PURE__ */ new Date()).toISOString(), latestVersion, registry: options.registry });
|
|
9603
9776
|
}
|
|
9604
9777
|
return {
|
|
9605
9778
|
currentVersion,
|
|
9606
|
-
isUpdateAvailable:
|
|
9779
|
+
isUpdateAvailable: compareVersions2(currentVersion, latestVersion) < 0,
|
|
9607
9780
|
latestVersion,
|
|
9608
9781
|
registry: options.registry
|
|
9609
9782
|
};
|
|
9610
9783
|
}
|
|
9611
9784
|
async function currentPackageVersion() {
|
|
9612
|
-
const rawPackage = await (0,
|
|
9785
|
+
const rawPackage = await (0, import_promises9.readFile)((0, import_node_path10.join)(toolRoot(), "package.json"), "utf8");
|
|
9613
9786
|
const parsed = JSON.parse(rawPackage);
|
|
9614
9787
|
if (!isJsonObject(parsed) || typeof parsed.version !== "string") {
|
|
9615
9788
|
throw new Error("Could not read current threadnote package version.");
|
|
9616
9789
|
}
|
|
9617
9790
|
return parsed.version;
|
|
9618
9791
|
}
|
|
9619
|
-
async function
|
|
9792
|
+
async function fetchLatestVersion2(registry) {
|
|
9620
9793
|
const url = new URL(`${NPM_PACKAGE_NAME}/latest`, normalizeRegistry(registry));
|
|
9621
9794
|
const controller = new AbortController();
|
|
9622
9795
|
const timeout = setTimeout(() => {
|
|
@@ -9657,13 +9830,13 @@ async function readFreshCache(config, registry) {
|
|
|
9657
9830
|
return void 0;
|
|
9658
9831
|
}
|
|
9659
9832
|
}
|
|
9660
|
-
async function
|
|
9833
|
+
async function writeUpdateCache2(config, cache) {
|
|
9661
9834
|
await ensureDirectory(config.agentContextHome, false);
|
|
9662
|
-
await (0,
|
|
9835
|
+
await (0, import_promises9.writeFile)(updateCachePath(config), `${JSON.stringify(cache, null, 2)}
|
|
9663
9836
|
`, { encoding: "utf8", mode: 384 });
|
|
9664
9837
|
}
|
|
9665
9838
|
function updateCachePath(config) {
|
|
9666
|
-
return (0,
|
|
9839
|
+
return (0, import_node_path10.join)(config.agentContextHome, "update-check.json");
|
|
9667
9840
|
}
|
|
9668
9841
|
async function runApplicablePostUpdateMigrations(config, options) {
|
|
9669
9842
|
const state = await readPostUpdateState(config);
|
|
@@ -9713,10 +9886,10 @@ async function applicablePostUpdateMigrations(config, options) {
|
|
|
9713
9886
|
if (handled.has(migration.id)) {
|
|
9714
9887
|
continue;
|
|
9715
9888
|
}
|
|
9716
|
-
if (
|
|
9889
|
+
if (compareVersions2(options.fromVersion, migration.introducedIn) >= 0) {
|
|
9717
9890
|
continue;
|
|
9718
9891
|
}
|
|
9719
|
-
if (
|
|
9892
|
+
if (compareVersions2(migration.introducedIn, options.toVersion) > 0) {
|
|
9720
9893
|
continue;
|
|
9721
9894
|
}
|
|
9722
9895
|
if (migration.requiresLegacyHandoffs === true && !await hasLegacyLifecycleHandoffCandidates(config)) {
|
|
@@ -9727,7 +9900,7 @@ async function applicablePostUpdateMigrations(config, options) {
|
|
|
9727
9900
|
return applicable;
|
|
9728
9901
|
}
|
|
9729
9902
|
async function readPostUpdateMigrations() {
|
|
9730
|
-
const raw = await readFileIfExists((0,
|
|
9903
|
+
const raw = await readFileIfExists((0, import_node_path10.join)(toolRoot(), "config", POST_UPDATE_MIGRATIONS_FILE));
|
|
9731
9904
|
if (!raw) {
|
|
9732
9905
|
return [];
|
|
9733
9906
|
}
|
|
@@ -9766,7 +9939,7 @@ function printPostUpdateMigration(migration) {
|
|
|
9766
9939
|
}
|
|
9767
9940
|
}
|
|
9768
9941
|
async function confirmPostUpdateMigration(prompt) {
|
|
9769
|
-
const readline = (0,
|
|
9942
|
+
const readline = (0, import_promises10.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
9770
9943
|
try {
|
|
9771
9944
|
const answer = (await readline.question(prompt)).trim().toLowerCase();
|
|
9772
9945
|
return answer === "y" || answer === "yes";
|
|
@@ -9798,11 +9971,11 @@ async function readPostUpdateState(config) {
|
|
|
9798
9971
|
}
|
|
9799
9972
|
async function writePostUpdateState(config, state) {
|
|
9800
9973
|
await ensureDirectory(config.agentContextHome, false);
|
|
9801
|
-
await (0,
|
|
9974
|
+
await (0, import_promises9.writeFile)(postUpdateStatePath(config), `${JSON.stringify(state, null, 2)}
|
|
9802
9975
|
`, { encoding: "utf8", mode: 384 });
|
|
9803
9976
|
}
|
|
9804
9977
|
function postUpdateStatePath(config) {
|
|
9805
|
-
return (0,
|
|
9978
|
+
return (0, import_node_path10.join)(config.agentContextHome, POST_UPDATE_STATE_FILE);
|
|
9806
9979
|
}
|
|
9807
9980
|
async function resolveUpdateRuntime(runtime) {
|
|
9808
9981
|
if (runtime !== "auto") {
|
|
@@ -9832,18 +10005,18 @@ async function runtimeThreadnoteBin(runtime) {
|
|
|
9832
10005
|
if (runtime === "npm") {
|
|
9833
10006
|
const result = await runCommand("npm", ["prefix", "--global"], { allowFailure: true });
|
|
9834
10007
|
const prefix = result.stdout.trim();
|
|
9835
|
-
return prefix ? (0,
|
|
10008
|
+
return prefix ? (0, import_node_path10.join)(prefix, "bin", NPM_PACKAGE_NAME) : void 0;
|
|
9836
10009
|
}
|
|
9837
10010
|
if (runtime === "bun") {
|
|
9838
10011
|
const result = await runCommand("bun", ["pm", "bin", "-g"], { allowFailure: true });
|
|
9839
10012
|
const binDir = result.stdout.trim();
|
|
9840
|
-
return binDir ? (0,
|
|
10013
|
+
return binDir ? (0, import_node_path10.join)(binDir, NPM_PACKAGE_NAME) : void 0;
|
|
9841
10014
|
}
|
|
9842
|
-
return (0,
|
|
10015
|
+
return (0, import_node_path10.join)(process.env.DENO_INSTALL ?? (0, import_node_path10.join)((0, import_node_os5.homedir)(), ".deno"), "bin", NPM_PACKAGE_NAME);
|
|
9843
10016
|
}
|
|
9844
10017
|
async function isExecutable(path) {
|
|
9845
10018
|
try {
|
|
9846
|
-
await (0,
|
|
10019
|
+
await (0, import_promises9.access)(path, import_node_fs5.constants.X_OK);
|
|
9847
10020
|
return true;
|
|
9848
10021
|
} catch (_err) {
|
|
9849
10022
|
return false;
|
|
@@ -9884,9 +10057,9 @@ function updateRegistry() {
|
|
|
9884
10057
|
function isUpdateNotificationDisabled() {
|
|
9885
10058
|
return process.env.CI !== void 0 || process.env.NO_UPDATE_NOTIFIER !== void 0 || process.env.THREADNOTE_NO_UPDATE_CHECK !== void 0;
|
|
9886
10059
|
}
|
|
9887
|
-
function
|
|
9888
|
-
const current =
|
|
9889
|
-
const latest =
|
|
10060
|
+
function compareVersions2(currentVersion, latestVersion) {
|
|
10061
|
+
const current = parseVersion2(currentVersion);
|
|
10062
|
+
const latest = parseVersion2(latestVersion);
|
|
9890
10063
|
for (let index = 0; index < 3; index += 1) {
|
|
9891
10064
|
const difference = current.numbers[index] - latest.numbers[index];
|
|
9892
10065
|
if (difference !== 0) {
|
|
@@ -9904,7 +10077,7 @@ function compareVersions(currentVersion, latestVersion) {
|
|
|
9904
10077
|
}
|
|
9905
10078
|
return current.prerelease.localeCompare(latest.prerelease);
|
|
9906
10079
|
}
|
|
9907
|
-
function
|
|
10080
|
+
function parseVersion2(version) {
|
|
9908
10081
|
const normalized = version.trim().replace(/^v/, "");
|
|
9909
10082
|
const [core2, prerelease] = normalized.split("-", 2);
|
|
9910
10083
|
const parts = core2.split(".").map((part) => Number(part));
|
|
@@ -9934,9 +10107,9 @@ async function runDoctor(config, options) {
|
|
|
9934
10107
|
checks.push(await commandShimCheck());
|
|
9935
10108
|
checks.push(...await userAgentInstructionsChecks());
|
|
9936
10109
|
checks.push(await manifestCheck(config.manifestPath));
|
|
9937
|
-
checks.push(await fileCheck((0,
|
|
9938
|
-
checks.push(await fileCheck((0,
|
|
9939
|
-
checks.push(await fileCheck((0,
|
|
10110
|
+
checks.push(await fileCheck((0, import_node_path11.join)(toolRoot(), ".threadnoteignore"), "ignore file"));
|
|
10111
|
+
checks.push(await fileCheck((0, import_node_path11.join)(toolRoot(), "config", "ov.conf.template.json"), "server config template"));
|
|
10112
|
+
checks.push(await fileCheck((0, import_node_path11.join)(toolRoot(), "config", "ovcli.conf.template.json"), "cli config template"));
|
|
9940
10113
|
checks.push(await healthCheck(config));
|
|
9941
10114
|
for (const check of checks) {
|
|
9942
10115
|
console.log(`${formatStatus(check.status)} ${check.name}: ${check.detail}`);
|
|
@@ -9953,9 +10126,9 @@ async function runInstall(config, options) {
|
|
|
9953
10126
|
const repairInvalidConfigs = options.repairInvalidConfigs === true;
|
|
9954
10127
|
const dryRun = options.dryRun === true;
|
|
9955
10128
|
await ensureDirectory(config.agentContextHome, dryRun);
|
|
9956
|
-
await ensureDirectory((0,
|
|
9957
|
-
await ensureDirectory((0,
|
|
9958
|
-
await ensureDirectory((0,
|
|
10129
|
+
await ensureDirectory((0, import_node_path11.join)(config.agentContextHome, "logs"), dryRun);
|
|
10130
|
+
await ensureDirectory((0, import_node_path11.join)(config.agentContextHome, "redacted"), dryRun);
|
|
10131
|
+
await ensureDirectory((0, import_node_path11.join)(config.agentContextHome, "mcp"), dryRun);
|
|
9959
10132
|
await installCommandShim(dryRun);
|
|
9960
10133
|
await installUserAgentInstructions(dryRun);
|
|
9961
10134
|
const serverPath = await findExecutable([OPENVIKING_SERVER_COMMAND]);
|
|
@@ -9981,17 +10154,17 @@ async function runInstall(config, options) {
|
|
|
9981
10154
|
}
|
|
9982
10155
|
await writeTemplateIfMissing({
|
|
9983
10156
|
config,
|
|
9984
|
-
destinationPath: (0,
|
|
10157
|
+
destinationPath: (0, import_node_path11.join)(config.agentContextHome, "ov.conf"),
|
|
9985
10158
|
dryRun,
|
|
9986
10159
|
shouldRepair: (content) => shouldRepairOpenVikingConfig(content, config) || repairInvalidConfigs && parseJsonConfigObject(content) === void 0,
|
|
9987
|
-
templatePath: (0,
|
|
10160
|
+
templatePath: (0, import_node_path11.join)(toolRoot(), "config", "ov.conf.template.json")
|
|
9988
10161
|
});
|
|
9989
10162
|
await writeTemplateIfMissing({
|
|
9990
10163
|
config,
|
|
9991
|
-
destinationPath: (0,
|
|
10164
|
+
destinationPath: (0, import_node_path11.join)(config.agentContextHome, "ovcli.conf"),
|
|
9992
10165
|
dryRun,
|
|
9993
10166
|
shouldRepair: (content) => shouldRepairLegacyOvCliConfig(content) || repairInvalidConfigs && parseJsonConfigObject(content) === void 0,
|
|
9994
|
-
templatePath: (0,
|
|
10167
|
+
templatePath: (0, import_node_path11.join)(toolRoot(), "config", "ovcli.conf.template.json")
|
|
9995
10168
|
});
|
|
9996
10169
|
if (options.start !== false) {
|
|
9997
10170
|
const healthy = await repairServerHealth(config, dryRun);
|
|
@@ -10045,7 +10218,7 @@ async function runUninstall(config, options) {
|
|
|
10045
10218
|
}
|
|
10046
10219
|
console.log("Uninstalling local Threadnote setup.");
|
|
10047
10220
|
await runStop(config, { dryRun });
|
|
10048
|
-
await removePathIfExists((0,
|
|
10221
|
+
await removePathIfExists((0, import_node_path11.join)(config.agentContextHome, "openviking-server.pid"), "pid file", dryRun);
|
|
10049
10222
|
await removeLaunchAgent(dryRun);
|
|
10050
10223
|
await removeMcpConfigs(options.mcp ?? "available", dryRun);
|
|
10051
10224
|
await removeMcpSnippets(config, dryRun);
|
|
@@ -10102,16 +10275,16 @@ async function repairManifest(config, dryRun) {
|
|
|
10102
10275
|
console.log(output2.trimEnd());
|
|
10103
10276
|
return;
|
|
10104
10277
|
}
|
|
10105
|
-
await ensureDirectory((0,
|
|
10278
|
+
await ensureDirectory((0, import_node_path11.dirname)(config.manifestPath), false);
|
|
10106
10279
|
const currentContent = await readFileIfExists(config.manifestPath);
|
|
10107
10280
|
if (currentContent !== void 0) {
|
|
10108
10281
|
const backupPath = `${config.manifestPath}.legacy-${safeTimestamp()}`;
|
|
10109
|
-
await (0,
|
|
10110
|
-
await (0,
|
|
10282
|
+
await (0, import_promises11.writeFile)(backupPath, currentContent, { encoding: "utf8", mode: 384 });
|
|
10283
|
+
await (0, import_promises11.chmod)(backupPath, 384);
|
|
10111
10284
|
console.log(`Backup: ${backupPath}`);
|
|
10112
10285
|
}
|
|
10113
|
-
await (0,
|
|
10114
|
-
await (0,
|
|
10286
|
+
await (0, import_promises11.writeFile)(config.manifestPath, output2, { encoding: "utf8", mode: 384 });
|
|
10287
|
+
await (0, import_promises11.chmod)(config.manifestPath, 384);
|
|
10115
10288
|
console.log(`Wrote replacement manifest: ${config.manifestPath}`);
|
|
10116
10289
|
}
|
|
10117
10290
|
async function repairServerHealth(config, dryRun) {
|
|
@@ -10152,16 +10325,16 @@ async function runStart(config, options) {
|
|
|
10152
10325
|
);
|
|
10153
10326
|
}
|
|
10154
10327
|
const logPath = openVikingLogPath(config);
|
|
10155
|
-
await ensureDirectory((0,
|
|
10328
|
+
await ensureDirectory((0, import_node_path11.dirname)(logPath), false);
|
|
10156
10329
|
if (options.foreground === true) {
|
|
10157
10330
|
const result = await runInteractive(server, args);
|
|
10158
10331
|
process.exitCode = result;
|
|
10159
10332
|
return;
|
|
10160
10333
|
}
|
|
10161
|
-
const logFd = (0,
|
|
10334
|
+
const logFd = (0, import_node_fs6.openSync)(logPath, "a");
|
|
10162
10335
|
const child = spawnDetachedServerWithLog(server, args, logFd);
|
|
10163
10336
|
child.unref();
|
|
10164
|
-
await (0,
|
|
10337
|
+
await (0, import_promises11.writeFile)((0, import_node_path11.join)(config.agentContextHome, "openviking-server.pid"), `${child.pid}
|
|
10165
10338
|
`, "utf8");
|
|
10166
10339
|
const health = await waitForOpenVikingHealth(config, START_HEALTH_TIMEOUT_MS);
|
|
10167
10340
|
if (health) {
|
|
@@ -10176,11 +10349,11 @@ function spawnDetachedServerWithLog(server, args, logFd) {
|
|
|
10176
10349
|
try {
|
|
10177
10350
|
return spawnDetachedServer(server, args, logFd);
|
|
10178
10351
|
} finally {
|
|
10179
|
-
(0,
|
|
10352
|
+
(0, import_node_fs6.closeSync)(logFd);
|
|
10180
10353
|
}
|
|
10181
10354
|
}
|
|
10182
10355
|
function spawnDetachedServer(server, args, logFd) {
|
|
10183
|
-
return (0,
|
|
10356
|
+
return (0, import_node_child_process3.spawn)(server, args, {
|
|
10184
10357
|
detached: true,
|
|
10185
10358
|
stdio: ["ignore", logFd, logFd]
|
|
10186
10359
|
});
|
|
@@ -10194,7 +10367,7 @@ async function runStop(config, options) {
|
|
|
10194
10367
|
console.log(`No LaunchAgent found: ${launchAgentPath}`);
|
|
10195
10368
|
}
|
|
10196
10369
|
}
|
|
10197
|
-
const pidPath = (0,
|
|
10370
|
+
const pidPath = (0, import_node_path11.join)(config.agentContextHome, "openviking-server.pid");
|
|
10198
10371
|
const pidText = await readFileIfExists(pidPath);
|
|
10199
10372
|
if (!pidText) {
|
|
10200
10373
|
console.log("No pid file found for detached OpenViking server.");
|
|
@@ -10290,7 +10463,7 @@ async function pythonSystemCertificatesCheck() {
|
|
|
10290
10463
|
};
|
|
10291
10464
|
}
|
|
10292
10465
|
async function commandShimCheck() {
|
|
10293
|
-
const shimPath = (0,
|
|
10466
|
+
const shimPath = (0, import_node_path11.join)(expandPath(process.env.THREADNOTE_BIN_DIR ?? "~/.local/bin"), "threadnote");
|
|
10294
10467
|
const content = await readFileIfExists(shimPath);
|
|
10295
10468
|
if (content === void 0) {
|
|
10296
10469
|
return { name: "threadnote shim", status: "warn", detail: `${shimPath} missing; repair will create it` };
|
|
@@ -10356,11 +10529,11 @@ async function hasPythonModule(serverPath, moduleName) {
|
|
|
10356
10529
|
async function siblingPythonForExecutable(executablePath) {
|
|
10357
10530
|
let resolvedPath;
|
|
10358
10531
|
try {
|
|
10359
|
-
resolvedPath = await (0,
|
|
10532
|
+
resolvedPath = await (0, import_promises11.realpath)(executablePath);
|
|
10360
10533
|
} catch (_err) {
|
|
10361
10534
|
return void 0;
|
|
10362
10535
|
}
|
|
10363
|
-
const pythonPath = (0,
|
|
10536
|
+
const pythonPath = (0, import_node_path11.join)((0, import_node_path11.dirname)(resolvedPath), "python");
|
|
10364
10537
|
return await exists(pythonPath) ? pythonPath : void 0;
|
|
10365
10538
|
}
|
|
10366
10539
|
async function manifestCheck(path) {
|
|
@@ -10431,7 +10604,7 @@ async function offerToInstallUv() {
|
|
|
10431
10604
|
);
|
|
10432
10605
|
return false;
|
|
10433
10606
|
}
|
|
10434
|
-
const readline = (0,
|
|
10607
|
+
const readline = (0, import_promises12.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
|
|
10435
10608
|
let answer;
|
|
10436
10609
|
try {
|
|
10437
10610
|
answer = (await readline.question(
|
|
@@ -10554,38 +10727,38 @@ function printInstallNextSteps(options) {
|
|
|
10554
10727
|
}
|
|
10555
10728
|
async function writeTemplateIfMissing(options) {
|
|
10556
10729
|
if (await exists(options.destinationPath)) {
|
|
10557
|
-
const currentContent = await (0,
|
|
10730
|
+
const currentContent = await (0, import_promises11.readFile)(options.destinationPath, "utf8");
|
|
10558
10731
|
if (options.shouldRepair?.(currentContent) !== true) {
|
|
10559
10732
|
console.log(`Already exists: ${options.destinationPath}`);
|
|
10560
10733
|
return;
|
|
10561
10734
|
}
|
|
10562
|
-
const rendered2 = renderTemplate(await (0,
|
|
10735
|
+
const rendered2 = renderTemplate(await (0, import_promises11.readFile)(options.templatePath, "utf8"), options.config);
|
|
10563
10736
|
if (options.dryRun) {
|
|
10564
10737
|
console.log(`Would repair generated config: ${options.destinationPath}`);
|
|
10565
10738
|
return;
|
|
10566
10739
|
}
|
|
10567
10740
|
const backupPath = `${options.destinationPath}.legacy-${safeTimestamp()}`;
|
|
10568
|
-
await (0,
|
|
10569
|
-
await (0,
|
|
10570
|
-
await (0,
|
|
10571
|
-
await (0,
|
|
10741
|
+
await (0, import_promises11.writeFile)(backupPath, currentContent, { encoding: "utf8", mode: 384 });
|
|
10742
|
+
await (0, import_promises11.chmod)(backupPath, 384);
|
|
10743
|
+
await (0, import_promises11.writeFile)(options.destinationPath, rendered2, { encoding: "utf8", mode: 384 });
|
|
10744
|
+
await (0, import_promises11.chmod)(options.destinationPath, 384);
|
|
10572
10745
|
console.log(`Repaired generated config: ${options.destinationPath}`);
|
|
10573
10746
|
console.log(`Backup: ${backupPath}`);
|
|
10574
10747
|
return;
|
|
10575
10748
|
}
|
|
10576
|
-
const rendered = renderTemplate(await (0,
|
|
10749
|
+
const rendered = renderTemplate(await (0, import_promises11.readFile)(options.templatePath, "utf8"), options.config);
|
|
10577
10750
|
if (options.dryRun) {
|
|
10578
10751
|
console.log(`Would write ${options.destinationPath}`);
|
|
10579
10752
|
return;
|
|
10580
10753
|
}
|
|
10581
|
-
await ensureDirectory((0,
|
|
10582
|
-
await (0,
|
|
10583
|
-
await (0,
|
|
10754
|
+
await ensureDirectory((0, import_node_path11.dirname)(options.destinationPath), false);
|
|
10755
|
+
await (0, import_promises11.writeFile)(options.destinationPath, rendered, { encoding: "utf8", mode: 384 });
|
|
10756
|
+
await (0, import_promises11.chmod)(options.destinationPath, 384);
|
|
10584
10757
|
console.log(`Wrote ${options.destinationPath}`);
|
|
10585
10758
|
}
|
|
10586
10759
|
async function installCommandShim(dryRun) {
|
|
10587
10760
|
const binDir = expandPath(process.env.THREADNOTE_BIN_DIR ?? "~/.local/bin");
|
|
10588
|
-
const shimPath = (0,
|
|
10761
|
+
const shimPath = (0, import_node_path11.join)(binDir, "threadnote");
|
|
10589
10762
|
const existingContent = await readFileIfExists(shimPath);
|
|
10590
10763
|
if (existingContent && !isManagedCommandShim(existingContent)) {
|
|
10591
10764
|
console.log(`WARN not overwriting existing command shim: ${shimPath}`);
|
|
@@ -10601,12 +10774,12 @@ async function installCommandShim(dryRun) {
|
|
|
10601
10774
|
return;
|
|
10602
10775
|
}
|
|
10603
10776
|
await ensureDirectory(binDir, false);
|
|
10604
|
-
await (0,
|
|
10605
|
-
await (0,
|
|
10777
|
+
await (0, import_promises11.writeFile)(shimPath, content, { encoding: "utf8", mode: 493 });
|
|
10778
|
+
await (0, import_promises11.chmod)(shimPath, 493);
|
|
10606
10779
|
console.log(`Wrote command shim: ${shimPath}`);
|
|
10607
10780
|
}
|
|
10608
10781
|
async function removeCommandShim(dryRun) {
|
|
10609
|
-
const shimPath = (0,
|
|
10782
|
+
const shimPath = (0, import_node_path11.join)(expandPath(process.env.THREADNOTE_BIN_DIR ?? "~/.local/bin"), "threadnote");
|
|
10610
10783
|
const content = await readFileIfExists(shimPath);
|
|
10611
10784
|
if (content === void 0) {
|
|
10612
10785
|
console.log(`Already absent: ${shimPath}`);
|
|
@@ -10640,8 +10813,8 @@ async function installUserAgentInstructions(dryRun) {
|
|
|
10640
10813
|
console.log(currentContent === void 0 ? `Would write ${targetPath}` : `Would update ${targetPath}`);
|
|
10641
10814
|
continue;
|
|
10642
10815
|
}
|
|
10643
|
-
await ensureDirectory((0,
|
|
10644
|
-
await (0,
|
|
10816
|
+
await ensureDirectory((0, import_node_path11.dirname)(targetPath), false);
|
|
10817
|
+
await (0, import_promises11.writeFile)(targetPath, nextContent, { encoding: "utf8", mode: 420 });
|
|
10645
10818
|
console.log(currentContent === void 0 ? `Wrote ${targetPath}` : `Updated ${targetPath}`);
|
|
10646
10819
|
}
|
|
10647
10820
|
}
|
|
@@ -10678,7 +10851,7 @@ async function removeUserAgentInstructions(dryRun) {
|
|
|
10678
10851
|
console.log(`Would update ${targetPath}`);
|
|
10679
10852
|
continue;
|
|
10680
10853
|
}
|
|
10681
|
-
await (0,
|
|
10854
|
+
await (0, import_promises11.writeFile)(targetPath, nextContent, { encoding: "utf8", mode: 420 });
|
|
10682
10855
|
console.log(`Updated ${targetPath}`);
|
|
10683
10856
|
}
|
|
10684
10857
|
}
|
|
@@ -10698,7 +10871,7 @@ async function renderUserAgentInstructions(target) {
|
|
|
10698
10871
|
].join("\n");
|
|
10699
10872
|
}
|
|
10700
10873
|
async function renderUserAgentInstructionsBlock() {
|
|
10701
|
-
const instructions = (await (0,
|
|
10874
|
+
const instructions = (await (0, import_promises11.readFile)((0, import_node_path11.join)(toolRoot(), "docs", "agent-instructions.md"), "utf8")).trim();
|
|
10702
10875
|
return `${USER_INSTRUCTIONS_START_MARKER}
|
|
10703
10876
|
${instructions}
|
|
10704
10877
|
${USER_INSTRUCTIONS_END_MARKER}`;
|
|
@@ -10776,9 +10949,9 @@ async function installLaunchAgent(config, dryRun) {
|
|
|
10776
10949
|
if ((0, import_node_os6.platform)() !== "darwin") {
|
|
10777
10950
|
throw new Error("launchd autostart is only supported on macOS.");
|
|
10778
10951
|
}
|
|
10779
|
-
const source = (0,
|
|
10952
|
+
const source = (0, import_node_path11.join)(toolRoot(), "config", "launchd", `${LAUNCHD_LABEL}.plist.template`);
|
|
10780
10953
|
const destination = expandPath(`~/Library/LaunchAgents/${LAUNCHD_LABEL}.plist`);
|
|
10781
|
-
const rendered = renderTemplate(await (0,
|
|
10954
|
+
const rendered = renderTemplate(await (0, import_promises11.readFile)(source, "utf8"), config);
|
|
10782
10955
|
if (dryRun) {
|
|
10783
10956
|
console.log(`Would write ${destination}`);
|
|
10784
10957
|
console.log(`Would run: launchctl unload ${destination}`);
|
|
@@ -10786,9 +10959,9 @@ async function installLaunchAgent(config, dryRun) {
|
|
|
10786
10959
|
console.log(`Would run: launchctl start ${LAUNCHD_LABEL}`);
|
|
10787
10960
|
return;
|
|
10788
10961
|
}
|
|
10789
|
-
await ensureDirectory((0,
|
|
10790
|
-
await ensureDirectory((0,
|
|
10791
|
-
await (0,
|
|
10962
|
+
await ensureDirectory((0, import_node_path11.dirname)(destination), false);
|
|
10963
|
+
await ensureDirectory((0, import_node_path11.dirname)(openVikingLogPath(config)), false);
|
|
10964
|
+
await (0, import_promises11.writeFile)(destination, rendered, "utf8");
|
|
10792
10965
|
await maybeRun(false, "launchctl", ["unload", destination], { allowFailure: true });
|
|
10793
10966
|
await maybeRun(false, "launchctl", ["load", destination]);
|
|
10794
10967
|
await maybeRun(false, "launchctl", ["start", LAUNCHD_LABEL]);
|
|
@@ -10851,7 +11024,7 @@ function isGeneratedLocalPilotConfig(parsed, config) {
|
|
|
10851
11024
|
if (typeof parsed.default_user !== "string") {
|
|
10852
11025
|
return false;
|
|
10853
11026
|
}
|
|
10854
|
-
if (!isJsonObject(parsed.storage) || parsed.storage.workspace !== (0,
|
|
11027
|
+
if (!isJsonObject(parsed.storage) || parsed.storage.workspace !== (0, import_node_path11.join)(config.agentContextHome, "data")) {
|
|
10855
11028
|
return false;
|
|
10856
11029
|
}
|
|
10857
11030
|
return isJsonObject(parsed.server) && parsed.server.host === config.host && String(parsed.server.port) === String(config.port);
|