@scopebond/agent 0.3.2 → 0.4.1

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/update.d.ts CHANGED
@@ -12,7 +12,12 @@ export declare function compareVersions(a: string, b: string): number;
12
12
  export declare function commandHookVersion(command: string): string | null;
13
13
  /** The command an agent-maintained settings entry runs: the hook version this agent carries,
14
14
  * through npx, so it resolves Node at run time and an agent update never swaps files under it. */
15
+ /** The hook command upkeep writes. The hook this agent carries is pinned by its absolute path (fast,
16
+ * and it needs neither the registry nor npx on the coding tool's PATH); another version, or a pin that
17
+ * cannot be made, falls back to the portable npx form. */
15
18
  export declare function maintainedHookCommand(harness: Harness, version?: string): string;
19
+ /** This Node's own npm, run directly (no shell, and never another Node's npm first on PATH), or null. */
20
+ export declare function ownNpm(): [string, string[]] | null;
16
21
  /** Bring the user-level Scopebond hook entries to `version`, and repair any that cannot start.
17
22
  * Entries of other tools are never touched. Returns the files changed. */
18
23
  export declare function maintainHookEntries(harnesses: Harness[], version?: string, moveVersions?: boolean): Array<{
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,OAAO,EAAE,KAAK,cAAc,EAClC,MAAM,iBAAiB,CAAC;AAIzB,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,MAAM,WAAW,aAAa;IAAG,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AAE5G,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,YAAY,CAAC,EAAE,SAAS,GAAE,OAAO,KAAa,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAUnL;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIjE;AAED;mGACmG;AACnG,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,SAAgB,GAAG,MAAM,CAEvF;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,OAAO,SAAgB,EAAE,YAAY,UAAO,GAAG,KAAK,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAajK;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAa,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAa9G"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,OAAO,EAAE,KAAK,cAAc,EAClC,MAAM,iBAAiB,CAAC;AAIzB,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED,MAAM,WAAW,aAAa;IAAG,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AAE5G,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,YAAY,CAAC,EAAE,SAAS,GAAE,OAAO,KAAa,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAUnL;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIjE;AAED;mGACmG;AACnG;;2DAE2D;AAC3D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,SAAgB,GAAG,MAAM,CASvF;AAED,yGAAyG;AACzG,wBAAgB,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAGlD;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,OAAO,SAAgB,EAAE,YAAY,UAAO,GAAG,KAAK,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAajK;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAa,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB9G"}
package/dist/update.js CHANGED
@@ -3,8 +3,10 @@
3
3
  // matching hook, pinned exactly) and restarts; with "hold" it changes nothing. The hook entries in
4
4
  // the agent settings are moved to the hook version the agent carries.
5
5
  import { spawn } from "node:child_process";
6
- import { readFileSync } from "node:fs";
7
- import { configuredHookCommands, hookCommandResolves, hookVersion, isScopebondHookCommand, userHarnessFile, writeHarnessConfig, } from "@scopebond/hook";
6
+ import { existsSync, readFileSync } from "node:fs";
7
+ import { createRequire } from "node:module";
8
+ import { dirname, join } from "node:path";
9
+ import { absoluteHookCommand, ensureDurableRuntime, configuredHookCommands, hookCommandResolves, hookVersion, isScopebondHookCommand, userHarnessFile, writeHarnessConfig, } from "@scopebond/hook";
8
10
  const VERSION = /^[0-9]+\.[0-9]+\.[0-9]+$/;
