threadnote 0.7.4 → 0.7.5
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.
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<string>io.threadnote.openviking</string>
|
|
7
7
|
<key>ProgramArguments</key>
|
|
8
8
|
<array>
|
|
9
|
-
<string>
|
|
9
|
+
<string>{{OPENVIKING_SERVER_PATH}}</string>
|
|
10
10
|
<string>--config</string>
|
|
11
11
|
<string>{{THREADNOTE_HOME}}/ov.conf</string>
|
|
12
12
|
<string>--host</string>
|
package/dist/threadnote.cjs
CHANGED
|
@@ -3850,6 +3850,27 @@ async function exists(path) {
|
|
|
3850
3850
|
return false;
|
|
3851
3851
|
}
|
|
3852
3852
|
}
|
|
3853
|
+
async function isExecutable(path) {
|
|
3854
|
+
try {
|
|
3855
|
+
await (0, import_promises.access)(path, import_node_fs.constants.X_OK);
|
|
3856
|
+
return true;
|
|
3857
|
+
} catch (_err) {
|
|
3858
|
+
return false;
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
function suggestedShellRc(shellPath, currentPlatform) {
|
|
3862
|
+
const shell = shellPath ?? "";
|
|
3863
|
+
if (shell.endsWith("/zsh")) {
|
|
3864
|
+
return "~/.zshrc";
|
|
3865
|
+
}
|
|
3866
|
+
if (shell.endsWith("/bash")) {
|
|
3867
|
+
return currentPlatform === "darwin" ? "~/.bash_profile" : "~/.bashrc";
|
|
3868
|
+
}
|
|
3869
|
+
if (shell.endsWith("/fish")) {
|
|
3870
|
+
return "~/.config/fish/config.fish";
|
|
3871
|
+
}
|
|
3872
|
+
return "your shell rc";
|
|
3873
|
+
}
|
|
3853
3874
|
async function isFile(path) {
|
|
3854
3875
|
try {
|
|
3855
3876
|
return (await (0, import_promises.stat)(path)).isFile();
|
|
@@ -7258,8 +7279,12 @@ function openVikingServerArgs(config) {
|
|
|
7258
7279
|
function withIdentity(config, args) {
|
|
7259
7280
|
return [...args, "--account", config.account, "--user", config.user, "--agent-id", config.agentId];
|
|
7260
7281
|
}
|
|
7261
|
-
function renderTemplate(template, config) {
|
|
7262
|
-
|
|
7282
|
+
function renderTemplate(template, config, extras = {}) {
|
|
7283
|
+
let rendered = template.replaceAll("{{THREADNOTE_HOME}}", config.agentContextHome).replaceAll("{{OPENVIKING_ACCOUNT}}", config.account).replaceAll("{{OPENVIKING_AGENT_ID}}", config.agentId).replaceAll("{{OPENVIKING_HOST}}", config.host).replaceAll("{{OPENVIKING_PORT}}", String(config.port)).replaceAll("{{OPENVIKING_USER}}", config.user);
|
|
7284
|
+
for (const [key, value] of Object.entries(extras)) {
|
|
7285
|
+
rendered = rendered.replaceAll(`{{${key}}}`, () => value);
|
|
7286
|
+
}
|
|
7287
|
+
return rendered;
|
|
7263
7288
|
}
|
|
7264
7289
|
|
|
7265
7290
|
// src/share.ts
|
|
@@ -10513,14 +10538,6 @@ async function runtimeThreadnoteBin(runtime) {
|
|
|
10513
10538
|
}
|
|
10514
10539
|
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);
|
|
10515
10540
|
}
|
|
10516
|
-
async function isExecutable(path) {
|
|
10517
|
-
try {
|
|
10518
|
-
await (0, import_promises9.access)(path, import_node_fs5.constants.X_OK);
|
|
10519
|
-
return true;
|
|
10520
|
-
} catch (_err) {
|
|
10521
|
-
return false;
|
|
10522
|
-
}
|
|
10523
|
-
}
|
|
10524
10541
|
function updatePackageCommand(runtime, registry) {
|
|
10525
10542
|
if (runtime === "npm") {
|
|
10526
10543
|
return { executable: "npm", args: ["install", "--global", `${NPM_PACKAGE_NAME}@latest`, `--registry=${registry}`] };
|
|
@@ -10564,7 +10581,7 @@ async function runDoctor(config, options) {
|
|
|
10564
10581
|
checks.push({ name: "platform", status: (0, import_node_os6.platform)() === "darwin" ? "ok" : "warn", detail: (0, import_node_os6.platform)() });
|
|
10565
10582
|
checks.push(await commandCheck("node", ["--version"]));
|
|
10566
10583
|
checks.push(await commandCheck("python3", ["--version"]));
|
|
10567
|
-
checks.push(await
|
|
10584
|
+
checks.push(await openVikingServerCheck());
|
|
10568
10585
|
checks.push(await firstCommandCheck("openviking cli", ["ov", "openviking"], ["--help"]));
|
|
10569
10586
|
checks.push(await localEmbeddingCheck());
|
|
10570
10587
|
checks.push(await pythonSystemCertificatesCheck());
|
|
@@ -10598,7 +10615,8 @@ async function runInstall(config, options) {
|
|
|
10598
10615
|
await ensureDirectory((0, import_node_path11.join)(config.agentContextHome, "mcp"), dryRun);
|
|
10599
10616
|
await installCommandShim(dryRun);
|
|
10600
10617
|
await installUserAgentInstructions(dryRun);
|
|
10601
|
-
const serverPath = await
|
|
10618
|
+
const serverPath = await findOpenVikingServer();
|
|
10619
|
+
let serverInstallRan = false;
|
|
10602
10620
|
if (serverPath) {
|
|
10603
10621
|
console.log(`OpenViking server already installed: ${serverPath}`);
|
|
10604
10622
|
const localEmbeddingMissing = await hasLocalEmbeddingDependency(serverPath) === false;
|
|
@@ -10606,6 +10624,7 @@ async function runInstall(config, options) {
|
|
|
10606
10624
|
if (options.force === true) {
|
|
10607
10625
|
console.log(`Reinstalling OpenViking at pinned version ${config.openVikingVersion} (--force).`);
|
|
10608
10626
|
await runInstallCommands(config, options.packageManager, true, dryRun);
|
|
10627
|
+
serverInstallRan = true;
|
|
10609
10628
|
} else if (localEmbeddingMissing) {
|
|
10610
10629
|
const repairReasons = [];
|
|
10611
10630
|
repairReasons.push("local embedding extra is missing");
|
|
@@ -10614,6 +10633,7 @@ async function runInstall(config, options) {
|
|
|
10614
10633
|
}
|
|
10615
10634
|
console.log(`OpenViking install needs repair: ${repairReasons.join("; ")}.`);
|
|
10616
10635
|
await runInstallCommands(config, options.packageManager, true, dryRun);
|
|
10636
|
+
serverInstallRan = true;
|
|
10617
10637
|
} else if (pythonSystemCertificatesMissing) {
|
|
10618
10638
|
console.log("OpenViking install needs repair: Python system certificate bridge is missing.");
|
|
10619
10639
|
const installCommand = await getPythonSystemCertificatesInstallCommand(serverPath);
|
|
@@ -10621,6 +10641,11 @@ async function runInstall(config, options) {
|
|
|
10621
10641
|
}
|
|
10622
10642
|
} else {
|
|
10623
10643
|
await runInstallCommands(config, options.packageManager, false, dryRun);
|
|
10644
|
+
serverInstallRan = true;
|
|
10645
|
+
}
|
|
10646
|
+
const resolvedServerPath = serverInstallRan ? await findOpenVikingServer() : serverPath;
|
|
10647
|
+
if (resolvedServerPath && !dryRun) {
|
|
10648
|
+
await maybePrintOpenVikingPathHint(resolvedServerPath);
|
|
10624
10649
|
}
|
|
10625
10650
|
await writeTemplateIfMissing({
|
|
10626
10651
|
config,
|
|
@@ -10757,6 +10782,64 @@ async function repairManifest(config, dryRun) {
|
|
|
10757
10782
|
await (0, import_promises11.chmod)(config.manifestPath, 384);
|
|
10758
10783
|
console.log(`Wrote replacement manifest: ${config.manifestPath}`);
|
|
10759
10784
|
}
|
|
10785
|
+
async function findOpenVikingServer() {
|
|
10786
|
+
const onPath = await findExecutable([OPENVIKING_SERVER_COMMAND]);
|
|
10787
|
+
if (onPath) {
|
|
10788
|
+
return onPath;
|
|
10789
|
+
}
|
|
10790
|
+
for (const candidateDir of await openVikingServerCandidateDirs()) {
|
|
10791
|
+
const candidate = (0, import_node_path11.join)(candidateDir, OPENVIKING_SERVER_COMMAND);
|
|
10792
|
+
if (await isExecutable(candidate)) {
|
|
10793
|
+
return candidate;
|
|
10794
|
+
}
|
|
10795
|
+
}
|
|
10796
|
+
return void 0;
|
|
10797
|
+
}
|
|
10798
|
+
var candidateDirsPromise;
|
|
10799
|
+
async function openVikingServerCandidateDirs() {
|
|
10800
|
+
if (!candidateDirsPromise) {
|
|
10801
|
+
candidateDirsPromise = computeOpenVikingServerCandidateDirs();
|
|
10802
|
+
}
|
|
10803
|
+
return candidateDirsPromise;
|
|
10804
|
+
}
|
|
10805
|
+
async function computeOpenVikingServerCandidateDirs() {
|
|
10806
|
+
const dirs = [];
|
|
10807
|
+
const uv = await findExecutable(["uv"]);
|
|
10808
|
+
if (uv) {
|
|
10809
|
+
const result = await runCommand(uv, ["tool", "dir", "--bin"], { allowFailure: true });
|
|
10810
|
+
if (result.exitCode === 0) {
|
|
10811
|
+
const dir = result.stdout.trim();
|
|
10812
|
+
if (dir) {
|
|
10813
|
+
dirs.push(dir);
|
|
10814
|
+
}
|
|
10815
|
+
}
|
|
10816
|
+
}
|
|
10817
|
+
if (process.env.UV_TOOL_BIN_DIR) {
|
|
10818
|
+
dirs.push(process.env.UV_TOOL_BIN_DIR);
|
|
10819
|
+
}
|
|
10820
|
+
dirs.push(expandPath("~/.local/bin"));
|
|
10821
|
+
return Array.from(new Set(dirs));
|
|
10822
|
+
}
|
|
10823
|
+
async function requireOpenVikingServer() {
|
|
10824
|
+
const resolved = await findOpenVikingServer();
|
|
10825
|
+
if (!resolved) {
|
|
10826
|
+
throw new Error(
|
|
10827
|
+
`${OPENVIKING_SERVER_COMMAND} was not found in PATH, uv tool bin dir, $UV_TOOL_BIN_DIR, or ~/.local/bin. Run \`threadnote install\` first.`
|
|
10828
|
+
);
|
|
10829
|
+
}
|
|
10830
|
+
return resolved;
|
|
10831
|
+
}
|
|
10832
|
+
async function maybePrintOpenVikingPathHint(serverPath) {
|
|
10833
|
+
const onPath = await findExecutable([OPENVIKING_SERVER_COMMAND]);
|
|
10834
|
+
if (onPath) {
|
|
10835
|
+
return;
|
|
10836
|
+
}
|
|
10837
|
+
const binDir = (0, import_node_path11.dirname)(serverPath);
|
|
10838
|
+
const rcHint = suggestedShellRc(process.env.SHELL, (0, import_node_os6.platform)());
|
|
10839
|
+
console.log(
|
|
10840
|
+
`Note: ${serverPath} is installed but ${binDir} is not on this shell's PATH. Add \`export PATH="${binDir}:$PATH"\` to ${rcHint} so other tools can find openviking-server.`
|
|
10841
|
+
);
|
|
10842
|
+
}
|
|
10760
10843
|
async function repairServerHealth(config, dryRun) {
|
|
10761
10844
|
const existingHealth = await readOpenVikingHealthIfAvailable(config, 800);
|
|
10762
10845
|
if (existingHealth) {
|
|
@@ -10777,7 +10860,7 @@ async function runStart(config, options) {
|
|
|
10777
10860
|
await installLaunchAgent(config, options.dryRun === true);
|
|
10778
10861
|
return;
|
|
10779
10862
|
}
|
|
10780
|
-
const server = options.dryRun === true ? await
|
|
10863
|
+
const server = options.dryRun === true ? await findOpenVikingServer() ?? OPENVIKING_SERVER_COMMAND : await requireOpenVikingServer();
|
|
10781
10864
|
const args = openVikingServerArgs(config);
|
|
10782
10865
|
if (options.dryRun === true) {
|
|
10783
10866
|
console.log(formatShellCommand(server, args));
|
|
@@ -10871,6 +10954,21 @@ async function commandCheck(name, args) {
|
|
|
10871
10954
|
detail: firstLine(result.stdout || result.stderr) || executable
|
|
10872
10955
|
};
|
|
10873
10956
|
}
|
|
10957
|
+
async function openVikingServerCheck() {
|
|
10958
|
+
const name = OPENVIKING_SERVER_COMMAND;
|
|
10959
|
+
const executable = await findOpenVikingServer();
|
|
10960
|
+
if (!executable) {
|
|
10961
|
+
return { name, status: "fail", detail: "missing; install will fetch it via uv or pipx" };
|
|
10962
|
+
}
|
|
10963
|
+
const result = await runCommand(executable, ["--help"], { allowFailure: true });
|
|
10964
|
+
const onPath = await findExecutable([OPENVIKING_SERVER_COMMAND]);
|
|
10965
|
+
const detail = onPath ? executable : `${executable} (found outside PATH; add ${(0, import_node_path11.dirname)(executable)} to PATH)`;
|
|
10966
|
+
return {
|
|
10967
|
+
name,
|
|
10968
|
+
status: result.exitCode === 0 ? "ok" : "warn",
|
|
10969
|
+
detail: result.exitCode === 0 ? detail : firstLine(result.stderr || result.stdout) || detail
|
|
10970
|
+
};
|
|
10971
|
+
}
|
|
10874
10972
|
async function commandPresenceCheck(name, args) {
|
|
10875
10973
|
const executable = await findExecutable([name]);
|
|
10876
10974
|
if (!executable) {
|
|
@@ -10899,7 +10997,7 @@ async function firstCommandCheck(name, commands, args) {
|
|
|
10899
10997
|
return { name, status: "fail", detail: `none found: ${commands.join(", ")}` };
|
|
10900
10998
|
}
|
|
10901
10999
|
async function localEmbeddingCheck() {
|
|
10902
|
-
const serverPath = await
|
|
11000
|
+
const serverPath = await findOpenVikingServer();
|
|
10903
11001
|
if (!serverPath) {
|
|
10904
11002
|
return { name: "local embedding extra", status: "warn", detail: "openviking-server missing" };
|
|
10905
11003
|
}
|
|
@@ -10918,7 +11016,7 @@ async function localEmbeddingCheck() {
|
|
|
10918
11016
|
};
|
|
10919
11017
|
}
|
|
10920
11018
|
async function pythonSystemCertificatesCheck() {
|
|
10921
|
-
const serverPath = await
|
|
11019
|
+
const serverPath = await findOpenVikingServer();
|
|
10922
11020
|
if (!serverPath) {
|
|
10923
11021
|
return { name: "python system certs", status: "warn", detail: "openviking-server missing" };
|
|
10924
11022
|
}
|
|
@@ -11099,6 +11197,7 @@ async function installUv() {
|
|
|
11099
11197
|
console.log(result.stdout.trim());
|
|
11100
11198
|
}
|
|
11101
11199
|
if (await findExecutable(["uv"])) {
|
|
11200
|
+
candidateDirsPromise = void 0;
|
|
11102
11201
|
return true;
|
|
11103
11202
|
}
|
|
11104
11203
|
} else {
|
|
@@ -11115,6 +11214,7 @@ async function installUv() {
|
|
|
11115
11214
|
console.log(result.stdout.trim());
|
|
11116
11215
|
}
|
|
11117
11216
|
if (await findExecutable(["uv"])) {
|
|
11217
|
+
candidateDirsPromise = void 0;
|
|
11118
11218
|
return true;
|
|
11119
11219
|
}
|
|
11120
11220
|
console.warn(
|
|
@@ -11419,10 +11519,20 @@ async function installLaunchAgent(config, dryRun) {
|
|
|
11419
11519
|
if ((0, import_node_os6.platform)() !== "darwin") {
|
|
11420
11520
|
throw new Error("launchd autostart is only supported on macOS.");
|
|
11421
11521
|
}
|
|
11522
|
+
const resolvedServer = await findOpenVikingServer();
|
|
11523
|
+
if (!resolvedServer && !dryRun) {
|
|
11524
|
+
throw new Error(
|
|
11525
|
+
`Cannot install LaunchAgent: ${OPENVIKING_SERVER_COMMAND} was not found in PATH, uv tool bin dir, $UV_TOOL_BIN_DIR, or ~/.local/bin. Run \`threadnote install\` first.`
|
|
11526
|
+
);
|
|
11527
|
+
}
|
|
11422
11528
|
const source = (0, import_node_path11.join)(toolRoot(), "config", "launchd", `${LAUNCHD_LABEL}.plist.template`);
|
|
11423
11529
|
const destination = expandPath(`~/Library/LaunchAgents/${LAUNCHD_LABEL}.plist`);
|
|
11424
|
-
const rendered = renderTemplate(await (0, import_promises11.readFile)(source, "utf8"), config
|
|
11530
|
+
const rendered = renderTemplate(await (0, import_promises11.readFile)(source, "utf8"), config, {
|
|
11531
|
+
OPENVIKING_SERVER_PATH: resolvedServer ?? OPENVIKING_SERVER_COMMAND
|
|
11532
|
+
});
|
|
11425
11533
|
if (dryRun) {
|
|
11534
|
+
const resolutionDetail = resolvedServer ?? `<not found; would use bare \`${OPENVIKING_SERVER_COMMAND}\`>`;
|
|
11535
|
+
console.log(`Resolved openviking-server: ${resolutionDetail}`);
|
|
11426
11536
|
console.log(`Would write ${destination}`);
|
|
11427
11537
|
console.log(`Would run: launchctl unload ${destination}`);
|
|
11428
11538
|
console.log(`Would run: launchctl load ${destination}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "threadnote",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"main": "dist/threadnote.cjs",
|
|
6
6
|
"description": "Shared local context and handoffs for development agents",
|
|
@@ -43,18 +43,21 @@
|
|
|
43
43
|
"clean": "rm -rf dist",
|
|
44
44
|
"dev": "tsx src/threadnote.ts",
|
|
45
45
|
"dev:mcp-server": "tsx src/mcp_server.ts",
|
|
46
|
-
"lint": "eslint \"src/**/*.ts\"",
|
|
47
|
-
"lint:fix": "eslint \"src/**/*.ts\" --fix",
|
|
46
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
47
|
+
"lint:fix": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --fix",
|
|
48
48
|
"prepare": "husky",
|
|
49
|
-
"precommit": "npm run lint && npm run prettier:check",
|
|
49
|
+
"precommit": "npm run lint && npm run prettier:check && npm run test",
|
|
50
50
|
"prepack": "npm run build",
|
|
51
51
|
"prettier:check": "prettier --check \"**/*.{ts,js,cjs,json,md,yaml,yml}\"",
|
|
52
52
|
"prettier:write": "prettier --write \"**/*.{ts,js,cjs,json,md,yaml,yml}\"",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:watch": "vitest",
|
|
55
|
+
"test:coverage": "vitest run --coverage",
|
|
53
56
|
"threadnote": "npm run build --silent && node ./bin/threadnote.cjs",
|
|
54
57
|
"doctor": "npm run build --silent && node ./bin/threadnote.cjs doctor",
|
|
55
58
|
"mcp-server": "npm run build --silent && node ./bin/threadnote-mcp-server.cjs",
|
|
56
59
|
"pack:dry-run": "npm pack --dry-run",
|
|
57
|
-
"typecheck": "tsc --noEmit"
|
|
60
|
+
"typecheck": "tsc --noEmit && tsc -p test/tsconfig.json --noEmit"
|
|
58
61
|
},
|
|
59
62
|
"engines": {
|
|
60
63
|
"node": ">=20"
|
|
@@ -64,6 +67,7 @@
|
|
|
64
67
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
65
68
|
"@types/js-yaml": "^4.0.9",
|
|
66
69
|
"@types/node": "^25.6.0",
|
|
70
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
67
71
|
"commander": "^14.0.3",
|
|
68
72
|
"esbuild": "^0.27.7",
|
|
69
73
|
"eslint": "^10.3.0",
|
|
@@ -74,6 +78,7 @@
|
|
|
74
78
|
"tsx": "^4.21.0",
|
|
75
79
|
"typescript": "^6.0.3",
|
|
76
80
|
"typescript-eslint": "^8.59.2",
|
|
81
|
+
"vitest": "^4.1.7",
|
|
77
82
|
"zod": "^4.4.3"
|
|
78
83
|
}
|
|
79
84
|
}
|