brainclaw 0.29.2 → 1.5.4

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 (197) hide show
  1. package/LICENSE +21 -74
  2. package/README.md +199 -176
  3. package/dist/brainclaw-vscode.vsix +0 -0
  4. package/dist/cli.js +710 -25
  5. package/dist/commands/accept.js +3 -0
  6. package/dist/commands/add-step.js +11 -26
  7. package/dist/commands/agent-board.js +70 -3
  8. package/dist/commands/audit.js +19 -0
  9. package/dist/commands/check-policy.js +54 -0
  10. package/dist/commands/check-security-mcp.js +145 -0
  11. package/dist/commands/check-security.js +106 -0
  12. package/dist/commands/claim-resource.js +1 -0
  13. package/dist/commands/codev.js +672 -0
  14. package/dist/commands/compact.js +74 -0
  15. package/dist/commands/complete-step.js +16 -26
  16. package/dist/commands/constraint.js +8 -20
  17. package/dist/commands/decision.js +9 -20
  18. package/dist/commands/delete-plan.js +10 -12
  19. package/dist/commands/delete-step.js +16 -0
  20. package/dist/commands/dispatch.js +163 -0
  21. package/dist/commands/doctor.js +1122 -49
  22. package/dist/commands/enable-agent.js +1 -0
  23. package/dist/commands/export.js +280 -22
  24. package/dist/commands/handoff.js +33 -0
  25. package/dist/commands/harvest.js +189 -0
  26. package/dist/commands/hooks.js +82 -25
  27. package/dist/commands/inbox.js +169 -0
  28. package/dist/commands/init.js +38 -31
  29. package/dist/commands/install-hooks.js +71 -44
  30. package/dist/commands/link.js +89 -0
  31. package/dist/commands/list-claims.js +48 -3
  32. package/dist/commands/list-plans.js +129 -25
  33. package/dist/commands/loops-handlers.js +409 -0
  34. package/dist/commands/mcp-read-handlers.js +1628 -0
  35. package/dist/commands/mcp-schemas.generated.js +269 -0
  36. package/dist/commands/mcp.js +4224 -1501
  37. package/dist/commands/plan-resource.js +64 -0
  38. package/dist/commands/plan.js +12 -26
  39. package/dist/commands/prune.js +37 -2
  40. package/dist/commands/reflect.js +20 -7
  41. package/dist/commands/release-claim.js +11 -6
  42. package/dist/commands/release-notes.js +170 -0
  43. package/dist/commands/repair.js +210 -0
  44. package/dist/commands/run-profile.js +57 -0
  45. package/dist/commands/sequence.js +113 -0
  46. package/dist/commands/session-end.js +423 -14
  47. package/dist/commands/session-start.js +214 -41
  48. package/dist/commands/setup-security.js +103 -0
  49. package/dist/commands/setup.js +42 -4
  50. package/dist/commands/stale.js +109 -0
  51. package/dist/commands/switch.js +100 -2
  52. package/dist/commands/trap.js +14 -31
  53. package/dist/commands/update-handoff.js +63 -4
  54. package/dist/commands/update-plan.js +21 -28
  55. package/dist/commands/update-step.js +37 -0
  56. package/dist/commands/upgrade.js +313 -6
  57. package/dist/commands/usage.js +102 -0
  58. package/dist/commands/version.js +20 -0
  59. package/dist/commands/who.js +33 -5
  60. package/dist/commands/worktree.js +105 -0
  61. package/dist/core/actions.js +315 -0
  62. package/dist/core/agent-capability.js +610 -17
  63. package/dist/core/agent-context.js +7 -1
  64. package/dist/core/agent-files.js +1169 -85
  65. package/dist/core/agent-integrations.js +160 -5
  66. package/dist/core/agent-inventory.js +2 -0
  67. package/dist/core/agent-profiles.js +93 -0
  68. package/dist/core/agent-registry.js +162 -30
  69. package/dist/core/agentrun-reconciler.js +345 -0
  70. package/dist/core/agentruns.js +424 -0
  71. package/dist/core/ai-agent-detection.js +31 -10
  72. package/dist/core/archival.js +77 -0
  73. package/dist/core/assignment-sweeper.js +82 -0
  74. package/dist/core/assignments.js +367 -0
  75. package/dist/core/audit.js +30 -0
  76. package/dist/core/brainclaw-version.js +94 -2
  77. package/dist/core/candidates.js +93 -2
  78. package/dist/core/claims.js +419 -0
  79. package/dist/core/codev-metrics.js +77 -0
  80. package/dist/core/codev-personas.js +31 -0
  81. package/dist/core/codev-plan-gen.js +35 -0
  82. package/dist/core/codev-prompts.js +74 -0
  83. package/dist/core/codev-responses.js +62 -0
  84. package/dist/core/codev-rounds.js +218 -0
  85. package/dist/core/config.js +4 -0
  86. package/dist/core/context.js +381 -34
  87. package/dist/core/coordination.js +201 -6
  88. package/dist/core/cross-project.js +230 -16
  89. package/dist/core/default-profiles/doctor.yaml +11 -0
  90. package/dist/core/default-profiles/janitor.yaml +11 -0
  91. package/dist/core/default-profiles/onboarder.yaml +11 -0
  92. package/dist/core/default-profiles/reviewer.yaml +13 -0
  93. package/dist/core/dispatcher.js +1189 -0
  94. package/dist/core/duplicates.js +2 -2
  95. package/dist/core/entity-operations.js +450 -0
  96. package/dist/core/entity-registry.js +344 -0
  97. package/dist/core/events.js +106 -2
  98. package/dist/core/execution-adapters.js +154 -0
  99. package/dist/core/execution-context.js +63 -0
  100. package/dist/core/execution-profile.js +270 -0
  101. package/dist/core/execution.js +255 -0
  102. package/dist/core/facade-schema.js +81 -0
  103. package/dist/core/federation-cloud.js +99 -0
  104. package/dist/core/federation-message.js +52 -0
  105. package/dist/core/federation-transport.js +65 -0
  106. package/dist/core/gc-semantic.js +482 -0
  107. package/dist/core/governance.js +247 -0
  108. package/dist/core/guards.js +19 -0
  109. package/dist/core/ideation.js +72 -0
  110. package/dist/core/identity.js +110 -25
  111. package/dist/core/ids.js +6 -0
  112. package/dist/core/input-validation.js +2 -2
  113. package/dist/core/instruction-templates.js +344 -136
  114. package/dist/core/io.js +90 -11
  115. package/dist/core/lock.js +6 -2
  116. package/dist/core/loops/brief-assembly.js +213 -0
  117. package/dist/core/loops/facade-schema.js +148 -0
  118. package/dist/core/loops/index.js +7 -0
  119. package/dist/core/loops/iteration-engine.js +139 -0
  120. package/dist/core/loops/lock.js +385 -0
  121. package/dist/core/loops/store.js +201 -0
  122. package/dist/core/loops/types.js +403 -0
  123. package/dist/core/loops/verbs.js +534 -0
  124. package/dist/core/markdown.js +15 -3
  125. package/dist/core/memory-compactor.js +432 -0
  126. package/dist/core/memory-git.js +152 -8
  127. package/dist/core/messaging.js +278 -0
  128. package/dist/core/migration.js +32 -1
  129. package/dist/core/mutation-pipeline.js +4 -2
  130. package/dist/core/operations/memory-mutation.js +129 -0
  131. package/dist/core/operations/memory-write.js +78 -0
  132. package/dist/core/operations/plan.js +190 -0
  133. package/dist/core/policy.js +169 -0
  134. package/dist/core/reputation.js +9 -3
  135. package/dist/core/schema.js +491 -6
  136. package/dist/core/search.js +21 -2
  137. package/dist/core/security-cache.js +71 -0
  138. package/dist/core/security-guard.js +152 -0
  139. package/dist/core/security-scoring.js +86 -0
  140. package/dist/core/sequence.js +130 -0
  141. package/dist/core/socket-client.js +113 -0
  142. package/dist/core/staleness.js +246 -0
  143. package/dist/core/state.js +98 -22
  144. package/dist/core/store-resolution.js +43 -11
  145. package/dist/core/toml-writer.js +76 -0
  146. package/dist/core/upgrades/backup.js +232 -0
  147. package/dist/core/upgrades/health-check.js +169 -0
  148. package/dist/core/upgrades/patches/candidate-archive.js +145 -0
  149. package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
  150. package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
  151. package/dist/core/upgrades/schema-version.js +97 -0
  152. package/dist/core/worktree.js +606 -0
  153. package/dist/facts.js +114 -0
  154. package/dist/facts.json +111 -0
  155. package/docs/architecture/project-refs.md +5 -1
  156. package/docs/cli.md +690 -43
  157. package/docs/concepts/ideation-loop.md +317 -0
  158. package/docs/concepts/loop-engine.md +456 -0
  159. package/docs/concepts/mcp-governance.md +268 -0
  160. package/docs/concepts/memory-staleness.md +122 -0
  161. package/docs/concepts/multi-agent-workflows.md +166 -0
  162. package/docs/concepts/plans-and-claims.md +31 -6
  163. package/docs/concepts/project-md-convention.md +35 -0
  164. package/docs/concepts/troubleshooting.md +220 -0
  165. package/docs/concepts/upgrade-cli.md +202 -0
  166. package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
  167. package/docs/context-format-changelog.md +2 -2
  168. package/docs/context-format.md +2 -2
  169. package/docs/index.md +68 -0
  170. package/docs/integrations/agents.md +15 -16
  171. package/docs/integrations/cline.md +88 -0
  172. package/docs/integrations/codex.md +75 -23
  173. package/docs/integrations/continue.md +60 -0
  174. package/docs/integrations/copilot.md +67 -9
  175. package/docs/integrations/kilocode.md +72 -0
  176. package/docs/integrations/mcp.md +304 -21
  177. package/docs/integrations/mistral-vibe.md +122 -0
  178. package/docs/integrations/opencode.md +84 -0
  179. package/docs/integrations/overview.md +23 -8
  180. package/docs/integrations/roo.md +74 -0
  181. package/docs/integrations/windsurf.md +83 -0
  182. package/docs/mcp-schema-changelog.md +191 -1
  183. package/docs/playbooks/integration/index.md +121 -0
  184. package/docs/playbooks/productivity/index.md +102 -0
  185. package/docs/playbooks/team/index.md +122 -0
  186. package/docs/product/agent-first-model.md +184 -0
  187. package/docs/product/entity-model-audit.md +462 -0
  188. package/docs/product/positioning.md +10 -10
  189. package/docs/quickstart-existing-project.md +135 -0
  190. package/docs/quickstart.md +124 -37
  191. package/docs/release-maintenance.md +79 -0
  192. package/docs/review.md +2 -0
  193. package/docs/server-operations.md +118 -0
  194. package/package.json +21 -13
  195. package/dist/commands/claude-desktop-extension.js +0 -18
  196. package/dist/commands/diff.js +0 -99
  197. package/dist/core/claude-desktop-extension.js +0 -224
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Pure business logic for plan operations.
3
+ *
4
+ * No console.log, no process.exit, no MCP formatting.
5
+ * Both CLI commands and MCP handlers call these functions.
6
+ *
7
+ * @module
8
+ */
9
+ import { mutateState } from '../state.js';
10
+ import { generateIdWithLabel, generateId, nowISO } from '../ids.js';
11
+ export function createPlan(input, cwd) {
12
+ if (input.estimatedEffort !== undefined) {
13
+ if (!Number.isInteger(input.estimatedEffort) || input.estimatedEffort <= 0) {
14
+ throw new Error('estimate must be a positive integer (minutes)');
15
+ }
16
+ }
17
+ const result = mutateState((state) => {
18
+ const { id, short_label } = generateIdWithLabel('plan_items', cwd);
19
+ const timestamp = nowISO();
20
+ const entry = {
21
+ id,
22
+ short_label,
23
+ text: input.text,
24
+ type: input.type,
25
+ created_at: timestamp,
26
+ updated_at: timestamp,
27
+ author: input.author,
28
+ status: 'todo',
29
+ priority: input.priority ?? 'medium',
30
+ assignee: input.assignee,
31
+ project: input.project,
32
+ tags: input.tags ?? [],
33
+ related_paths: input.relatedPaths,
34
+ depends_on: input.dependsOn ?? [],
35
+ estimated_effort: input.estimatedEffort,
36
+ };
37
+ state.plan_items.push(entry);
38
+ return { id, shortLabel: short_label, text: input.text };
39
+ }, cwd);
40
+ return result;
41
+ }
42
+ export function addStep(input, cwd) {
43
+ const result = mutateState((state) => {
44
+ const plan = state.plan_items.find((p) => p.id === input.planId || p.short_label === input.planId);
45
+ if (!plan) {
46
+ throw new Error(`Plan '${input.planId}' not found.`);
47
+ }
48
+ const step = {
49
+ id: generateId('plan_steps'),
50
+ text: input.text,
51
+ status: 'todo',
52
+ assignee: input.assignee,
53
+ created_at: nowISO(),
54
+ updated_at: nowISO(),
55
+ };
56
+ plan.steps = [...(plan.steps ?? []), step];
57
+ plan.updated_at = nowISO();
58
+ return {
59
+ stepId: step.id,
60
+ planId: plan.id,
61
+ totalSteps: plan.steps.length,
62
+ doneSteps: plan.steps.filter((s) => s.status === 'done').length,
63
+ };
64
+ }, cwd);
65
+ return result;
66
+ }
67
+ export function updatePlan(input, cwd) {
68
+ const result = mutateState((state) => {
69
+ const plan = state.plan_items.find((p) => p.id === input.id || p.short_label === input.id);
70
+ if (!plan) {
71
+ throw new Error(`Plan item '${input.id}' not found.`);
72
+ }
73
+ const timestamp = nowISO();
74
+ if (input.status) {
75
+ plan.status = input.status;
76
+ if (input.status === 'in_progress' && !plan.started_at)
77
+ plan.started_at = timestamp;
78
+ if (input.status === 'done' && !plan.completed_at)
79
+ plan.completed_at = timestamp;
80
+ }
81
+ if (input.assignee !== undefined)
82
+ plan.assignee = input.assignee;
83
+ if (input.priority)
84
+ plan.priority = input.priority;
85
+ if (input.actualEffort)
86
+ plan.actual_effort = input.actualEffort;
87
+ if (input.patch) {
88
+ Object.assign(plan, input.patch);
89
+ }
90
+ plan.updated_at = timestamp;
91
+ return { id: plan.id, text: plan.text, status: plan.status };
92
+ }, cwd);
93
+ return result;
94
+ }
95
+ export function completeStep(input, cwd) {
96
+ const result = mutateState((state) => {
97
+ const plan = state.plan_items.find((p) => p.id === input.planId || p.short_label === input.planId);
98
+ if (!plan) {
99
+ throw new Error(`Plan '${input.planId}' not found.`);
100
+ }
101
+ if (!plan.steps || plan.steps.length === 0) {
102
+ throw new Error(`Plan '${input.planId}' has no steps.`);
103
+ }
104
+ const step = plan.steps.find((s) => s.id === input.stepId || s.text.toLowerCase().includes(input.stepId.toLowerCase()));
105
+ if (!step) {
106
+ throw new Error(`Step '${input.stepId}' not found in plan '${input.planId}'.`);
107
+ }
108
+ const timestamp = nowISO();
109
+ step.status = 'done';
110
+ step.updated_at = timestamp;
111
+ plan.updated_at = timestamp;
112
+ const totalSteps = plan.steps.length;
113
+ const doneSteps = plan.steps.filter((s) => s.status === 'done').length;
114
+ let planAutoCompleted = false;
115
+ if (doneSteps === totalSteps && plan.status !== 'done') {
116
+ plan.status = 'done';
117
+ plan.completed_at = timestamp;
118
+ planAutoCompleted = true;
119
+ }
120
+ return { stepId: step.id, planId: plan.id, totalSteps, doneSteps, planAutoCompleted };
121
+ }, cwd);
122
+ return result;
123
+ }
124
+ export function updateStep(input, cwd) {
125
+ const result = mutateState((state) => {
126
+ const plan = state.plan_items.find((p) => p.id === input.planId || p.short_label === input.planId);
127
+ if (!plan) {
128
+ throw new Error(`Plan '${input.planId}' not found.`);
129
+ }
130
+ if (!plan.steps || plan.steps.length === 0) {
131
+ throw new Error(`Plan '${input.planId}' has no steps.`);
132
+ }
133
+ const step = plan.steps.find((s) => s.id === input.stepId);
134
+ if (!step) {
135
+ throw new Error(`Step '${input.stepId}' not found in plan '${input.planId}'.`);
136
+ }
137
+ const timestamp = nowISO();
138
+ if (input.status)
139
+ step.status = input.status;
140
+ if (input.text !== undefined)
141
+ step.text = input.text;
142
+ if (input.assignee !== undefined)
143
+ step.assignee = input.assignee || undefined;
144
+ step.updated_at = timestamp;
145
+ plan.updated_at = timestamp;
146
+ const totalSteps = plan.steps.length;
147
+ const doneSteps = plan.steps.filter((s) => s.status === 'done').length;
148
+ let planAutoCompleted = false;
149
+ if (doneSteps === totalSteps && plan.status !== 'done') {
150
+ plan.status = 'done';
151
+ plan.completed_at = timestamp;
152
+ planAutoCompleted = true;
153
+ }
154
+ return { stepId: step.id, planId: plan.id, totalSteps, doneSteps, planAutoCompleted };
155
+ }, cwd);
156
+ return result;
157
+ }
158
+ export function deleteStep(input, cwd) {
159
+ const result = mutateState((state) => {
160
+ const plan = state.plan_items.find((p) => p.id === input.planId || p.short_label === input.planId);
161
+ if (!plan) {
162
+ throw new Error(`Plan '${input.planId}' not found.`);
163
+ }
164
+ if (!plan.steps || plan.steps.length === 0) {
165
+ throw new Error(`Plan '${input.planId}' has no steps.`);
166
+ }
167
+ const idx = plan.steps.findIndex((s) => s.id === input.stepId);
168
+ if (idx < 0) {
169
+ throw new Error(`Step '${input.stepId}' not found in plan '${input.planId}'.`);
170
+ }
171
+ plan.steps.splice(idx, 1);
172
+ plan.updated_at = nowISO();
173
+ const totalSteps = plan.steps.length;
174
+ const doneSteps = plan.steps.filter((s) => s.status === 'done').length;
175
+ return { stepId: input.stepId, planId: plan.id, totalSteps, doneSteps };
176
+ }, cwd);
177
+ return result;
178
+ }
179
+ export function deletePlan(planId, cwd) {
180
+ const result = mutateState((state) => {
181
+ const idx = state.plan_items.findIndex((p) => p.id === planId || p.short_label === planId);
182
+ if (idx < 0) {
183
+ throw new Error(`Plan item '${planId}' not found.`);
184
+ }
185
+ const removed = state.plan_items.splice(idx, 1)[0];
186
+ return { id: removed.id, text: removed.text };
187
+ }, cwd);
188
+ return result;
189
+ }
190
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Pre-execution policy checks.
3
+ *
4
+ * Deterministic guardrails that verify whether an agent is allowed
5
+ * to act on a given scope. No AI, no external dependencies —
6
+ * just claims, constraints, traps and instructions.
7
+ *
8
+ * @module
9
+ */
10
+ import { listClaims, isClaimExpired } from './claims.js';
11
+ import { loadState } from './state.js';
12
+ import { loadInstructions, resolveInstructions } from './instructions.js';
13
+ const CROSS_PROJECT_SIGNALING_ENTITIES = new Set(['candidate', 'handoff', 'runtime_note']);
14
+ export function checkCrossProjectBoundary(entity, targetProject) {
15
+ if (!targetProject) {
16
+ return { allowed: true };
17
+ }
18
+ if (CROSS_PROJECT_SIGNALING_ENTITIES.has(entity)) {
19
+ return { allowed: true };
20
+ }
21
+ return {
22
+ allowed: false,
23
+ issue: {
24
+ kind: 'cross_project_boundary',
25
+ severity: 'block',
26
+ message: `Cross-project writes are limited to signaling entities (candidate, handoff, runtime_note). ${entity} stays local to the current project.`,
27
+ },
28
+ };
29
+ }
30
+ export function assertCrossProjectBoundary(entity, targetProject) {
31
+ const result = checkCrossProjectBoundary(entity, targetProject);
32
+ if (!result.allowed) {
33
+ throw new Error(result.issue?.message ?? 'Cross-project boundary violation.');
34
+ }
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // Path matching (reuses check-constraints pattern)
38
+ // ---------------------------------------------------------------------------
39
+ function normPath(p) {
40
+ return p.replace(/\\/g, '/').replace(/^\.\//, '');
41
+ }
42
+ /**
43
+ * Returns true if `targetScope` overlaps with `relatedPath`.
44
+ * Matches exactly or via prefix (directory containment) in both directions.
45
+ */
46
+ function scopeOverlaps(targetScope, relatedPath) {
47
+ const s = normPath(targetScope).replace(/\/$/, '');
48
+ const r = normPath(relatedPath).replace(/\/$/, '');
49
+ // Exact match
50
+ if (s === r)
51
+ return true;
52
+ // Target is inside related path (e.g. scope=src/core/foo.ts, related=src/core)
53
+ if (s.startsWith(r + '/'))
54
+ return true;
55
+ // Related path is inside target scope (e.g. scope=src/core, related=src/core/foo.ts)
56
+ if (r.startsWith(s + '/'))
57
+ return true;
58
+ return false;
59
+ }
60
+ /**
61
+ * Check if a claim's scope overlaps with the target scope.
62
+ * Claims use free-form scope strings — may be a single path, a directory,
63
+ * or multiple space-separated paths (e.g. "src/views/A.astro src/components/B.astro").
64
+ */
65
+ function claimScopeOverlaps(targetScope, claimScope) {
66
+ // Split space-separated scopes and check each segment
67
+ const segments = claimScope.split(/\s+/).filter(Boolean);
68
+ return segments.some(segment => scopeOverlaps(targetScope, segment));
69
+ }
70
+ // ---------------------------------------------------------------------------
71
+ // Core check
72
+ // ---------------------------------------------------------------------------
73
+ export function checkPolicy(options) {
74
+ const cwd = options.cwd;
75
+ const scope = options.scope;
76
+ const agent = options.agent;
77
+ const blocks = [];
78
+ const warnings = [];
79
+ // --- 1. Claim check ---
80
+ const allClaims = listClaims(cwd);
81
+ const activeClaims = allClaims.filter(c => c.status === 'active' && !isClaimExpired(c));
82
+ const claimsOnScope = activeClaims.filter(c => claimScopeOverlaps(scope, c.scope));
83
+ if (agent) {
84
+ const agentLower = agent.toLowerCase();
85
+ const myClaimsOnScope = claimsOnScope.filter(c => c.agent.toLowerCase() === agentLower ||
86
+ c.agent_id?.toLowerCase() === agentLower);
87
+ const otherClaimsOnScope = claimsOnScope.filter(c => c.agent.toLowerCase() !== agentLower &&
88
+ c.agent_id?.toLowerCase() !== agentLower);
89
+ if (myClaimsOnScope.length === 0 && claimsOnScope.length === 0) {
90
+ blocks.push({
91
+ kind: 'no_claim',
92
+ severity: 'block',
93
+ message: `No active claim on scope "${scope}". Run bclaw_claim first.`,
94
+ });
95
+ }
96
+ else if (myClaimsOnScope.length === 0 && otherClaimsOnScope.length > 0) {
97
+ for (const c of otherClaimsOnScope) {
98
+ blocks.push({
99
+ kind: 'claim_conflict',
100
+ severity: 'block',
101
+ id: c.id,
102
+ message: `Scope "${scope}" is claimed by ${c.agent} [${c.id}]: ${c.description}`,
103
+ });
104
+ }
105
+ }
106
+ // Check for expired claims by this agent (informational)
107
+ const expiredMyClaims = allClaims.filter(c => c.status === 'active' && isClaimExpired(c) &&
108
+ (c.agent.toLowerCase() === agentLower || c.agent_id?.toLowerCase() === agentLower) &&
109
+ claimScopeOverlaps(scope, c.scope));
110
+ for (const c of expiredMyClaims) {
111
+ warnings.push({
112
+ kind: 'claim_expired',
113
+ severity: 'warn',
114
+ id: c.id,
115
+ message: `Your claim [${c.id}] on "${c.scope}" has expired. Re-claim before editing.`,
116
+ });
117
+ }
118
+ }
119
+ else {
120
+ // No agent specified — just report claim state
121
+ if (claimsOnScope.length === 0) {
122
+ warnings.push({
123
+ kind: 'no_claim',
124
+ severity: 'warn',
125
+ message: `No active claim on scope "${scope}".`,
126
+ });
127
+ }
128
+ }
129
+ // --- 2. Constraint check ---
130
+ const state = loadState(cwd);
131
+ const matchingConstraints = state.active_constraints.filter(c => c.related_paths?.some(rp => scopeOverlaps(scope, rp)));
132
+ for (const c of matchingConstraints) {
133
+ const catLabel = c.category ? ` [${c.category}]` : '';
134
+ warnings.push({
135
+ kind: 'constraint',
136
+ severity: 'warn',
137
+ id: c.id,
138
+ message: `Constraint${catLabel}: ${c.text}`,
139
+ });
140
+ }
141
+ // --- 3. Trap check ---
142
+ const matchingTraps = state.known_traps.filter(t => t.status === 'active' &&
143
+ t.related_paths?.some(rp => scopeOverlaps(scope, rp)));
144
+ for (const t of matchingTraps) {
145
+ const sevLabel = t.severity ? ` [${t.severity}]` : '';
146
+ warnings.push({
147
+ kind: 'trap',
148
+ severity: 'warn',
149
+ id: t.id,
150
+ message: `Trap${sevLabel}: ${t.text}`,
151
+ });
152
+ }
153
+ // --- 4. Instructions (governance context — no matching in v1) ---
154
+ const allInstructions = loadInstructions(cwd);
155
+ const activeInstructions = resolveInstructions(allInstructions, {});
156
+ const allowed = blocks.length === 0;
157
+ return {
158
+ allowed,
159
+ blocks,
160
+ warnings,
161
+ governance_context: {
162
+ active_instructions: activeInstructions,
163
+ matching_constraints: matchingConstraints,
164
+ matching_traps: matchingTraps,
165
+ active_claims_on_scope: claimsOnScope,
166
+ },
167
+ };
168
+ }
169
+ //# sourceMappingURL=policy.js.map
@@ -110,7 +110,13 @@ function trackCandidateSignals(candidate, bucket, store, sinceMs, config, resolv
110
110
  if (bucket === 'rejected') {
111
111
  stats.signals.rejected_candidates_authored += 1;
112
112
  }
113
- if (candidate.source?.startsWith('runtime-note:')) {
113
+ // Count runtime-origin candidates: either explicit `source: 'auto'` (session-end
114
+ // auto handoffs) or any runtime-note / session-end origin string (back-compat
115
+ // with writers that still set only `origin`).
116
+ const isRuntimeOrigin = candidate.source === 'auto'
117
+ || candidate.origin?.startsWith('runtime-note:') === true
118
+ || candidate.origin?.startsWith('session-end:') === true;
119
+ if (isRuntimeOrigin) {
114
120
  stats.signals.promoted_runtime_candidates += 1;
115
121
  if (bucket === 'accepted') {
116
122
  stats.signals.promoted_runtime_accepted += 1;
@@ -354,8 +360,8 @@ export function buildReputationRankingLookup(cwd) {
354
360
  return 0;
355
361
  }
356
362
  const trust = getInternalTrust(actorId, actorName);
357
- const bonus = (trust / 100) * (rankingWeight * 10);
358
- return Math.max(0, Math.min(1.5, Number(bonus.toFixed(2))));
363
+ const bonus = (trust / 100) * (rankingWeight * 20);
364
+ return Math.max(0, Math.min(3, Number(bonus.toFixed(2))));
359
365
  };
360
366
  return {
361
367
  enabled: snapshot.enabled,