total-recall-brain 3.41.1 → 3.41.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/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +1456 -12
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +210 -27
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +10 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/rotation-capability.mjs +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-env-export.mjs +78 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-merge.mjs +131 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-remote-deploy.mjs +111 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-store.mjs +26 -5
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/{src/core/headscale-server.mjs → capability/control-server.mjs} +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/capability/headscale-api.mjs +192 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/capability/index.mjs +46 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +23 -22
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +6 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +242 -8
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +14 -9
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/server.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/credentials.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/headscale-client.mjs +34 -181
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh-auth.mjs +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/presence.mjs +5 -5
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/screen-view.mjs +78 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +211 -12
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/card.js +323 -388
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +12 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +7 -4
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +34 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/bootstrap.mjs +99 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/templates/openwiki/README.md +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/templates/openwiki/architecture.md +5 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/templates/openwiki/ide.md +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/templates/openwiki/memory.md +11 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/templates/openwiki/secrets.md +7 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/templates/openwiki/skills.md +7 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/references/auth.md +2 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mesh control-server capability: the developer's own Headscale, host-free.
|
|
3
|
+
*
|
|
4
|
+
* A project that vendors this brick provisions, updates and administers its
|
|
5
|
+
* own control server without Total Recall. The caller supplies the target host,
|
|
6
|
+
* and may inject the command runner (`exec`), the release lookups and the HTTP
|
|
7
|
+
* transport; the defaults use only Node built-ins (`ssh` through
|
|
8
|
+
* child_process, global `fetch`). Credentials are never read from a store or
|
|
9
|
+
* the environment here: provisioning returns the new API key to the caller,
|
|
10
|
+
* and the API client takes the key as an argument.
|
|
11
|
+
*/
|
|
12
|
+
import {
|
|
13
|
+
meshTargetOf,
|
|
14
|
+
sshExec,
|
|
15
|
+
provisionHeadscale,
|
|
16
|
+
updateHeadscale,
|
|
17
|
+
installConsole,
|
|
18
|
+
updateConsole,
|
|
19
|
+
} from './control-server.mjs';
|
|
20
|
+
|
|
21
|
+
export { meshTargetOf, sshExec, shellQuote, patchConfig, parseChecksum, consoleConfig } from './control-server.mjs';
|
|
22
|
+
export { createHeadscaleApi, buildMeshSshPolicy, assertSecureControlUrl, normalizeControlUrl } from './headscale-api.mjs';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Bind the control-server lifecycle to one host.
|
|
26
|
+
* @param {{ target: { name?: string, host: string, user: string, port?: number, domain: string },
|
|
27
|
+
* exec?: Function, fetchJson?: Function, fetchText?: Function, checkDns?: Function,
|
|
28
|
+
* log?: Function, wait?: Function }} options
|
|
29
|
+
*/
|
|
30
|
+
export function createControlServer({ target, exec, ...deps } = {}) {
|
|
31
|
+
const resolved = meshTargetOf({ name: target?.name, ssh: { host: target?.host, user: target?.user, port: target?.port }, domain: target?.domain });
|
|
32
|
+
if (!resolved) throw new Error('A control-server target needs a valid SSH host, SSH user and a public domain pointing at that host');
|
|
33
|
+
const run = exec || sshExec(resolved);
|
|
34
|
+
const shared = Object.fromEntries(Object.entries(deps).filter(([, v]) => v !== undefined));
|
|
35
|
+
return {
|
|
36
|
+
target: resolved,
|
|
37
|
+
/** Install Headscale on a fresh Debian 12+/Ubuntu 22.04+ host; returns the control URL, API key and a 1-hour pre-auth key. */
|
|
38
|
+
provision: (opts = {}) => provisionHeadscale(resolved, { ...shared, ...opts, exec: run }),
|
|
39
|
+
/** Stage, trial, switch and roll back to the latest release; `checkOnly` reports without changing anything. */
|
|
40
|
+
update: (opts = {}) => updateHeadscale(resolved, { ...shared, ...opts, exec: run }),
|
|
41
|
+
/** Install the optional Headplane console, bound to loopback. */
|
|
42
|
+
installConsole: (opts = {}) => installConsole(resolved, { ...shared, ...opts, exec: run }),
|
|
43
|
+
/** Move the console to the latest release, restoring the previous image on failure. */
|
|
44
|
+
updateConsole: (opts = {}) => updateConsole(resolved, { ...shared, ...opts, exec: run }),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -18,7 +18,15 @@ export async function run(argv = []) {
|
|
|
18
18
|
const at=args.indexOf('--mode');const mode=at<0?0o600:Number.parseInt(args[at+1],8);
|
|
19
19
|
console.log(JSON.stringify(await putMeshFile({node:args[2],source:args[3],destination:args[4],mode})));return;
|
|
20
20
|
}
|
|
21
|
-
if (sub === '
|
|
21
|
+
if (sub === 'view') {
|
|
22
|
+
const { readMeshView } = await import('./src/core/screen-view.mjs');
|
|
23
|
+
if (args.slice(1).some(arg => arg.startsWith('-') && arg !== '--json')) throw new Error('view accepts a screen and --json only');
|
|
24
|
+
const names = args.slice(1).filter(arg => arg !== '--json');
|
|
25
|
+
if (names.length > 1) throw new Error('view accepts one screen');
|
|
26
|
+
console.log(JSON.stringify(await readMeshView(names[0])));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (sub === 'status' || sub === 'probe') {
|
|
22
30
|
const result = await meshStatus();
|
|
23
31
|
console.log(JSON.stringify(result));
|
|
24
32
|
if (sub === 'probe' && !result.control.verified) process.exitCode = 1;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tr-plugin-mesh",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "tr-plugin-mesh",
|
|
9
|
-
"version": "0.2.
|
|
9
|
+
"version": "0.2.4",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^5.2.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"jsdom": "^29.1.1",
|
|
16
|
-
"supertest": "^7.
|
|
17
|
-
"total-recall-brain": "3.
|
|
18
|
-
"vitest": "^4.1.
|
|
16
|
+
"supertest": "^7.3.1",
|
|
17
|
+
"total-recall-brain": "3.41.1",
|
|
18
|
+
"vitest": "^4.1.12"
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"node_modules/@asamuzakjp/css-color": {
|
|
@@ -1259,18 +1259,18 @@
|
|
|
1259
1259
|
}
|
|
1260
1260
|
},
|
|
1261
1261
|
"node_modules/body-parser": {
|
|
1262
|
-
"version": "2.
|
|
1263
|
-
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.
|
|
1264
|
-
"integrity": "sha512-
|
|
1262
|
+
"version": "2.4.0",
|
|
1263
|
+
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz",
|
|
1264
|
+
"integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==",
|
|
1265
1265
|
"license": "MIT",
|
|
1266
1266
|
"dependencies": {
|
|
1267
1267
|
"bytes": "^3.1.2",
|
|
1268
|
-
"content-type": "^2.
|
|
1268
|
+
"content-type": "^2.1.0",
|
|
1269
1269
|
"debug": "^4.4.3",
|
|
1270
1270
|
"http-errors": "^2.0.1",
|
|
1271
|
-
"iconv-lite": "^0.7.
|
|
1271
|
+
"iconv-lite": "^0.7.3",
|
|
1272
1272
|
"on-finished": "^2.4.1",
|
|
1273
|
-
"qs": "^6.
|
|
1273
|
+
"qs": "^6.16.1",
|
|
1274
1274
|
"raw-body": "^3.0.2",
|
|
1275
1275
|
"type-is": "^2.1.0"
|
|
1276
1276
|
},
|
|
@@ -4187,22 +4187,22 @@
|
|
|
4187
4187
|
}
|
|
4188
4188
|
},
|
|
4189
4189
|
"node_modules/tldts": {
|
|
4190
|
-
"version": "7.4.
|
|
4191
|
-
"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.
|
|
4192
|
-
"integrity": "sha512-
|
|
4190
|
+
"version": "7.4.19",
|
|
4191
|
+
"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.19.tgz",
|
|
4192
|
+
"integrity": "sha512-48dH6aSpQnpbzDUc4vIQZ1VjB8tkK+e8c1yx05/SZK+rkssgjEOlxDd/yU8/a4vGYQ9vRgJr9dwMq9TJ0b3X2Q==",
|
|
4193
4193
|
"dev": true,
|
|
4194
4194
|
"license": "MIT",
|
|
4195
4195
|
"dependencies": {
|
|
4196
|
-
"tldts-core": "^7.4.
|
|
4196
|
+
"tldts-core": "^7.4.19"
|
|
4197
4197
|
},
|
|
4198
4198
|
"bin": {
|
|
4199
4199
|
"tldts": "bin/cli.js"
|
|
4200
4200
|
}
|
|
4201
4201
|
},
|
|
4202
4202
|
"node_modules/tldts-core": {
|
|
4203
|
-
"version": "7.4.
|
|
4204
|
-
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.
|
|
4205
|
-
"integrity": "sha512-
|
|
4203
|
+
"version": "7.4.19",
|
|
4204
|
+
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.19.tgz",
|
|
4205
|
+
"integrity": "sha512-goNXV6Ho9TIOfpJZanTd6CKG5DyYgYAL+k+22T0SLh8l6+KHIfBUPFuePuSZv05UttIaaLmI9tb7TmGIdK5AkQ==",
|
|
4206
4206
|
"dev": true,
|
|
4207
4207
|
"license": "MIT"
|
|
4208
4208
|
},
|
|
@@ -4216,9 +4216,9 @@
|
|
|
4216
4216
|
}
|
|
4217
4217
|
},
|
|
4218
4218
|
"node_modules/total-recall-brain": {
|
|
4219
|
-
"version": "3.
|
|
4220
|
-
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.
|
|
4221
|
-
"integrity": "sha512-
|
|
4219
|
+
"version": "3.41.1",
|
|
4220
|
+
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.1.tgz",
|
|
4221
|
+
"integrity": "sha512-QraXzcZpCTMssx1gaz8xjvSKf5KqirAaxzzER/ICBrWvawdNTLUDDMsVEYQUA/7thgwtL1QVIxU4dpfCGZwp+g==",
|
|
4222
4222
|
"dev": true,
|
|
4223
4223
|
"license": "MIT",
|
|
4224
4224
|
"workspaces": [
|
|
@@ -4247,7 +4247,8 @@
|
|
|
4247
4247
|
"bin": {
|
|
4248
4248
|
"antigravity": "bin/antigravity.mjs",
|
|
4249
4249
|
"total-recall": "bin/total-recall.mjs",
|
|
4250
|
-
"total-recall-memory": "bin/total-recall-memory.mjs"
|
|
4250
|
+
"total-recall-memory": "bin/total-recall-memory.mjs",
|
|
4251
|
+
"vibebrain": "bin/total-recall.mjs"
|
|
4251
4252
|
},
|
|
4252
4253
|
"optionalDependencies": {
|
|
4253
4254
|
"playwright": "^1.60.0"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tr-plugin-mesh",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Headscale and Tailscale SSH control-server mesh administration and node discovery",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --test test/*.test.mjs"
|
|
7
|
+
"test": "node --test test/*.test.mjs && vitest run"
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"dependencies": {
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"README.md",
|
|
17
17
|
"LICENSE",
|
|
18
18
|
"ui/",
|
|
19
|
-
"
|
|
19
|
+
"capability/",
|
|
20
|
+
"src/",
|
|
21
|
+
"!src/**/*.spec.mjs",
|
|
22
|
+
"!src/**/*.test.mjs"
|
|
20
23
|
]
|
|
21
24
|
}
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
"$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
|
|
3
3
|
"id": "mesh",
|
|
4
4
|
"name": "Headscale",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.4",
|
|
6
6
|
"description": "Control-server mesh administration, Tailscale SSH, and peer node discovery.",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"requires": [
|
|
9
|
+
{
|
|
10
|
+
"id": "auth",
|
|
11
|
+
"range": ">=1.2.1"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
8
14
|
"branding": {
|
|
9
15
|
"name": "Headscale",
|
|
10
16
|
"color": "#818cf8",
|
|
@@ -90,10 +96,34 @@
|
|
|
90
96
|
"effect": "write",
|
|
91
97
|
"output": "json",
|
|
92
98
|
"args": [
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
{
|
|
100
|
+
"name": "operation",
|
|
101
|
+
"label": "Operation",
|
|
102
|
+
"type": "string",
|
|
103
|
+
"positional": true,
|
|
104
|
+
"required": true
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "node",
|
|
108
|
+
"label": "Node",
|
|
109
|
+
"type": "string",
|
|
110
|
+
"positional": true,
|
|
111
|
+
"required": true
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "source",
|
|
115
|
+
"label": "Source",
|
|
116
|
+
"type": "string",
|
|
117
|
+
"positional": true,
|
|
118
|
+
"required": true
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "destination",
|
|
122
|
+
"label": "Destination",
|
|
123
|
+
"type": "string",
|
|
124
|
+
"positional": true,
|
|
125
|
+
"required": true
|
|
126
|
+
}
|
|
97
127
|
]
|
|
98
128
|
},
|
|
99
129
|
{
|
|
@@ -103,8 +133,30 @@
|
|
|
103
133
|
},
|
|
104
134
|
{
|
|
105
135
|
"name": "view",
|
|
106
|
-
"description": "
|
|
107
|
-
"effect": "read"
|
|
136
|
+
"description": "Read independent owner observations for mesh screens",
|
|
137
|
+
"effect": "read",
|
|
138
|
+
"timeout_ms": 60000,
|
|
139
|
+
"args": [
|
|
140
|
+
{
|
|
141
|
+
"name": "screen",
|
|
142
|
+
"label": "Screen",
|
|
143
|
+
"type": "choice",
|
|
144
|
+
"positional": true,
|
|
145
|
+
"options": [
|
|
146
|
+
"machines",
|
|
147
|
+
"flows",
|
|
148
|
+
"placement",
|
|
149
|
+
"boundary",
|
|
150
|
+
"join"
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "json",
|
|
155
|
+
"label": "JSON output",
|
|
156
|
+
"type": "boolean",
|
|
157
|
+
"flag": "--json"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
108
160
|
},
|
|
109
161
|
{
|
|
110
162
|
"name": "nodes",
|
|
@@ -145,7 +197,7 @@
|
|
|
145
197
|
{
|
|
146
198
|
"name": "enroll",
|
|
147
199
|
"description": "Mesh enroll operation",
|
|
148
|
-
"effect": "
|
|
200
|
+
"effect": "destructive"
|
|
149
201
|
},
|
|
150
202
|
{
|
|
151
203
|
"name": "preauthkey",
|
|
@@ -292,5 +344,187 @@
|
|
|
292
344
|
"distribution": {
|
|
293
345
|
"tier": "official",
|
|
294
346
|
"license": "open"
|
|
347
|
+
},
|
|
348
|
+
"mesh": {
|
|
349
|
+
"version": 1,
|
|
350
|
+
"description": "Declared support and observation contracts; declarations are not live readiness or primitive grants.",
|
|
351
|
+
"provides": [
|
|
352
|
+
{
|
|
353
|
+
"id": "node-inventory",
|
|
354
|
+
"operation": "status",
|
|
355
|
+
"runtime": "mesh",
|
|
356
|
+
"observation": "machines.status"
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"id": "execution-probe",
|
|
360
|
+
"operation": "doctor",
|
|
361
|
+
"runtime": "mesh",
|
|
362
|
+
"observation": "doctor"
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"id": "remote-execution",
|
|
366
|
+
"operation": "exec",
|
|
367
|
+
"runtime": "mesh",
|
|
368
|
+
"observation": "doctor"
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"id": "path-probe",
|
|
372
|
+
"operation": "ping",
|
|
373
|
+
"runtime": "mesh",
|
|
374
|
+
"observation": "ping"
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"id": "presence",
|
|
378
|
+
"operation": "presence",
|
|
379
|
+
"runtime": "presence",
|
|
380
|
+
"observation": "machines.presence"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"id": "file-push",
|
|
384
|
+
"operation": "file",
|
|
385
|
+
"runtime": "mesh",
|
|
386
|
+
"observation": null
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"id": "secret-grants",
|
|
390
|
+
"operation": "grants",
|
|
391
|
+
"runtime": "mesh-identity",
|
|
392
|
+
"observation": "flows.grants"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"id": "control-policy",
|
|
396
|
+
"operation": "policy",
|
|
397
|
+
"runtime": "headscale-client",
|
|
398
|
+
"observation": "boundary.policy"
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"id": "enrollment",
|
|
402
|
+
"operation": "enroll",
|
|
403
|
+
"runtime": "mesh-enroll",
|
|
404
|
+
"observation": "join.status"
|
|
405
|
+
}
|
|
406
|
+
],
|
|
407
|
+
"integrations": [
|
|
408
|
+
{
|
|
409
|
+
"id": "auth",
|
|
410
|
+
"owner": "auth",
|
|
411
|
+
"purpose": "One host credential store; no values in views",
|
|
412
|
+
"observation": "machines.status",
|
|
413
|
+
"evidence": "control.verified"
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"id": "headscale",
|
|
417
|
+
"owner": "mesh",
|
|
418
|
+
"purpose": "Control server authentication and membership",
|
|
419
|
+
"observation": "machines.status",
|
|
420
|
+
"evidence": "control.verified"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"id": "tailscale",
|
|
424
|
+
"owner": "mesh",
|
|
425
|
+
"purpose": "Client enrollment and mesh network state",
|
|
426
|
+
"observation": "machines.status",
|
|
427
|
+
"evidence": "network_available"
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"id": "ssh",
|
|
431
|
+
"owner": "mesh",
|
|
432
|
+
"purpose": "Per-machine execution probes",
|
|
433
|
+
"observation": "doctor",
|
|
434
|
+
"evidence": "reachable per machine"
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
"id": "presence",
|
|
438
|
+
"owner": "mesh",
|
|
439
|
+
"purpose": "Authenticated fresh activity observations",
|
|
440
|
+
"observation": "machines.presence",
|
|
441
|
+
"evidence": "peer states and timestamps"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"id": "plugin-sharing",
|
|
445
|
+
"owner": "mesh",
|
|
446
|
+
"purpose": "Peer plugin inventories",
|
|
447
|
+
"observation": "flows.plugins",
|
|
448
|
+
"evidence": "peer status"
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"id": "updates",
|
|
452
|
+
"owner": "core",
|
|
453
|
+
"purpose": "Last automatic maintenance report",
|
|
454
|
+
"observation": "flows.updates",
|
|
455
|
+
"evidence": "recorded last result"
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"id": "schedules",
|
|
459
|
+
"owner": "user-automations",
|
|
460
|
+
"purpose": "Task declarations and node placement",
|
|
461
|
+
"observation": "flows.tasks",
|
|
462
|
+
"evidence": "node inventory; no execution inferred"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
"id": "agents",
|
|
466
|
+
"owner": "core",
|
|
467
|
+
"purpose": "Running and recent process inventory",
|
|
468
|
+
"observation": "flows.agents",
|
|
469
|
+
"evidence": "process records"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
"id": "alerts",
|
|
473
|
+
"owner": "operator-alerts",
|
|
474
|
+
"purpose": "Recorded delivery attempts",
|
|
475
|
+
"observation": "flows.alerts",
|
|
476
|
+
"evidence": "ledger result; no recipient view inferred"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"id": "deployments",
|
|
480
|
+
"owner": "deploy",
|
|
481
|
+
"purpose": "Selected project release state",
|
|
482
|
+
"observation": "flows.deployments",
|
|
483
|
+
"evidence": "configured slot; no fleet-wide inference"
|
|
484
|
+
}
|
|
485
|
+
],
|
|
486
|
+
"endpoints": [
|
|
487
|
+
{
|
|
488
|
+
"path": "/api/mesh/presence/local",
|
|
489
|
+
"method": "GET",
|
|
490
|
+
"runtime": "route-mesh-presence",
|
|
491
|
+
"authentication": "mesh peer"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"path": "/api/mesh/plugins",
|
|
495
|
+
"method": "GET",
|
|
496
|
+
"runtime": "route-plugins-mesh",
|
|
497
|
+
"authentication": "mesh peer"
|
|
498
|
+
}
|
|
499
|
+
],
|
|
500
|
+
"task_placement": "Declared task placement is selected-node or per-node; actual execution requires a verified daemon report.",
|
|
501
|
+
"unavailable": [
|
|
502
|
+
"transfer-history",
|
|
503
|
+
"service-health-cli",
|
|
504
|
+
"exit-node-management",
|
|
505
|
+
"subnet-route-management",
|
|
506
|
+
"tunnel-inventory",
|
|
507
|
+
"public-exposure-inventory",
|
|
508
|
+
"speed-measurement",
|
|
509
|
+
"messages",
|
|
510
|
+
"shared-file-spaces"
|
|
511
|
+
]
|
|
512
|
+
},
|
|
513
|
+
"capability": {
|
|
514
|
+
"entry": "capability/index.mjs",
|
|
515
|
+
"dependencies": [],
|
|
516
|
+
"exports": [
|
|
517
|
+
"createControlServer",
|
|
518
|
+
"createHeadscaleApi",
|
|
519
|
+
"buildMeshSshPolicy",
|
|
520
|
+
"meshTargetOf",
|
|
521
|
+
"sshExec",
|
|
522
|
+
"assertSecureControlUrl",
|
|
523
|
+
"normalizeControlUrl",
|
|
524
|
+
"shellQuote",
|
|
525
|
+
"patchConfig",
|
|
526
|
+
"parseChecksum",
|
|
527
|
+
"consoleConfig"
|
|
528
|
+
]
|
|
295
529
|
}
|
|
296
530
|
}
|
|
@@ -46,6 +46,7 @@ function printHelp() {
|
|
|
46
46
|
Usage: total-recall mesh <command> [options]
|
|
47
47
|
|
|
48
48
|
status Control-server reachability and credential state
|
|
49
|
+
view <screen> Read Machines, Flows, Placement, Boundary or Join sources (--json)
|
|
49
50
|
doctor Probe reachability & compute capabilities across all nodes
|
|
50
51
|
nodes List mesh nodes and how to reach each one
|
|
51
52
|
ssh <node> [cmd…] Open a session using the node's recorded access
|
|
@@ -194,9 +195,9 @@ export default async function meshCli(argv = []) {
|
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
if (command === 'doctor' || command === 'diagnostics') {
|
|
197
|
-
console.log('\n🩺 Total Recall — Mesh Diagnostics & Compute Capability Audit\n');
|
|
198
198
|
const enriched = listEnrichedMeshNodes(vaultRoot);
|
|
199
199
|
const isJson = args.includes('--json');
|
|
200
|
+
if (!isJson) console.log('\n🩺 Total Recall — Mesh Diagnostics & Compute Capability Audit\n');
|
|
200
201
|
|
|
201
202
|
const stripAnsi = (s) => String(s || '').replace(/\x1b\[[0-9;]*m/g, '');
|
|
202
203
|
const pad = (s, l) => String(s || '') + ' '.repeat(Math.max(0, l - stripAnsi(s).length));
|
|
@@ -217,13 +218,17 @@ export default async function meshCli(argv = []) {
|
|
|
217
218
|
reachable: false,
|
|
218
219
|
error: null
|
|
219
220
|
};
|
|
221
|
+
nodeInfo.tested_runtimes = ['ollama', 'docker', 'node', 'git'];
|
|
222
|
+
nodeInfo.tested_harnesses = ['agy', 'claude', 'codex', 'gemini'];
|
|
220
223
|
|
|
221
224
|
if (node.self) {
|
|
222
225
|
try {
|
|
223
226
|
const { detectHarnesses } = await import('../core/meta-harness.mjs');
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
+
const detected = detectHarnesses();
|
|
228
|
+
nodeInfo.harnesses = detected.filter(h => h.available).map(h => h.id);
|
|
229
|
+
nodeInfo.tested_harnesses = detected.map(h => h.id);
|
|
230
|
+
} catch { nodeInfo.tested_harnesses = []; }
|
|
231
|
+
nodeInfo.runtimes = nodeInfo.tested_runtimes.filter(tool => spawnSync('/bin/sh', ['-c', 'command -v "$1"', 'mesh-probe', tool], { encoding: 'utf8', timeout: 3000 }).status === 0);
|
|
227
232
|
nodeInfo.reachable = true;
|
|
228
233
|
} else if (resolved.complete) {
|
|
229
234
|
try {
|
|
@@ -233,16 +238,12 @@ export default async function meshCli(argv = []) {
|
|
|
233
238
|
// reachable machines as down.
|
|
234
239
|
const res = await execMeshCommand(node.hostname, probeCmd, { vaultRoot, timeoutMs: 15000 });
|
|
235
240
|
nodeInfo.reachable = res.success;
|
|
236
|
-
if (res.success && !node.access?.verified_at) {
|
|
237
|
-
// A login that just worked is the only kind worth sharing with peers.
|
|
238
|
-
await setMeshNodeAccess(node.hostname, { verified_at: new Date().toISOString() }, { vaultRoot });
|
|
239
|
-
}
|
|
240
241
|
if (res.success) {
|
|
241
242
|
const parts = res.stdout.split(/\s+/);
|
|
242
243
|
for (const part of parts) {
|
|
243
244
|
const [k, v] = part.split('=');
|
|
244
245
|
if (v && v.trim()) {
|
|
245
|
-
if (['agy', 'claude', 'codex', 'gemini'
|
|
246
|
+
if (['agy', 'claude', 'codex', 'gemini'].includes(k)) {
|
|
246
247
|
nodeInfo.harnesses.push(k);
|
|
247
248
|
} else {
|
|
248
249
|
nodeInfo.runtimes.push(k);
|
|
@@ -770,6 +771,10 @@ export default async function meshCli(argv = []) {
|
|
|
770
771
|
if (reportPolicyModeError(err)) return;
|
|
771
772
|
throw err;
|
|
772
773
|
}
|
|
774
|
+
if (args.includes('--json')) {
|
|
775
|
+
console.log(JSON.stringify({ configured: current.configured, policy: current.policy, updatedAt: current.updatedAt || null }));
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
773
778
|
if (!current.configured) {
|
|
774
779
|
console.log('No policy is set on the control server.');
|
|
775
780
|
console.log('Run `total-recall mesh policy init-ssh` to enable Tailscale SSH.');
|
|
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
|
-
import { meshTargetOf, provisionHeadscale, updateHeadscale, updateConsole, sshExec } from '
|
|
6
|
+
import { meshTargetOf, provisionHeadscale, updateHeadscale, updateConsole, sshExec } from '../../capability/control-server.mjs';
|
|
7
7
|
import { saveCredential } from '../core/credentials.mjs';
|
|
8
8
|
import { brainDir } from '../core/config.mjs';
|
|
9
9
|
import { PluginStateStore } from '../ssss-store.mjs';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { importHostModule } from '../host-runtime.mjs';
|
|
2
2
|
const { loadPluginModule: __loadOwnedPlugin } = await importHostModule('src/core/plugin-runtime.mjs');
|
|
3
3
|
import { assertSecureControlUrl, normalizeControlUrl, headscaleUrlFromEnv, findHeadscaleKeyMeta } from './headscale-client.mjs';
|
|
4
|
-
const { setSecret
|
|
4
|
+
const { setSecret } = await __loadOwnedPlugin('auth', 'secrets-store');
|
|
5
|
+
const { hostSecretsBrainDir } = await __loadOwnedPlugin('auth', 'host-secrets-store');
|
|
5
6
|
|
|
6
7
|
export async function verifyCredential(value, url, fetchImpl = fetch) {
|
|
7
8
|
if (typeof value !== 'string' || !value.trim()) throw new Error('A credential is required');
|
|
@@ -18,8 +19,9 @@ export async function verifyCredential(value, url, fetchImpl = fetch) {
|
|
|
18
19
|
return { verified: true, url: normalizeControlUrl(url) };
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
export async function saveCredential({ key, value, configuration = {}
|
|
22
|
+
export async function saveCredential({ key, value, configuration = {} }, dependencies = {}) {
|
|
22
23
|
if (key !== 'HEADSCALE_API_KEY') throw new Error('Unsupported mesh credential');
|
|
24
|
+
const brainDir = hostSecretsBrainDir();
|
|
23
25
|
const meta = await findHeadscaleKeyMeta(brainDir);
|
|
24
26
|
const url = configuration.controlUrl || headscaleUrlFromEnv() || meta?.headscale_url;
|
|
25
27
|
if (!url) throw new Error('Set the control server URL before saving the credential');
|