total-recall-brain 3.41.6 → 3.42.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.
Files changed (86) hide show
  1. package/package.json +1 -1
  2. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +3118 -17
  3. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +7 -2
  4. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +84 -40
  5. package/scaffold/.agent/skills/total-recall/plugins/auth/src/exit-after-flush.mjs +22 -0
  6. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-api-rotation.mjs +61 -6
  7. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +1 -0
  8. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-remote-deploy.mjs +8 -0
  9. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-rotate.mjs +20 -1
  10. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-store.mjs +3 -0
  11. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/state.mjs +15 -7
  12. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +4 -4
  13. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +4 -4
  14. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +4 -4
  15. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +4 -4
  16. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +4 -4
  17. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +51 -7
  18. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +67 -25
  19. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +4 -4
  20. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +52 -6
  21. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +1 -1
  22. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +21 -8
  23. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/compat-harness.mjs +110 -0
  24. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +48 -22
  25. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +9 -4
  26. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +21 -9
  27. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +9 -5
  28. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +10 -4
  29. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +30 -3
  30. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +6 -1
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +19 -3
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +222 -0
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-worker.mjs +18 -0
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +94 -0
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +70 -0
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +60 -19
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +32 -7
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/termination.mjs +24 -0
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +88 -125
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +110 -29
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +35 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +95 -5
  43. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +13 -1
  44. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +5 -5
  45. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +78 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/context-provider.mjs +113 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +4 -4
  48. package/src/cli/agent.mjs +11 -6
  49. package/src/cli/compact.mjs +3 -3
  50. package/src/cli/context.mjs +52 -19
  51. package/src/cli/harness.mjs +65 -147
  52. package/src/cli/init.mjs +4 -2
  53. package/src/cli/preflight.mjs +56 -13
  54. package/src/core/agent-manager.mjs +23 -329
  55. package/src/core/context-compactor.mjs +2 -1
  56. package/src/core/context-compiler.mjs +16 -25
  57. package/src/core/context-providers.mjs +69 -0
  58. package/src/core/meta-harness.mjs +27 -749
  59. package/src/core/plugin-runner.mjs +12 -5
  60. package/src/core/plugin-runtime.mjs +4 -2
  61. package/src/core/runtime.mjs +30 -604
  62. package/src/core/task-context.mjs +122 -0
  63. package/src/server/routes/context.mjs +4 -1
  64. package/scaffold/.agent/skills/decision/SKILL.md +0 -20
  65. package/scaffold/.agent/skills/decision/references/integration.md +0 -25
  66. package/scaffold/.agent/skills/decision/references/use-cases.md +0 -20
  67. package/scaffold/.agent/skills/meta-harness/SKILL.md +0 -15
  68. package/scaffold/.agent/skills/meta-harness/references/optimized/index.md +0 -20
  69. package/scaffold/.agent/skills/meta-harness/references/optimized/manifest.json +0 -79
  70. package/scaffold/.agent/skills/meta-harness/references/optimized/original.md +0 -135
  71. package/scaffold/.agent/skills/meta-harness/references/optimized/section-01.md +0 -5
  72. package/scaffold/.agent/skills/meta-harness/references/optimized/section-02.md +0 -17
  73. package/scaffold/.agent/skills/meta-harness/references/optimized/section-03.md +0 -8
  74. package/scaffold/.agent/skills/meta-harness/references/optimized/section-04.md +0 -2
  75. package/scaffold/.agent/skills/meta-harness/references/optimized/section-05.md +0 -6
  76. package/scaffold/.agent/skills/meta-harness/references/optimized/section-06.md +0 -14
  77. package/scaffold/.agent/skills/meta-harness/references/optimized/section-07.md +0 -8
  78. package/scaffold/.agent/skills/meta-harness/references/optimized/section-08.md +0 -4
  79. package/scaffold/.agent/skills/meta-harness/references/optimized/section-09.md +0 -20
  80. package/scaffold/.agent/skills/meta-harness/references/optimized/section-10.md +0 -6
  81. package/scaffold/.agent/skills/meta-harness/references/optimized/section-11.md +0 -5
  82. package/scaffold/.agent/skills/meta-harness/references/optimized/section-12.md +0 -7
  83. package/scaffold/.agent/skills/meta-harness/references/optimized/section-13.md +0 -4
  84. package/scaffold/.agent/skills/meta-harness/references/optimized/section-14.md +0 -7
  85. package/scaffold/.agent/skills/meta-harness/references/optimized/section-15.md +0 -9
  86. package/scaffold/.agent/skills/meta-harness/references/optimized/section-16.md +0 -5
@@ -80,6 +80,8 @@ export function mergeSecretMeta(prev = {}, patch = {}) {
80
80
  });
81
81
  assign('auto_rotate', (v) => !!v);
82
82
  assign('notes', (v) => (v == null || v === '' ? null : String(v)));
83
+ // The provider's id for the live key, so the next rotation can revoke it.
84
+ assign('provider_key_id', (v) => (v == null || v === '' ? null : String(v)));
83
85
  // The app-facing name a production key stands in for: GRO_CRM_TICKETS_SIGNING_SECRET
84
86
  // provides TICKETS_SIGNING_SECRET to the repos it is bound to (see resolveSecretKey).
