thinkpool-pair 0.7.364 → 0.7.366

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 (116) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +20 -0
  3. package/abort-turn-barrier.mjs +1 -23
  4. package/account.mjs +1 -1437
  5. package/acp-client.mjs +1 -140
  6. package/agent-detect.mjs +1 -28
  7. package/agent-notify.mjs +1 -142
  8. package/agent-visibility.mjs +1 -67
  9. package/auth-store.mjs +1 -120
  10. package/bridge.mjs +1 -6266
  11. package/byok-detect.mjs +1 -126
  12. package/claude-command-catalog.mjs +1 -91
  13. package/claude-session.mjs +1 -1519
  14. package/code-event-contract.mjs +1 -118
  15. package/codex-app-server.mjs +1 -340
  16. package/codex-commands.mjs +1 -83
  17. package/codex-event-mapper.mjs +1 -232
  18. package/codex-images.mjs +1 -69
  19. package/codex-mcp-http.mjs +1 -131
  20. package/codex-session.mjs +1 -1295
  21. package/command-catalog.mjs +1 -118
  22. package/command-guidance.mjs +1 -8
  23. package/context-contract.mjs +1 -95
  24. package/context-windows.mjs +1 -107
  25. package/cross-terminal.mjs +1 -789
  26. package/cumulative-event-relay.mjs +1 -53
  27. package/design-edit.mjs +1 -424
  28. package/design-source-contract.mjs +1 -4
  29. package/direct-pair-room.mjs +1 -57
  30. package/dispatch-lease.mjs +1 -37
  31. package/dispatch-permission-cleanup.mjs +1 -86
  32. package/edit-diff.mjs +1 -136
  33. package/error-recovery.mjs +1 -50
  34. package/event-bounds.mjs +1 -121
  35. package/event-delivery-queue.mjs +1 -60
  36. package/event-id.mjs +1 -549
  37. package/evidence-citations.mjs +1 -50
  38. package/evidence-compact.mjs +1 -11
  39. package/flow-assembly.mjs +1 -196
  40. package/flow-budget.mjs +1 -84
  41. package/flow-conductor.mjs +1 -259
  42. package/flow-context-store.mjs +1 -387
  43. package/flow-host-revert.mjs +1 -42
  44. package/flow-models.mjs +1 -139
  45. package/flow-preview.mjs +1 -148
  46. package/flow-receipt.mjs +1 -122
  47. package/flow-redispatch.mjs +1 -72
  48. package/flow-review-gate.mjs +1 -402
  49. package/flow-review-reflect.mjs +1 -115
  50. package/flow-review.mjs +1 -152
  51. package/flow-scope-evidence.mjs +1 -117
  52. package/flow-skill-registry.mjs +1 -140
  53. package/flow-task-graph.mjs +1 -562
  54. package/flow-worktree.mjs +1 -71
  55. package/git-diff-report.mjs +1 -121
  56. package/hermes-delegation-guard.mjs +1 -14
  57. package/hermes-event-mapper.mjs +1 -194
  58. package/hermes-isolation.mjs +1 -61
  59. package/hermes-model-cache.mjs +1 -54
  60. package/hermes-policy.mjs +1 -92
  61. package/hermes-probe.mjs +1 -57
  62. package/hermes-session.mjs +1 -683
  63. package/hermes-setup.mjs +1 -167
  64. package/host-memory.mjs +1 -116
  65. package/interrupted-resume.mjs +1 -95
  66. package/keep-awake.mjs +1 -148
  67. package/key-shape.mjs +1 -49
  68. package/lane-continuation.mjs +1 -83
  69. package/lane-lifecycle.mjs +1 -189
  70. package/lane-worktree.mjs +1 -77
  71. package/launcher.mjs +1 -354
  72. package/mcp-flight-recorder.mjs +1 -79
  73. package/mockup-delivery.mjs +1 -57
  74. package/model-prices.mjs +1 -113
  75. package/package.json +13 -4
  76. package/pair-bus.mjs +1 -98
  77. package/pair-control-authority.mjs +1 -89
  78. package/past-work-search.mjs +1 -105
  79. package/plan-meters.mjs +1 -144
  80. package/presence.mjs +1 -191
  81. package/privacy-report.mjs +1 -108
  82. package/provider-resilience.mjs +1 -356
  83. package/provider.mjs +1 -133
  84. package/providers.mjs +1 -491
  85. package/publish-guard.mjs +2 -0
  86. package/publish-manifest.json +129 -0
  87. package/question-response.mjs +1 -58
  88. package/reap-terminal.mjs +1 -68
  89. package/recap.mjs +1 -297
  90. package/replay-transport.mjs +1 -64
  91. package/repo-search.mjs +1 -190
  92. package/review-check.mjs +1 -182
  93. package/runtime-contract.mjs +1 -93
  94. package/runtime-registry.mjs +1 -64
  95. package/runtime-session.mjs +1 -20
  96. package/scheduled-run-admission.mjs +1 -364
  97. package/scheduled-runs.mjs +1 -268
  98. package/sdk-admission.mjs +1 -9
  99. package/sdk-smoke.mjs +1 -61
  100. package/serve-consent.mjs +1 -118
  101. package/serve-dir.mjs +1 -40
  102. package/service.mjs +1 -877
  103. package/session-store.mjs +1 -484
  104. package/side-lane.mjs +1 -63
  105. package/supabase-key.mjs +1 -176
  106. package/supervisor-ready.mjs +1 -57
  107. package/switch-provider.mjs +1 -84
  108. package/terminal-name.mjs +1 -359
  109. package/terminal-row-reconcile.mjs +1 -70
  110. package/thinkpool-prompt-contracts.mjs +1 -85
  111. package/thinkpool-room-prompt.mjs +1 -187
  112. package/transcript-sanitize.mjs +1 -332
  113. package/turn-stall.mjs +1 -61
  114. package/update-gate.mjs +1 -53
  115. package/viewport.mjs +1 -810
  116. package/worker-completion.mjs +1 -57
