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.
- package/LICENSE +21 -74
- package/README.md +199 -176
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +710 -25
- package/dist/commands/accept.js +3 -0
- package/dist/commands/add-step.js +11 -26
- package/dist/commands/agent-board.js +70 -3
- package/dist/commands/audit.js +19 -0
- package/dist/commands/check-policy.js +54 -0
- package/dist/commands/check-security-mcp.js +145 -0
- package/dist/commands/check-security.js +106 -0
- package/dist/commands/claim-resource.js +1 -0
- package/dist/commands/codev.js +672 -0
- package/dist/commands/compact.js +74 -0
- package/dist/commands/complete-step.js +16 -26
- package/dist/commands/constraint.js +8 -20
- package/dist/commands/decision.js +9 -20
- package/dist/commands/delete-plan.js +10 -12
- package/dist/commands/delete-step.js +16 -0
- package/dist/commands/dispatch.js +163 -0
- package/dist/commands/doctor.js +1122 -49
- package/dist/commands/enable-agent.js +1 -0
- package/dist/commands/export.js +280 -22
- package/dist/commands/handoff.js +33 -0
- package/dist/commands/harvest.js +189 -0
- package/dist/commands/hooks.js +82 -25
- package/dist/commands/inbox.js +169 -0
- package/dist/commands/init.js +38 -31
- package/dist/commands/install-hooks.js +71 -44
- package/dist/commands/link.js +89 -0
- package/dist/commands/list-claims.js +48 -3
- package/dist/commands/list-plans.js +129 -25
- package/dist/commands/loops-handlers.js +409 -0
- package/dist/commands/mcp-read-handlers.js +1628 -0
- package/dist/commands/mcp-schemas.generated.js +269 -0
- package/dist/commands/mcp.js +4224 -1501
- package/dist/commands/plan-resource.js +64 -0
- package/dist/commands/plan.js +12 -26
- package/dist/commands/prune.js +37 -2
- package/dist/commands/reflect.js +20 -7
- package/dist/commands/release-claim.js +11 -6
- package/dist/commands/release-notes.js +170 -0
- package/dist/commands/repair.js +210 -0
- package/dist/commands/run-profile.js +57 -0
- package/dist/commands/sequence.js +113 -0
- package/dist/commands/session-end.js +423 -14
- package/dist/commands/session-start.js +214 -41
- package/dist/commands/setup-security.js +103 -0
- package/dist/commands/setup.js +42 -4
- package/dist/commands/stale.js +109 -0
- package/dist/commands/switch.js +100 -2
- package/dist/commands/trap.js +14 -31
- package/dist/commands/update-handoff.js +63 -4
- package/dist/commands/update-plan.js +21 -28
- package/dist/commands/update-step.js +37 -0
- package/dist/commands/upgrade.js +313 -6
- package/dist/commands/usage.js +102 -0
- package/dist/commands/version.js +20 -0
- package/dist/commands/who.js +33 -5
- package/dist/commands/worktree.js +105 -0
- package/dist/core/actions.js +315 -0
- package/dist/core/agent-capability.js +610 -17
- package/dist/core/agent-context.js +7 -1
- package/dist/core/agent-files.js +1169 -85
- package/dist/core/agent-integrations.js +160 -5
- package/dist/core/agent-inventory.js +2 -0
- package/dist/core/agent-profiles.js +93 -0
- package/dist/core/agent-registry.js +162 -30
- package/dist/core/agentrun-reconciler.js +345 -0
- package/dist/core/agentruns.js +424 -0
- package/dist/core/ai-agent-detection.js +31 -10
- package/dist/core/archival.js +77 -0
- package/dist/core/assignment-sweeper.js +82 -0
- package/dist/core/assignments.js +367 -0
- package/dist/core/audit.js +30 -0
- package/dist/core/brainclaw-version.js +94 -2
- package/dist/core/candidates.js +93 -2
- package/dist/core/claims.js +419 -0
- package/dist/core/codev-metrics.js +77 -0
- package/dist/core/codev-personas.js +31 -0
- package/dist/core/codev-plan-gen.js +35 -0
- package/dist/core/codev-prompts.js +74 -0
- package/dist/core/codev-responses.js +62 -0
- package/dist/core/codev-rounds.js +218 -0
- package/dist/core/config.js +4 -0
- package/dist/core/context.js +381 -34
- package/dist/core/coordination.js +201 -6
- package/dist/core/cross-project.js +230 -16
- package/dist/core/default-profiles/doctor.yaml +11 -0
- package/dist/core/default-profiles/janitor.yaml +11 -0
- package/dist/core/default-profiles/onboarder.yaml +11 -0
- package/dist/core/default-profiles/reviewer.yaml +13 -0
- package/dist/core/dispatcher.js +1189 -0
- package/dist/core/duplicates.js +2 -2
- package/dist/core/entity-operations.js +450 -0
- package/dist/core/entity-registry.js +344 -0
- package/dist/core/events.js +106 -2
- package/dist/core/execution-adapters.js +154 -0
- package/dist/core/execution-context.js +63 -0
- package/dist/core/execution-profile.js +270 -0
- package/dist/core/execution.js +255 -0
- package/dist/core/facade-schema.js +81 -0
- package/dist/core/federation-cloud.js +99 -0
- package/dist/core/federation-message.js +52 -0
- package/dist/core/federation-transport.js +65 -0
- package/dist/core/gc-semantic.js +482 -0
- package/dist/core/governance.js +247 -0
- package/dist/core/guards.js +19 -0
- package/dist/core/ideation.js +72 -0
- package/dist/core/identity.js +110 -25
- package/dist/core/ids.js +6 -0
- package/dist/core/input-validation.js +2 -2
- package/dist/core/instruction-templates.js +344 -136
- package/dist/core/io.js +90 -11
- package/dist/core/lock.js +6 -2
- package/dist/core/loops/brief-assembly.js +213 -0
- package/dist/core/loops/facade-schema.js +148 -0
- package/dist/core/loops/index.js +7 -0
- package/dist/core/loops/iteration-engine.js +139 -0
- package/dist/core/loops/lock.js +385 -0
- package/dist/core/loops/store.js +201 -0
- package/dist/core/loops/types.js +403 -0
- package/dist/core/loops/verbs.js +534 -0
- package/dist/core/markdown.js +15 -3
- package/dist/core/memory-compactor.js +432 -0
- package/dist/core/memory-git.js +152 -8
- package/dist/core/messaging.js +278 -0
- package/dist/core/migration.js +32 -1
- package/dist/core/mutation-pipeline.js +4 -2
- package/dist/core/operations/memory-mutation.js +129 -0
- package/dist/core/operations/memory-write.js +78 -0
- package/dist/core/operations/plan.js +190 -0
- package/dist/core/policy.js +169 -0
- package/dist/core/reputation.js +9 -3
- package/dist/core/schema.js +491 -6
- package/dist/core/search.js +21 -2
- package/dist/core/security-cache.js +71 -0
- package/dist/core/security-guard.js +152 -0
- package/dist/core/security-scoring.js +86 -0
- package/dist/core/sequence.js +130 -0
- package/dist/core/socket-client.js +113 -0
- package/dist/core/staleness.js +246 -0
- package/dist/core/state.js +98 -22
- package/dist/core/store-resolution.js +43 -11
- package/dist/core/toml-writer.js +76 -0
- package/dist/core/upgrades/backup.js +232 -0
- package/dist/core/upgrades/health-check.js +169 -0
- package/dist/core/upgrades/patches/candidate-archive.js +145 -0
- package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
- package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
- package/dist/core/upgrades/schema-version.js +97 -0
- package/dist/core/worktree.js +606 -0
- package/dist/facts.js +114 -0
- package/dist/facts.json +111 -0
- package/docs/architecture/project-refs.md +5 -1
- package/docs/cli.md +690 -43
- package/docs/concepts/ideation-loop.md +317 -0
- package/docs/concepts/loop-engine.md +456 -0
- package/docs/concepts/mcp-governance.md +268 -0
- package/docs/concepts/memory-staleness.md +122 -0
- package/docs/concepts/multi-agent-workflows.md +166 -0
- package/docs/concepts/plans-and-claims.md +31 -6
- package/docs/concepts/project-md-convention.md +35 -0
- package/docs/concepts/troubleshooting.md +220 -0
- package/docs/concepts/upgrade-cli.md +202 -0
- package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
- package/docs/context-format-changelog.md +2 -2
- package/docs/context-format.md +2 -2
- package/docs/index.md +68 -0
- package/docs/integrations/agents.md +15 -16
- package/docs/integrations/cline.md +88 -0
- package/docs/integrations/codex.md +75 -23
- package/docs/integrations/continue.md +60 -0
- package/docs/integrations/copilot.md +67 -9
- package/docs/integrations/kilocode.md +72 -0
- package/docs/integrations/mcp.md +304 -21
- package/docs/integrations/mistral-vibe.md +122 -0
- package/docs/integrations/opencode.md +84 -0
- package/docs/integrations/overview.md +23 -8
- package/docs/integrations/roo.md +74 -0
- package/docs/integrations/windsurf.md +83 -0
- package/docs/mcp-schema-changelog.md +191 -1
- package/docs/playbooks/integration/index.md +121 -0
- package/docs/playbooks/productivity/index.md +102 -0
- package/docs/playbooks/team/index.md +122 -0
- package/docs/product/agent-first-model.md +184 -0
- package/docs/product/entity-model-audit.md +462 -0
- package/docs/product/positioning.md +10 -10
- package/docs/quickstart-existing-project.md +135 -0
- package/docs/quickstart.md +124 -37
- package/docs/release-maintenance.md +79 -0
- package/docs/review.md +2 -0
- package/docs/server-operations.md +118 -0
- package/package.json +21 -13
- package/dist/commands/claude-desktop-extension.js +0 -18
- package/dist/commands/diff.js +0 -99
- package/dist/core/claude-desktop-extension.js +0 -224
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const LOOP_ARTIFACT_BODY_MAX_BYTES = 4096;
|
|
3
|
+
export const LOOP_KINDS = ['review', 'ideation', 'implementation', 'research', 'debug'];
|
|
4
|
+
export const LOOP_STATUSES = ['open', 'paused', 'completed', 'blocked', 'cancelled'];
|
|
5
|
+
export const REVIEW_MODES = ['asymmetric', 'symmetric'];
|
|
6
|
+
/**
|
|
7
|
+
* Slot lifecycle states. `done` / `failed` / `cancelled` are terminal and
|
|
8
|
+
* mirror the `complete_turn` outcome so a caller reading the thread can
|
|
9
|
+
* observe the per-slot outcome without replaying the event journal.
|
|
10
|
+
*/
|
|
11
|
+
export const SLOT_STATUSES = ['open', 'assigned', 'working', 'done', 'failed', 'cancelled'];
|
|
12
|
+
export const TERMINAL_SLOT_STATUSES = ['done', 'failed', 'cancelled'];
|
|
13
|
+
export const LOOP_REF_KINDS = ['plan', 'sequence', 'claim', 'handoff', 'candidate', 'message'];
|
|
14
|
+
export const LoopRefSchema = z.object({
|
|
15
|
+
kind: z.enum(LOOP_REF_KINDS),
|
|
16
|
+
id: z.string().min(1),
|
|
17
|
+
});
|
|
18
|
+
export const LoopLinksSchema = z.object({
|
|
19
|
+
plan_ids: z.array(z.string().min(1)).optional(),
|
|
20
|
+
sequence_ids: z.array(z.string().min(1)).optional(),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Memory categories a loop phase can request via `context_filter` (pln#492).
|
|
24
|
+
*
|
|
25
|
+
* The driver uses this list to assemble the context bundle handed to a slot
|
|
26
|
+
* for a given phase. Brainclaw entity categories are user-facing memory the
|
|
27
|
+
* slot may consult; loop-internal categories ('critique_history',
|
|
28
|
+
* 'revision_history', 'synthesis_artifact') refer to artifacts produced
|
|
29
|
+
* earlier in the same loop.
|
|
30
|
+
*
|
|
31
|
+
* The wildcard '*' means "all categories" — used by phases that need
|
|
32
|
+
* unconstrained context (proposal seed, revision after critique, synthesis).
|
|
33
|
+
*
|
|
34
|
+
* 'feedback' is a logical grouping for user auto-memory feedback notes;
|
|
35
|
+
* it is intentionally separate from 'runtime_notes' because the driver
|
|
36
|
+
* may source them from different stores.
|
|
37
|
+
*/
|
|
38
|
+
export const LOOP_CONTEXT_CATEGORIES = [
|
|
39
|
+
'traps',
|
|
40
|
+
'feedback',
|
|
41
|
+
'runtime_notes',
|
|
42
|
+
'decisions',
|
|
43
|
+
'constraints',
|
|
44
|
+
'handoffs',
|
|
45
|
+
'plans',
|
|
46
|
+
'candidates',
|
|
47
|
+
'project_vision',
|
|
48
|
+
'critique_history',
|
|
49
|
+
'revision_history',
|
|
50
|
+
'synthesis_artifact',
|
|
51
|
+
'*',
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* Critique artifact subtypes for the ideation_loop critic phase (pln#492).
|
|
55
|
+
*
|
|
56
|
+
* Collapsed from 6 to 3 per the reframer findings on pln#492's own design
|
|
57
|
+
* (runtime_note 'reframer_phase_simulation_transcript', 2026-05-03):
|
|
58
|
+
* finer subtype taxonomy adds schema and test surface without buying any
|
|
59
|
+
* behavioural differentiation in v1.0. Defer to v1.1 only if downstream
|
|
60
|
+
* UX or routing turns out to need it.
|
|
61
|
+
*/
|
|
62
|
+
export const CRITIQUE_ARTIFACT_SUBTYPES = ['memory_conflict', 'coverage_gap', 'scope_creep'];
|
|
63
|
+
export const LoopPhaseSchema = z.object({
|
|
64
|
+
name: z.string().min(1),
|
|
65
|
+
advance_when: z.enum(['all', 'any']).optional(),
|
|
66
|
+
/**
|
|
67
|
+
* Memory categories visible to the slot when this phase runs (pln#492).
|
|
68
|
+
* If omitted, the driver applies its kind-default context bundle.
|
|
69
|
+
* Use ['*'] to request the full bundle explicitly.
|
|
70
|
+
*/
|
|
71
|
+
context_filter: z.array(z.enum(LOOP_CONTEXT_CATEGORIES)).min(1).optional(),
|
|
72
|
+
/**
|
|
73
|
+
* Optional condition that must hold for the driver to advance OUT of
|
|
74
|
+
* this phase (pln#492). Re-uses the StopCondition shape so callers can
|
|
75
|
+
* compose any/all/min_artifacts_by_type/etc. When the gate fails the
|
|
76
|
+
* driver emits a `phase_advance_blocked` system event with a structured
|
|
77
|
+
* gate_reason; it does NOT silently hang.
|
|
78
|
+
*
|
|
79
|
+
* z.lazy because StopConditionSchema is defined further down in this
|
|
80
|
+
* file and references LoopPhase indirectly; the lazy wrapper avoids
|
|
81
|
+
* the temporal-dead-zone.
|
|
82
|
+
*/
|
|
83
|
+
advance_gate: z.lazy(() => StopConditionSchema).optional(),
|
|
84
|
+
});
|
|
85
|
+
/**
|
|
86
|
+
* Iteration block for protocols with an inner cycle (e.g. ideation_loop's
|
|
87
|
+
* critique↔revision). Defines which phases form the cycle, the cap, and
|
|
88
|
+
* the exit criterion.
|
|
89
|
+
*
|
|
90
|
+
* - `cycle` lists phase names that repeat. The driver advances through
|
|
91
|
+
* them in order, then loops back until exit_when is satisfied or
|
|
92
|
+
* max_iterations is reached.
|
|
93
|
+
* - `exit_when` selects the convergence criterion:
|
|
94
|
+
* 'critic_signal' — critic explicitly produced a 'sufficient' marker.
|
|
95
|
+
* 'no_new_critique_artifacts' — a full cycle completed without adding
|
|
96
|
+
* any new critique artifact. Stable convergence by saturation.
|
|
97
|
+
*/
|
|
98
|
+
export const LoopIterationSchema = z.object({
|
|
99
|
+
cycle: z.array(z.string().min(1)).min(1),
|
|
100
|
+
max_iterations: z.number().int().positive(),
|
|
101
|
+
exit_when: z.enum(['critic_signal', 'no_new_critique_artifacts']),
|
|
102
|
+
});
|
|
103
|
+
export const LoopProtocolConfigSchema = z.object({
|
|
104
|
+
review_mode: z.enum(REVIEW_MODES).optional(),
|
|
105
|
+
iteration: LoopIterationSchema.optional(),
|
|
106
|
+
});
|
|
107
|
+
export const LoopSlotSchema = z.object({
|
|
108
|
+
slot_id: z.string().regex(/^lsl_[0-9a-z]+$/),
|
|
109
|
+
role: z.string().min(1),
|
|
110
|
+
agent: z.string().optional(),
|
|
111
|
+
agent_id: z.string().optional(),
|
|
112
|
+
assignment_id: z.string().optional(),
|
|
113
|
+
claim_id: z.string().optional(),
|
|
114
|
+
phase: z.string().optional(),
|
|
115
|
+
status: z.enum(SLOT_STATUSES),
|
|
116
|
+
});
|
|
117
|
+
export const LoopArtifactSchema = z
|
|
118
|
+
.object({
|
|
119
|
+
artifact_id: z.string().min(1),
|
|
120
|
+
phase: z.string().min(1),
|
|
121
|
+
type: z.string().min(1),
|
|
122
|
+
ref: LoopRefSchema.optional(),
|
|
123
|
+
body: z.string().optional(),
|
|
124
|
+
produced_by: z.string().optional(),
|
|
125
|
+
produced_at: z.string().datetime(),
|
|
126
|
+
/**
|
|
127
|
+
* pln#492 — synthesis schema. When the synthesis phase emits a
|
|
128
|
+
* `plan_draft` artifact, it MUST cite the critique artifact_ids it
|
|
129
|
+
* addresses (or explicitly waives) so a reviewer can audit which
|
|
130
|
+
* critiques were folded in vs dropped. Field-presence enforced by
|
|
131
|
+
* `superRefine` below; semantic validation (each id maps to a real
|
|
132
|
+
* critique artifact) is deferred to v1.1 per the plan.
|
|
133
|
+
*/
|
|
134
|
+
addresses_critique: z.array(z.string().min(1)).optional(),
|
|
135
|
+
/**
|
|
136
|
+
* pln#492 phase 2.b — iteration window the artifact was produced in.
|
|
137
|
+
* 0-indexed (proposal/early phases produce iteration=0). Optional for
|
|
138
|
+
* backward compatibility with non-iterating loops (review): when
|
|
139
|
+
* absent, gate evaluators fall back to "all artifacts in this phase".
|
|
140
|
+
* The iteration engine populates this from `thread.iteration_count`
|
|
141
|
+
* at artifact creation time so callers don't have to track it.
|
|
142
|
+
*/
|
|
143
|
+
iteration: z.number().int().nonnegative().optional(),
|
|
144
|
+
})
|
|
145
|
+
.superRefine((artifact, ctx) => {
|
|
146
|
+
if (artifact.body !== undefined && Buffer.byteLength(artifact.body, 'utf8') > LOOP_ARTIFACT_BODY_MAX_BYTES) {
|
|
147
|
+
ctx.addIssue({
|
|
148
|
+
code: z.ZodIssueCode.custom,
|
|
149
|
+
message: `LoopArtifact.body must be ≤ ${LOOP_ARTIFACT_BODY_MAX_BYTES} bytes; use a ref for larger content`,
|
|
150
|
+
path: ['body'],
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (artifact.type === 'plan_draft') {
|
|
154
|
+
if (!artifact.addresses_critique || artifact.addresses_critique.length === 0) {
|
|
155
|
+
ctx.addIssue({
|
|
156
|
+
code: z.ZodIssueCode.custom,
|
|
157
|
+
message: "LoopArtifact of type 'plan_draft' must include addresses_critique:[ids] " +
|
|
158
|
+
'(at least one) so synthesis can be audited against the critiques it folded in',
|
|
159
|
+
path: ['addresses_critique'],
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
export const AtomicStopConditionSchema = z.discriminatedUnion('kind', [
|
|
165
|
+
z.object({ kind: z.literal('phase_reached'), phase: z.string().min(1) }),
|
|
166
|
+
z.object({ kind: z.literal('reviewer_green') }),
|
|
167
|
+
z.object({ kind: z.literal('max_iterations'), n: z.number().int().positive() }),
|
|
168
|
+
z.object({
|
|
169
|
+
kind: z.literal('artifact_produced'),
|
|
170
|
+
phase: z.string().min(1),
|
|
171
|
+
type: z.string().min(1),
|
|
172
|
+
}),
|
|
173
|
+
// pln#492 — saturate by artifact count. `scope: 'phase'` counts only
|
|
174
|
+
// artifacts produced in the current phase; `scope: 'loop'` counts across
|
|
175
|
+
// every phase in the loop (used by the ideation gate to require ≥3
|
|
176
|
+
// critique artifacts in the current critique round before allowing the
|
|
177
|
+
// critique→revision advance).
|
|
178
|
+
z.object({
|
|
179
|
+
kind: z.literal('min_artifacts_by_type'),
|
|
180
|
+
type: z.string().min(1),
|
|
181
|
+
n: z.number().int().positive(),
|
|
182
|
+
scope: z.enum(['phase', 'loop']),
|
|
183
|
+
}),
|
|
184
|
+
z.object({ kind: z.literal('manual') }),
|
|
185
|
+
]);
|
|
186
|
+
export const StopConditionSchema = z.lazy(() => z.union([
|
|
187
|
+
AtomicStopConditionSchema,
|
|
188
|
+
z.object({ kind: z.literal('any'), conditions: z.array(StopConditionSchema).min(1) }),
|
|
189
|
+
z.object({ kind: z.literal('all'), conditions: z.array(StopConditionSchema).min(1) }),
|
|
190
|
+
]));
|
|
191
|
+
export const LoopThreadSchema = z
|
|
192
|
+
.object({
|
|
193
|
+
schema_version: z.literal(1),
|
|
194
|
+
id: z.string().regex(/^lop_[0-9a-z]+$/),
|
|
195
|
+
version: z.number().int().nonnegative(),
|
|
196
|
+
mutation_id: z.string().min(1),
|
|
197
|
+
kind: z.enum(LOOP_KINDS),
|
|
198
|
+
title: z.string().min(1),
|
|
199
|
+
goal: z.string().optional(),
|
|
200
|
+
protocol: LoopProtocolConfigSchema.optional(),
|
|
201
|
+
status: z.enum(LOOP_STATUSES),
|
|
202
|
+
phases: z.array(LoopPhaseSchema).min(1),
|
|
203
|
+
current_phase: z.string().min(1),
|
|
204
|
+
iteration_count: z.number().int().nonnegative(),
|
|
205
|
+
slots: z.array(LoopSlotSchema),
|
|
206
|
+
artifacts: z.array(LoopArtifactSchema),
|
|
207
|
+
linked: LoopLinksSchema.optional(),
|
|
208
|
+
stop_condition: StopConditionSchema.optional(),
|
|
209
|
+
created_at: z.string().datetime(),
|
|
210
|
+
updated_at: z.string().datetime(),
|
|
211
|
+
closed_at: z.string().datetime().optional(),
|
|
212
|
+
created_by: z.string().min(1),
|
|
213
|
+
})
|
|
214
|
+
.superRefine((thread, ctx) => {
|
|
215
|
+
const names = thread.phases.map((p) => p.name);
|
|
216
|
+
const uniqueNames = new Set(names);
|
|
217
|
+
if (uniqueNames.size !== names.length) {
|
|
218
|
+
ctx.addIssue({
|
|
219
|
+
code: z.ZodIssueCode.custom,
|
|
220
|
+
message: 'LoopThread.phases names must be unique',
|
|
221
|
+
path: ['phases'],
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (!uniqueNames.has(thread.current_phase)) {
|
|
225
|
+
ctx.addIssue({
|
|
226
|
+
code: z.ZodIssueCode.custom,
|
|
227
|
+
message: `LoopThread.current_phase "${thread.current_phase}" is not in phases`,
|
|
228
|
+
path: ['current_phase'],
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const LoopEventBaseShape = {
|
|
233
|
+
event_id: z.string().min(1),
|
|
234
|
+
loop_id: z.string().regex(/^lop_[0-9a-z]+$/),
|
|
235
|
+
seq: z.number().int().positive(),
|
|
236
|
+
at: z.string().datetime(),
|
|
237
|
+
by: z.string().optional(),
|
|
238
|
+
mutation_id: z.string().min(1),
|
|
239
|
+
};
|
|
240
|
+
export const LoopEventSchema = z.discriminatedUnion('kind', [
|
|
241
|
+
z.object({
|
|
242
|
+
...LoopEventBaseShape,
|
|
243
|
+
kind: z.literal('opened'),
|
|
244
|
+
initial_phase: z.string().min(1),
|
|
245
|
+
created_by: z.string().min(1),
|
|
246
|
+
}),
|
|
247
|
+
z.object({
|
|
248
|
+
...LoopEventBaseShape,
|
|
249
|
+
kind: z.literal('phase_advanced'),
|
|
250
|
+
from_phase: z.string().min(1),
|
|
251
|
+
to_phase: z.string().min(1),
|
|
252
|
+
iteration: z.number().int().nonnegative(),
|
|
253
|
+
reason: z.string().optional(),
|
|
254
|
+
}),
|
|
255
|
+
z.object({
|
|
256
|
+
...LoopEventBaseShape,
|
|
257
|
+
kind: z.literal('turn_assigned'),
|
|
258
|
+
slot_id: z.string().min(1),
|
|
259
|
+
phase: z.string().min(1),
|
|
260
|
+
assignment_id: z.string().optional(),
|
|
261
|
+
input: z.string().optional(),
|
|
262
|
+
retry_of: z.string().optional(),
|
|
263
|
+
}),
|
|
264
|
+
z.object({
|
|
265
|
+
...LoopEventBaseShape,
|
|
266
|
+
kind: z.literal('turn_completed'),
|
|
267
|
+
slot_id: z.string().min(1),
|
|
268
|
+
phase: z.string().min(1),
|
|
269
|
+
artifact_id: z.string().optional(),
|
|
270
|
+
outcome: z.enum(['done', 'failed', 'cancelled']),
|
|
271
|
+
failure_reason: z.string().optional(),
|
|
272
|
+
}),
|
|
273
|
+
z.object({
|
|
274
|
+
...LoopEventBaseShape,
|
|
275
|
+
kind: z.literal('artifact_added'),
|
|
276
|
+
artifact_id: z.string().min(1),
|
|
277
|
+
phase: z.string().min(1),
|
|
278
|
+
type: z.string().min(1),
|
|
279
|
+
produced_by: z.string().optional(),
|
|
280
|
+
}),
|
|
281
|
+
z.object({
|
|
282
|
+
...LoopEventBaseShape,
|
|
283
|
+
kind: z.literal('linked'),
|
|
284
|
+
target: LoopRefSchema,
|
|
285
|
+
}),
|
|
286
|
+
z.object({
|
|
287
|
+
...LoopEventBaseShape,
|
|
288
|
+
kind: z.literal('paused'),
|
|
289
|
+
reason: z.string().optional(),
|
|
290
|
+
}),
|
|
291
|
+
z.object({
|
|
292
|
+
...LoopEventBaseShape,
|
|
293
|
+
kind: z.literal('resumed'),
|
|
294
|
+
}),
|
|
295
|
+
z.object({
|
|
296
|
+
...LoopEventBaseShape,
|
|
297
|
+
kind: z.literal('closed'),
|
|
298
|
+
final_status: z.enum(['completed', 'cancelled', 'blocked']),
|
|
299
|
+
reason: z.string().optional(),
|
|
300
|
+
}),
|
|
301
|
+
// pln#492 — system events emitted by the iteration / phase-advance gate.
|
|
302
|
+
// Carried in the same event journal rather than as artifacts so consumers
|
|
303
|
+
// do not have to filter is_system before processing artifact content.
|
|
304
|
+
z.object({
|
|
305
|
+
...LoopEventBaseShape,
|
|
306
|
+
kind: z.literal('phase_advance_blocked'),
|
|
307
|
+
phase: z.string().min(1),
|
|
308
|
+
gate_reason: z.string().min(1),
|
|
309
|
+
}),
|
|
310
|
+
z.object({
|
|
311
|
+
...LoopEventBaseShape,
|
|
312
|
+
kind: z.literal('max_iterations_reached'),
|
|
313
|
+
phase: z.string().min(1),
|
|
314
|
+
iteration: z.number().int().nonnegative(),
|
|
315
|
+
max_iterations: z.number().int().positive(),
|
|
316
|
+
}),
|
|
317
|
+
]);
|
|
318
|
+
export const LoopConflictRecordSchema = z.object({
|
|
319
|
+
conflict_id: z.string().min(1),
|
|
320
|
+
loop_id: z.string().regex(/^lop_[0-9a-z]+$/),
|
|
321
|
+
at: z.string().datetime(),
|
|
322
|
+
attempted_by: z.string().min(1),
|
|
323
|
+
expected_version: z.number().int().nonnegative(),
|
|
324
|
+
actual_version: z.number().int().nonnegative(),
|
|
325
|
+
rejected_intent: z.string().min(1),
|
|
326
|
+
client_request_id: z.string().optional(),
|
|
327
|
+
});
|
|
328
|
+
/**
|
|
329
|
+
* Default protocol per LoopKind. The loop driver reads this when a thread
|
|
330
|
+
* is opened without an explicit protocol override.
|
|
331
|
+
*
|
|
332
|
+
* `iteration` is optional — only ideation_loop uses it in v1 (pln#492);
|
|
333
|
+
* other kinds remain linear-with-stop-condition.
|
|
334
|
+
*/
|
|
335
|
+
export const DEFAULT_PROTOCOLS = {
|
|
336
|
+
review: {
|
|
337
|
+
phases: [
|
|
338
|
+
{ name: 'change_summary' },
|
|
339
|
+
{ name: 'findings' },
|
|
340
|
+
{ name: 'author_response' },
|
|
341
|
+
{ name: 'followup_review' },
|
|
342
|
+
{ name: 'verdict' },
|
|
343
|
+
],
|
|
344
|
+
stop_condition: {
|
|
345
|
+
kind: 'any',
|
|
346
|
+
conditions: [{ kind: 'reviewer_green' }, { kind: 'max_iterations', n: 3 }],
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
// pln#492 — ideation_loop: memory-confrontation protocol with inner
|
|
350
|
+
// critique↔revision cycle. `context_filter` per phase makes critic see
|
|
351
|
+
// adversarial memory only (traps + feedback + runtime_notes), while
|
|
352
|
+
// proposal sees positive context and revision/synthesis see everything.
|
|
353
|
+
ideation: {
|
|
354
|
+
phases: [
|
|
355
|
+
{
|
|
356
|
+
name: 'proposal',
|
|
357
|
+
context_filter: ['decisions', 'constraints', 'plans', 'project_vision'],
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: 'critique',
|
|
361
|
+
context_filter: ['traps', 'feedback', 'runtime_notes', 'critique_history'],
|
|
362
|
+
// pln#492 — gate: cannot advance critique→revision until ≥3 critique
|
|
363
|
+
// artifacts have been produced in the current critique phase. Below
|
|
364
|
+
// that floor, the loop hasn't accumulated enough adversarial pressure
|
|
365
|
+
// to make revision useful. Phase 2.b iteration engine will refine
|
|
366
|
+
// this to per-iteration scope; phase 2.a counts across the phase.
|
|
367
|
+
advance_gate: {
|
|
368
|
+
kind: 'min_artifacts_by_type',
|
|
369
|
+
type: 'critique',
|
|
370
|
+
n: 3,
|
|
371
|
+
scope: 'phase',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
{ name: 'revision', context_filter: ['*'] },
|
|
375
|
+
{ name: 'synthesis', context_filter: ['*'] },
|
|
376
|
+
],
|
|
377
|
+
iteration: {
|
|
378
|
+
cycle: ['critique', 'revision'],
|
|
379
|
+
max_iterations: 3,
|
|
380
|
+
exit_when: 'no_new_critique_artifacts',
|
|
381
|
+
},
|
|
382
|
+
stop_condition: { kind: 'artifact_produced', phase: 'synthesis', type: 'plan_draft' },
|
|
383
|
+
},
|
|
384
|
+
implementation: {
|
|
385
|
+
phases: [
|
|
386
|
+
{ name: 'sequence_build' },
|
|
387
|
+
{ name: 'dispatch' },
|
|
388
|
+
{ name: 'execute' },
|
|
389
|
+
{ name: 'self_check' },
|
|
390
|
+
{ name: 'handoff_ready' },
|
|
391
|
+
],
|
|
392
|
+
stop_condition: { kind: 'artifact_produced', phase: 'handoff_ready', type: 'handoff' },
|
|
393
|
+
},
|
|
394
|
+
research: {
|
|
395
|
+
phases: [{ name: 'investigate' }, { name: 'synthesize' }],
|
|
396
|
+
stop_condition: { kind: 'manual' },
|
|
397
|
+
},
|
|
398
|
+
debug: {
|
|
399
|
+
phases: [{ name: 'reproduce' }, { name: 'hypothesize' }, { name: 'isolate' }, { name: 'fix' }],
|
|
400
|
+
stop_condition: { kind: 'manual' },
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
//# sourceMappingURL=types.js.map
|