85
87
  assign('provides', (v) => (v == null || v === '' ? null : String(v)));
@@ -270,6 +272,7 @@ export async function listSecretsMeta(brainDir) {
270
272
  provider: providerId,
271
273
  provider_name: catalog?.name || providerId,
272
274
  label: m.label || null,
275
+ provider_key_id: m.provider_key_id || null,
273
276
  repos,
274
277
  repo: repos.length === 1 ? repos[0] : null,
275
278
  multi_repo_error: false,
@@ -1,20 +1,28 @@
1
1
  /**
2
2
  * Where a repository keeps its code-quality state (config.json, reports, lock).
3
3
  * The runner itself lives in this plugin and is never copied into a repo.
4
- * TR_CODE_QUALITY_STATE overrides; otherwise the nearest enclosing
5
- * .agent/skills/code-quality directory, or one beside the current directory.
4
+ * TR_CODE_QUALITY_STATE overrides; otherwise state belongs to the nearest
5
+ * repository and is never inherited from another repository or the home skill.
6
6
  */
7
7
  import fs from 'node:fs';
8
8
  import path from 'node:path';
9
+ import os from 'node:os';
9
10
 
10
- export function stateDir(start = process.cwd()) {
11
- if (process.env.TR_CODE_QUALITY_STATE) return path.resolve(process.env.TR_CODE_QUALITY_STATE);
12
- let dir = path.resolve(start);
11
+ export function stateDir(start = process.cwd(), env = process.env) {
12
+ if (env.TR_CODE_QUALITY_STATE) return path.resolve(env.TR_CODE_QUALITY_STATE);
13
+ const origin = path.resolve(start);
14
+ const home = path.resolve(env.HOME || os.homedir());
15
+ const stateAt = directory => path.join(directory, '.agent', 'skills', 'code-quality');
16
+ let dir = origin;
13
17
  for (;;) {
14
- const candidate = path.join(dir, '.agent', 'skills', 'code-quality');
18
+ // A shared home skill supplies methods, never another project's configuration.
19
+ if (dir === home && dir !== origin) return stateAt(origin);
20
+ const candidate = stateAt(dir);
15
21
  if (fs.existsSync(candidate)) return candidate;
22
+ // Linked worktrees and submodules use a .git file instead of a directory.
23
+ if (fs.existsSync(path.join(dir, '.git'))) return candidate;
16
24
  const parent = path.dirname(dir);
17
- if (parent === dir) return path.join(path.resolve(start), '.agent', 'skills', 'code-quality');
25
+ if (parent === dir) return stateAt(origin);
18
26
  dir = parent;
19
27
  }
20
28
  }
@@ -12,7 +12,7 @@
12
12
  "@gregiteen/ssss-cli": "0.14.4"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.41.5"
15
+ "total-recall-brain": "3.41.6"
16
16
  }
17
17
  },
18
18
  "node_modules/@alcalzone/ansi-tokenize": {
@@ -5543,9 +5543,9 @@
5543
5543
  }
5544
5544
  },
5545
5545
  "node_modules/total-recall-brain": {
5546
- "version": "3.41.5",
5547
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
5548
- "integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
5546
+ "version": "3.41.6",
5547
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.6.tgz",
5548
+ "integrity": "sha512-ibJulU7/jxO9BwEzOaW54z9eBEQzanDfEFy8FS1yNnz/3QDhl9mqLFikLAXAlp34i5Ev4UC5KvjhNJa/sC49Rg==",
5549
5549
  "dev": true,
5550
5550
  "license": "MIT",
5551
5551
  "workspaces": [
@@ -12,7 +12,7 @@
12
12
  "@gregiteen/ssss-cli": "0.14.4"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.41.5"
15
+ "total-recall-brain": "3.41.6"
16
16
  }
17
17
  },
18
18
  "node_modules/@alcalzone/ansi-tokenize": {
@@ -5543,9 +5543,9 @@
5543
5543
  }
5544
5544
  },
5545
5545
  "node_modules/total-recall-brain": {
5546
- "version": "3.41.5",
5547
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
5548
- "integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
5546
+ "version": "3.41.6",
5547
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.6.tgz",
5548
+ "integrity": "sha512-ibJulU7/jxO9BwEzOaW54z9eBEQzanDfEFy8FS1yNnz/3QDhl9mqLFikLAXAlp34i5Ev4UC5KvjhNJa/sC49Rg==",
5549
5549
  "dev": true,
5550
5550
  "license": "MIT",
5551
5551
  "workspaces": [
@@ -12,7 +12,7 @@
12
12
  "@gregiteen/ssss-cli": "0.14.4"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.41.5"
15
+ "total-recall-brain": "3.41.6"
16
16
  }
17
17
  },
18
18
  "node_modules/@alcalzone/ansi-tokenize": {
@@ -5539,9 +5539,9 @@
5539
5539
  }
5540
5540
  },
