weir-harness 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/cordis.patch.yml +0 -2
  2. package/lib/client.blackboard-model.js +172 -56
  3. package/lib/client.capability-manager.js +0 -1
  4. package/lib/client.capability-model.js +378 -31
  5. package/lib/client.chain-model.js +80 -0
  6. package/lib/client.disabled-categories-editor.js +22 -0
  7. package/lib/client.edit-lock-maintenance.js +239 -246
  8. package/lib/client.edit-lock-panel.js +110 -0
  9. package/lib/client.hash-edit-model.js +48 -0
  10. package/lib/client.js +267 -1549
  11. package/lib/client.lsp-model.js +92 -0
  12. package/lib/client.lsp-panel.js +11 -16
  13. package/lib/client.lsp-toggle.js +18 -0
  14. package/lib/client.notify-permissions.js +112 -20
  15. package/lib/client.notify-web.js +14 -11
  16. package/lib/client.robash-model.js +26 -0
  17. package/lib/client.settings-page.js +287 -17
  18. package/lib/client.worktree-model.js +225 -0
  19. package/package.json +5 -2
  20. package/src/blackboard/durable.js +12 -0
  21. package/src/blackboard/index.js +2 -2
  22. package/src/blackboard/kernel.js +23 -6
  23. package/src/blackboard/notify.js +10 -3
  24. package/src/blackboard/remote.js +31 -13
  25. package/src/blackboard/storage.js +13 -5
  26. package/src/capabilities/apply-engine.js +189 -101
  27. package/src/capabilities/defaults-transaction.js +136 -1
  28. package/src/capabilities/lifecycle-snapshot.js +83 -204
  29. package/src/capabilities/mcp-admission.js +1 -23
  30. package/src/capabilities/mcp-drain.js +30 -19
  31. package/src/capabilities/mcp-facade.js +23 -3
  32. package/src/capabilities/preset-library.js +247 -0
  33. package/src/capabilities/preset-package.js +212 -1
  34. package/src/capabilities/same-name-policy.js +3 -41
  35. package/src/capabilities/selection-notify.js +324 -21
  36. package/src/capabilities/skill-office-adapter.js +7 -1
  37. package/src/capabilities/skill-selection-plugin.js +315 -729
  38. package/src/capabilities/store/checked-contract.d.ts +5 -0
  39. package/src/capabilities/store/fs-adapter.js +52 -0
  40. package/src/capabilities/store/lock.js +86 -0
  41. package/src/capabilities/store/paths.js +5 -0
  42. package/src/capabilities/store/store.js +105 -5
  43. package/src/creative-guide/guide.js +1 -1
  44. package/src/delegate/child-composition.js +258 -0
  45. package/src/delegate/group-coordinator.js +25 -27
  46. package/src/delegate/index.js +21 -2
  47. package/src/delegate/rehydrate.js +24 -4
  48. package/src/delegate/robash-guard-core.js +2 -2
  49. package/src/delegate/spawn-adapter.js +214 -100
  50. package/src/delegate/status-tool.js +9 -6
  51. package/src/delegate/supervision-mount.js +35 -6
  52. package/src/delegate/tool.js +29 -4
  53. package/src/{shared → delegate}/whitelist-defaults.js +2 -2
  54. package/src/edit-lock/admin-ledger.js +8 -11
  55. package/src/edit-lock/admin-recovery.js +2 -1
  56. package/src/edit-lock/admission.js +12 -2
  57. package/src/edit-lock/binding-guidance.js +28 -10
  58. package/src/edit-lock/binding-machine.js +312 -0
  59. package/src/edit-lock/derived-facts.js +67 -0
  60. package/src/edit-lock/index.js +44 -244
  61. package/src/edit-lock/inspect.js +113 -1
  62. package/src/edit-lock/lifecycle.js +8 -5
  63. package/src/edit-lock/limits.js +61 -0
  64. package/src/edit-lock/maintenance.js +5 -2
  65. package/src/edit-lock/manager.js +6 -2
  66. package/src/edit-lock/operation-history.js +1 -1
  67. package/src/edit-lock/peer-client.js +9 -2
  68. package/src/edit-lock/peer-transport.js +7 -1
  69. package/src/edit-lock/remote.js +11 -4
  70. package/src/edit-lock/state.js +2 -4
  71. package/src/edit-lock/view.js +10 -11
  72. package/src/lsp/admin.js +2 -24
  73. package/src/lsp/index.js +1 -1
  74. package/src/lsp/manager.js +1 -1
  75. package/src/notify/permissions-admin.js +1 -1
  76. package/src/{lsp/child-process.js → process/index.js} +23 -6
  77. package/src/settings/env-admin.js +1 -1
  78. package/src/settings/index.js +1 -1
  79. package/src/settings/sections.js +0 -54
  80. package/src/shared/audit.js +12 -0
  81. package/src/shared/child-scope.js +3 -1
  82. package/src/shared/http-json.js +28 -0
  83. package/src/{delegate/audit-readers.js → shared/terminal-evidence.js} +34 -4
  84. package/src/worktree/errors.js +3 -0
  85. package/src/worktree/index.js +1 -2
  86. package/src/worktree/lane-core.js +641 -0
  87. package/src/worktree/lane-views.js +147 -0
  88. package/src/worktree/lane-workflows.js +853 -0
  89. package/src/worktree/lanes.js +24 -1513
  90. package/src/worktree/runner.js +5 -4
  91. package/src/capabilities/content-pin.js +0 -88
  92. package/src/capabilities/content-refresh.js +0 -331
  93. package/src/capabilities/distribution-manifest.js +0 -78
  94. package/src/capabilities/isolated-exec.js +0 -106
  95. package/src/capabilities/publisher.js +0 -129
  96. package/src/capabilities/skill-admission.js +0 -181
  97. package/src/capabilities/update-lifecycle.js +0 -106
  98. package/src/edit-lock/remote-service.js +0 -28
  99. package/src/worktree/contract-guidance.test.js +0 -100
