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
@@ -0,0 +1,147 @@
1
+ // Lane read views: actionsFor / view / safeMode / diffOf / board / summaryOf.
2
+ // Read-only over the ledger (repo.ledger.read()); refresh is reused from the
3
+ // core, so the read path keeps its existing reconciliation side effects
4
+ // (expired-watch pruning and orphan-card declines still audit there). This
5
+ // module itself adds no writes.
6
+ import { existsSync } from 'node:fs'
7
+ import { WorktreeError } from './errors.js'
8
+ import { CHECKABLE, LANDABLE_FROM, TRANSIENT, isActive, nextFor } from './state.js'
9
+ import { watchFacts } from './watches.js'
10
+ import { hasExclude } from './exclude.js'
11
+ import { renderBoard } from './prompts.js'
12
+
13
+ /** @param {ReturnType<typeof import('./lane-core.js').createLaneCore>} core */
14
+ export function createLaneViews(core) {
15
+ const { deps, git, approveModeSafe, approveModeSourceSafe, cwdOf, repoFor, repoCached, laneOf, refresh, readConfig } = core
16
+
17
+ // ─── views ────────────────────────────────────────────────────────────
18
+
19
+ /** Legal actions per lane for the panel (disabled ones carry the reason). @param {any} lane */
20
+ function actionsFor(lane) {
21
+ const deny = (/** @type {string} */ reason) => ({ enabled: false, reason })
22
+ const allow = { enabled: true }
23
+ const exists = !['cleaned'].includes(lane.state) && !(lane.state === 'abandoned' && lane.cleanup?.mode !== 'keep')
24
+ return {
25
+ diff: lane.state === 'preparing' ? deny('setup is still running') : allow,
26
+ check: !CHECKABLE.includes(lane.state) ? deny(`not available while ${lane.state}`) : lane.boundChild ? deny('a worker is running in this lane') : allow,
27
+ land: !LANDABLE_FROM.includes(lane.state) ? deny(`only a landable lane can be merged (now ${lane.state})`) : lane.baseMoved ? deny(`the main worktree is not on ${lane.base.branch}`) : allow,
28
+ clean: ['landed', 'kept'].includes(lane.state) || (lane.state === 'abandoned' && lane.cleanup?.mode === 'keep') ? allow : deny('cleanup applies after merging'),
29
+ abandon: isActive(lane) ? (lane.boundChild ? deny('a worker is running in this lane') : allow) : deny(`already ${lane.state}`),
30
+ setup: lane.state === 'setup-failed' ? allow : deny('setup only reruns after a failure'),
31
+ copyPath: exists ? allow : deny('the worktree was removed'),
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Full read-only view for the GUI panel.
37
+ * @param {any} session
38
+ * @param {{ mode?: boolean, approve?: string | null, approveSource?: 'session' | 'global' }} [options] - cold-read override: a boolean
39
+ * `mode` replaces the live projection read (a pseudo session folded from
40
+ * the persisted log by sessionQuery has no live projection cells); `approve`
41
+ * and `approveSource` carry the cold-folded auto-approve override the same
42
+ * way (null = no override → the global default answers).
43
+ */
44
+ async function view(session, options) {
45
+ const viewMode = () => (typeof options?.mode === 'boolean' ? options.mode : safeMode(session))
46
+ const viewApproveMode = () => (options && typeof options.approve === 'string' ? options.approve : approveModeSafe(session))
47
+ const viewApproveModeSource = () => (options && (options.approveSource === 'session' || options.approveSource === 'global') ? options.approveSource : approveModeSourceSafe(session))
48
+ let repo
49
+ try {
50
+ repo = await repoFor(cwdOf(session))
51
+ } catch (error) {
52
+ const known = error instanceof WorktreeError
53
+ return { available: false, mode: viewMode(), approveMode: viewApproveMode(), approveModeSource: viewApproveModeSource(), error: known ? error.toJSON() : { code: 'ERROR', message: String(/** @type {any} */ (error)?.message ?? error) } }
54
+ }
55
+ try {
56
+ const { mainBranch, unmanaged } = await refresh(repo)
57
+ const ledger = repo.ledger.read()
58
+ /** @type {any} */
59
+ let verification
60
+ try {
61
+ const repoConfig = readConfig(repo)
62
+ verification = { enabled: repoConfig.check.length > 0, commands: repoConfig.check.map((entry) => entry.name), setup: repoConfig.setup }
63
+ } catch (error) {
64
+ verification = { enabled: true, commands: [], error: String(/** @type {any} */ (error)?.message ?? error) }
65
+ }
66
+ const lanes = []
67
+ for (const lane of [...ledger.lanes].reverse()) {
68
+ const exists = existsSync(lane.path)
69
+ let counts = null
70
+ let stat = null
71
+ if ((await git.branchExists(repo.mainRoot, lane.branch).catch(() => false))) {
72
+ counts = await git.aheadBehind(repo.mainRoot, lane.base.branch, lane.branch).catch(() => null)
73
+ stat = await git.diffStat(repo.mainRoot, lane.base.branch, lane.branch).catch(() => null)
74
+ }
75
+ lanes.push({
76
+ ...lane,
77
+ history: (lane.history ?? []).slice(-12),
78
+ exists,
79
+ ahead: counts?.ahead ?? null,
80
+ behind: counts?.behind ?? null,
81
+ stat,
82
+ next: nextFor(lane),
83
+ transient: TRANSIENT.includes(lane.state),
84
+ ...watchFacts(ledger.watches, lane.id),
85
+ actions: actionsFor(lane),
86
+ })
87
+ }
88
+ return {
89
+ available: true,
90
+ mode: viewMode(),
91
+ approveMode: viewApproveMode(),
92
+ approveModeSource: viewApproveModeSource(),
93
+ ownedBySession: lanes.filter((lane) => lane.ownerSession === session?.id).map((lane) => lane.id),
94
+ repo: { mainRoot: repo.mainRoot, root: repo.root, rootPath: repo.rootPath, branch: mainBranch, gitVersion: repo.version?.join('.') ?? null, exclude: hasExclude(repo.commonDir, repo.root), verification },
95
+ lanes,
96
+ unmanaged,
97
+ }
98
+ } catch (error) {
99
+ const known = error instanceof WorktreeError
100
+ return { available: false, mode: viewMode(), approveMode: viewApproveMode(), approveModeSource: viewApproveModeSource(), error: known ? error.toJSON() : { code: 'ERROR', message: String(/** @type {any} */ (error)?.message ?? error) } }
101
+ }
102
+ }
103
+
104
+ /** @param {any} session */
105
+ function safeMode(session) {
106
+ try {
107
+ return deps.modeOf(session) === true
108
+ } catch {
109
+ return false
110
+ }
111
+ }
112
+
113
+ /** @param {any} session @param {string} laneId */
114
+ async function diffOf(session, laneId) {
115
+ const repo = await repoFor(cwdOf(session))
116
+ const lane = laneOf(repo, laneId)
117
+ if (lane.land?.commit) return git.diff(repo.mainRoot, `${lane.land.commit}^1`, lane.land.commit)
118
+ return git.diff(repo.mainRoot, lane.base.branch, lane.branch)
119
+ }
120
+
121
+ /** Runtime-context board (sync; empty until the repo resolved once). @param {any} session */
122
+ function board(session) {
123
+ const repo = repoCached(session)
124
+ const mode = safeMode(session)
125
+ if (!repo) return mode ? renderBoard({ lanes: [], mode }) : ''
126
+ try {
127
+ const ledger = repo.ledger.read()
128
+ return renderBoard({ lanes: ledger.lanes, watches: ledger.watches, mode })
129
+ } catch {
130
+ return ''
131
+ }
132
+ }
133
+
134
+ /** Lane ids this session owns / active counts for quick status. @param {any} session */
135
+ function summaryOf(session) {
136
+ const repo = repoCached(session)
137
+ if (!repo) return null
138
+ try {
139
+ const lanes = repo.ledger.read().lanes.filter((/** @type {any} */ lane) => lane.ownerSession === session?.id)
140
+ return { active: lanes.filter(isActive).length, awaiting: lanes.filter((/** @type {any} */ lane) => lane.state === 'awaiting-approval').length }
141
+ } catch {
142
+ return null
143
+ }
144
+ }
145
+
146
+ return { actionsFor, view, diffOf, board, summaryOf }
147
+ }