5541
5541
  "node_modules/total-recall-brain": {
5542
- "version": "3.41.5",
5543
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
5544
- "integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
5542
+ "version": "3.41.6",
5543
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.6.tgz",
5544
+ "integrity": "sha512-ibJulU7/jxO9BwEzOaW54z9eBEQzanDfEFy8FS1yNnz/3QDhl9mqLFikLAXAlp34i5Ev4UC5KvjhNJa/sC49Rg==",
5545
5545
  "dev": true,
5546
5546
  "license": "MIT",
5547
5547
  "workspaces": [
@@ -12,7 +12,7 @@
12
12
  "@gregiteen/ssss-cli": "0.14.4"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.41.5",
15
+ "total-recall-brain": "3.41.6",
16
16
  "vitest": "^4.1.10"
17
17
  }
18
18
  },
@@ -6533,9 +6533,9 @@
6533
6533
  }
6534
6534
  },
6535
6535
  "node_modules/total-recall-brain": {
6536
- "version": "3.41.5",
6537
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
6538
- "integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
6536
+ "version": "3.41.6",
6537
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.6.tgz",
6538
+ "integrity": "sha512-ibJulU7/jxO9BwEzOaW54z9eBEQzanDfEFy8FS1yNnz/3QDhl9mqLFikLAXAlp34i5Ev4UC5KvjhNJa/sC49Rg==",
6539
6539
  "dev": true,
6540
6540
  "license": "MIT",
6541
6541
  "workspaces": [
@@ -15,7 +15,7 @@
15
15
  "devDependencies": {
16
16
  "jsdom": "^29.1.1",
17
17
  "supertest": "^7.3.1",
18
- "total-recall-brain": "3.41.5",
18
+ "total-recall-brain": "3.41.6",
19
19
  "vitest": "^4.1.12"
20
20
  }
21
21
  },
@@ -7177,9 +7177,9 @@
7177
7177
  }
7178
7178
  },
