total-recall-brain 3.43.2 → 3.44.0
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/bin/total-recall-server-release.mjs +4 -0
- package/docs/reference/cli-reference.md +14 -0
- package/package.json +5 -4
- package/scaffold/.agent/skills/plugin/SKILL.md +7 -2
- package/scaffold/.agent/skills/plugin/evals/README.md +5 -0
- package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +1 -0
- package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +1 -0
- package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +1 -0
- package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +1 -0
- package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +1 -0
- package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +1 -0
- package/scaffold/.agent/skills/plugin/evals/cases/07-missing-reuse.mjs +11 -0
- package/scaffold/.agent/skills/plugin/evals/cases/08-unresolved-owner-command.mjs +12 -0
- package/scaffold/.agent/skills/plugin/evals/cases/09-missing-brick.mjs +12 -0
- package/scaffold/.agent/skills/plugin/prompts/01-function.md +4 -3
- package/scaffold/.agent/skills/plugin/prompts/08-verify.md +1 -0
- package/scaffold/.agent/skills/plugin/references/surfaces.md +12 -2
- package/scaffold/.agent/skills/plugin/scripts/record.mjs +59 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +8 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-gh-login.mjs +102 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +18 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +157 -13
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +161 -17
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/README.md +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +39 -6
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/config.schema.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +38 -5
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +38 -7
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +85 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adoption.mjs +104 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +12 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +15 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch-request.mjs +38 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +42 -11
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +40 -13
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/included-usage.mjs +249 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +16 -8
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +1 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +5 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +27 -11
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +28 -6
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/usage-queue.mjs +110 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +322 -40
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +14 -13
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/ssss/assets/scaffold.json +5 -5
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +1 -1
- package/src/cli/connect.mjs +2 -29
- package/src/cli/context.mjs +1 -0
- package/src/cli/ingest-okf.mjs +4 -4
- package/src/cli/release.mjs +27 -2
- package/src/cli/startup.mjs +1 -0
- package/src/cli/update.mjs +14 -3
- package/src/core/automatic-brain-updates.mjs +13 -3
- package/src/core/autopull-install.mjs +14 -0
- package/src/core/brain-updates.mjs +12 -2
- package/src/core/context-compactor.mjs +7 -2
- package/src/core/context-compiler.mjs +6 -1
- package/src/core/context-policy.mjs +7 -3
- package/src/core/daemon-control.mjs +22 -0
- package/src/core/global-brain-updates.mjs +3 -3
- package/src/core/mesh-brain-updates.mjs +20 -5
- package/src/core/running-server.mjs +76 -0
- package/src/core/server-release.mjs +487 -0
- package/src/core/server-restart.mjs +128 -7
- package/src/core/source-brain-updates.mjs +35 -6
- package/src/core/ssss-kernel-bridge.mjs +1 -2
- package/src/core/startup-health.mjs +13 -2
- package/src/core/surface.mjs +3 -3
- package/src/core/task-context.mjs +9 -8
- package/src/core/validated-write.mjs +4 -0
- package/src/core/vault-files.mjs +8 -2
- package/src/core/vault.mjs +1 -1
- package/src/server/index.mjs +17 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
|
|
3
3
|
"id": "openwiki",
|
|
4
4
|
"name": "OpenWiki",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.10",
|
|
6
6
|
"description": "Multi-repo knowledge graph and documentation wiki engine for Total Recall.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"runtime": {
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tr-plugin-security",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "tr-plugin-security",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.6",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@gregiteen/ssss-cli": "0.14.
|
|
12
|
+
"@gregiteen/ssss-cli": "0.14.5"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"jsdom": "^26.1.0",
|
|
16
|
-
"total-recall-brain": "3.
|
|
16
|
+
"total-recall-brain": "3.43.3"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"node_modules/@alcalzone/ansi-tokenize": {
|
|
@@ -845,9 +845,9 @@
|
|
|
845
845
|
}
|
|
846
846
|
},
|
|
847
847
|
"node_modules/@gregiteen/ssss-cli": {
|
|
848
|
-
"version": "0.14.
|
|
849
|
-
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.
|
|
850
|
-
"integrity": "sha512-
|
|
848
|
+
"version": "0.14.5",
|
|
849
|
+
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.5.tgz",
|
|
850
|
+
"integrity": "sha512-qVEYOocnwn97uJ0eDzmuwN06CYsYWr2t3+iKylpisBHX4wlLWk7P8EmFFdBlx7NyKVIZDDeYT164Gd7/T8UGgw==",
|
|
851
851
|
"license": "ISC",
|
|
852
852
|
"bin": {
|
|
853
853
|
"ssss": "scripts/ssss.mjs"
|
|
@@ -1686,9 +1686,9 @@
|
|
|
1686
1686
|
},
|
|
1687
1687
|
"node_modules/@ssss/cli": {
|
|
1688
1688
|
"name": "@gregiteen/ssss-cli",
|
|
1689
|
-
"version": "0.14.
|
|
1690
|
-
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.
|
|
1691
|
-
"integrity": "sha512-
|
|
1689
|
+
"version": "0.14.5",
|
|
1690
|
+
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.5.tgz",
|
|
1691
|
+
"integrity": "sha512-qVEYOocnwn97uJ0eDzmuwN06CYsYWr2t3+iKylpisBHX4wlLWk7P8EmFFdBlx7NyKVIZDDeYT164Gd7/T8UGgw==",
|
|
1692
1692
|
"dev": true,
|
|
1693
1693
|
"license": "ISC",
|
|
1694
1694
|
"bin": {
|
|
@@ -5698,9 +5698,9 @@
|
|
|
5698
5698
|
}
|
|
5699
5699
|
},
|
|
5700
5700
|
"node_modules/total-recall-brain": {
|
|
5701
|
-
"version": "3.
|
|
5702
|
-
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.
|
|
5703
|
-
"integrity": "sha512-
|
|
5701
|
+
"version": "3.43.3",
|
|
5702
|
+
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.43.3.tgz",
|
|
5703
|
+
"integrity": "sha512-yjfPN/BQxEEa+iodyFXQov/6fRt1pZg/7RcmgsbpALwBt6Ki3JJjT3tzArBC7NxHQmXgGYyKnCYId6xe/W2rPg==",
|
|
5704
5704
|
"dev": true,
|
|
5705
5705
|
"license": "MIT",
|
|
5706
5706
|
"workspaces": [
|
|
@@ -5731,6 +5731,7 @@
|
|
|
5731
5731
|
"antigravity": "bin/antigravity.mjs",
|
|
5732
5732
|
"total-recall": "bin/total-recall.mjs",
|
|
5733
5733
|
"total-recall-memory": "bin/total-recall-memory.mjs",
|
|
5734
|
+
"total-recall-server-release": "bin/total-recall-server-release.mjs",
|
|
5734
5735
|
"vibebrain": "bin/total-recall.mjs"
|
|
5735
5736
|
},
|
|
5736
5737
|
"optionalDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tr-plugin-security",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Standalone security suite for Total Recall: static analysis, file and permission hardening schemes, AES-256-GCM encryption tools, and egress audit controls",
|
|
6
6
|
"scripts": {
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@gregiteen/ssss-cli": "0.14.
|
|
27
|
+
"@gregiteen/ssss-cli": "0.14.5"
|
|
28
28
|
},
|
|
29
29
|
"overrides": {
|
|
30
|
-
"@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.
|
|
30
|
+
"@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.5"
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
|
|
3
3
|
"id": "security",
|
|
4
4
|
"name": "Security Assessments",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.6",
|
|
6
6
|
"description": "Machine and device security assessments for macOS, Linux, Windows, Android, Chromebook, iPhone and iPad, with explicit measured and manual coverage.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"requires": [{ "id": "auth", "range": ">=1.2.1" }],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.14.
|
|
2
|
+
"version": "0.14.5",
|
|
3
3
|
"files": {
|
|
4
4
|
".gitignore": {
|
|
5
5
|
"sha256": "0d6c69a5cbd2270c9163d8e1563976b6d15131d0ef599e6fbc413ee287a86da0",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"content": "# ssss-project — System Architecture & Design\n\n> Technical design and architecture specification for ssss-project.\n\n## Overview\n\n<High-level summary of the system and its primary goals.>\n\n## Component Architecture\n\n- **Vault Structure**: Typed Markdown documents under `vault/` serving as the source of truth.\n- **Workflows & Execution**: Automated procedures defined in `vault/workflows/` triggered by operational events.\n- **Capabilities & Resources**: Tools and external service integrations required for execution.\n\n## Data & Schema Contracts\n\n<Core entities, external dependencies, and integration interfaces.>\n\n## Open Decisions & Invariants\n\n- SSSS VFS is the single source of truth for application state.\n- Structural business logic is strictly decoupled from private tenant operational data.\n- App-specific primitives reside in `registry/extensions/` within this repository and extend `core`.\n- Core SSSS library (`@gregiteen/ssss-cli`) remains vendor-neutral and dependency-free.\n"
|
|
19
19
|
},
|
|
20
20
|
"package.json": {
|
|
21
|
-
"sha256": "
|
|
22
|
-
"content": "{\n \"name\": \"ssss-project\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"description\": \"An SSSS-native project — Markdown vault as source of truth.\",\n \"scripts\": {\n \"ssss\": \"ssss\",\n \"test\": \"node --test\",\n \"export\": \"ssss export vault --profile sale --out dist/bundle.ucw.json\",\n \"validate\": \"ssss conformance --engine\"\n },\n \"dependencies\": {\n \"@gregiteen/ssss-cli\": \"github:gregiteen/ssss#v0.14.
|
|
21
|
+
"sha256": "ea77c2944b853999741a8e603de257604048c63b5db8754a0e8b92f383ff973b",
|
|
22
|
+
"content": "{\n \"name\": \"ssss-project\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"description\": \"An SSSS-native project — Markdown vault as source of truth.\",\n \"scripts\": {\n \"ssss\": \"ssss\",\n \"test\": \"node --test\",\n \"export\": \"ssss export vault --profile sale --out dist/bundle.ucw.json\",\n \"validate\": \"ssss conformance --engine\"\n },\n \"dependencies\": {\n \"@gregiteen/ssss-cli\": \"github:gregiteen/ssss#v0.14.5\"\n }\n}\n"
|
|
23
23
|
},
|
|
24
24
|
"test/ssss-conformance.test.mjs": {
|
|
25
25
|
"sha256": "f626d2f56799fcfda74375d3ddf546cc181a10caf2df08b72b7f2e36782c9bc1",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"skill": {
|
|
46
|
-
"SKILL.md": "
|
|
47
|
-
"core/SKILL.md": "
|
|
46
|
+
"SKILL.md": "e5c2c0aa2c0fb5480c1f7bdb37928f935e1160bff18fd6b63366a04f3e281938",
|
|
47
|
+
"core/SKILL.md": "12543720135f13650efcd7afd751e3253996692c6ab805fd7da99788b6fc4af9",
|
|
48
48
|
"core/references/core-registry.json": "16831aa3b6be3f561a9ca7abdc36065a4843ff595aa3acf5c3fb8af2d733b7e3",
|
|
49
49
|
"core/references/ssss-spec.md": "cc319e78b1b568651d5717695348363349d502c0e20663da9858369022ddfc3b",
|
|
50
50
|
"core/scripts/maintain.mjs": "eebcae898f2ce0cf3f0059c6f6737bee8877409de2d370d54a4015a9a82414e9",
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tr-plugin-ssss",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "tr-plugin-ssss",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.3",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@gregiteen/ssss-cli": "0.14.
|
|
12
|
+
"@gregiteen/ssss-cli": "0.14.5"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"node_modules/@gregiteen/ssss-cli": {
|
|
16
|
-
"version": "0.14.
|
|
17
|
-
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.
|
|
18
|
-
"integrity": "sha512-
|
|
16
|
+
"version": "0.14.5",
|
|
17
|
+
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.5.tgz",
|
|
18
|
+
"integrity": "sha512-qVEYOocnwn97uJ0eDzmuwN06CYsYWr2t3+iKylpisBHX4wlLWk7P8EmFFdBlx7NyKVIZDDeYT164Gd7/T8UGgw==",
|
|
19
19
|
"license": "ISC",
|
|
20
20
|
"bin": {
|
|
21
21
|
"ssss": "scripts/ssss.mjs"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tr-plugin-ssss",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Canonical SSSS distribution, scaffolding and validation for Total Recall installations.",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"check:ssss-conformance": "node cli.mjs conformance"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@gregiteen/ssss-cli": "0.14.
|
|
22
|
+
"@gregiteen/ssss-cli": "0.14.5"
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT"
|
|
25
25
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
|
|
3
3
|
"id": "ssss",
|
|
4
4
|
"name": "SSSS",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.3",
|
|
6
6
|
"description": "Canonical SSSS distribution, scaffolding and validation for Total Recall installations.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"use_cases": ["software-development", "state-conformance"],
|
package/src/cli/connect.mjs
CHANGED
|
@@ -80,11 +80,10 @@ export const CLIENTS = {
|
|
|
80
80
|
},
|
|
81
81
|
openclaw: {
|
|
82
82
|
label: 'OpenClaw',
|
|
83
|
-
mode: '
|
|
83
|
+
mode: 'symlink',
|
|
84
84
|
enforcement: 'enforced',
|
|
85
85
|
enforcementReason: 'before_tool_call hook denies unreceipted tool calls with exit 2',
|
|
86
|
-
|
|
87
|
-
agentsTarget: 'AGENTS.md',
|
|
86
|
+
target: 'AGENTS.md',
|
|
88
87
|
},
|
|
89
88
|
cursor: {
|
|
90
89
|
label: 'Cursor',
|
|
@@ -880,32 +879,6 @@ export default async function connect(args) {
|
|
|
880
879
|
result.notes.push(` DeepSeek Harness MEMORY.md → ${globalMemPath}`);
|
|
881
880
|
}
|
|
882
881
|
result.notes.push(` DeepSeek Harness AGENTS.md → INSTRUCTIONS.md`);
|
|
883
|
-
} else if (preset.mode === 'openclaw') {
|
|
884
|
-
// OpenClaw: write MEMORY.md + symlink AGENTS.md in cwd
|
|
885
|
-
const instructions = readInstructions(cwd, agentDir);
|
|
886
|
-
if (!instructions) throw new Error('No INSTRUCTIONS.md found. Run npx total-recall init or compile first.');
|
|
887
|
-
// MEMORY.md — curated facts extracted from instructions
|
|
888
|
-
const memPath = path.join(cwd, preset.memoryTarget);
|
|
889
|
-
if (!fs.existsSync(memPath) || opts.force) {
|
|
890
|
-
fs.writeFileSync(memPath, instructions, 'utf8');
|
|
891
|
-
}
|
|
892
|
-
// AGENTS.md — symlink to INSTRUCTIONS.md
|
|
893
|
-
const agentsPath = path.join(cwd, preset.agentsTarget);
|
|
894
|
-
if (pathExists(agentsPath)) {
|
|
895
|
-
if (opts.force) {
|
|
896
|
-
try {
|
|
897
|
-
fs.unlinkSync(agentsPath);
|
|
898
|
-
} catch {
|
|
899
|
-
fs.rmSync(agentsPath, { force: true, recursive: true });
|
|
900
|
-
}
|
|
901
|
-
fs.symlinkSync('INSTRUCTIONS.md', agentsPath);
|
|
902
|
-
}
|
|
903
|
-
} else {
|
|
904
|
-
fs.symlinkSync('INSTRUCTIONS.md', agentsPath);
|
|
905
|
-
}
|
|
906
|
-
result.projection = { targetPath: memPath, action: 'written' };
|
|
907
|
-
result.notes.push(` OpenClaw MEMORY.md written to ${memPath}`);
|
|
908
|
-
result.notes.push(` OpenClaw AGENTS.md → INSTRUCTIONS.md`);
|
|
909
882
|
} else if (preset.mode === 'vault') {
|
|
910
883
|
result.projection = writeVaultProjection(agentDir, preset, opts);
|
|
911
884
|
const folderName = result.projection.folderName || preset.folderName;
|
package/src/cli/context.mjs
CHANGED
|
@@ -61,6 +61,7 @@ async function printCompacted({ query, actions, budget, format, version, rulesHa
|
|
|
61
61
|
if (format !== 'json') return result.context;
|
|
62
62
|
const payload = { ready: true, compacted: true, ranking: result.ranking, context: result.context, counts: result.counts,
|
|
63
63
|
stats: { version, rules_hash: rulesHash, budget, retrieval: summarizeRetrieval(knowledge?.summary), token_measurement: 'estimated_chars_divided_by_four' } };
|
|
64
|
+
if (result.evidenceStart !== undefined) payload.evidence_start = result.evidenceStart;
|
|
64
65
|
for (let index = 0; index < 10; index++) {
|
|
65
66
|
const tokens = estimateTokens(`${JSON.stringify(payload)}\n`);
|
|
66
67
|
if (tokens === payload.stats.total_tokens) break;
|
package/src/cli/ingest-okf.mjs
CHANGED
|
@@ -11,7 +11,7 @@ export async function runOkfIngest(args) {
|
|
|
11
11
|
dryRun: false,
|
|
12
12
|
category: null,
|
|
13
13
|
importance: null,
|
|
14
|
-
onConflict: '
|
|
14
|
+
onConflict: 'skip',
|
|
15
15
|
typeMap: null,
|
|
16
16
|
help: false
|
|
17
17
|
};
|
|
@@ -118,10 +118,10 @@ function printIngestOkfHelp() {
|
|
|
118
118
|
|
|
119
119
|
Options:
|
|
120
120
|
--dry-run Validate concepts and preview import without writing
|
|
121
|
-
--category <name>
|
|
121
|
+
--category <name> Choose a descriptive category for imported concepts
|
|
122
122
|
--importance <1-5> Override default importance (default: 3)
|
|
123
|
-
--on-conflict <strategy>
|
|
124
|
-
--type-map <mapping>
|
|
123
|
+
--on-conflict <strategy> 'skip' (default), 'warn' (report and skip), or 'overwrite' (same imported concept)
|
|
124
|
+
--type-map <mapping> Map types to descriptive categories, e.g. "Type A=facts,Type B=concepts"
|
|
125
125
|
--global Target the global brain
|
|
126
126
|
--project Target the project brain (default)
|
|
127
127
|
--help, -h Show this help
|
package/src/cli/release.mjs
CHANGED
|
@@ -73,7 +73,8 @@ function printHelp() {
|
|
|
73
73
|
plan Resolve the release version and report gate/consumer readiness. No writes.
|
|
74
74
|
publish Run the package's prepublish gate, then npm publish. Requires --apply.
|
|
75
75
|
propagate Pin the published version across every registered consumer (update --all-brains).
|
|
76
|
-
verify Independently confirm the registry artifact
|
|
76
|
+
verify Independently confirm the registry artifact, each consumer's resolved install,
|
|
77
|
+
and that the server on this host runs the release.
|
|
77
78
|
all plan → publish → propagate → verify, stopping at the first failure.
|
|
78
79
|
|
|
79
80
|
Rules enforced here:
|
|
@@ -140,7 +141,10 @@ export async function tarballServed(pkg, version, { exec = spawnSync, fetchImpl
|
|
|
140
141
|
* Wait until a just-published version can be installed: listed as latest, and its tarball served.
|
|
141
142
|
* 3.42.0 took about six minutes and 3.42.1 about eight, its listing four minutes ahead of its tarball.
|
|
142
143
|
*/
|
|
143
|
-
|
|
144
|
+
/** npm has taken 8 and then 23 minutes to serve an accepted publish, so a shorter wait reports failure on a good release. */
|
|
145
|
+
export const REGISTRY_WAIT = Object.freeze({ attempts: 120, delayMs: 20000 });
|
|
146
|
+
|
|
147
|
+
export async function awaitPublished(pkg, version, { attempts = REGISTRY_WAIT.attempts, delayMs = REGISTRY_WAIT.delayMs, exec = spawnSync, sleep, tarball = tarballServed } = {}) {
|
|
144
148
|
const pause = sleep || ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
145
149
|
let last = null;
|
|
146
150
|
for (let i = 0; i < attempts; i++) {
|
|
@@ -295,6 +299,20 @@ export function verifyConsumers(pkg, version, opts = {}) {
|
|
|
295
299
|
};
|
|
296
300
|
}
|
|
297
301
|
|
|
302
|
+
/**
|
|
303
|
+
* What the server on this host runs. Files moving does not replace a running process, so a
|
|
304
|
+
* release is not verified here until the process is on it. Packages other than the brain and
|
|
305
|
+
* explicit --root runs have no server to ask about.
|
|
306
|
+
*/
|
|
307
|
+
export async function verifyRunningServer(pkg, version, { check, explicitRoot = false } = {}) {
|
|
308
|
+
if (pkg !== 'total-recall-brain' || explicitRoot) return { checked: false, ok: true };
|
|
309
|
+
const server = await (check || (async (args) => {
|
|
310
|
+
const [{ runningServerStatus }, { brainDir }] = await Promise.all([import('../core/running-server.mjs'), import('../core/config.mjs')]);
|
|
311
|
+
return runningServerStatus({ brainDir, ...args });
|
|
312
|
+
}))({ latest: version });
|
|
313
|
+
return { checked: true, ok: !['stale', 'down'].includes(server.status), server };
|
|
314
|
+
}
|
|
315
|
+
|
|
298
316
|
function runPrepublish(dir, pkgJson, { exec = spawnSync, timeoutMs } = {}) {
|
|
299
317
|
if (!pkgJson?.scripts?.prepublishOnly) return { ok: true, skipped: true };
|
|
300
318
|
const manager = fs.existsSync(path.join(dir, 'pnpm-lock.yaml')) ? 'pnpm' : 'npm';
|
|
@@ -374,6 +392,13 @@ export async function run(argv = process.argv, deps = {}) {
|
|
|
374
392
|
if (consumers.failing > 0) {
|
|
375
393
|
return fail(`${pkg}@${version}: ${consumers.failing}/${consumers.consumers} consumers not satisfied. First: ${consumers.failures[0].root} (${consumers.failures[0].installed ?? 'not installed'}).`);
|
|
376
394
|
}
|
|
395
|
+
const running = await verifyRunningServer(pkg, version, { check: deps.runningServerStatus, explicitRoot: Boolean(opts.root) });
|
|
396
|
+
entry.running_server = running.server || null;
|
|
397
|
+
if (!running.ok) {
|
|
398
|
+
return fail(`${pkg}@${version}: ${running.server.reason} Replace it with: total-recall deploy release ${version} --adapter-secret <DEPLOY_MESH_REFERENCE>, or restart it on a host that is not production.`);
|
|
399
|
+
}
|
|
400
|
+
if (running.server?.status === 'current') log(` ✓ the server on this host runs ${version}`);
|
|
401
|
+
else if (running.server?.status === 'unknown') log(` The server on this host could not be read: ${running.server.reason}`);
|
|
377
402
|
log(` ✓ ${pkg}@${version} verified: registry + ${consumers.consumers}/${consumers.consumers} consumers`);
|
|
378
403
|
if (consumers.pin_behind.length) log(` ${consumers.pin_behind.length} run it with an older pin in package.json, such as ${consumers.pin_behind[0].root}`);
|
|
379
404
|
if (consumers.dev_not_installed.length) log(` ${consumers.dev_not_installed.length} keep no dev copy of it and run under the shared install`);
|
package/src/cli/startup.mjs
CHANGED
|
@@ -36,6 +36,7 @@ export default async function startup(args = []) {
|
|
|
36
36
|
if (args.includes('--json')) console.log(JSON.stringify(report, null, 2));
|
|
37
37
|
else {
|
|
38
38
|
console.log(`Startup: required plugins ${report.required_plugins?.status || 'unknown'}; server ${report.server?.status || 'unknown'}; brain ${report.brain?.status || 'unknown'}; daemon ${report.daemon?.status || 'unknown'}; SSSS tooling ${report.ssss?.status || 'unknown'}; app ${report.app?.status || 'unknown'}`);
|
|
39
|
+
if (report.server?.stale) console.log(`Server: running ${report.server.stale.running} with ${report.server.stale.on_disk} on disk; it has not been replaced.`);
|
|
39
40
|
for (const error of report.required_plugins?.errors || []) console.log(`Required plugin: ${error}`);
|
|
40
41
|
const harnesses = await queryHarnessUsage().catch(() => []);
|
|
41
42
|
const availH = harnesses.filter(h => h.available);
|
package/src/cli/update.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import { installAutoPull } from '../core/autopull-install.mjs';
|
|
|
20
20
|
import { updateAllBrains } from '../core/brain-updates.mjs';
|
|
21
21
|
import { installHarnessHooks } from '../core/harness-hooks.mjs';
|
|
22
22
|
import { automaticUpdateStatus, runAutomaticBrainUpdates } from '../core/automatic-brain-updates.mjs';
|
|
23
|
+
import { runningServerStatus } from '../core/running-server.mjs';
|
|
23
24
|
|
|
24
25
|
/** @param {string[]} args */
|
|
25
26
|
export function parseArgs(args) {
|
|
@@ -78,21 +79,26 @@ function printHelp() {
|
|
|
78
79
|
writing package.json or the lockfile. Register it to develop it here.
|
|
79
80
|
total-recall update --automatic [--json]
|
|
80
81
|
Daemon maintenance: update both packages, ensure defaults, update every
|
|
81
|
-
installed plugin from its recorded source and refresh surfaces.
|
|
82
|
+
installed plugin from its recorded source and refresh surfaces. Where a
|
|
83
|
+
per-user service (LaunchAgent, systemd user unit) runs the server from
|
|
84
|
+
the global install, also restart a stale server and verify /health.
|
|
82
85
|
total-recall update --status [--json]
|
|
83
86
|
Read the actual last automatic maintenance report without starting work.
|
|
87
|
+
Also reports what the server on this host runs against the release.
|
|
84
88
|
|
|
85
89
|
This brain's own checkout (git):
|
|
86
90
|
total-recall update --install-autopull [--port N] [--no-build] [--dry-run]
|
|
87
91
|
Every 5 minutes fast-forward this checkout to origin/main, install and
|
|
88
92
|
rebuild what changed, restart the brain and verify /health reports the
|
|
89
|
-
new version (scripts/auto-pull.sh).
|
|
93
|
+
new version (scripts/auto-pull.sh). Refused where systemd serves the
|
|
94
|
+
checkout, because a restart there has a gap: use total-recall deploy. macOS: LaunchAgent
|
|
90
95
|
com.totalrecall.autopull; Linux: crontab. A dev checkout (other branch,
|
|
91
96
|
uncommitted or unpushed work) is never touched. --no-build: never build
|
|
92
97
|
the dashboard on this host (laptops).
|
|
93
98
|
|
|
94
99
|
Env:
|
|
95
100
|
TR_AUTO_UPDATE_PACKAGE=0 Disable daemon cron auto-update (default: on)
|
|
101
|
+
TR_SERVER_AUTO_RESTART=0 Report a stale server instead of restarting it (default: on)
|
|
96
102
|
TR_SYNC_REPOS=/a:/b Extra project roots
|
|
97
103
|
|
|
98
104
|
Source monorepos named ${PACKAGE_NAME} are skipped (use git, not npm into self).
|
|
@@ -106,7 +112,12 @@ export default async function update(args = []) {
|
|
|
106
112
|
return;
|
|
107
113
|
}
|
|
108
114
|
|
|
109
|
-
if(opts.status){
|
|
115
|
+
if(opts.status){
|
|
116
|
+
const status=automaticUpdateStatus(brainDir);
|
|
117
|
+
status.server=await runningServerStatus({brainDir,latest:status.last?.versions?.['total-recall-brain']});
|
|
118
|
+
console.log(JSON.stringify(status,null,2));
|
|
119
|
+
return status;
|
|
120
|
+
}
|
|
110
121
|
if(opts.automatic){
|
|
111
122
|
const report=await runAutomaticBrainUpdates({brainDir,force:opts.force,fleet:!opts.localOnly});
|
|
112
123
|
console.log(JSON.stringify(report,null,2));
|
|
@@ -12,6 +12,8 @@ import { updateGlobalBrainPackages } from './global-brain-updates.mjs';
|
|
|
12
12
|
import { updateMeshBrainPackages } from './mesh-brain-updates.mjs';
|
|
13
13
|
import { updateSourceBrainPackages } from './source-brain-updates.mjs';
|
|
14
14
|
import { updateInstalledPlugins } from './plugin-updates.mjs';
|
|
15
|
+
import { runningServerStatus } from './running-server.mjs';
|
|
16
|
+
import { replaceStaleServer } from './server-restart.mjs';
|
|
15
17
|
|
|
16
18
|
export function automaticUpdateStatus(brainDir) {
|
|
17
19
|
let last;
|
|
@@ -36,7 +38,7 @@ export function startAutomaticBrainUpdates({brainDir,intervalMs=60*60*1000,run=r
|
|
|
36
38
|
return {tick,stop(){stopped=true;clearInterval(timer);}};
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false,skipThrottle=false,intervalMs=60*60*1000,update=updateAllBrains,compile=maintainCliSurfaces,globalUpdate=updateGlobalBrainPackages,meshUpdate=updateMeshBrainPackages,sourceUpdate=updateSourceBrainPackages,pluginUpdate=updateInstalledPlugins,skillMaintenance=maintainPortableSkills,now=Date.now}={}) {
|
|
41
|
+
export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false,skipThrottle=false,intervalMs=60*60*1000,update=updateAllBrains,compile=maintainCliSurfaces,globalUpdate=updateGlobalBrainPackages,meshUpdate=updateMeshBrainPackages,sourceUpdate=updateSourceBrainPackages,pluginUpdate=updateInstalledPlugins,skillMaintenance=maintainPortableSkills,serverCheck=runningServerStatus,replaceServer=replaceStaleServer,now=Date.now}={}) {
|
|
40
42
|
if(!force && !isPackageAutoUpdateEnabled())return {skipped:true,reason:'disabled',results:[]};
|
|
41
43
|
const file=path.join(brainDir,'memory-derived/automatic-brain-updates.json');
|
|
42
44
|
let saved;try{saved=JSON.parse(fs.readFileSync(file,'utf8'));}catch{}
|
|
@@ -66,11 +68,19 @@ export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false
|
|
|
66
68
|
const changed=summary.updated>0 || plugins.updated>0 || global.results.some(row=>row.status==='updated') || sources.results.some(row=>row.status==='updated') || JSON.stringify(saved?.versions)!==JSON.stringify(summary.versions);
|
|
67
69
|
const skills=await skillMaintenance({brainDir});
|
|
68
70
|
const surfaces=await compile({brainDir,force:changed || skills.updated > 0});
|
|
71
|
+
// Last, so a replaced server starts on everything this run moved. Where maintenance cannot
|
|
72
|
+
// replace it, a lagging server is reported and not counted as a failure, which would retry
|
|
73
|
+
// every five minutes for nothing: in production that is a deploy decision. Where it can, a
|
|
74
|
+
// hold or a failed attempt is this machine's own failure, which is what makes a peer dispatch it again.
|
|
75
|
+
let server=await serverCheck({brainDir,latest:summary.versions?.['total-recall-brain']});
|
|
76
|
+
if(server.status==='stale')server=await replaceServer({brainDir,server,globalRoot:global.root,previous:saved?.server});
|
|
77
|
+
if(server.status==='stale' || server.status==='down')logger.error('automatic-brain-updates',`Running server: ${server.replacement?.reason || server.reason}`);
|
|
78
|
+
const serverFailed=['held','failed'].includes(server.replacement?.state)?1:0;
|
|
69
79
|
// local_failed is this node's own maintenance. Peers judge a node by it, not by
|
|
70
80
|
// `failed`, which also counts the node's view of its peers: judging by that made
|
|
71
81
|
// every fleet pass mark every peer failed forever, each because the others had.
|
|
72
|
-
const local_failed=(summary.failed || 0)+global.failed+sources.failed+plugins.failed+(skills.failed || 0)+(surfaces.ok?0:surfaces.results.filter(row=>row.status==='failed').length);
|
|
73
|
-
report={...summary,global,sources,plugins,mesh,skills,surfaces,local_failed,failed:local_failed+mesh.failed,checkedAt:now()};
|
|
82
|
+
const local_failed=(summary.failed || 0)+global.failed+sources.failed+plugins.failed+(skills.failed || 0)+(surfaces.ok?0:surfaces.results.filter(row=>row.status==='failed').length)+serverFailed;
|
|
83
|
+
report={...summary,global,sources,plugins,mesh,server,skills,surfaces,local_failed,failed:local_failed+mesh.failed,checkedAt:now()};
|
|
74
84
|
}catch(error){report={failed:1,error:error.message,checkedAt:now(),results:[]};}
|
|
75
85
|
const temporary=`${file}.${process.pid}.tmp`;fs.writeFileSync(temporary,JSON.stringify(report,null,2));fs.renameSync(temporary,file);
|
|
76
86
|
return report;
|
|
@@ -122,6 +122,16 @@ function readPlistValue(file, key) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Whether systemd serves this checkout. auto-pull stops the brain and starts another with
|
|
127
|
+
* nohup, so on such a host it would cause an outage and leave a process outside the unit.
|
|
128
|
+
*/
|
|
129
|
+
export function systemdServesCheckout(repoDir, { exec = spawnSync } = {}) {
|
|
130
|
+
const shown = exec('systemctl', ['show', 'total-recall-server.service', '-p', 'LoadState', '-p', 'ExecStart'], { encoding: 'utf8', timeout: 5000 });
|
|
131
|
+
if (shown.status !== 0) return false;
|
|
132
|
+
return /^LoadState=loaded$/m.test(shown.stdout || '') && (shown.stdout || '').includes(`${repoDir}/`);
|
|
133
|
+
}
|
|
134
|
+
|
|
125
135
|
/**
|
|
126
136
|
* Install (or refresh) the timer. Returns what it did; `dryRun` returns the
|
|
127
137
|
* plan without writing.
|
|
@@ -133,12 +143,16 @@ export function installAutoPull({
|
|
|
133
143
|
platform = process.platform,
|
|
134
144
|
home = os.homedir(),
|
|
135
145
|
dryRun = false,
|
|
146
|
+
exec = spawnSync,
|
|
136
147
|
} = {}) {
|
|
137
148
|
const script = path.join(repoDir, 'scripts', 'auto-pull.sh');
|
|
138
149
|
if (!fs.existsSync(path.join(repoDir, '.git'))) {
|
|
139
150
|
throw new Error(`${repoDir} is not a git checkout; npm installs update through the daemon (total-recall update --apply).`);
|
|
140
151
|
}
|
|
141
152
|
if (!fs.existsSync(script)) throw new Error(`Missing ${script}`);
|
|
153
|
+
if (platform === 'linux' && systemdServesCheckout(repoDir, { exec })) {
|
|
154
|
+
throw new Error(`systemd serves ${repoDir}, and a restart there has a gap. Replace it with: total-recall deploy release <version> --adapter-secret <DEPLOY_MESH_REFERENCE>`);
|
|
155
|
+
}
|
|
142
156
|
|
|
143
157
|
const resolvedPort =
|
|
144
158
|
port || Number(process.env.TR_PORT) || (platform === 'darwin' ? detectLaunchAgentPort(repoDir, { home }) : null) || 3000;
|
|
@@ -19,6 +19,13 @@ const sections = ['dependencies', 'devDependencies', 'optionalDependencies', 'pe
|
|
|
19
19
|
const ignored = new Set(['node_modules', 'vendor', 'dist', 'build', 'coverage', 'venv',
|
|
20
20
|
'test', 'tests', '__tests__', 'fixtures', 'tmp', 'scratch', 'scaffold', 'memory-derived']);
|
|
21
21
|
const canonical = key => key === '@ssss/cli' ? '@gregiteen/ssss-cli' : key;
|
|
22
|
+
// Plugins also force the engine alias through `overrides`. Those pins move with the dependency,
|
|
23
|
+
// or a consumer ends up asking for two versions of the same package.
|
|
24
|
+
const overrideKeys = pkg => Object.entries(pkg.overrides || {})
|
|
25
|
+
.filter(([key, spec]) => typeof spec === 'string' && BRAIN_PACKAGES.includes(canonical(key)) && canonical(key) !== pkg.name)
|
|
26
|
+
.map(([key]) => key);
|
|
27
|
+
const overridesLag = (pkg, versions) => overrideKeys(pkg)
|
|
28
|
+
.some(key => versions[canonical(key)] && pkg.overrides[key] !== targetSpec(key, versions[canonical(key)]));
|
|
22
29
|
const read = file => JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
23
30
|
const isLink = file => { try { return fs.lstatSync(file).isSymbolicLink(); } catch { return false; } };
|
|
24
31
|
export const brainUpdateLockPath = owner => path.join(os.tmpdir(),
|
|
@@ -196,7 +203,7 @@ const absentDevDep = (dep) => dep.section === 'devDependencies' && !dep.file;
|
|
|
196
203
|
* The daemon runs with NODE_ENV=production, and under that npm and pnpm remove dev dependencies
|
|
197
204
|
* from whatever they install in. An install that wants a runtime tree says so with a flag.
|
|
198
205
|
*/
|
|
199
|
-
function installEnv(env = process.env) {
|
|
206
|
+
export function installEnv(env = process.env) {
|
|
200
207
|
const { NODE_ENV, npm_config_omit, NPM_CONFIG_OMIT, npm_config_production, NPM_CONFIG_PRODUCTION, ...kept } = env;
|
|
201
208
|
return kept;
|
|
202
209
|
}
|
|
@@ -261,7 +268,7 @@ export async function updateAllBrains(opts = {}) {
|
|
|
261
268
|
row.status = 'failed'; row.error = 'Newer local/preview package; refusing an implicit downgrade'; continue;
|
|
262
269
|
}
|
|
263
270
|
const shared = isLink(path.join(owner.owner, 'node_modules')) || isLink(path.join(consumer.root, 'node_modules'));
|
|
264
|
-
const needsChange = shared || consumer.deps.some(dep => {
|
|
271
|
+
const needsChange = shared || (!consumer.runtimeOnly && overridesLag(consumer.pkg, versions)) || consumer.deps.some(dep => {
|
|
265
272
|
const pinLags = !consumer.runtimeOnly && dep.declared !== targetSpec(dep.key, versions[dep.package]);
|
|
266
273
|
if (absentDevDep(dep)) return pinLags;
|
|
267
274
|
return pinLags || dep.version !== versions[dep.package]
|
|
@@ -296,6 +303,9 @@ export async function updateAllBrains(opts = {}) {
|
|
|
296
303
|
saved.set(consumer.file, text);
|
|
297
304
|
const pkg = read(consumer.file);
|
|
298
305
|
for (const dep of consumer.deps) pkg[dep.section][dep.key] = targetSpec(dep.key, versions[dep.package]);
|
|
306
|
+
for (const key of overrideKeys(pkg)) {
|
|
307
|
+
if (versions[canonical(key)]) pkg.overrides[key] = targetSpec(key, versions[canonical(key)]);
|
|
308
|
+
}
|
|
299
309
|
const indent = /\n([ \t]+)"/.exec(text)?.[1] || 2;
|
|
300
310
|
fs.writeFileSync(consumer.file, JSON.stringify(pkg, null, indent) + '\n');
|
|
301
311
|
}
|
|
@@ -62,6 +62,9 @@ export function compactRules(items, { budget, expand = [], header, complete = fa
|
|
|
62
62
|
if (unknown.length) throw new Error(`Cannot expand rules not in this capsule: ${unknown.join(', ')}`);
|
|
63
63
|
const duplicateOf = findDuplicates(ranked.filter(item => !expand.includes(item.slug)));
|
|
64
64
|
const tiers = new Map(ranked.map(item => [item.slug, 'omitted']));
|
|
65
|
+
const isEvidence = item => item.taskEvidence && !item.required;
|
|
66
|
+
const supplement = supplemental.filter(item => item.text && !isEvidence(item)).map(item => item.text.trim());
|
|
67
|
+
const evidence = supplemental.filter(item => item.text && isEvidence(item)).map(item => item.text.trim()).join('\n\n---\n\n');
|
|
65
68
|
|
|
66
69
|
const render = () => {
|
|
67
70
|
const of = tier => ranked.filter(item => tiers.get(item.slug) === tier);
|
|
@@ -71,10 +74,11 @@ export function compactRules(items, { budget, expand = [], header, complete = fa
|
|
|
71
74
|
const blocks = [
|
|
72
75
|
...full.map(item => item.text.trim()),
|
|
73
76
|
...summary.map(item => `[${item.slug}] ${summarizeRule(item.body)}`),
|
|
74
|
-
...
|
|
77
|
+
...supplement,
|
|
75
78
|
];
|
|
76
79
|
if (reference.length) blocks.push(`Referenced: ${reference.map(item => item.slug).join(', ')}`);
|
|
77
80
|
if (duplicate.length) blocks.push(`Duplicates: ${duplicate.map(item => `${item.slug} (of ${duplicateOf.get(item.slug)})`).join(', ')}`);
|
|
81
|
+
if (evidence) blocks.push(evidence);
|
|
78
82
|
const body = blocks.join('\n\n---\n\n');
|
|
79
83
|
// The token count sits inside the text it counts, so iterate to a stable value.
|
|
80
84
|
let tokens = estimateTokens(body);
|
|
@@ -142,5 +146,6 @@ export function compactRules(items, { budget, expand = [], header, complete = fa
|
|
|
142
146
|
for (const slug of duplicateOf.keys()) tryTier(ranked.find(item => item.slug === slug), 'duplicate');
|
|
143
147
|
|
|
144
148
|
const { context, counts, tokens } = render();
|
|
145
|
-
return { context, counts, tokens, tiers: Object.fromEntries(tiers)
|
|
149
|
+
return { context, counts, tokens, tiers: Object.fromEntries(tiers),
|
|
150
|
+
...(evidence && { evidenceStart: context.length - evidence.length }) };
|
|
146
151
|
}
|
|
@@ -109,7 +109,10 @@ export async function compileContext({
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
const cliContributions = cliVerbContribution ? [cliVerbContribution] : [];
|
|
112
|
-
const
|
|
112
|
+
const evidence = knowledge.summary.selected
|
|
113
|
+
? knowledge.contributions.map(item => ({ ...item, taskEvidence: true }))
|
|
114
|
+
: knowledge.contributions;
|
|
115
|
+
const supporting = [...evidence, ...cliContributions];
|
|
113
116
|
const result = assembleContext([...required, ...supporting, ...contributions], { total: b.total });
|
|
114
117
|
const evidenceMissing = supporting.some(item => !result.stats.contributions.some(placed => placed.id === item.id));
|
|
115
118
|
// Compaction may reclaim rule explanation space; never claim readiness after losing selected task evidence.
|
|
@@ -163,6 +166,8 @@ export function capsuleResponse(result, { total = 4000, debug = false, format =
|
|
|
163
166
|
retrieval: summarizeRetrieval(result.stats.retrieval),
|
|
164
167
|
};
|
|
165
168
|
const response = { ready: result.ready, context: result.context, stats };
|
|
169
|
+
// This offset refers to the decoded context string, not the escaped JSON bytes.
|
|
170
|
+
if (result.evidenceStart !== undefined) response.evidence_start = result.evidenceStart;
|
|
166
171
|
stats.budget = total;
|
|
167
172
|
// Counts affect serialization themselves. Iterate to a stable representation.
|
|
168
173
|
for (let i = 0; i < 20; i++) {
|
|
@@ -100,14 +100,18 @@ export function assembleContext(contributions, { total = 4000 } = {}) {
|
|
|
100
100
|
if (estimateTokens(render([...selected, item])) <= total) selected.push(item);
|
|
101
101
|
else excluded.push(item.id);
|
|
102
102
|
}
|
|
103
|
-
const
|
|
103
|
+
const isEvidence = item => item.taskEvidence && !item.required;
|
|
104
|
+
const evidence = selected.filter(isEvidence);
|
|
105
|
+
const ordered = [...selected.filter(item => !isEvidence(item)), ...evidence];
|
|
106
|
+
const context = render(ordered);
|
|
107
|
+
const evidenceText = render(evidence);
|
|
104
108
|
const totalTokens = estimateTokens(context);
|
|
105
|
-
return { context, ready: requiredTokens <= total, stats: {
|
|
109
|
+
return { context, ...(evidenceText && { evidenceStart: context.length - evidenceText.length }), ready: requiredTokens <= total, stats: {
|
|
106
110
|
token_measurement: 'estimated_chars_divided_by_four', total_tokens: totalTokens,
|
|
107
111
|
budget_used: totalTokens, budget_remaining: Math.max(0, total - totalTokens),
|
|
108
112
|
required_tokens: requiredTokens, overflow_tokens: Math.max(0, requiredTokens - total),
|
|
109
113
|
required_ids: required.map(c => c.id), excluded_ids: excluded,
|
|
110
|
-
contributions:
|
|
114
|
+
contributions: ordered.map(c => ({ id: c.id, required: Boolean(c.required), chars: c.text.length, estimated_tokens: estimateTokens(c.text) })),
|
|
111
115
|
version: crypto.createHash('sha256').update(JSON.stringify({ total, contributions })).digest('hex'),
|
|
112
116
|
} };
|
|
113
117
|
}
|
|
@@ -37,6 +37,28 @@ export function getDaemonStatus() {
|
|
|
37
37
|
return status === 'not-started' ? 'not_started' : status === 'stopped' ? 'dead' : status;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Remove the lock of a daemon that is gone, for a server told to run none.
|
|
42
|
+
*
|
|
43
|
+
* startDaemon is the only other thing that recovers this lock, and such a server never
|
|
44
|
+
* calls it. A daemon that went down with the machine left a lock nothing would ever
|
|
45
|
+
* clear, so the server reported `dead` and `degraded` for good. Only a lock whose process
|
|
46
|
+
* is verified gone is removed: a live process or one that cannot be identified keeps it.
|
|
47
|
+
* @returns {boolean} True if a lock was removed.
|
|
48
|
+
*/
|
|
49
|
+
export function clearStaleDaemonLock({ observe = getDaemonObservation } = {}) {
|
|
50
|
+
try {
|
|
51
|
+
const before = fs.readFileSync(PID_FILE, 'utf8');
|
|
52
|
+
if (observe().status !== 'stopped') return false;
|
|
53
|
+
if (fs.readFileSync(PID_FILE, 'utf8') !== before) return false;
|
|
54
|
+
fs.unlinkSync(PID_FILE);
|
|
55
|
+
logger.info('daemon-control', `Removed the lock of daemon PID ${before.trim()}, which is gone. This server runs no daemon.`);
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
40
62
|
/**
|
|
41
63
|
* Detaches the daemon script in the background and writes its PID to file.
|
|
42
64
|
* @returns {number} The PID of the newly spawned daemon.
|