@quolu/lattice 0.52.0 → 0.52.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/LICENSE +147 -147
- package/README.ja.md +355 -355
- package/README.md +258 -258
- package/bin/lattice-mcp.mjs +0 -0
- package/bin/lattice-scripted-adapter.mjs +0 -0
- package/bin/lattice-scripted-worker.mjs +0 -0
- package/bin/lattice-work-order-adapter.mjs +0 -0
- package/bin/lattice.mjs +0 -0
- package/docs/bridge-setup.md +132 -132
- package/docs/schemas/lattice.executor_packet.v1.schema.json +57 -57
- package/docs/schemas/lattice.executor_receipt.v1.schema.json +66 -66
- package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +360 -360
- package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -56
- package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -72
- package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -81
- package/docs/schemas/lattice.plan_create_input.v4.schema.json +85 -85
- package/docs/schemas/lattice.run_request.v1.schema.json +238 -238
- package/docs/schemas/lattice.runtime_adapter_capabilities.v2.schema.json +55 -55
- package/docs/schemas/lattice.runtime_adapter_registration_input.v1.schema.json +78 -78
- package/docs/schemas/lattice.runtime_adapter_registration_input.v2.schema.json +86 -86
- package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -298
- package/docs/schemas/lattice.todo_extraction.v3.schema.json +146 -146
- package/docs/schemas/lattice.todo_revision.v2.schema.json +260 -260
- package/docs/schemas/lattice.todo_revision_set.v3.schema.json +363 -363
- package/package.json +103 -103
- package/sensor/LICENSE +21 -21
- package/sensor/NOTICE +19 -19
- package/sensor/dist/bin/lattice-sensor.js +9 -9
- package/sensor/dist/db/index.js +24 -24
- package/sensor/dist/db/migrations.js +41 -41
- package/sensor/dist/db/queries.js +164 -164
- package/sensor/dist/db/schema.sql +205 -205
- package/sensor/dist/directory.js +5 -5
- package/sensor/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/sensor/dist/mcp/liveness-watchdog.js +53 -53
- package/sensor/dist/mcp/server-instructions.js +95 -95
- package/sensor/package.json +56 -56
- package/src/artifact-contracts-v2.mjs +325 -325
- package/src/artifact-contracts.mjs +895 -895
- package/src/boundary-compiler.mjs +712 -712
- package/src/boundary-observation-compiler-v2.mjs +344 -344
- package/src/bounded-seam.mjs +230 -230
- package/src/bridge-address.mjs +107 -107
- package/src/bridge-cli.mjs +297 -297
- package/src/bridge-config.mjs +346 -346
- package/src/bridge-daemon.mjs +378 -378
- package/src/bridge-launch-agent.mjs +323 -323
- package/src/bridge-registrar.mjs +102 -102
- package/src/bridge-server.mjs +376 -376
- package/src/cli-help.mjs +308 -308
- package/src/cli-stdio.mjs +40 -40
- package/src/control-compiler.mjs +532 -532
- package/src/dag-chain.mjs +261 -261
- package/src/factory-diagnostics.mjs +188 -188
- package/src/hash-chain.mjs +76 -76
- package/src/hooks-cli.mjs +1057 -1053
- package/src/isolation-runner.mjs +409 -409
- package/src/node-version-guard.mjs +44 -44
- package/src/project-cli.mjs +697 -697
- package/src/project-identity.mjs +130 -130
- package/src/rc1-black-box-oracle.mjs +906 -906
- package/src/rc1-comparison.mjs +154 -154
- package/src/rc1-evidence-bundle.mjs +456 -456
- package/src/rc1-v4-campaign.mjs +708 -708
- package/src/rc1-v4-transform.mjs +467 -467
- package/src/rc1-v5-artifact-set.mjs +855 -855
- package/src/rc1-v5-behavior-evidence.mjs +594 -594
- package/src/rc1-v5-campaign.mjs +797 -797
- package/src/rc1-v5-transform.mjs +421 -421
- package/src/rc1-v6-artifact-set.mjs +807 -807
- package/src/rc1-v6-behavior-evidence.mjs +273 -273
- package/src/rc1-v6-campaign.mjs +623 -623
- package/src/rc1-v6-causal-binding.mjs +473 -473
- package/src/rc1-v6-measurement.mjs +313 -313
- package/src/rc2-artifact-set.mjs +1584 -1584
- package/src/rc2-campaign.mjs +1506 -1502
- package/src/rc2-delivery-policy-front-end.mjs +1079 -1079
- package/src/rc2-delivery-policy-oracle.mjs +134 -134
- package/src/rc2-delivery-policy-transform.mjs +1127 -1127
- package/src/rc2-rc1-transfer-front-end.mjs +511 -511
- package/src/rc3-actual-dogfood.mjs +652 -652
- package/src/rc3-dogfood-scaffold.mjs +315 -315
- package/src/rc3-scripted-campaign.mjs +1383 -1383
- package/src/rc4-stage1-dogfood.mjs +673 -673
- package/src/runtime-adapter-registry.mjs +524 -520
- package/src/runtime-cli.mjs +4588 -4584
- package/src/runtime-contracts.mjs +824 -824
- package/src/runtime-control-store.mjs +604 -600
- package/src/runtime-controller-protocol.mjs +587 -587
- package/src/runtime-decision-verifier.mjs +701 -701
- package/src/runtime-diff-observer.mjs +361 -361
- package/src/runtime-direct-os-observer.mjs +301 -301
- package/src/runtime-driver-state.mjs +166 -162
- package/src/runtime-engine.mjs +779 -779
- package/src/runtime-errors.mjs +356 -356
- package/src/runtime-event-store.mjs +189 -189
- package/src/runtime-front-end.mjs +925 -925
- package/src/runtime-gate-store.mjs +481 -477
- package/src/runtime-hold-recompile.mjs +916 -916
- package/src/runtime-io-sentinel.mjs +391 -391
- package/src/runtime-lifecycle-lock.mjs +294 -290
- package/src/runtime-managed-supervisor.mjs +1490 -1490
- package/src/runtime-multi-epoch-store.mjs +838 -834
- package/src/runtime-projection.mjs +269 -269
- package/src/runtime-pull-intake.mjs +1192 -1188
- package/src/runtime-scripted-adapter-controller.mjs +1160 -1156
- package/src/runtime-scripted-executor.mjs +163 -163
- package/src/runtime-scripted-worktree.mjs +104 -104
- package/src/runtime-seam-resolve.mjs +428 -428
- package/src/runtime-seam-treatment.mjs +173 -173
- package/src/runtime-socket-owner.mjs +125 -125
- package/src/runtime-work-order-contracts.mjs +91 -91
- package/src/runtime-work-order-controller.mjs +1171 -1167
- package/src/runtime-worktree-executor.mjs +199 -199
- package/src/schedulability-compiler-v2.mjs +303 -303
- package/src/schedulability-verifier-v2.mjs +317 -317
- package/src/seam-apply.mjs +549 -549
- package/src/seam-commit-shared.mjs +22 -22
- package/src/seam-commit-transform.mjs +81 -81
- package/src/seam-commit.mjs +18 -18
- package/src/seam-cost.mjs +322 -322
- package/src/seam-derivation.mjs +188 -188
- package/src/seam-gate.mjs +146 -146
- package/src/seam-proposal-contracts.mjs +446 -446
- package/src/seam-proposal-queries.mjs +521 -521
- package/src/seam-proposal.mjs +2011 -2011
- package/src/seam-ref.mjs +33 -33
- package/src/seam-rewrite.mjs +286 -286
- package/src/seam-transform.mjs +554 -554
- package/src/seam-verification.mjs +260 -260
- package/src/sensor-adapter.mjs +432 -432
- package/src/sensor-cli.mjs +139 -139
- package/src/sensor-diff.mjs +661 -661
- package/src/sensor-node-runtime.mjs +53 -53
- package/src/sensor-runtime.mjs +52 -52
- package/src/timestamp-contract.mjs +8 -8
- package/src/todo-audit-pending.mjs +91 -91
- package/src/todo-chain.mjs +178 -178
- package/src/todo-cli.mjs +3141 -3126
- package/src/todo-contracts.mjs +728 -728
- package/src/todo-dashboard-registry.mjs +573 -573
- package/src/todo-dispatch-shape.mjs +190 -190
- package/src/todo-gantt-html-independence.mjs +239 -239
- package/src/todo-gantt-html-shared.mjs +226 -226
- package/src/todo-gantt-html-style.mjs +131 -131
- package/src/todo-gantt-html.mjs +248 -248
- package/src/todo-gantt-layout.mjs +974 -974
- package/src/todo-gantt-live.mjs +361 -361
- package/src/todo-gantt-nested.mjs +263 -263
- package/src/todo-gantt-presentation.mjs +217 -217
- package/src/todo-gantt-scope.mjs +123 -123
- package/src/todo-gantt-svg.mjs +353 -353
- package/src/todo-independence-contracts.mjs +595 -595
- package/src/todo-independence-guidance.mjs +322 -322
- package/src/todo-independence.mjs +640 -640
- package/src/todo-markdown-renderer.mjs +260 -260
- package/src/todo-migration.mjs +448 -448
- package/src/todo-narrative-anchor.mjs +130 -130
- package/src/todo-note-store.mjs +629 -625
- package/src/todo-parallel-candidates.mjs +114 -114
- package/src/todo-revision.mjs +995 -995
- package/src/todo-split.mjs +472 -472
- package/src/todo-status.mjs +690 -690
- package/src/todo-store-git-transaction.mjs +418 -418
- package/src/todo-store.mjs +4322 -4314
- package/src/treatment-compiler.mjs +728 -728
- package/src/treatment-runner.mjs +656 -656
- package/src/witness-scaffold.mjs +180 -180
package/src/bridge-registrar.mjs
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bridge upstream self-registration.
|
|
3
|
-
*
|
|
4
|
-
* The public site is reverse-proxied to a literal LAN address held by another
|
|
5
|
-
* host. When this host's address moves — a DHCP lease change is enough — that
|
|
6
|
-
* literal goes stale and the site starts failing, with nothing on either side
|
|
7
|
-
* noticing. Registration closes that loop: after the bridge binds, it tells the
|
|
8
|
-
* reverse proxy where it actually is.
|
|
9
|
-
*
|
|
10
|
-
* This is an explicit connector, not a hook into someone else's tooling. It
|
|
11
|
-
* runs one fixed shape — `ssh <host> <script> <port>` — over the operator's
|
|
12
|
-
* existing ssh trust, and both operands are validated. Lattice never sends a
|
|
13
|
-
* command string, so the reverse proxy host decides what registration means and
|
|
14
|
-
* can refuse anything it does not like. The remote script is expected to derive
|
|
15
|
-
* the address from the ssh source rather than trusting anything sent to it.
|
|
16
|
-
*
|
|
17
|
-
* Opt-in via environment, so an unconfigured host simply never registers:
|
|
18
|
-
* LATTICE_BRIDGE_REGISTRAR_SSH_HOST ssh destination (an ssh_config alias)
|
|
19
|
-
* LATTICE_BRIDGE_REGISTRAR_SCRIPT absolute path of the remote script
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { execFile } from 'node:child_process';
|
|
23
|
-
|
|
24
|
-
export const REGISTRAR_RESULT_SCHEMA = 'lattice.bridge_registrar_result.v1';
|
|
25
|
-
|
|
26
|
-
const SSH_HOST = /^[A-Za-z0-9][A-Za-z0-9._-]{0,253}$/u;
|
|
27
|
-
const REMOTE_SCRIPT = /^\/[A-Za-z0-9._\-/]{1,255}$/u;
|
|
28
|
-
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
29
|
-
|
|
30
|
-
export class BridgeRegistrarError extends Error {
|
|
31
|
-
constructor(code, message, detail = null) {
|
|
32
|
-
super(message);
|
|
33
|
-
this.name = 'BridgeRegistrarError';
|
|
34
|
-
this.code = code;
|
|
35
|
-
this.detail = detail;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Registrar settings, or null when the operator has not opted in.
|
|
41
|
-
* A half-configured registrar is an error rather than a silent no-op: it means
|
|
42
|
-
* someone intended to register and the site will quietly rot if we skip it.
|
|
43
|
-
*/
|
|
44
|
-
export function bridgeRegistrarSettings(env = process.env) {
|
|
45
|
-
const host = env.LATTICE_BRIDGE_REGISTRAR_SSH_HOST ?? '';
|
|
46
|
-
const script = env.LATTICE_BRIDGE_REGISTRAR_SCRIPT ?? '';
|
|
47
|
-
if (host === '' && script === '') return null;
|
|
48
|
-
if (!SSH_HOST.test(host)) {
|
|
49
|
-
throw new BridgeRegistrarError('BRIDGE_REGISTRAR_INVALID',
|
|
50
|
-
'LATTICE_BRIDGE_REGISTRAR_SSH_HOST must be a bare ssh destination', { host });
|
|
51
|
-
}
|
|
52
|
-
if (!REMOTE_SCRIPT.test(script)) {
|
|
53
|
-
throw new BridgeRegistrarError('BRIDGE_REGISTRAR_INVALID',
|
|
54
|
-
'LATTICE_BRIDGE_REGISTRAR_SCRIPT must be an absolute path without spaces', { script });
|
|
55
|
-
}
|
|
56
|
-
return Object.freeze({ host, script });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function runSsh({ host, script, port, timeoutMs, runner }) {
|
|
60
|
-
const args = ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10', host, script, String(port)];
|
|
61
|
-
return new Promise((resolve) => {
|
|
62
|
-
runner('ssh', args, { timeout: timeoutMs, encoding: 'utf8' }, (error, stdout, stderr) => {
|
|
63
|
-
resolve({ error, stdout: String(stdout ?? ''), stderr: String(stderr ?? '') });
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Register `port` on the reverse proxy host. The address is deliberately NOT
|
|
70
|
-
* sent: the remote end reads it from the ssh connection, so this host can only
|
|
71
|
-
* ever register itself.
|
|
72
|
-
*
|
|
73
|
-
* Never throws for a remote failure — the bridge is still serving locally and
|
|
74
|
-
* taking it down would turn a proxy-config problem into an outage. The failure
|
|
75
|
-
* is returned typed so callers surface it instead of swallowing it.
|
|
76
|
-
*/
|
|
77
|
-
export async function registerBridgeUpstream({
|
|
78
|
-
port, env = process.env, timeoutMs = DEFAULT_TIMEOUT_MS, runner = execFile,
|
|
79
|
-
} = {}) {
|
|
80
|
-
if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {
|
|
81
|
-
throw new BridgeRegistrarError('BRIDGE_REGISTRAR_INVALID', 'registration port is invalid', { port });
|
|
82
|
-
}
|
|
83
|
-
const settings = bridgeRegistrarSettings(env);
|
|
84
|
-
if (settings === null) {
|
|
85
|
-
return { schema: REGISTRAR_RESULT_SCHEMA, state: 'not_configured', port,
|
|
86
|
-
host: null, remote: null, detail: null };
|
|
87
|
-
}
|
|
88
|
-
const { error, stdout, stderr } = await runSsh({ ...settings, port, timeoutMs, runner });
|
|
89
|
-
if (error) {
|
|
90
|
-
return { schema: REGISTRAR_RESULT_SCHEMA, state: 'failed', port, host: settings.host,
|
|
91
|
-
remote: null, detail: (stderr.trim() || error.message || 'ssh registration failed').slice(0, 500) };
|
|
92
|
-
}
|
|
93
|
-
let remote = null;
|
|
94
|
-
try { remote = JSON.parse(stdout.trim()); } catch { remote = null; }
|
|
95
|
-
if (remote === null) {
|
|
96
|
-
return { schema: REGISTRAR_RESULT_SCHEMA, state: 'failed', port, host: settings.host,
|
|
97
|
-
remote: null, detail: `registrar returned no parsable result: ${stdout.trim().slice(0, 200)}` };
|
|
98
|
-
}
|
|
99
|
-
return { schema: REGISTRAR_RESULT_SCHEMA,
|
|
100
|
-
state: remote.changed === true ? 'updated' : 'unchanged',
|
|
101
|
-
port, host: settings.host, remote, detail: null };
|
|
102
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Bridge upstream self-registration.
|
|
3
|
+
*
|
|
4
|
+
* The public site is reverse-proxied to a literal LAN address held by another
|
|
5
|
+
* host. When this host's address moves — a DHCP lease change is enough — that
|
|
6
|
+
* literal goes stale and the site starts failing, with nothing on either side
|
|
7
|
+
* noticing. Registration closes that loop: after the bridge binds, it tells the
|
|
8
|
+
* reverse proxy where it actually is.
|
|
9
|
+
*
|
|
10
|
+
* This is an explicit connector, not a hook into someone else's tooling. It
|
|
11
|
+
* runs one fixed shape — `ssh <host> <script> <port>` — over the operator's
|
|
12
|
+
* existing ssh trust, and both operands are validated. Lattice never sends a
|
|
13
|
+
* command string, so the reverse proxy host decides what registration means and
|
|
14
|
+
* can refuse anything it does not like. The remote script is expected to derive
|
|
15
|
+
* the address from the ssh source rather than trusting anything sent to it.
|
|
16
|
+
*
|
|
17
|
+
* Opt-in via environment, so an unconfigured host simply never registers:
|
|
18
|
+
* LATTICE_BRIDGE_REGISTRAR_SSH_HOST ssh destination (an ssh_config alias)
|
|
19
|
+
* LATTICE_BRIDGE_REGISTRAR_SCRIPT absolute path of the remote script
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { execFile } from 'node:child_process';
|
|
23
|
+
|
|
24
|
+
export const REGISTRAR_RESULT_SCHEMA = 'lattice.bridge_registrar_result.v1';
|
|
25
|
+
|
|
26
|
+
const SSH_HOST = /^[A-Za-z0-9][A-Za-z0-9._-]{0,253}$/u;
|
|
27
|
+
const REMOTE_SCRIPT = /^\/[A-Za-z0-9._\-/]{1,255}$/u;
|
|
28
|
+
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
29
|
+
|
|
30
|
+
export class BridgeRegistrarError extends Error {
|
|
31
|
+
constructor(code, message, detail = null) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'BridgeRegistrarError';
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.detail = detail;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Registrar settings, or null when the operator has not opted in.
|
|
41
|
+
* A half-configured registrar is an error rather than a silent no-op: it means
|
|
42
|
+
* someone intended to register and the site will quietly rot if we skip it.
|
|
43
|
+
*/
|
|
44
|
+
export function bridgeRegistrarSettings(env = process.env) {
|
|
45
|
+
const host = env.LATTICE_BRIDGE_REGISTRAR_SSH_HOST ?? '';
|
|
46
|
+
const script = env.LATTICE_BRIDGE_REGISTRAR_SCRIPT ?? '';
|
|
47
|
+
if (host === '' && script === '') return null;
|
|
48
|
+
if (!SSH_HOST.test(host)) {
|
|
49
|
+
throw new BridgeRegistrarError('BRIDGE_REGISTRAR_INVALID',
|
|
50
|
+
'LATTICE_BRIDGE_REGISTRAR_SSH_HOST must be a bare ssh destination', { host });
|
|
51
|
+
}
|
|
52
|
+
if (!REMOTE_SCRIPT.test(script)) {
|
|
53
|
+
throw new BridgeRegistrarError('BRIDGE_REGISTRAR_INVALID',
|
|
54
|
+
'LATTICE_BRIDGE_REGISTRAR_SCRIPT must be an absolute path without spaces', { script });
|
|
55
|
+
}
|
|
56
|
+
return Object.freeze({ host, script });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function runSsh({ host, script, port, timeoutMs, runner }) {
|
|
60
|
+
const args = ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10', host, script, String(port)];
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
runner('ssh', args, { timeout: timeoutMs, encoding: 'utf8' }, (error, stdout, stderr) => {
|
|
63
|
+
resolve({ error, stdout: String(stdout ?? ''), stderr: String(stderr ?? '') });
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Register `port` on the reverse proxy host. The address is deliberately NOT
|
|
70
|
+
* sent: the remote end reads it from the ssh connection, so this host can only
|
|
71
|
+
* ever register itself.
|
|
72
|
+
*
|
|
73
|
+
* Never throws for a remote failure — the bridge is still serving locally and
|
|
74
|
+
* taking it down would turn a proxy-config problem into an outage. The failure
|
|
75
|
+
* is returned typed so callers surface it instead of swallowing it.
|
|
76
|
+
*/
|
|
77
|
+
export async function registerBridgeUpstream({
|
|
78
|
+
port, env = process.env, timeoutMs = DEFAULT_TIMEOUT_MS, runner = execFile,
|
|
79
|
+
} = {}) {
|
|
80
|
+
if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {
|
|
81
|
+
throw new BridgeRegistrarError('BRIDGE_REGISTRAR_INVALID', 'registration port is invalid', { port });
|
|
82
|
+
}
|
|
83
|
+
const settings = bridgeRegistrarSettings(env);
|
|
84
|
+
if (settings === null) {
|
|
85
|
+
return { schema: REGISTRAR_RESULT_SCHEMA, state: 'not_configured', port,
|
|
86
|
+
host: null, remote: null, detail: null };
|
|
87
|
+
}
|
|
88
|
+
const { error, stdout, stderr } = await runSsh({ ...settings, port, timeoutMs, runner });
|
|
89
|
+
if (error) {
|
|
90
|
+
return { schema: REGISTRAR_RESULT_SCHEMA, state: 'failed', port, host: settings.host,
|
|
91
|
+
remote: null, detail: (stderr.trim() || error.message || 'ssh registration failed').slice(0, 500) };
|
|
92
|
+
}
|
|
93
|
+
let remote = null;
|
|
94
|
+
try { remote = JSON.parse(stdout.trim()); } catch { remote = null; }
|
|
95
|
+
if (remote === null) {
|
|
96
|
+
return { schema: REGISTRAR_RESULT_SCHEMA, state: 'failed', port, host: settings.host,
|
|
97
|
+
remote: null, detail: `registrar returned no parsable result: ${stdout.trim().slice(0, 200)}` };
|
|
98
|
+
}
|
|
99
|
+
return { schema: REGISTRAR_RESULT_SCHEMA,
|
|
100
|
+
state: remote.changed === true ? 'updated' : 'unchanged',
|
|
101
|
+
port, host: settings.host, remote, detail: null };
|
|
102
|
+
}
|