7179
7179
  "node_modules/total-recall-brain": {
7180
- "version": "3.41.5",
7181
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
7182
- "integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
7180
+ "version": "3.41.6",
7181
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.6.tgz",
7182
+ "integrity": "sha512-ibJulU7/jxO9BwEzOaW54z9eBEQzanDfEFy8FS1yNnz/3QDhl9mqLFikLAXAlp34i5Ev4UC5KvjhNJa/sC49Rg==",
7183
7183
  "dev": true,
7184
7184
  "license": "MIT",
7185
7185
  "workspaces": [
@@ -1,14 +1,16 @@
1
- # Command Fleet
1
+ # Meta Harness
2
2
 
3
- All nine adapters share one plugin: Claude Code, Codex, Antigravity, Cursor,
4
- DSH, Grok, Muse, Pi and Hermes. `runtime <agent> ...` exposes their native runtime
5
- commands; DSH observations and Hermes gateway management live here as well.
3
+ Built-in and validated custom adapters share one plugin. `runtime <agent> ...`
4
+ exposes native runtime commands; DSH observations and Hermes gateway management
5
+ live here as well. `meta-harness` is the primary namespace; `cli-agents` is an alias.
6
6
 
7
7
  `total-recall cli-agents setup` connects all nine native instruction surfaces.
8
8
  The declared setup operation also runs during daemon-owned plugin refresh.
9
- Every dispatched agent receives a freshly checked Total Recall context, complete
10
- core help, installed plugin operations and composed commands. Setup failure or
11
- an unready context stops dispatch.
9
+ Every dispatched agent receives freshly assembled Total Recall task context and
10
+ a preflight receipt. The configured context budget is honored. Complete CLI,
11
+ plugin and composed-command inventories are supplied in a private temporary
12
+ reference file, keeping their full metadata out of the inline prompt. That file
13
+ is removed after execution. Setup failure or an unready context stops dispatch.
12
14
 
13
15
  `docs-refresh`, `docs-ensure`, `docs-status`, `docs-read` and `docs-search` manage
14
16
  downloaded official documentation rather than a list of links. Content is hashed,
@@ -63,3 +65,45 @@ A completed model turn is distinct from a completed plugin operation. Structured
63
65
  | Hermes | [Official command reference](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/reference/cli-commands.md) |
64
66
 
65
67
  Cursor discovery uses `cursor-agent`; an ambiguous `agent` binary is not assumed to be Cursor. Missing installations are listed as unavailable. Unknown authentication requires explicit agent selection and remains unverified until a real run. Tests exercise literal stdin, bounded child-process cleanup, command admission, recorded SSH access, account checks and completed-result parsing. Run suites on the configured sanctioned test node.
68
+
69
+ ## Isolated task workflows
70
+
71
+ ```sh
72
+ total-recall meta-harness route "describe the task" --json
73
+ total-recall meta-harness route "describe the task" --execute --gate --background --json
74
+ total-recall meta-harness coordinate "describe the task" --mode pipeline --execute --gate --background --json
75
+ total-recall meta-harness review --staged --author <author-harness> --json
76
+ ```
77
+
78
+ Pipeline stages use isolated branches and independent verification. Council
79
+ assessments run concurrently; race candidates require a passing deterministic
80
+ gate. Failed stages stop subsequent work and clean failed checkouts. Deliverable
81
+ branches remain available for review and are never merged automatically. Empty
82
+ diffs return `NO_DIFF`; unreadable reviews never become approvals. Unknown login
83
+ state requires explicit `--allow-unknown-auth`.
84
+
85
+ Single-agent remote commands use recorded mesh access and an explicit absolute
86
+ workspace. Coordinated isolated work and gates reject unsupported remote placement;
87
+ remote worktree/gate transport remains an acceptance gap.
88
+
89
+ All agent dispatch paths, including agent-mediated plugin commands, append native
90
+ SSSS execution receipts. Actual process exit and finish metadata are distinct from
91
+ verification results; unavailable model metadata remains null. Thread operations
92
+ include list, show, create, update, close and delete, using native SSSS state.
93
+
94
+ Custom adapter declarations preserve scoped credentials, optional authentication
95
+ probes and HTTPS documentation URLs. IDs and paths reject traversal and symbolic
96
+ links. Credentials reach only the declaring runner through the auth store. A
97
+ changed documentation URL invalidates old cache freshness.
98
+
99
+ ## Verification status
100
+
101
+ The active five-file suite and evidence live in
102
+ `docs/projects/in-progress/META_HARNESS_UNIFICATION/`. Completion requires current
103
+ owner/core suites, plugin/scaffold validation, real dashboard inspection and
104
+ recorded acceptance evidence. Fixture tests do not certify live accounts, remote
105
+ execution or recurring maintenance. The operator requires completing verification
106
+ before Meta Harness runs task work.
107
+
108
+ Cloudroom setup material remains under `cloudroom/`. Its plugin implementation
109
+ follows this foundation and requires its own current audit and plan.
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import { spawn } from 'node:child_process';
4
4
  import { pathToFileURL } from 'node:url';
5
5
  import { configDir } from './src/paths.mjs';
6
- import { inspectAgents, getActiveAdapters, getCustomAdaptersDirs, loadCustomAdapters } from './src/worker.mjs';
6
+ import { inspectAgents, getActiveAdapters, getCustomAdaptersDirs, loadCustomAdapters, validateCustomAdapter, adapterPath } from './src/worker.mjs';
7
7
  import { inspectNode, listTargets, executeCommand, executeOnNode } from './src/executor.mjs';
8
8
  import { DOC_SOURCES, documentationStatus, refreshDocumentation, ensureDocumentation, maintainDocumentation, readDocumentation, searchDocumentation } from './src/documentation.mjs';
9
9
  import { manageRuntime } from './src/runtime.mjs';
@@ -15,12 +15,13 @@ import { executeRoutedTask } from './src/cascade.mjs';
15
15
  import { dispatchWithReceipt } from './src/dispatch.mjs';
16
16
  import { resolvePool } from './src/pool.mjs';
17
17
  import { checkAlerts, notifyAlert } from './src/alerts.mjs';
18
- import { learnFromHistory } from './src/learner.mjs';
18
+ import { learnFromHistory, voidReceipts } from './src/learner.mjs';
19
19
  import { decomposeTask } from './capability/index.mjs';
20
- import { listThreads, getThread, createThread, closeThread, deleteThread } from './src/threads.mjs';
20
+ import { listThreads, getThread, createThread, updateThread, closeThread, deleteThread } from './src/threads.mjs';
21
21
  import { executeCodeReview } from './src/review.mjs';
22
+ import { stopOnTermination } from './src/termination.mjs';
22
23
 
23
- const VALUE_FLAGS = ['--node', '--mode', '--orchestrator', '--branch', '--reviewer', '--thread', '--status', '--platform', '--agent', '--url', '--query', '--tier', '--threshold', '--author', '--explorer', '--architect', '--implementer', '--verifier'];
24
+ const VALUE_FLAGS = ['--node', '--mode', '--orchestrator', '--branch', '--reviewer', '--thread', '--status', '--platform', '--agent', '--url', '--query', '--tier', '--threshold', '--author', '--explorer', '--architect', '--implementer', '--verifier', '--title', '--summary', '--cwd', '--tools', '--setting-sources', '--model', '--name', '--tail', '--timeout-ms', '--void', '--reason'];
24
25
  export function parseArguments(args) {
25
26
  const positional = [];
26
27
  for (let index = 1; index < args.length; index += 1) {
@@ -37,6 +38,7 @@ export function parseArguments(args) {
37
38
  }
38
39
 
39
40
  export async function run(argv = []) {
41
+ stopOnTermination();
40
42
  try { await runOperation(argv); }
41
43
  catch (error) {
42
44
  const message = String(error?.message || error);
@@ -47,22 +49,30 @@ export async function run(argv = []) {
47
49
  }
48
50
 
49
51
  /** The host stops a plugin command after 10 minutes, so long runs detach and report through their thread and log. */
50
- function detachRun(argv) {
52
+ async function detachRun(argv) {
51
53
  const directory = path.join(configDir(), 'jobs');
52
54
  fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
53
55
  const log = path.join(directory, `${Date.now().toString(36)}.log`);
54
56
  const output = fs.openSync(log, 'a', 0o600);
55
57
  const entry = new URL('./cli.mjs', import.meta.url).href;
56
58
  const child = spawn(process.execPath, ['--input-type=module', '-e', `import(${JSON.stringify(entry)}).then(m=>m.run(${JSON.stringify(argv.filter(arg => arg !== '--background'))}))`], { cwd: process.cwd(), detached: true, stdio: ['ignore', output, output], env: process.env });
57
- child.unref();
58
- fs.closeSync(output);
59
- return { ok: true, background: true, pid: child.pid, log, follow: 'total-recall meta-harness threads list --json' };
59
+ try {
60
+ await new Promise((resolve, reject) => { child.once('spawn', resolve); child.once('error', reject); });
61
+ child.unref();
62
+ } finally { fs.closeSync(output); }
63
+ return { ok: true, background: true, pid: child.pid, log, follow: `The final JSON result is written to ${log}; a pipeline also records a thread.` };
60
64
  }
61
65
 
62
66
  async function runOperation(argv) {
63
67
  const args = argv.slice(3); const operation = args[0] || 'status';
64
68
  const { positional, value, has } = parseArguments(args);
65
- if (has('--background') && ['route', 'coordinate', 'orchestrate'].includes(operation) && has('--execute')) { console.log(JSON.stringify(detachRun(argv))); return; }
69
+ const remoteTimeout = () => {
70
+ const raw = value('--timeout-ms');
71
+ if (raw === undefined) return {};
72
+ const timeoutMs = Number(raw);
73
+ if (!Number.isInteger(timeoutMs)) throw new Error('--timeout-ms must be a whole number of milliseconds');
74
+ return { timeoutMs };
75
+ };
66
76
  // Help anywhere in the arguments prints usage; it must never run an operation.
67
77
  if (operation === 'help' || args.some(arg => arg === '--help' || arg === '-h')) {
68
78
  const manifest=JSON.parse(fs.readFileSync(new URL('./plugin.json',import.meta.url),'utf8'));
@@ -70,8 +80,9 @@ async function runOperation(argv) {
70
80
  for(const command of manifest.cli.subcommands)console.log(` ${command.name} ${(command.args || []).map(arg=>arg.flag?`${arg.flag} <${arg.name}>`:`<${arg.name}>`).join(' ')} — ${command.description}`);
71
81
  return;
72
82
  }
83
+ if (has('--background') && ['route', 'coordinate', 'orchestrate'].includes(operation) && has('--execute')) { console.log(JSON.stringify(await detachRun(argv))); return; }
73
84
  let result;
74
- if (operation === 'status') result = {...await inspectAgents(),documentation:documentationStatus()};
85
+ if (operation === 'status') result = {...await inspectNode(value('--node') || 'local'),documentation:documentationStatus()};
75
86
  else if (operation === 'catalog') result = { adapters: getActiveAdapters(), permissions: ['read', 'write', 'send', 'destructive'] };
76
87
  else if (operation === 'nodes') result = await listTargets();
77
88
  else if (operation === 'quota') result = await inspectQuotas({ node: value('--node') || 'local' });
@@ -79,14 +90,14 @@ async function runOperation(argv) {
79
90
  else if (operation === 'route') {
80
91
  const task = positional.join(' ');
81
92
  if (!task) throw new Error('route requires a task description');
82
- const options = { jev: has('--jev'), preferLocal: has('--prefer-local'), preferFrontier: has('--prefer-frontier') };
93
+ const options = { jev: has('--jev'), preferLocal: has('--prefer-local'), preferFrontier: has('--prefer-frontier'), node: value('--node'), cwd: value('--cwd'), allowUnknownAuth: has('--allow-unknown-auth'), ...remoteTimeout() };
83
94
  result = has('--execute') ? await executeRoutedTask(task, { ...options, gate: has('--gate'), gateOptions: { tier: value('--tier') || 'fast' } }) : await routeTask(task, options);
84
95
  if (!result.ok) process.exitCode = 1;
85
96
  }
86
97
  else if (operation === 'decompose') {
87
98
  const task = positional.join(' ');
88
99
  if (!task) throw new Error('decompose requires a task description');
89
- const pool = await resolvePool();
100
+ const pool = await resolvePool({ allowUnknownAuth: has('--allow-unknown-auth') });
90
101
  result = { ...decomposeTask(task, { availableHarnesses: pool.ready.map(h => h.id) }), excluded: pool.excluded };
91
102
  }
92
103
  else if (operation === 'coordinate' || operation === 'orchestrate') {
@@ -95,6 +106,7 @@ async function runOperation(argv) {
95
106
  result = await coordinateTask(task, {
96
107
  mode: value('--mode') || 'pipeline', execute: has('--execute'), orchestrator: value('--orchestrator'), explorer: value('--explorer'), architect: value('--architect'), implementer: value('--implementer'), verifier: value('--verifier'),
97
108
  branch: value('--branch'), subagents: !has('--no-subagents'), autoReview: has('--auto-review'), gate: has('--gate'), gateOptions: { tier: value('--tier') || 'fast' }, allowSameFamily: has('--allow-same-family'), reviewer: value('--reviewer'),
109
+ node: value('--node') || 'local', cwd: value('--cwd'), allowUnknownAuth: has('--allow-unknown-auth'), ...remoteTimeout(),
98
110
  });
99
111
  if (!result.ok) process.exitCode = 1;
100
112
  }
@@ -113,14 +125,18 @@ async function runOperation(argv) {
113
125
  result = getThread(id);
114
126
  if (!result) throw new Error(`Thread not found: ${id}`);
115
127
  } else if (sub === 'create') {
116
- const title = args.slice(2).filter(a => !a.startsWith('--')).join(' ');
117
- const platformIdx = args.indexOf('--platform');
118
- const branchIdx = args.indexOf('--branch');
128
+ const title = value('--title') || positional.slice(1).join(' ');
119
129
  result = createThread({
120
130
  title: title || 'New Agent Thread',
121
- platform: platformIdx >= 0 ? args[platformIdx + 1] : 'universal',
122
- branch: branchIdx >= 0 ? args[branchIdx + 1] : null
131
+ platform: value('--platform') || 'universal',
132
+ branch: value('--branch') || null
123
133
  });
134
+ } else if (sub === 'update') {
135
+ const id = positional[1];
136
+ if (!id) throw new Error('threads update requires a thread id');
137
+ const patch = Object.fromEntries(['title', 'status', 'platform', 'branch', 'summary'].map(key => [key, value(`--${key}`)]).filter(([, entry]) => entry !== undefined));
138
+ if (!Object.keys(patch).length) throw new Error('threads update requires at least one field');
139
+ result = updateThread(id, patch);
124
140
  } else if (sub === 'close') {
125
141
  const id = args[2];
126
142
  if (!id) throw new Error('threads close requires a thread id');
@@ -134,11 +150,13 @@ async function runOperation(argv) {
134
150
  }
135
151
  }
136
152
  else if (operation === 'review') {
137
- result = await executeCodeReview({ target: positional[0] || null, reviewer: value('--reviewer'), author: value('--author'), threadId: value('--thread'), staged: has('--staged') });
153
+ result = await executeCodeReview({ target: positional[0] || null, reviewer: value('--reviewer'), author: value('--author'), threadId: value('--thread'), staged: has('--staged'), node: value('--node') || 'local', cwd: value('--cwd'), allowUnknownAuth: has('--allow-unknown-auth'), ...remoteTimeout() });
138
154
  if (!result.ok) process.exitCode = 1;
139
155
  }
140
156
  else if (operation === 'learn') {
141
- result = await learnFromHistory({ emit: has('--emit') });
157
+ result = value('--void') !== undefined
158
+ ? await voidReceipts({ ids: String(value('--void')).split(',').map(id => id.trim()).filter(Boolean), reason: value('--reason') })
159
+ : await learnFromHistory({ emit: has('--emit') });
142
160
  if (!result.ok) process.exitCode = 1;
143
161
  }
144
162
  else if (operation === 'alerts') {
@@ -165,11 +183,11 @@ async function runOperation(argv) {
165
183
  } catch {
166
184
  throw new Error('Invalid adapter JSON specification');
167
185
  }
168
- if (!spec.id || !spec.binary) throw new Error('Adapter specification must define id and binary');
186
+ spec = validateCustomAdapter(spec);
169
187
  const dirs = getCustomAdaptersDirs();
170
188
  fs.mkdirSync(dirs[0], { recursive: true });
171
- const dest = path.join(dirs[0], `${spec.id}.json`);
172
- fs.writeFileSync(dest, JSON.stringify(spec, null, 2), 'utf8');
189
+ const dest = adapterPath(dirs[0], spec.id);
190
+ fs.writeFileSync(dest, JSON.stringify(spec, null, 2), { encoding: 'utf8', mode: 0o600, flag: 'wx' });
173
191
  result = { ok: true, added: spec.id, path: dest };
174
192
  } else if (sub === 'remove') {
175
193
  const id = args[2];
@@ -177,14 +195,15 @@ async function runOperation(argv) {
177
195
  const dirs = getCustomAdaptersDirs();
178
196
  let removed = false;
179
197
  for (const d of dirs) {
180
- const dest = path.join(d, `${id}.json`);
198
+ const dest = adapterPath(d, id);
181
199
  if (fs.existsSync(dest)) {
182
200
  fs.unlinkSync(dest);
183
201
  removed = true;
184
202
  }
185
203
  }
186
204
  result = { ok: removed, removed: id };
187
- }
205
+ if (!removed) process.exitCode = 1;
206
+ } else throw new Error(`Unsupported adapter operation: ${sub}`);
188
207
  }
189
208
  else if(operation==='docs-sources')result={sources:DOC_SOURCES};
190
209
  else if(operation==='docs-read' || operation==='docs-search') {
@@ -218,8 +237,31 @@ async function runOperation(argv) {
218
237
  result = node==='local' ? await manageRuntime(agent,runtimeArgs) : await executeOnNode(node,{operation:'direct',cwd:process.cwd(),argv:['total-recall','meta-harness','runtime',agent,...runtimeArgs,'--json']});
219
238
  if(!result.ok)process.exitCode=1;
220
239
  }
240
+ else if (operation === 'process') {
241
+ const processes = await import('./src/process-manager.mjs');
242
+ const [action = 'list', target, ...task] = positional;
243
+ if (action === 'list') result = { ok: true, agents: processes.listAgents() };
244
+ else if (action === 'status') {
245
+ result = processes.listAgents().find(record => record.id === target || String(record.pid) === target);
246
+ if (!result) throw new Error('Managed process not found');
247
+ } else if (action === 'spawn') {
248
+ if (!target || !task.length) throw new Error('process spawn requires a harness and task');
249
+ result = await processes.spawnAgent(target, task.join(' '), {
250
+ node: value('--node') || 'local', cwd: value('--cwd'), name: value('--name'),
251
+ tools: value('--tools'), settingSources: value('--setting-sources'), model: value('--model'),
252
+ detach: !has('--no-detach'), write: !has('--read-only'), allowUnknownAuth: has('--allow-unknown-auth'),
253
+ });
254
+ if (result.status === 'failed') process.exitCode = 1;
255
+ } else if (action === 'kill') {
256
+ if (!target) throw new Error('process kill requires a managed process id');
257
+ result = await processes.killAgent(target);
258
+ } else if (action === 'logs') {
259
+ if (!target) throw new Error('process logs requires a managed process id');
260
+ result = { ok: true, logs: await processes.getAgentLogs(target, Number(value('--tail') || 50)) };
261
+ } else throw new Error(`Unsupported process operation: ${action}`);
262
+ }
221
263
  else if(operation==='dispatch') {
222
- if(!args.includes('--stdin'))throw new Error('Task requests must arrive through stdin');
264
+ if(!args.includes('--stdin'))throw new Error('Task requests must arrive through stdin: pass --stdin with JSON {agent, cwd, prompt}');
223
265
  const input=fs.readFileSync(0,'utf8');if(Buffer.byteLength(input)>65536)throw new Error('Task request too large');
224
266
  const request=JSON.parse(input);
225
267
  result=await dispatchWithReceipt({...request,allowUnknownAuth:request.allowUnknownAuth===true},{node:request.node || 'local',role:'Dispatch'});
@@ -11,7 +11,7 @@
11
11
  "@gregiteen/ssss-cli": "0.14.4"
12
12
  },
13
13
  "devDependencies": {
14
- "total-recall-brain": "3.41.5"
14
+ "total-recall-brain": "3.41.6"
15
15
  }
16
16
  },
17
17
  "node_modules/@alcalzone/ansi-tokenize": {
@@ -5546,9 +5546,9 @@
5546
5546
  }
5547
5547
  },
5548
5548
  "node_modules/total-recall-brain": {
5549
- "version": "3.41.5",
5550
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
5551
- "integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
5549
+ "version": "3.41.6",
5550
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.6.tgz",
5551
+ "integrity": "sha512-ibJulU7/jxO9BwEzOaW54z9eBEQzanDfEFy8FS1yNnz/3QDhl9mqLFikLAXAlp34i5Ev4UC5KvjhNJa/sC49Rg==",
5552
5552
  "dev": true,
5553
5553
  "license": "MIT",
5554
5554
  "workspaces": [
@@ -308,7 +308,12 @@
308
308
  "flag": "--tier",
309
309
  "type": "string",
310
310
  "label": "Gate tier: fast | full | remote"
311
- }
311
+ },
312
+ { "name": "cwd", "flag": "--cwd", "type": "string", "label": "Explicit workspace on the selected node" },
313
+ { "name": "node", "flag": "--node", "type": "string", "label": "Selected mesh node" },
314
+ { "name": "allowUnknownAuth", "flag": "--allow-unknown-auth", "type": "boolean", "label": "Explicitly allow a runner without a login probe" },
315
+ { "name": "background", "flag": "--background", "type": "boolean", "label": "Return the owned job and log for a long run" },
316
+ { "name": "timeoutMs", "flag": "--timeout-ms", "type": "number", "label": "Remote wall-clock limit in milliseconds" }
312
317
  ]
313
318
  },
314
319
  {
@@ -353,7 +358,12 @@
353
358
  "flag": "--allow-same-family",
354
359
  "type": "boolean",
355
360
  "label": "Accept a Verifier from the Implementer's model family"
356
- }
361
+ },
362
+ { "name": "cwd", "flag": "--cwd", "type": "string", "label": "Explicit workspace on the selected node" },
363
+ { "name": "node", "flag": "--node", "type": "string", "label": "Selected mesh node" },
364
+ { "name": "allowUnknownAuth", "flag": "--allow-unknown-auth", "type": "boolean", "label": "Explicitly allow a runner without a login probe" },
365
+ { "name": "background", "flag": "--background", "type": "boolean", "label": "Return the owned job and log for a long run" },
366
+ { "name": "timeoutMs", "flag": "--timeout-ms", "type": "number", "label": "Remote wall-clock limit in milliseconds" }
357
367
  ],
358
368
  "timeout_ms": 600000
359
369
  },
@@ -368,7 +378,9 @@
368
378
  "flag": "--emit",
369
379
  "type": "boolean",
370
380
  "label": "Write proposals through the memory owner"
371
- }
381
+ },
382
+ { "name": "void", "flag": "--void", "type": "string", "label": "Comma-separated receipt ids to void" },
383
+ { "name": "reason", "flag": "--reason", "type": "string", "label": "Why the receipts are void" }
372
384
  ]
373
385
  },