@@ -1,6 +1,7 @@
1
1
  // Supervised group coordinator: registry state machine for grouped delegation.
2
2
  // Pure logic (no DSH imports) — the mount layer (index.js/tool.js) feeds it
3
3
  // session events and injects the effectors (sendMessage/interrupt/timers).
4
+ import { isTerminalStatus, parseTerminalStatus } from '../shared/terminal-evidence.js'
4
5
 
5
6
  export const SUPERVISION_CONTRACT = `
6
7
 
@@ -30,15 +31,6 @@ export const DEFAULT_SUPERVISION = {
30
31
  /** Bounded wait for the last settlement notice before the fallback delivery. */
31
32
  export const SIGNAL_FALLBACK_MS = 1000
32
33
 
33
- /** Parse a child's final assistant text into a terminal status, or null. */
34
- export function parseTerminalStatus(text) {
35
- if (typeof text !== 'string' || text.length === 0) return null
36
- const match = /^STATUS:[ \t]*(completed|blocked)[ \t]*$/m.exec(text)
37
- if (!match) return null
38
- const reportMatch = /^REPORT:[ \t]*([\s\S]*)$/m.exec(text.slice(match.index))
39
- return { status: match[1], report: (reportMatch?.[1] ?? '').trim() }
40
- }
41
-
42
34
  /**
43
35
  * Canonical member record shape: eight fields, fixed order. The single source
44
36
  * every construction site converges on (registerMember, hydrate, rehydrate).
@@ -55,26 +47,31 @@ export function createGroupRecord(name, { sealed = false, settled = false, membe
55
47
  }
56
48
 
57
49
  /**
58
- * Single exit for the terminal-status predicate: statuses that count toward
59
- * group completion (blocked waits for a resume, so it is NOT terminal here).
60
- */
61
- export function isTerminalStatus(status) {
62
- return status === 'completed' || status === 'terminated'
63
- }
64
-
65
- /**
66
- * Single exit for the untracked-catalog predicate: continuable catalog entries
67
- * the registry does not track. mode is normalized (undefined → 'continuable');
68
- * the row shape is { id, label, mode }. `isTracked(id)` is the caller's lookup.
50
+ * Single exit for the untracked-catalog predicate: catalog children the
51
+ * supervision registry does not track AND no one-shot/continuable spawn fact
52
+ * claims. The row shape is { id, label, mode } (mode is passed through
53
+ * verbatim: DSH 0.2.1 reports every local child as 'continuable' and may also
54
+ * report 'external', so the catalog mode no longer discriminates lanes — the
55
+ * durable spawn facts do).
56
+ * `isTracked(id)` is the caller's registry lookup. `spawnFactOf(id)` returns
57
+ * the durable delegate/spawn fact for a weir-spawned child (lane included):
58
+ * one-shot and plain-continuable children must never be resurrected as
59
+ * supervision orphans, while a supervised child normally IS tracked and a
60
+ * supervised child missing from the fact chain stays visible as an orphan
61
+ * (never hidden). Only a fact-less orphan (not spawned by this weir build)
62
+ * keeps the promoted/recovered semantics.
63
+ * @param {object[]} entries - DSH catalog children
64
+ * @param {(id: string) => boolean} isTracked
65
+ * @param {(id: string) => { lane?: string } | undefined} [spawnFactOf]
69
66
  */
70
- export function untrackedCatalogEntries(entries, isTracked) {
67
+ export function untrackedCatalogEntries(entries, isTracked, spawnFactOf) {
71
68
  const untracked = []
72
69
  for (const entry of entries ?? []) {
73
70
  if (!entry || typeof entry !== 'object') continue
74
- const mode = entry.mode === undefined ? 'continuable' : entry.mode
75
- if (mode !== 'continuable') continue
76
71
  if (isTracked(entry.id)) continue
77
- untracked.push({ id: entry.id, label: entry.label ?? '', mode })
72
+ const lane = spawnFactOf?.(entry.id)?.lane
73
+ if (lane === 'one-shot' || lane === 'continuable') continue
74
+ untracked.push({ id: entry.id, label: entry.label ?? '', mode: entry.mode })
78
75
  }
79
76
  return untracked
80
77
  }
@@ -89,7 +86,8 @@ export function untrackedCatalogEntries(entries, isTracked) {
89
86
  * @param {(delayMs: number, fn: () => void) => void} deps.schedule - delayed retry scheduler
90
87
  * @param {(reason: string) => void} [deps.onAudit]
91
88
  * @param {(fact: object) => void} [deps.onFact] - structured supervision facts (durability)
92
- * @param {(text: string) => void} [deps.notifyParent] - deliver a parent-facing signal (timer-deferred followup)
89
+ * @param {(text: string) => void} [deps.notifyParent] - deliver a parent-facing signal (timer-deferred followup)
90
+ * @param {(childId: string) => { lane?: string } | undefined} [deps.spawnFactOf] - durable delegate/spawn fact for one child id (lane decides orphan resurrection; see untrackedCatalogEntries)
93
91
  */
94
92
  export function createGroupCoordinator(deps, config = {}) {
95
93
  const cfg = { ...DEFAULT_SUPERVISION, ...config }
@@ -190,9 +188,9 @@ export function createGroupCoordinator(deps, config = {}) {
190
188
  }
191
189
  }
192
190
 
193
- /** Catalog cross-check: continuable catalog entries this registry does not track. */
191
+ /** Catalog cross-check: catalog children this registry does not track (spawn-fact aware). */
194
192
  function untrackedAgainstCatalog(entries) {
195
- return untrackedCatalogEntries(entries, (id) => children.has(id))
193
+ return untrackedCatalogEntries(entries, (id) => children.has(id), deps.spawnFactOf)
196
194
  }
197
195
 
198
196
  function noteAssistantText(childId, text) {
@@ -1,7 +1,9 @@
1
1
  // Weir delegate plugin: category registry + curated agents + the delegate
2
2
  // tool. Plain ESM, ctx-only. Composition root: all policy lives in the sibling
3
3
  // modules (settings-overlay / target-resolver / supervision-tools /
4
- // supervision-mount / audit-readers); apply() only constructs and wires them.
4
+ // supervision-mount); apply() only constructs and wires them. The terminal-
5
+ // evidence cold readers live in src/shared/terminal-evidence.js (shared with
6
+ // the worktree plugin).
5
7
  import { CURATED_AGENTS } from './agents.js'
6
8
  import { createSettingsOverlay } from './settings-overlay.js'
7
9
  import { createTargetResolver } from './target-resolver.js'
@@ -11,11 +13,12 @@ import { skillSelectionFor } from '../capabilities/skill-selection-plugin.js'
11
13
  import { createResumeTool, createTerminateTool } from './supervision-tools.js'
12
14
  import { mountSupervision } from './supervision-mount.js'
13
15
  import { createAudit } from '../shared/audit.js'
14
- import { FALLBACK_TABLES } from '../shared/whitelist-defaults.js'
16
+ import { FALLBACK_TABLES } from './whitelist-defaults.js'
15
17
  import { createDelegateTool } from './tool.js'
16
18
  import { attachWorktreeModeGuard } from './worktree-mode.js'
17
19
  import { DOCTRINE_SECTION_ORDER } from '../core/doctrine.js'
18
20
  import { isDelegatedChild } from '../shared/child-scope.js'
21
+ import { createChildComposition } from './child-composition.js'
19
22
  import {
20
23
  DELEGATE_TARGETS_SECTION_NAME,
21
24
  DELEGATE_TARGETS_SECTION_ORDER_OFFSET,
@@ -95,6 +98,20 @@ function apply(ctx, config = {}) {
95
98
  onAdaptersUpdated: (fn) => ctx.on('llm/adapters-updated', fn),
96
99
  })
97
100
 
101
+ // Creation-window child composition (DSH 0.2.1 removed the request-level
102
+ // persona/toolFilter): the shim applies the reserved spawn's composition in
103
+ // the child's agent/created window and replays it from the audit channel on
104
+ // cold resume. One instance per plugin context; dispose unregisters it.
105
+ const composition = createChildComposition({
106
+ ctx,
107
+ audit,
108
+ logger: ctx.logger,
109
+ restrictableNames: () => ctx.tools.view?.(undefined)?.restrictableNames,
110
+ // Feed the supervision catalog cross-check the same durable fact without a
111
+ // file re-read (spawn-fact lane decides orphan resurrection).
112
+ onSpawn: mount.noteSpawnFact,
113
+ })
114
+
98
115
  ctx.tools.register(
99
116
  createDelegateTool({
100
117
  resolveTarget: targetResolver.resolveTarget,
@@ -112,6 +129,7 @@ function apply(ctx, config = {}) {
112
129
  // names, so the child deny list names only tools this composition
113
130
  // actually registers (tools.restrict() rejects unknown deny names).
114
131
  restrictableNames: () => ctx.tools.view?.(undefined)?.restrictableNames,
132
+ composition,
115
133
  }),
116
134
  )
117
135
 
@@ -163,6 +181,7 @@ function apply(ctx, config = {}) {
163
181
  return () => {
164
182
  offModeGuard()
165
183
  mount.dispose()
184
+ composition.dispose()
166
185
  }
167
186
  }
168
187
 
@@ -2,27 +2,44 @@
2
2
  // restart. Pure logic — the mount layer feeds it parsed audit records and the
3
3
  // DSH catalog; no DSH imports, no fs.
4
4
 
5
- import { parseTerminalStatus, createMemberRecord, createGroupRecord, isTerminalStatus, untrackedCatalogEntries } from './group-coordinator.js'
5
+ import { createMemberRecord, createGroupRecord, untrackedCatalogEntries } from './group-coordinator.js'
6
+ import { parseTerminalStatus, isTerminalStatus } from '../shared/terminal-evidence.js'
6
7
 
7
8
  /**
8
9
  * Rebuild supervision state by replaying structured audit facts and
9
10
  * cross-checking the DSH subagent catalog.
10
11
  *
12
+ * Two fact channels ride the same audit file: the supervision facts
13
+ * (`weir/supervision/<kind>`) and the child-composition spawn facts
14
+ * (`weir/delegate/spawn`, which carry the lane). The spawn facts decide which
15
+ * catalog children are supervision orphans — DSH 0.2.1 reports every local
16
+ * child as mode 'continuable', so the catalog mode can no longer tell a
17
+ * one-shot child from a supervised one.
18
+ *
11
19
  * @param {object} input
12
20
  * @param {string} input.parentId - the parent session id (record filter key)
13
21
  * @param {object[]} input.records - parsed audit JSONL records (already tail-read; may contain other sessions/types)
14
22
  * @param {object[]} input.catalogChildren - DSH catalog entries ({ id, label?, mode? }); best-effort
15
- * @returns {{ children: object[], groups: object[], untracked: object[], confidence: 'full'|'partial', factsSeen: number }}
23
+ * @returns {{ children: object[], groups: object[], untracked: object[], spawnFacts: object[], confidence: 'full'|'partial', factsSeen: number }}
16
24
  */
17
25
  export function rehydrateSupervision({ parentId, records, catalogChildren }) {
18
26
  const children = new Map()
19
27
  const groups = new Map()
28
+ /** @type {Map<string, { childId: string, lane?: string }>} */
29
+ const spawnFacts = new Map()
20
30
  let factsSeen = 0
21
31
 
22
32
  for (const record of records ?? []) {
23
33
  if (!record || typeof record !== 'object') continue
24
34
  if (record.session !== undefined && record.session !== null && record.session !== parentId) continue
25
35
  const type = typeof record.type === 'string' ? record.type : ''
36
+ if (type === 'weir/delegate/spawn') {
37
+ const fact = record.data
38
+ if (fact && typeof fact === 'object' && typeof fact.childId === 'string' && fact.childId.length > 0) {
39
+ spawnFacts.set(fact.childId, { childId: fact.childId, lane: typeof fact.lane === 'string' ? fact.lane : undefined })
40
+ }
41
+ continue
42
+ }
26
43
  if (!type.startsWith('weir/supervision/')) continue
27
44
  const fact = record.data
28
45
  if (!fact || typeof fact !== 'object' || typeof fact.kind !== 'string') continue
@@ -36,13 +53,16 @@ export function rehydrateSupervision({ parentId, records, catalogChildren }) {
36
53
  group.settled = group.sealed === true && group.memberIds.length > 0 && terminal
37
54
  }
38
55
 
39
- // Catalog cross-check: continuable children the registry does not track.
40
- const untracked = untrackedCatalogEntries(catalogChildren, (id) => children.has(id))
56
+ // Catalog cross-check: only fact-less orphans remain untracked (the spawn
57
+ // facts identify the one-shot/continuable children this registry must never
58
+ // resurrect, and keep a supervised child whose fact chain is broken visible).
59
+ const untracked = untrackedCatalogEntries(catalogChildren, (id) => children.has(id), (id) => spawnFacts.get(id))
41
60
 
42
61
  return {
43
62
  children: [...children.values()],
44
63
  groups: [...groups.values()],
45
64
  untracked,
65
+ spawnFacts: [...spawnFacts.values()],
46
66
  confidence: factsSeen > 0 ? 'full' : 'partial',
47
67
  factsSeen,
48
68
  }
@@ -1,7 +1,7 @@
1
1
  // Read-only shell guard core: the single canonical home of every cross-shell
2
2
  // policy the bash and pwsh adapters share — the whitelist tables (one
3
3
  // representation, consumed by the guard adapters, delegate/index.js, and
4
- // shared/whitelist-defaults.js), the git gate, the GIT_CONFIG_* environment
4
+ // whitelist-defaults.js), the git gate, the GIT_CONFIG_* environment
5
5
  // smuggle refusal, the recursion budget, the redirect sink policy, and the
6
6
  // per-executable verdict tail. Pure functions, no ctx access.
7
7
  //
@@ -10,7 +10,7 @@
10
10
  // the three & roles, alias expansion), so the scanners are not merged.
11
11
 
12
12
  /** Canonical whitelist tables, organized by the five published keys so
13
- * shared/whitelist-defaults.js derives FALLBACK_TABLES with zero translation.
13
+ * whitelist-defaults.js derives FALLBACK_TABLES with zero translation.
14
14
  * Entries moved verbatim from the former DEFAULT_ROBASH (robash-guard.js) and
15
15
  * DEFAULT_ROBASH_PWSH (robash-guard-pwsh.js); pwsh entries keep their original
16
16
  * casing (the pwsh adapter lowercases at lookup) so the shipped