9
11
  export function agentVersion() {
10
12
  try {
@@ -46,9 +48,26 @@ export function commandHookVersion(command) {
46
48
  }
47
49
  /** The command an agent-maintained settings entry runs: the hook version this agent carries,
48
50
  * through npx, so it resolves Node at run time and an agent update never swaps files under it. */
51
+ /** The hook command upkeep writes. The hook this agent carries is pinned by its absolute path (fast,
52
+ * and it needs neither the registry nor npx on the coding tool's PATH); another version, or a pin that
53
+ * cannot be made, falls back to the portable npx form. */
49
54
  export function maintainedHookCommand(harness, version = hookVersion()) {
55
+ if (version === hookVersion()) {
56
+ try {
57
+ const cli = join(dirname(createRequire(import.meta.url).resolve("@scopebond/hook")), "cli.js");
58
+ const pin = ensureDurableRuntime(cli, version);
59
+ if (pin.cli)
60
+ return absoluteHookCommand(pin.cli, harness);
61
+ }
62
+ catch { /* fall back below */ }
63
+ }
50
64
  return `npx -y @scopebond/hook@${version} ${harness}`;
51
65
  }
66
+ /** This Node's own npm, run directly (no shell, and never another Node's npm first on PATH), or null. */
67
+ export function ownNpm() {
68
+ const cli = join(dirname(process.execPath), process.platform === "win32" ? "" : "../lib", "node_modules", "npm", "bin", "npm-cli.js");
69
+ return existsSync(cli) ? [process.execPath, [cli]] : null;
70
+ }
52
71
  /** Bring the user-level Scopebond hook entries to `version`, and repair any that cannot start.
53
72
  * Entries of other tools are never touched. Returns the files changed. */
54
73
  export function maintainHookEntries(harnesses, version = hookVersion(), moveVersions = true) {
@@ -73,8 +92,11 @@ export function installAgent(version, timeoutMs = 5 * 60_000) {
73
92
  return Promise.resolve({ ok: false, output: "not a version" });
74
93
  return new Promise((resolve) => {
75
94
  const win = process.platform === "win32";
76
- // npm on Windows is a .cmd file, which Node only starts through a shell; the arguments are fixed and the version is validated.
77
- const child = spawn(win ? "npm.cmd" : "npm", ["install", "-g", `@scopebond/agent@${version}`, "--no-fund", "--no-audit"], { shell: win, windowsHide: true });
95
+ const args = ["install", "-g", `@scopebond/agent@${version}`, "--no-fund", "--no-audit"];
96
+ // This Node's own npm when it can be found; otherwise npm on PATH (a .cmd on Windows, which Node only
97
+ // starts through a shell; the arguments are fixed and the version is validated).
98
+ const own = ownNpm();
99
+ const child = own ? spawn(own[0], [...own[1], ...args], { windowsHide: true }) : spawn(win ? "npm.cmd" : "npm", args, { shell: win, windowsHide: true });
78
100
  let output = "";
79
101
  child.stdout?.on("data", (d) => { output += d; });
80
102
  child.stderr?.on("data", (d) => { output += d; });
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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","sourcesContent":["// Updates under the workspace's control (D130). The agent asks the workspace which versions this\n// computer should run; with \"recommended\" it installs the named agent from npm (which brings the\n// matching hook, pinned exactly) and restarts; with \"hold\" it changes nothing. The hook entries in\n// the agent settings are moved to the hook version the agent carries.\n\nimport { spawn } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport {\n configuredHookCommands, hookCommandResolves, hookVersion, isScopebondHookCommand, userHarnessFile, writeHarnessConfig,\n type Harness, type HookConnection,\n} from \"@scopebond/hook\";\n\nconst VERSION = /^[0-9]+\\.[0-9]+\\.[0-9]+$/;\n\nexport function agentVersion(): string {\n try {\n const pkg = JSON.parse(readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\")) as { version?: string };\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch { return \"0.0.0\"; }\n}\n\nexport interface ClientVersion { policy: \"recommended\" | \"hold\"; hook: string | null; agent: string | null }\n\nexport async function fetchClientVersion(connection: Pick<HookConnection, \"url\" | \"credential\">, fetchImpl: typeof fetch = fetch, timeoutMs = 10_000): Promise<ClientVersion | null> {\n try {\n const res = await fetchImpl(new URL(\"/v1/client-version\", connection.url).toString(), {\n headers: { authorization: `Bearer ${connection.credential}` }, redirect: \"error\", signal: AbortSignal.timeout(timeoutMs),\n });\n if (!res.ok) return null;\n const body = await res.json() as Partial<ClientVersion>;\n const ok = (v: unknown) => typeof v === \"string\" && VERSION.test(v) ? v : null;\n return { policy: body.policy === \"hold\" ? \"hold\" : \"recommended\", hook: ok(body.hook), agent: ok(body.agent) };\n } catch { return null; }\n}\n\n/** Compare x.y.z versions: negative when a < b. */\nexport function compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number), pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) - (pb[i] ?? 0);\n return 0;\n}\n\n/** The hook version a settings command runs, when it names one (an `npx` pin or a pinned copy). */\nexport function commandHookVersion(command: string): string | null {\n return /@scopebond\\/hook@([0-9]+\\.[0-9]+\\.[0-9]+)/.exec(command)?.[1]\n ?? /[\\\\/]runtime[\\\\/]([0-9]+\\.[0-9]+\\.[0-9]+)[\\\\/]/.exec(command)?.[1]\n ?? null;\n}\n\n/** The command an agent-maintained settings entry runs: the hook version this agent carries,\n * through npx, so it resolves Node at run time and an agent update never swaps files under it. */\nexport function maintainedHookCommand(harness: Harness, version = hookVersion()): string {\n return `npx -y @scopebond/hook@${version} ${harness}`;\n}\n\n/** Bring the user-level Scopebond hook entries to `version`, and repair any that cannot start.\n * Entries of other tools are never touched. Returns the files changed. */\nexport function maintainHookEntries(harnesses: Harness[], version = hookVersion(), moveVersions = true): Array<{ harness: Harness; file: string; reason: string }> {\n const changed: Array<{ harness: Harness; file: string; reason: string }> = [];\n for (const harness of harnesses) {\n const file = userHarnessFile(harness);\n const ours = configuredHookCommands(file).filter((c) => isScopebondHookCommand(c));\n if (!ours.length) continue;\n const broken = ours.some((c) => !hookCommandResolves(c));\n const behind = moveVersions && ours.some((c) => { const v = commandHookVersion(c); return v !== null && compareVersions(v, version) < 0; });\n if (!broken && !behind) continue;\n writeHarnessConfig(file, harness, maintainedHookCommand(harness, version));\n changed.push({ harness, file, reason: broken ? \"the hook command could not start\" : `moved to hook ${version}` });\n }\n return changed;\n}\n\n/** Install `@scopebond/agent@version` globally with this computer's npm. */\nexport function installAgent(version: string, timeoutMs = 5 * 60_000): Promise<{ ok: boolean; output: string }> {\n if (!VERSION.test(version)) return Promise.resolve({ ok: false, output: \"not a version\" });\n return new Promise((resolve) => {\n const win = process.platform === \"win32\";\n // npm on Windows is a .cmd file, which Node only starts through a shell; the arguments are fixed and the version is validated.\n const child = spawn(win ? \"npm.cmd\" : \"npm\", [\"install\", \"-g\", `@scopebond/agent@${version}`, \"--no-fund\", \"--no-audit\"], { shell: win, windowsHide: true });\n let output = \"\";\n child.stdout?.on(\"data\", (d) => { output += d; });\n child.stderr?.on(\"data\", (d) => { output += d; });\n const timer = setTimeout(() => { child.kill(); resolve({ ok: false, output: output + \"\\ntimed out\" }); }, timeoutMs);\n child.on(\"error\", (error) => { clearTimeout(timer); resolve({ ok: false, output: String(error) }); });\n child.on(\"close\", (code) => { clearTimeout(timer); resolve({ ok: code === 0, output: output.slice(-2000) }); });\n });\n}\n"]}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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","sourcesContent":["// Updates under the workspace's control (D130). The agent asks the workspace which versions this\n// computer should run; with \"recommended\" it installs the named agent from npm (which brings the\n// matching hook, pinned exactly) and restarts; with \"hold\" it changes nothing. The hook entries in\n// the agent settings are moved to the hook version the agent carries.\n\nimport { spawn } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport {\n absoluteHookCommand, ensureDurableRuntime,\n configuredHookCommands, hookCommandResolves, hookVersion, isScopebondHookCommand, userHarnessFile, writeHarnessConfig,\n type Harness, type HookConnection,\n} from \"@scopebond/hook\";\n\nconst VERSION = /^[0-9]+\\.[0-9]+\\.[0-9]+$/;\n\nexport function agentVersion(): string {\n try {\n const pkg = JSON.parse(readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\")) as { version?: string };\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch { return \"0.0.0\"; }\n}\n\nexport interface ClientVersion { policy: \"recommended\" | \"hold\"; hook: string | null; agent: string | null }\n\nexport async function fetchClientVersion(connection: Pick<HookConnection, \"url\" | \"credential\">, fetchImpl: typeof fetch = fetch, timeoutMs = 10_000): Promise<ClientVersion | null> {\n try {\n const res = await fetchImpl(new URL(\"/v1/client-version\", connection.url).toString(), {\n headers: { authorization: `Bearer ${connection.credential}` }, redirect: \"error\", signal: AbortSignal.timeout(timeoutMs),\n });\n if (!res.ok) return null;\n const body = await res.json() as Partial<ClientVersion>;\n const ok = (v: unknown) => typeof v === \"string\" && VERSION.test(v) ? v : null;\n return { policy: body.policy === \"hold\" ? \"hold\" : \"recommended\", hook: ok(body.hook), agent: ok(body.agent) };\n } catch { return null; }\n}\n\n/** Compare x.y.z versions: negative when a < b. */\nexport function compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number), pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) - (pb[i] ?? 0);\n return 0;\n}\n\n/** The hook version a settings command runs, when it names one (an `npx` pin or a pinned copy). */\nexport function commandHookVersion(command: string): string | null {\n return /@scopebond\\/hook@([0-9]+\\.[0-9]+\\.[0-9]+)/.exec(command)?.[1]\n ?? /[\\\\/]runtime[\\\\/]([0-9]+\\.[0-9]+\\.[0-9]+)[\\\\/]/.exec(command)?.[1]\n ?? null;\n}\n\n/** The command an agent-maintained settings entry runs: the hook version this agent carries,\n * through npx, so it resolves Node at run time and an agent update never swaps files under it. */\n/** The hook command upkeep writes. The hook this agent carries is pinned by its absolute path (fast,\n * and it needs neither the registry nor npx on the coding tool's PATH); another version, or a pin that\n * cannot be made, falls back to the portable npx form. */\nexport function maintainedHookCommand(harness: Harness, version = hookVersion()): string {\n if (version === hookVersion()) {\n try {\n const cli = join(dirname(createRequire(import.meta.url).resolve(\"@scopebond/hook\")), \"cli.js\");\n const pin = ensureDurableRuntime(cli, version);\n if (pin.cli) return absoluteHookCommand(pin.cli, harness);\n } catch { /* fall back below */ }\n }\n return `npx -y @scopebond/hook@${version} ${harness}`;\n}\n\n/** This Node's own npm, run directly (no shell, and never another Node's npm first on PATH), or null. */\nexport function ownNpm(): [string, string[]] | null {\n const cli = join(dirname(process.execPath), process.platform === \"win32\" ? \"\" : \"../lib\", \"node_modules\", \"npm\", \"bin\", \"npm-cli.js\");\n return existsSync(cli) ? [process.execPath, [cli]] : null;\n}\n\n/** Bring the user-level Scopebond hook entries to `version`, and repair any that cannot start.\n * Entries of other tools are never touched. Returns the files changed. */\nexport function maintainHookEntries(harnesses: Harness[], version = hookVersion(), moveVersions = true): Array<{ harness: Harness; file: string; reason: string }> {\n const changed: Array<{ harness: Harness; file: string; reason: string }> = [];\n for (const harness of harnesses) {\n const file = userHarnessFile(harness);\n const ours = configuredHookCommands(file).filter((c) => isScopebondHookCommand(c));\n if (!ours.length) continue;\n const broken = ours.some((c) => !hookCommandResolves(c));\n const behind = moveVersions && ours.some((c) => { const v = commandHookVersion(c); return v !== null && compareVersions(v, version) < 0; });\n if (!broken && !behind) continue;\n writeHarnessConfig(file, harness, maintainedHookCommand(harness, version));\n changed.push({ harness, file, reason: broken ? \"the hook command could not start\" : `moved to hook ${version}` });\n }\n return changed;\n}\n\n/** Install `@scopebond/agent@version` globally with this computer's npm. */\nexport function installAgent(version: string, timeoutMs = 5 * 60_000): Promise<{ ok: boolean; output: string }> {\n if (!VERSION.test(version)) return Promise.resolve({ ok: false, output: \"not a version\" });\n return new Promise((resolve) => {\n const win = process.platform === \"win32\";\n const args = [\"install\", \"-g\", `@scopebond/agent@${version}`, \"--no-fund\", \"--no-audit\"];\n // This Node's own npm when it can be found; otherwise npm on PATH (a .cmd on Windows, which Node only\n // starts through a shell; the arguments are fixed and the version is validated).\n const own = ownNpm();\n const child = own ? spawn(own[0], [...own[1], ...args], { windowsHide: true }) : spawn(win ? \"npm.cmd\" : \"npm\", args, { shell: win, windowsHide: true });\n let output = \"\";\n child.stdout?.on(\"data\", (d) => { output += d; });\n child.stderr?.on(\"data\", (d) => { output += d; });\n const timer = setTimeout(() => { child.kill(); resolve({ ok: false, output: output + \"\\ntimed out\" }); }, timeoutMs);\n child.on(\"error\", (error) => { clearTimeout(timer); resolve({ ok: false, output: String(error) }); });\n child.on(\"close\", (code) => { clearTimeout(timer); resolve({ ok: code === 0, output: output.slice(-2000) }); });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scopebond/agent",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "Free, open-source Scopebond Agent companion: deliver queued records, maintain rules and connections, and report computer health to the separate proprietary Scopebond Cloud workspace.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Avouro LLC",
@@ -39,13 +39,16 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
- "@scopebond/gateway": "0.13.0",
43
- "@scopebond/sdk": "0.1.4",
44
- "@scopebond/hook": "0.16.0"
42
+ "@scopebond/gateway": "0.15.0",
43
+ "@scopebond/hook": "0.18.0",
44
+ "@scopebond/sdk": "0.1.4"
45
45
  },
46
46
  "publishConfig": {
47
47
  "access": "public"
48
48
  },
49
+ "devDependencies": {
50
+ "@scopebond/fake-cloud": "0.1.0"
51
+ },
49
52
  "scripts": {
50
53
  "build": "tsc -p tsconfig.json",
51
54
  "test": "tsc -p tsconfig.json && node --test test/*.test.mjs"