374
386
  {
@@ -467,7 +479,7 @@
467
479
  {
468
480
  "name": "action",
469
481
  "type": "string",
470
- "label": "list | show | create | close | delete",
482
+ "label": "list | show | create | update | close | delete",
471
483
  "required": true,
472
484
  "positional": true
473
485
  },
@@ -476,7 +488,34 @@
476
488
  "type": "string",
477
489
  "label": "Thread ID or title",
478
490
  "positional": true
479
- }
491
+ },
492
+ { "name": "title", "flag": "--title", "type": "string", "label": "Thread title" },
493
+ { "name": "summary", "flag": "--summary", "type": "string", "label": "Thread summary" },
494
+ { "name": "status", "flag": "--status", "type": "string", "label": "Lifecycle status or list filter" },
495
+ { "name": "platform", "flag": "--platform", "type": "string", "label": "Harness platform or list filter" },
496
+ { "name": "branch", "flag": "--branch", "type": "string", "label": "Deliverable branch" }
497
+ ]
498
+ },
499
+ {
500
+ "name": "process",
501
+ "description": "Manage owned agent processes through isolated dispatch and SSSS lifecycle records",
502
+ "effect": "write",
503
+ "output": "json",
504
+ "timeout_ms": 600000,
505
+ "args": [
506
+ { "name": "action", "type": "string", "positional": true, "label": "list | status | spawn | kill | logs" },
507
+ { "name": "target", "type": "string", "positional": true, "label": "Harness to spawn or managed process ID" },
508
+ { "name": "task", "type": "string", "positional": true, "label": "Task for a spawned agent" },
509
+ { "name": "node", "type": "string", "flag": "--node", "label": "Recorded mesh node" },
510
+ { "name": "cwd", "type": "string", "flag": "--cwd", "label": "Explicit workspace on the selected node" },
511
+ { "name": "name", "type": "string", "flag": "--name", "label": "Managed process label" },
512
+ { "name": "tools", "type": "string", "flag": "--tools", "label": "Supported tool restriction" },
513
+ { "name": "settingSources", "type": "string", "flag": "--setting-sources", "label": "Supported instruction setting sources" },
514
+ { "name": "model", "type": "string", "flag": "--model", "label": "Explicit configured model selection" },
515
+ { "name": "tail", "type": "number", "flag": "--tail", "label": "Log tail line count" },
516
+ { "name": "readOnly", "type": "boolean", "flag": "--read-only", "label": "Disable code writes" },
517
+ { "name": "noDetach", "type": "boolean", "flag": "--no-detach", "label": "Await the managed process result" },
518
+ { "name": "allowUnknownAuth", "type": "boolean", "flag": "--allow-unknown-auth", "label": "Explicitly allow an unknown login state" }
480
519
  ]
481
520
  },