package/hermes-policy.mjs CHANGED
@@ -1,92 +1 @@
1
- // Bridge-owned Hermes ACP schema policy. This is intentionally a small, pure
2
- // contract: Python receives only this JSON and fails closed for anything else.
3
- import { PEER_MCP_TOOLS, PEER_READ_MCP_TOOLS } from './cross-terminal.mjs'
4
-
5
- export const HERMES_POLICY_VERSION = 1
6
- export const HERMES_QUESTION_MCP_TOOL = 'request_user_input'
7
- export const MCP_FLIGHT_RECORDER_TOOL = 'read_mcp_flight_recorder'
8
-
9
- export const CODING_TOOLS = Object.freeze([
10
- 'web_search', 'web_extract', 'terminal', 'process', 'read_file', 'write_file',
11
- 'patch', 'search_files', 'vision_analyze', 'skills_list', 'skill_view',
12
- 'skill_manage', 'browser_navigate', 'browser_snapshot', 'browser_click',
13
- 'browser_type', 'browser_scroll', 'browser_back', 'browser_press',
14
- 'browser_get_images', 'browser_vision', 'browser_console', 'browser_cdp',
15
- 'browser_dialog', 'todo', 'memory', 'execute_code',
16
- ])
17
-
18
- const READ_ONLY_TOOLS = Object.freeze(['read_file', 'search_files'])
19
- // Hermes providers advertise capabilities conditionally (for example browser
20
- // CDP/dialog support depends on the installed browser integration). These are
21
- // the only builtins an ordinary or builder lane must have to do useful coding
22
- // work; the complete coding allowlist above remains permitted when available.
23
- export const ESSENTIAL_CODING_TOOLS = Object.freeze([
24
- 'terminal', 'process', 'read_file', 'write_file', 'patch', 'search_files',
25
- ])
26
- const ROLE_REQUIRED = Object.freeze({
27
- ordinary: [...PEER_MCP_TOOLS, HERMES_QUESTION_MCP_TOOL, MCP_FLIGHT_RECORDER_TOOL, 'spawn_terminal', 'close_terminal'],
28
- plan: [],
29
- conductor: ['submit_flow_plan'],
30
- builder: ['mark_flow_done'],
31
- reviewer: ['submit_flow_review', 'run_review_check', 'read_review_file'],
32
- 'manual-review': ['run_review_check', 'read_review_file'],
33
- })
34
-
35
- export function hermesRoleFor({ flowRole, sliceType } = {}) {
36
- if (flowRole === 'conductor') return 'conductor'
37
- if (flowRole === 'reviewer') return 'reviewer'
38
- if (sliceType === 'review') return 'manual-review'
39
- if (flowRole === 'builder') return 'builder'
40
- return 'ordinary'
41
- }
42
-
43
- export function hermesPolicyForRole(role, { mcpTools } = {}) {
44
- if (!Object.hasOwn(ROLE_REQUIRED, role)) throw new Error(`Unknown Hermes role policy: ${role}`)
45
- const supplied = Array.isArray(mcpTools) ? mcpTools.map(String).filter(Boolean) : ROLE_REQUIRED[role]
46
- const required = ROLE_REQUIRED[role]
47
- // Ordinary worker leaves deliberately lack spawn/close. Main-lane proof is
48
- // enforced by requiredMcpTools at dispatch; keep this schema usable for a
49
- // non-delegating ordinary child without widening it.
50
- const minimum = role === 'ordinary' ? [...PEER_MCP_TOOLS, HERMES_QUESTION_MCP_TOOL, MCP_FLIGHT_RECORDER_TOOL] : required
51
- for (const tool of minimum) if (!supplied.includes(tool)) throw new Error(`Hermes ${role} policy is missing required ThinkPool tool ${tool}`)
52
- const restricted = role === 'plan' || role === 'conductor' || role === 'reviewer' || role === 'manual-review'
53
- const builtinTools = restricted ? READ_ONLY_TOOLS : CODING_TOOLS
54
- const requiredBuiltinTools = restricted ? READ_ONLY_TOOLS : ESSENTIAL_CODING_TOOLS
55
- return Object.freeze({
56
- version: HERMES_POLICY_VERSION,
57
- role,
58
- // `builtinTools` is the role's complete approved surface, not a promise
59
- // that an availability-gated upstream provider implements every tool.
60
- builtinTools,
61
- requiredBuiltinTools,
62
- mcpServer: 'thinkpool',
63
- mcpTools: [...new Set(supplied)].sort(),
64
- })
65
- }
66
-
67
- export function hermesRequiredMcpTools(role, { canSpawnWorkers = false } = {}) {
68
- if (role === 'ordinary') return [...PEER_MCP_TOOLS, HERMES_QUESTION_MCP_TOOL, MCP_FLIGHT_RECORDER_TOOL, ...(canSpawnWorkers ? ['spawn_terminal', 'close_terminal'] : [])]
69
- return [...ROLE_REQUIRED[role]]
70
- }
71
-
72
- export const HERMES_PLAN_SAFE_MCP_TOOLS = PEER_READ_MCP_TOOLS
73
-
74
- // Keep the bridge's local /tools proof on the same canonical inventory as the
75
- // process-local Python bootstrap. `allBuiltinTools` lets that proof reject a
76
- // known built-in which is not part of this role, rather than merely looking
77
- // for a couple of required MCP names.
78
- export function hermesExactInventory(role, options = {}) {
79
- const policy = hermesPolicyForRole(role, options)
80
- return Object.freeze({
81
- builtinTools: [...policy.builtinTools].sort(),
82
- requiredBuiltinTools: [...policy.requiredBuiltinTools].sort(),
83
- mcpTools: [...policy.mcpTools].sort(),
84
- // The two excluded upstream capabilities must be checked as forbidden too;
85
- // they are intentionally absent from CODING_TOOLS, not unknown to policy.
86
- allBuiltinTools: [...CODING_TOOLS, 'delegate_task', 'session_search'].sort(),
87
- })
88
- }
89
-
90
- export function hermesPolicyEnv(role, options = {}) {
91
- return JSON.stringify(hermesPolicyForRole(role, options))
92
- }
1
+ import{PEER_MCP_TOOLS as e,PEER_READ_MCP_TOOLS as r}from"./cross-terminal.mjs";export const HERMES_POLICY_VERSION=1;export const HERMES_QUESTION_MCP_TOOL="request_user_input";export const MCP_FLIGHT_RECORDER_TOOL="read_mcp_flight_recorder";export const CODING_TOOLS=Object.freeze(["web_search","web_extract","terminal","process","read_file","write_file","patch","search_files","vision_analyze","skills_list","skill_view","skill_manage","browser_navigate","browser_snapshot","browser_click","browser_type","browser_scroll","browser_back","browser_press","browser_get_images","browser_vision","browser_console","browser_cdp","browser_dialog","todo","memory","execute_code"]);const o=Object.freeze(["read_file","search_files"]);export const ESSENTIAL_CODING_TOOLS=Object.freeze(["terminal","process","read_file","write_file","patch","search_files"]);const s=Object.freeze({ordinary:[...e,"request_user_input",MCP_FLIGHT_RECORDER_TOOL,"spawn_terminal","close_terminal"],plan:[],conductor:["submit_flow_plan"],builder:["mark_flow_done"],reviewer:["submit_flow_review","run_review_check","read_review_file"],"manual-review":["run_review_check","read_review_file"]});export function hermesRoleFor({flowRole:e,sliceType:r}={}){return"conductor"===e?"conductor":"reviewer"===e?"reviewer":"review"===r?"manual-review":"builder"===e?"builder":"ordinary"}export function hermesPolicyForRole(r,{mcpTools:i}={}){if(!Object.hasOwn(s,r))throw new Error(`Unknown Hermes role policy: ${r}`);const t=Array.isArray(i)?i.map(String).filter(Boolean):s[r],n=s[r],l="ordinary"===r?[...e,"request_user_input",MCP_FLIGHT_RECORDER_TOOL]:n;for(const e of l)if(!t.includes(e))throw new Error(`Hermes ${r} policy is missing required ThinkPool tool ${e}`);const _="plan"===r||"conductor"===r||"reviewer"===r||"manual-review"===r,c=_?o:CODING_TOOLS,a=_?o:ESSENTIAL_CODING_TOOLS;return Object.freeze({version:1,role:r,builtinTools:c,requiredBuiltinTools:a,mcpServer:"thinkpool",mcpTools:[...new Set(t)].sort()})}export function hermesRequiredMcpTools(r,{canSpawnWorkers:o=!1}={}){return"ordinary"===r?[...e,"request_user_input",MCP_FLIGHT_RECORDER_TOOL,...o?["spawn_terminal","close_terminal"]:[]]:[...s[r]]}export const HERMES_PLAN_SAFE_MCP_TOOLS=r;export function hermesExactInventory(e,r={}){const o=hermesPolicyForRole(e,r);return Object.freeze({builtinTools:[...o.builtinTools].sort(),requiredBuiltinTools:[...o.requiredBuiltinTools].sort(),mcpTools:[...o.mcpTools].sort(),allBuiltinTools:[...CODING_TOOLS,"delegate_task","session_search"].sort()})}export function hermesPolicyEnv(e,r={}){return JSON.stringify(hermesPolicyForRole(e,r))}
package/hermes-probe.mjs CHANGED
@@ -1,57 +1 @@
1
- import { execFileSync } from 'node:child_process'
2
- import fs from 'node:fs'
3
- import path from 'node:path'
4
-
5
- const clean = (value) => String(value || '').replace(/[\r\n]+/g, ' ').trim()
6
-
7
- const INSTALL = /Install directory:\s*(.+?)(?:\r?\n|$)/i
8
- const PROFILE = /Config:\s*(.+?)(?:\r?\n|$)/i
9
- const NOUS_PROVIDER = /Model:\s*\{[^\r\n]*['"]provider['"]\s*:\s*['"]nous['"][^\r\n]*\}/i
10
-
11
- // Resolve the installed venv and isolated profile once, then launch ACP through
12
- // bridge-owned code. `thinkpool` is only queried for inventory; it is never the
13
- // executable that serves an ACP lane.
14
- export function resolveHermesAcpRuntime({ command = 'thinkpool', execFile = execFileSync, exists = fs.existsSync, bootstrap = new URL('./hermes-acp-bootstrap.py', import.meta.url) } = {}) {
15
- try {
16
- const versionOutput = execFile(command, ['--version'], { encoding: 'utf8', timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
17
- const install = clean(String(versionOutput).match(INSTALL)?.[1])
18
- if (!install || !path.isAbsolute(install)) throw new Error('Hermes did not report an absolute install directory')
19
- const python = path.join(install, 'venv', 'bin', 'python')
20
- const bootstrapPath = bootstrap instanceof URL ? bootstrap.pathname : String(bootstrap)
21
- if (!exists(python) || !exists(bootstrapPath)) throw new Error('Hermes venv Python or ThinkPool ACP bootstrap is missing')
22
- // `thinkpool` is the dedicated profile wrapper on supported installs. Its
23
- // config output is evidence, not the ACP launch path.
24
- const configOutput = execFile(command, ['config', 'show'], { encoding: 'utf8', timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
25
- if (!NOUS_PROVIDER.test(String(configOutput))) throw new Error('ThinkPool Hermes profile is not pinned to Nous Portal')
26
- const config = clean(String(configOutput).match(PROFILE)?.[1])
27
- const profile = config ? path.dirname(config) : ''
28
- if (!profile || !path.isAbsolute(profile) || path.basename(profile) !== 'thinkpool') throw new Error('Hermes did not report the isolated thinkpool profile')
29
- return { python, bootstrap: bootstrapPath, profile, install }
30
- } catch (error) {
31
- return { error: clean(error?.stderr || error?.message || error) || 'could not resolve Hermes ACP runtime' }
32
- }
33
- }
34
-
35
- export function probeHermesRuntime({ command = 'thinkpool', prefixArgs = [], execFile = execFileSync, env = process.env, strictBootstrap = false, exists = fs.existsSync } = {}) {
36
- try {
37
- const versionOutput = execFile(command, [...prefixArgs, '--version'], { encoding: 'utf8', env, timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
38
- const version = clean(versionOutput).match(/Hermes Agent v([^\s]+)/i)?.[1] || null
39
- const configOutput = execFile(command, [...prefixArgs, 'config', 'show'], { encoding: 'utf8', env, timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
40
- if (!NOUS_PROVIDER.test(String(configOutput))) return { available: false, version, reason: 'ThinkPool Hermes profile is not pinned to Nous Portal' }
41
- execFile(command, [...prefixArgs, 'acp', '--check'], { encoding: 'utf8', env, timeout: 15_000, stdio: ['ignore', 'pipe', 'pipe'] })
42
- const hooksOutput = execFile(command, [...prefixArgs, 'hooks', 'list'], { encoding: 'utf8', env, timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
43
- const doctorOutput = execFile(command, [...prefixArgs, 'hooks', 'doctor'], { encoding: 'utf8', env, timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
44
- const guardOutput = execFile(command, [...prefixArgs, 'hooks', 'test', 'pre_tool_call', '--for-tool', 'delegate_task'], { encoding: 'utf8', env, timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'] })
45
- const doctorHealthy = /All shell hooks look healthy/i.test(doctorOutput)
46
- && !/(?:issue\(s\) found|modified since approval|⚠)/i.test(doctorOutput)
47
- const delegationBlocked = /(?:action|decision)["']?\s*[:=]\s*["']block/i.test(guardOutput)
48
- && /ThinkPool blocks hidden Hermes delegation/i.test(guardOutput)
49
- && /pre_tool_call[\s\S]*delegate_task[\s\S]*(?:✓ allowed|allowed)/i.test(hooksOutput)
50
- if (!doctorHealthy || !delegationBlocked) return { available: false, version, reason: 'delegate_task guard is not healthy, unchanged, allowlisted, and structurally blocking in the dedicated Hermes profile' }
51
- const runtime = strictBootstrap ? resolveHermesAcpRuntime({ command, execFile, exists }) : null
52
- if (runtime?.error) return { available: false, version, reason: `Hermes ACP bootstrap unavailable: ${runtime.error}` }
53
- return { available: true, version, acpProtocol: 1, delegationBlocked: true, ...(runtime || {}) }
54
- } catch (error) {
55
- return { available: false, version: null, reason: clean(error?.stderr || error?.message || error) }
56
- }
57
- }
1
+ import{execFileSync as e}from"node:child_process";import o from"node:fs";import t from"node:path";const i=e=>String(e||"").replace(/[\r\n]+/g," ").trim(),n=/Install directory:\s*(.+?)(?:\r?\n|$)/i,r=/Config:\s*(.+?)(?:\r?\n|$)/i,s=/Model:\s*\{[^\r\n]*['"]provider['"]\s*:\s*['"]nous['"][^\r\n]*\}/i;export function resolveHermesAcpRuntime({command:l="thinkpool",execFile:a=e,exists:p=o.existsSync,bootstrap:c=new URL("./hermes-acp-bootstrap.py",import.meta.url)}={}){try{const e=a(l,["--version"],{encoding:"utf8",timeout:1e4,stdio:["ignore","pipe","pipe"]}),o=i(String(e).match(n)?.[1]);if(!o||!t.isAbsolute(o))throw new Error("Hermes did not report an absolute install directory");const d=t.join(o,"venv","bin","python"),m=c instanceof URL?c.pathname:String(c);if(!p(d)||!p(m))throw new Error("Hermes venv Python or ThinkPool ACP bootstrap is missing");const u=a(l,["config","show"],{encoding:"utf8",timeout:1e4,stdio:["ignore","pipe","pipe"]});if(!s.test(String(u)))throw new Error("ThinkPool Hermes profile is not pinned to Nous Portal");const h=i(String(u).match(r)?.[1]),g=h?t.dirname(h):"";if(!g||!t.isAbsolute(g)||"thinkpool"!==t.basename(g))throw new Error("Hermes did not report the isolated thinkpool profile");return{python:d,bootstrap:m,profile:g,install:o}}catch(e){return{error:i(e?.stderr||e?.message||e)||"could not resolve Hermes ACP runtime"}}}export function probeHermesRuntime({command:t="thinkpool",prefixArgs:n=[],execFile:r=e,env:l=process.env,strictBootstrap:a=!1,exists:p=o.existsSync}={}){try{const e=r(t,[...n,"--version"],{encoding:"utf8",env:l,timeout:1e4,stdio:["ignore","pipe","pipe"]}),o=i(e).match(/Hermes Agent v([^\s]+)/i)?.[1]||null,c=r(t,[...n,"config","show"],{encoding:"utf8",env:l,timeout:1e4,stdio:["ignore","pipe","pipe"]});if(!s.test(String(c)))return{available:!1,version:o,reason:"ThinkPool Hermes profile is not pinned to Nous Portal"};r(t,[...n,"acp","--check"],{encoding:"utf8",env:l,timeout:15e3,stdio:["ignore","pipe","pipe"]});const d=r(t,[...n,"hooks","list"],{encoding:"utf8",env:l,timeout:1e4,stdio:["ignore","pipe","pipe"]}),m=r(t,[...n,"hooks","doctor"],{encoding:"utf8",env:l,timeout:1e4,stdio:["ignore","pipe","pipe"]}),u=r(t,[...n,"hooks","test","pre_tool_call","--for-tool","delegate_task"],{encoding:"utf8",env:l,timeout:1e4,stdio:["ignore","pipe","pipe"]}),h=/All shell hooks look healthy/i.test(m)&&!/(?:issue\(s\) found|modified since approval|⚠)/i.test(m),g=/(?:action|decision)["']?\s*[:=]\s*["']block/i.test(u)&&/ThinkPool blocks hidden Hermes delegation/i.test(u)&&/pre_tool_call[\s\S]*delegate_task[\s\S]*(?:✓ allowed|allowed)/i.test(d);if(!h||!g)return{available:!1,version:o,reason:"delegate_task guard is not healthy, unchanged, allowlisted, and structurally blocking in the dedicated Hermes profile"};const f=a?resolveHermesAcpRuntime({command:t,execFile:r,exists:p}):null;return f?.error?{available:!1,version:o,reason:`Hermes ACP bootstrap unavailable: ${f.error}`}:{available:!0,version:o,acpProtocol:1,delegationBlocked:!0,...f||{}}}catch(e){return{available:!1,version:null,reason:i(e?.stderr||e?.message||e)}}}