482
521
  {
@@ -514,7 +553,11 @@
514
553
  "flag": "--thread",
515
554
  "type": "string",
516
555
  "label": "Thread to attach the review to"
517
- }
556
+ },
557
+ { "name": "cwd", "flag": "--cwd", "type": "string", "label": "Explicit workspace on the selected node" },
558
+ { "name": "node", "flag": "--node", "type": "string", "label": "Selected mesh node" },
559
+ { "name": "allowUnknownAuth", "flag": "--allow-unknown-auth", "type": "boolean", "label": "Explicitly allow a runner without a login probe" },
560
+ { "name": "timeoutMs", "flag": "--timeout-ms", "type": "number", "label": "Remote wall-clock limit in milliseconds" }
518
561
  ],
519
562
  "timeout_ms": 600000
520
563
  }
@@ -526,6 +569,9 @@
526
569
  "documentation": "src/documentation.mjs",
527
570
  "agent-runtime": "src/runtime.mjs",
528
571
  "tracker": "src/tracker.mjs",
572
+ "harness-compat": "src/compat-harness.mjs",
573
+ "reasoning-runtime": "src/reasoning.mjs",
574
+ "process-manager": "src/process-manager.mjs",
529
575
  "gate-adapters": "src/gate-adapters/index.mjs"
530
576
  },
531
577
  "setup_command": "setup"
@@ -12,7 +12,7 @@ Coordinates coding agent harnesses across mesh nodes. `cli-agents` is an alias o
12
12
  1. **Believe the status words.** `ready` was proved by a login probe. `unverified` has no probe, so only a completed run proves it. `needs_auth`, `blocked` and `exhausted` cannot take work; the reason is in `quotaNote` and in `excluded`.
13
13
  2. **No figure without a source.** `benchmarks` shows only fetched figures with their source and time. A dash means nobody measured it. Adapter quality and cost scores are configured priors, not measurements.
14
14
  3. **Writing happens on a branch.** `route --execute`, `coordinate --execute` and race work in their own worktree on a `meta-harness/...` branch. Nothing merges into your branch; review the branch and merge it yourself.
15
- 4. **Long runs go to the background.** The host stops plugin commands after 10 minutes, so add `--background` to any multi-stage `--execute` and follow it with `threads list`.
15
+ 4. **Long runs go to the background.** The host stops plugin commands after 10 minutes, so add `--background` to any multi-stage `--execute`. It prints a log path that receives the final JSON, and a pipeline also records a thread. Stopping a run stops its agents and removes its worktrees, unfinished branches and open thread. A remote job (`--node` with an absolute `--cwd`) has a one-hour budget; `--timeout-ms` changes it.
16
16
  5. **Cost.** dsh, hermes and other metered harnesses bill per token, and `route` warns when it picks one. `--jev` also makes a metered call.
17
17
 
18
18
  ## Commands