chati-dev 4.5.9 → 4.5.11
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/framework/agents/discover/brownfield-wu.md +1 -1
- package/framework/agents/plan/tasks.md +2 -2
- package/framework/config.yaml +2 -2
- package/framework/context/governance.md +10 -10
- package/framework/context/quality.md +6 -6
- package/framework/context/root.md +1 -1
- package/framework/data/entity-registry.yaml +1 -1
- package/framework/hooks/git-push-authority.js +8 -4
- package/framework/i18n/en.yaml +51 -0
- package/framework/i18n/es.yaml +51 -0
- package/framework/i18n/fr.yaml +51 -0
- package/framework/i18n/pt.yaml +51 -0
- package/framework/manifest.json +30 -30
- package/framework/manifest.sig +1 -1
- package/framework/orchestrator/chati.md +29 -20
- package/framework/schemas/session.schema.json +4 -4
- package/package.json +1 -1
- package/src/config/framework-adapter.js +10 -2
- package/src/context/layers/l1-global.js +2 -0
- package/src/installer/core.js +5 -5
- package/src/installer/templates.js +3 -2
- package/src/orchestrator/cli.js +104 -14
- package/src/orchestrator/pipeline-manager.js +2 -0
- package/src/orchestrator/runtime-installation-v2.js +38 -0
- package/src/orchestrator/session-manager.js +1 -1
- package/src/wizard/feedback.js +3 -2
- package/src/wizard/i18n.js +42 -0
- package/src/wizard/index.js +29 -28
- package/src/wizard/questions.js +28 -26
package/framework/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"createdAt": "2026-08-
|
|
2
|
+
"createdAt": "2026-08-27T14:40:11.488Z",
|
|
3
3
|
"files": {
|
|
4
4
|
"agents/build/dev.md": {
|
|
5
5
|
"hash": "13c2b3855c1f815154a2f4020b99fd8ee71e701b41783f5f26696222720a1466",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"type": "md"
|
|
18
18
|
},
|
|
19
19
|
"agents/discover/brownfield-wu.md": {
|
|
20
|
-
"hash": "
|
|
21
|
-
"size":
|
|
20
|
+
"hash": "fed8f14838b00e867bc932a3c4c212e38d7dc7c8f2e4443eb3242d19e6e3a286",
|
|
21
|
+
"size": 18172,
|
|
22
22
|
"type": "md"
|
|
23
23
|
},
|
|
24
24
|
"agents/discover/greenfield-wu.md": {
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"type": "md"
|
|
53
53
|
},
|
|
54
54
|
"agents/plan/tasks.md": {
|
|
55
|
-
"hash": "
|
|
56
|
-
"size":
|
|
55
|
+
"hash": "a42a321ca2834c20364edb663619d340ac29317b236820135f07013cae9a4a82",
|
|
56
|
+
"size": 27960,
|
|
57
57
|
"type": "md"
|
|
58
58
|
},
|
|
59
59
|
"agents/plan/ux-brand-architect.md": {
|
|
@@ -97,8 +97,8 @@
|
|
|
97
97
|
"type": "md"
|
|
98
98
|
},
|
|
99
99
|
"config.yaml": {
|
|
100
|
-
"hash": "
|
|
101
|
-
"size":
|
|
100
|
+
"hash": "1b1103f17b9c2ba5820d8fae13c388bedf1bb3cceec93d3cd613b1b6e878bfce",
|
|
101
|
+
"size": 2671,
|
|
102
102
|
"type": "yaml"
|
|
103
103
|
},
|
|
104
104
|
"constitution.md": {
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"type": "md"
|
|
108
108
|
},
|
|
109
109
|
"context/governance.md": {
|
|
110
|
-
"hash": "
|
|
111
|
-
"size":
|
|
110
|
+
"hash": "88b3a3463fc14a26459f3202bf939dc954392642e4ac20830429dffd0f209f1f",
|
|
111
|
+
"size": 6225,
|
|
112
112
|
"type": "md"
|
|
113
113
|
},
|
|
114
114
|
"context/protocols.md": {
|
|
@@ -117,18 +117,18 @@
|
|
|
117
117
|
"type": "md"
|
|
118
118
|
},
|
|
119
119
|
"context/quality.md": {
|
|
120
|
-
"hash": "
|
|
121
|
-
"size":
|
|
120
|
+
"hash": "d6cb70d274425b4385a63bd67c217038de9c12992d973b16000b370442905022",
|
|
121
|
+
"size": 2247,
|
|
122
122
|
"type": "md"
|
|
123
123
|
},
|
|
124
124
|
"context/root.md": {
|
|
125
|
-
"hash": "
|
|
126
|
-
"size":
|
|
125
|
+
"hash": "adb70c8b7cac6934f2650dd683e5b08a01f6d81dc6f380b0b546e05cce4963d4",
|
|
126
|
+
"size": 1218,
|
|
127
127
|
"type": "md"
|
|
128
128
|
},
|
|
129
129
|
"data/entity-registry.yaml": {
|
|
130
|
-
"hash": "
|
|
131
|
-
"size":
|
|
130
|
+
"hash": "e56261884e29b046f3c4b5f4d0a22b4fa27bceba17d669d0606ea0a25d3c8237",
|
|
131
|
+
"size": 34606,
|
|
132
132
|
"type": "yaml"
|
|
133
133
|
},
|
|
134
134
|
"data/model-limits.json": {
|
|
@@ -302,8 +302,8 @@
|
|
|
302
302
|
"type": "js"
|
|
303
303
|
},
|
|
304
304
|
"hooks/git-push-authority.js": {
|
|
305
|
-
"hash": "
|
|
306
|
-
"size":
|
|
305
|
+
"hash": "cb296129155464438b7f3f8834eb9d62674c34c0ef12ccba8769cd2938da97d8",
|
|
306
|
+
"size": 4666,
|
|
307
307
|
"type": "js"
|
|
308
308
|
},
|
|
309
309
|
"hooks/license-guard.js": {
|
|
@@ -377,23 +377,23 @@
|
|
|
377
377
|
"type": "js"
|
|
378
378
|
},
|
|
379
379
|
"i18n/en.yaml": {
|
|
380
|
-
"hash": "
|
|
381
|
-
"size":
|
|
380
|
+
"hash": "6b1ede4a442a86194d561d4a7a2fc5bf2259d23b23ae48eeaa973cf8fce79f33",
|
|
381
|
+
"size": 8046,
|
|
382
382
|
"type": "yaml"
|
|
383
383
|
},
|
|
384
384
|
"i18n/es.yaml": {
|
|
385
|
-
"hash": "
|
|
386
|
-
"size":
|
|
385
|
+
"hash": "2542bf4a6b68883cea81021ed5ea84f5f05368be3a47b79d1b797753966a18ed",
|
|
386
|
+
"size": 8632,
|
|
387
387
|
"type": "yaml"
|
|
388
388
|
},
|
|
389
389
|
"i18n/fr.yaml": {
|
|
390
|
-
"hash": "
|
|
391
|
-
"size":
|
|
390
|
+
"hash": "58c8d34b1d752592dbd6beb32b240475fdf297847558e8589174d713bae439c8",
|
|
391
|
+
"size": 8777,
|
|
392
392
|
"type": "yaml"
|
|
393
393
|
},
|
|
394
394
|
"i18n/pt.yaml": {
|
|
395
|
-
"hash": "
|
|
396
|
-
"size":
|
|
395
|
+
"hash": "fba6466fc35f464344d9a40d1172100d65c5e42d406285e3653c9bbad59b5607",
|
|
396
|
+
"size": 8516,
|
|
397
397
|
"type": "yaml"
|
|
398
398
|
},
|
|
399
399
|
"intelligence/confidence.yaml": {
|
|
@@ -472,8 +472,8 @@
|
|
|
472
472
|
"type": "md"
|
|
473
473
|
},
|
|
474
474
|
"orchestrator/chati.md": {
|
|
475
|
-
"hash": "
|
|
476
|
-
"size":
|
|
475
|
+
"hash": "fbba2ec83ded49329dc33f674accb391cc290cd1687048967a49fc70fb62f3af",
|
|
476
|
+
"size": 46016,
|
|
477
477
|
"type": "md"
|
|
478
478
|
},
|
|
479
479
|
"package.json": {
|
|
@@ -857,8 +857,8 @@
|
|
|
857
857
|
"type": "json"
|
|
858
858
|
},
|
|
859
859
|
"schemas/session.schema.json": {
|
|
860
|
-
"hash": "
|
|
861
|
-
"size":
|
|
860
|
+
"hash": "0c9218aeec82d4db591e87ffede20ea13eef6c549472f9471a1cee9ee637ba57",
|
|
861
|
+
"size": 19145,
|
|
862
862
|
"type": "json"
|
|
863
863
|
},
|
|
864
864
|
"schemas/task.schema.json": {
|
|
@@ -1352,5 +1352,5 @@
|
|
|
1352
1352
|
"type": "yaml"
|
|
1353
1353
|
}
|
|
1354
1354
|
},
|
|
1355
|
-
"version": "4.5.
|
|
1355
|
+
"version": "4.5.11"
|
|
1356
1356
|
}
|
package/framework/manifest.sig
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Bj1mLU/kLfzNbNJmeY/BPjrL5bTt0MdOuSyfbjFTPniA8ev8TVO7Om+EQDxO0a6V0PHMYmVXf1GcoYWz8Q/VDw==
|
|
@@ -65,7 +65,12 @@ When the user invokes `/chati`, execute this sequence:
|
|
|
65
65
|
|
|
66
66
|
/chati providers:
|
|
67
67
|
→ Run: node .chati.dev/orchestrator/chati-router.js providers
|
|
68
|
-
→
|
|
68
|
+
→ For v2, display three distinct blocks from JSON:
|
|
69
|
+
1. `planning_agent_models`, discovery and planning routing only
|
|
70
|
+
2. `rail_execution_pool`, eligible provider and model capabilities for task execution and review
|
|
71
|
+
3. `release_lane`, explicit authorization policy
|
|
72
|
+
→ Never describe `dev`, `qa-implementation`, `qa-visual`, or `devops` as v2 pipeline agents
|
|
73
|
+
→ Never infer that a provider with no planning agent assignment is unavailable to RAIL
|
|
69
74
|
→ Stay locked
|
|
70
75
|
|
|
71
76
|
/chati resume:
|
|
@@ -75,7 +80,7 @@ When the user invokes `/chati`, execute this sequence:
|
|
|
75
80
|
→ Display:
|
|
76
81
|
/chati Start or resume session
|
|
77
82
|
/chati status Show project dashboard
|
|
78
|
-
/chati providers
|
|
83
|
+
/chati providers Show planning routing and the RAIL execution pool
|
|
79
84
|
/chati exit Save and exit session
|
|
80
85
|
/chati help Show this help
|
|
81
86
|
→ Stay locked
|
|
@@ -319,7 +324,7 @@ returned `next` state. Do not treat it as an error.
|
|
|
319
324
|
|
|
320
325
|
Planning phase agents (detail, architect, ux) run simultaneously.
|
|
321
326
|
|
|
322
|
-
**NOTE (Article XXI):**
|
|
327
|
+
**NOTE (Article XXI):** For v2, when `features.agent_teams: true` in config.yaml, the orchestrator MUST attempt `spawn_team` first for the Planning Team (detail, architect, ux, qa-planning). Only fall back to `spawn_parallel` if team spawning is unavailable or fails. After Tasks, RAIL owns execution and review. A Build Team is never formed in v2.
|
|
323
328
|
|
|
324
329
|
1. Display naturally what is happening using user-facing language. Examples (pick one that fits the phase): "Working on the planning phase now." / "Reviewing the architecture and UX in parallel." NEVER say "spawning parallel group", "spawn_parallel", or list internal agent names like "detail, architect, ux".
|
|
325
330
|
2. If `parallel_spawn_commands` is non-empty, execute every member's `command`
|
|
@@ -363,7 +368,7 @@ Parse the JSON response. Extract these values - you will need them in Step 2:
|
|
|
363
368
|
|
|
364
369
|
If `fallback_required: true` → fall back silently to the "Action: Parallel Spawn" section. Do NOT display error messages.
|
|
365
370
|
|
|
366
|
-
Display naturally what is happening
|
|
371
|
+
Display naturally what is happening: "Working on the planning, designing the requirements, architecture, and user experience together." Never expose internal agent names.
|
|
367
372
|
|
|
368
373
|
### MANDATORY Step 2: Spawn Teammates via Agent Tool
|
|
369
374
|
|
|
@@ -421,6 +426,7 @@ Agent tool call 4:
|
|
|
421
426
|
Write your handoff to artifacts/handoffs/qa-planning-handoff.md when done.]
|
|
422
427
|
```
|
|
423
428
|
|
|
429
|
+
<!-- CHATI_LEGACY_BUILD_START -->
|
|
424
430
|
**Legacy compatibility only, installations without `.chati/v2/installation.json`: For Build Team** (BUILD phase) - Wave-Based Pipeline:
|
|
425
431
|
|
|
426
432
|
For a v2 installation this section MUST NOT run. The `tasks` handoff returns
|
|
@@ -593,6 +599,8 @@ Before dissolving the team, verify both handoffs exist:
|
|
|
593
599
|
STOP and return.]
|
|
594
600
|
2. `artifacts/handoffs/qa-implementation-handoff.md` - should exist from Final QA Wave
|
|
595
601
|
|
|
602
|
+
<!-- CHATI_LEGACY_BUILD_END -->
|
|
603
|
+
|
|
596
604
|
### Step 3: Collect Results
|
|
597
605
|
|
|
598
606
|
When all Agent tool calls return:
|
|
@@ -700,9 +708,9 @@ The user is returning to an active session.
|
|
|
700
708
|
|
|
701
709
|
---
|
|
702
710
|
|
|
703
|
-
## Action: User Preview
|
|
711
|
+
## Action: User Preview (legacy runtime only)
|
|
704
712
|
|
|
705
|
-
|
|
713
|
+
This action is invalid when `.chati/v2/installation.json` exists. V2 preview evidence and external authorization belong to the RAIL Release Lane.
|
|
706
714
|
|
|
707
715
|
1. Present QA results to user
|
|
708
716
|
2. Options:
|
|
@@ -718,7 +726,7 @@ QA-Implementation passed. User must approve before deploy.
|
|
|
718
726
|
|
|
719
727
|
## Action: Complete
|
|
720
728
|
|
|
721
|
-
|
|
729
|
+
The RAIL Release Lane has completed or the legacy pipeline has finished. Present the final project summary. Run `orchestrate exit`.
|
|
722
730
|
Congratulate the user.
|
|
723
731
|
|
|
724
732
|
---
|
|
@@ -862,12 +870,12 @@ interactive (default):
|
|
|
862
870
|
→ Agent-driven guided mode. Agent leads, user validates.
|
|
863
871
|
→ All 8 universal protocols apply.
|
|
864
872
|
|
|
865
|
-
autonomous
|
|
873
|
+
autonomous:
|
|
866
874
|
→ Requires: most recent QA gate score >= 95% (Article XVII prerequisite).
|
|
867
875
|
→ If quality gate not met, inform user and suggest guided mode instead.
|
|
868
876
|
→ Agent executes without asking unless blocker encountered.
|
|
869
|
-
→ Primarily for
|
|
870
|
-
→
|
|
877
|
+
→ Primarily for dependency-ready RAIL tasks.
|
|
878
|
+
→ Independent review and rework gates always run regardless of mode.
|
|
871
879
|
→ Activated by user request or orchestrator suggestion post-Brief.
|
|
872
880
|
```
|
|
873
881
|
|
|
@@ -906,12 +914,13 @@ discover/plan phase:
|
|
|
906
914
|
BLOCK write to: everything else
|
|
907
915
|
ALLOW read: everything
|
|
908
916
|
|
|
909
|
-
|
|
917
|
+
RAIL execution/review:
|
|
910
918
|
ALLOW write to: everything
|
|
911
919
|
ALLOW read: everything
|
|
912
920
|
|
|
913
|
-
|
|
914
|
-
ALLOW
|
|
921
|
+
Release Lane:
|
|
922
|
+
ALLOW evidence preparation
|
|
923
|
+
REQUIRE explicit human authorization before external action
|
|
915
924
|
```
|
|
916
925
|
|
|
917
926
|
### Backward Transitions
|
|
@@ -923,10 +932,10 @@ If QA finds spec or architecture issues:
|
|
|
923
932
|
|
|
924
933
|
### Root Layer Routing (Article XXII)
|
|
925
934
|
|
|
926
|
-
When
|
|
935
|
+
When the independent RAIL reviewer classifies a fault:
|
|
927
936
|
- `INTENT` → escalate to user via deviation protocol (requirement is flawed)
|
|
928
937
|
- `SPEC` → backward transition to Architect, UX, or Tasks agent
|
|
929
|
-
- `CODE` →
|
|
938
|
+
- `CODE` → bounded RAIL rework using the task's sealed execution binding
|
|
930
939
|
- `DEFER` → add to session backlog, do not block approval
|
|
931
940
|
|
|
932
941
|
---
|
|
@@ -936,13 +945,13 @@ When QA-Implementation classifies a fault via the Fault Vector Protocol:
|
|
|
936
945
|
### EXCLUSIVE (only orchestrator)
|
|
937
946
|
- Route messages to agents
|
|
938
947
|
- Activate/deactivate agents
|
|
939
|
-
- Execute mode transitions (
|
|
948
|
+
- Execute mode transitions (discovery → planning → RAIL → Release Lane)
|
|
940
949
|
- Manage session lock (activate/deactivate)
|
|
941
950
|
- Handle deviations and re-routing
|
|
942
951
|
- Manage backlog items
|
|
943
952
|
- Spawn parallel terminals
|
|
944
953
|
- Decide execution mode (interactive vs autonomous)
|
|
945
|
-
- Form and dissolve
|
|
954
|
+
- Form and dissolve the Planning Team (Team Lead role, Article XXI)
|
|
946
955
|
- Monitor shared task list and mailbox during team execution
|
|
947
956
|
- Detect and respond to echo events within teams (Article XXII)
|
|
948
957
|
- Route corrections to correct layer via Root Layer Routing (Article XXII)
|
|
@@ -955,11 +964,11 @@ When QA-Implementation classifies a fault via the Fault Vector Protocol:
|
|
|
955
964
|
- Generate session digests
|
|
956
965
|
|
|
957
966
|
### BLOCKED (never do this - redirect instead)
|
|
958
|
-
- Write code or implementation files → route
|
|
967
|
+
- Write code or implementation files outside RAIL → route through the sealed RAIL task
|
|
959
968
|
- Write specification documents → route to detail
|
|
960
969
|
- Make architectural decisions → route to architect
|
|
961
|
-
- Write tests → route
|
|
962
|
-
- Deploy or configure infrastructure → route to
|
|
970
|
+
- Write tests outside RAIL → route through the sealed RAIL task
|
|
971
|
+
- Deploy or configure infrastructure directly → route to the Release Lane authorization gate
|
|
963
972
|
- Modify constitution or config files
|
|
964
973
|
|
|
965
974
|
---
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"description": "Normalized active_model recorded when /chati-update last completed. Article XXIV: when active_model differs from this, the orchestrator advises a harness re-audit. The advisory is driven entirely by this comparison; there is no separate flag."
|
|
21
21
|
},
|
|
22
22
|
"mode": {
|
|
23
|
-
"enum": ["discover", "plan", "build", "validate", "deploy", "completed"],
|
|
23
|
+
"enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"],
|
|
24
24
|
"default": "discover",
|
|
25
25
|
"description": "Flat pipeline macro-phase (mirrors project.state). Read by prism-engine and mode-governance hooks."
|
|
26
26
|
},
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"properties": {
|
|
68
68
|
"name": { "type": "string", "description": "Project name" },
|
|
69
69
|
"type": { "enum": ["greenfield", "brownfield"], "description": "Project type" },
|
|
70
|
-
"state": { "enum": ["discover", "plan", "build", "validate", "deploy", "completed"], "description": "Current pipeline macro-phase" }
|
|
70
|
+
"state": { "enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"], "description": "Current pipeline macro-phase" }
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"execution_mode": {
|
|
@@ -235,8 +235,8 @@
|
|
|
235
235
|
"required": ["timestamp", "from", "to", "trigger"],
|
|
236
236
|
"properties": {
|
|
237
237
|
"timestamp": { "type": "string", "format": "date-time" },
|
|
238
|
-
"from": { "enum": ["discover", "plan", "build", "validate", "deploy", "completed"] },
|
|
239
|
-
"to": { "enum": ["discover", "plan", "build", "validate", "deploy", "completed"] },
|
|
238
|
+
"from": { "enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"] },
|
|
239
|
+
"to": { "enum": ["discover", "plan", "rail", "release", "build", "validate", "deploy", "completed"] },
|
|
240
240
|
"trigger": { "type": "string", "description": "What caused the transition (agent completion, override, backward)" },
|
|
241
241
|
"type": { "enum": ["automatic", "backward", "override"], "description": "Transition classification" },
|
|
242
242
|
"skipped_agents": {
|
package/package.json
CHANGED
|
@@ -201,11 +201,19 @@ function buildReplacementConfig(provider) {
|
|
|
201
201
|
* @returns {string} Adapted content for the target provider
|
|
202
202
|
*/
|
|
203
203
|
export function adaptFrameworkFile(content, filePath, provider) {
|
|
204
|
-
if (provider === 'claude') return content;
|
|
205
204
|
if (!content) return content;
|
|
206
205
|
|
|
207
|
-
const config = buildReplacementConfig(provider);
|
|
208
206
|
let result = content;
|
|
207
|
+
if (filePath === 'orchestrator/chati.md') {
|
|
208
|
+
result = result.replace(
|
|
209
|
+
/<!-- CHATI_LEGACY_BUILD_START -->[\s\S]*?<!-- CHATI_LEGACY_BUILD_END -->\s*/g,
|
|
210
|
+
'For installations without `.chati/v2/installation.json`, use the separately bundled legacy compatibility runtime.\n\n',
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (provider === 'claude') return result;
|
|
215
|
+
|
|
216
|
+
const config = buildReplacementConfig(provider);
|
|
209
217
|
|
|
210
218
|
// 1. Apply ordered string replacements (most specific first)
|
|
211
219
|
for (const [search, replace] of config.strings) {
|
package/src/installer/core.js
CHANGED
|
@@ -560,16 +560,16 @@ Governance rules are in \`.chati.dev/constitution.md\`.
|
|
|
560
560
|
\`\`\`
|
|
561
561
|
DISCOVER: WU -> Brief
|
|
562
562
|
PLAN: [Planning Team: Detail + Architect + UX + QA-Planning] -> Phases -> Tasks
|
|
563
|
-
|
|
564
|
-
|
|
563
|
+
RAIL: Sealed task graph -> Execute -> Independent Review -> Bounded Rework
|
|
564
|
+
RELEASE: Evidence gate -> Explicit human authorization -> External action
|
|
565
565
|
\`\`\`
|
|
566
566
|
|
|
567
567
|
## Agents
|
|
568
568
|
- DISCOVER: .chati.dev/agents/discover/
|
|
569
569
|
- PLAN: .chati.dev/agents/plan/
|
|
570
|
-
- Quality: .chati.dev/agents/quality/
|
|
571
|
-
-
|
|
572
|
-
-
|
|
570
|
+
- Planning Quality: .chati.dev/agents/quality/qa-planning.md
|
|
571
|
+
- RAIL Runtime: .chati.dev/_cli/ and .chati/v2/rail/
|
|
572
|
+
- Release Lane: RAIL completion evidence plus explicit authorization
|
|
573
573
|
`;
|
|
574
574
|
}
|
|
575
575
|
|
|
@@ -62,11 +62,12 @@ export function generateSessionYaml(config) {
|
|
|
62
62
|
reasoning_escalations: [],
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
//
|
|
65
|
+
// V2 ends the classic agent pipeline at Tasks. RAIL owns implementation,
|
|
66
|
+
// independent review, bounded rework and the Release Lane after handoff.
|
|
66
67
|
const agentNames = [
|
|
67
68
|
'greenfield-wu', 'brownfield-wu', 'brief', 'detail',
|
|
68
69
|
'architect', 'ux', 'phases', 'tasks',
|
|
69
|
-
'qa-planning',
|
|
70
|
+
'qa-planning',
|
|
70
71
|
];
|
|
71
72
|
|
|
72
73
|
for (const agent of agentNames) {
|
package/src/orchestrator/cli.js
CHANGED
|
@@ -53,7 +53,10 @@ import {
|
|
|
53
53
|
recordEvent, EventType, clearTimeline,
|
|
54
54
|
} from '../intelligence/timeline.js';
|
|
55
55
|
import { updateClaudeMd } from '../memory/magic-docs.js';
|
|
56
|
-
import {
|
|
56
|
+
import {
|
|
57
|
+
loadRuntimeInstallationV2, resolveRuntimeInvocationV2,
|
|
58
|
+
describeRuntimeInstallationV2, V2_PLANNING_AGENTS,
|
|
59
|
+
} from './runtime-installation-v2.js';
|
|
57
60
|
import { compilePlanningHandoff, PLANNING_V2_TASKS_PATH } from './planning-runtime.js';
|
|
58
61
|
import { persistRailHandoff } from './rail-runtime.js';
|
|
59
62
|
|
|
@@ -84,6 +87,16 @@ const RESUME_MESSAGES = {
|
|
|
84
87
|
fr: 'Session sauvee. Tapez /chati pour reprendre.',
|
|
85
88
|
};
|
|
86
89
|
|
|
90
|
+
function getRuntimeAgentPipeline(projectDir, session = null) {
|
|
91
|
+
if (!loadRuntimeInstallationV2(projectDir)) return AGENT_PIPELINE;
|
|
92
|
+
const projectType = session?.project_type || session?.project?.type || 'greenfield';
|
|
93
|
+
const selectedWu = projectType === 'brownfield' ? 'brownfield-wu' : 'greenfield-wu';
|
|
94
|
+
return AGENT_PIPELINE.filter(({ name }) =>
|
|
95
|
+
V2_PLANNING_AGENTS.includes(name)
|
|
96
|
+
&& (!name.endsWith('-wu') || name === selectedWu)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
// ---------------------------------------------------------------------------
|
|
88
101
|
// QA-Visual scope helpers (Fase 6 — scope isolation)
|
|
89
102
|
//
|
|
@@ -516,8 +529,13 @@ function errorResult(message, code) {
|
|
|
516
529
|
*/
|
|
517
530
|
function sessionToPipelineState(session, projectDir) {
|
|
518
531
|
const agents = {};
|
|
532
|
+
const installationV2 = loadRuntimeInstallationV2(projectDir);
|
|
533
|
+
const allowedAgents = installationV2
|
|
534
|
+
? new Set(getRuntimeAgentPipeline(projectDir, session).map(({ name }) => name))
|
|
535
|
+
: null;
|
|
519
536
|
if (session.agents) {
|
|
520
537
|
for (const [name, data] of Object.entries(session.agents)) {
|
|
538
|
+
if (allowedAgents && !allowedAgents.has(name)) continue;
|
|
521
539
|
agents[name] = {
|
|
522
540
|
status: data.status || 'pending',
|
|
523
541
|
score: data.score ?? null,
|
|
@@ -536,7 +554,9 @@ function sessionToPipelineState(session, projectDir) {
|
|
|
536
554
|
startedAt: session.started_at || new Date().toISOString(),
|
|
537
555
|
completedAt: null,
|
|
538
556
|
agents,
|
|
539
|
-
completedAgents:
|
|
557
|
+
completedAgents: allowedAgents
|
|
558
|
+
? (session.completed_agents || []).filter((name) => allowedAgents.has(name))
|
|
559
|
+
: (session.completed_agents || []),
|
|
540
560
|
currentAgent: session.current_agent || null,
|
|
541
561
|
modeTransitions: session.mode_transitions || [],
|
|
542
562
|
history: [],
|
|
@@ -767,11 +787,12 @@ async function handleNext(projectDir) {
|
|
|
767
787
|
const activating = ['activate_interactive', 'spawn_routed_interactive', 'spawn_autonomous', 'spawn_team', 'spawn_parallel'];
|
|
768
788
|
if (activating.includes(result.action)) {
|
|
769
789
|
try {
|
|
790
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, result.session);
|
|
770
791
|
writeSessionLock(projectDir, result.agent, {
|
|
771
792
|
phase: result.phase || 'discover',
|
|
772
793
|
mode: result.session?.execution_mode || 'interactive',
|
|
773
794
|
position: result.pipeline_progress?.completedAgents?.length ?? 0,
|
|
774
|
-
total:
|
|
795
|
+
total: runtimePipeline.length,
|
|
775
796
|
progress: result.pipeline_progress?.progress ?? 0,
|
|
776
797
|
});
|
|
777
798
|
} catch { /* non-fatal */ }
|
|
@@ -798,6 +819,38 @@ async function _handleNextInner(projectDir) {
|
|
|
798
819
|
return errorResult(`Session invalid: ${validation.reason}`, 'SESSION_INVALID');
|
|
799
820
|
}
|
|
800
821
|
|
|
822
|
+
const installationV2 = loadRuntimeInstallationV2(projectDir);
|
|
823
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, session);
|
|
824
|
+
if (installationV2 && session.rail_handoff_id) {
|
|
825
|
+
const completedPlanning = runtimePipeline.length;
|
|
826
|
+
return {
|
|
827
|
+
action: 'rail_execute',
|
|
828
|
+
agent: 'rail',
|
|
829
|
+
phase: 'rail',
|
|
830
|
+
handoff_id: session.rail_handoff_id,
|
|
831
|
+
rail_state: session.rail_state || 'ready',
|
|
832
|
+
pipeline_progress: {
|
|
833
|
+
phase: 'rail', progress: 100, completedCount: completedPlanning,
|
|
834
|
+
totalAgents: completedPlanning, completedAgents: session.completed_agents || [],
|
|
835
|
+
currentAgent: 'rail', nextAgent: null,
|
|
836
|
+
},
|
|
837
|
+
session: {
|
|
838
|
+
language: session.language,
|
|
839
|
+
project_type: session.project_type || session.project?.type,
|
|
840
|
+
execution_mode: session.execution_mode,
|
|
841
|
+
},
|
|
842
|
+
status_summary: 'Planning is sealed. Resume execution through RAIL.',
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const legacyExecutionAgents = new Set(['dev', 'qa-implementation', 'qa-visual', 'devops']);
|
|
847
|
+
if (installationV2 && legacyExecutionAgents.has(session.current_agent)) {
|
|
848
|
+
return errorResult(
|
|
849
|
+
'A v2 installation cannot resume a legacy Build/Deploy agent. Re-seal Tasks to create the RAIL handoff.',
|
|
850
|
+
'V2_RAIL_HANDOFF_REQUIRED',
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
|
|
801
854
|
const pipelineState = sessionToPipelineState(session, projectDir);
|
|
802
855
|
|
|
803
856
|
if (isPipelineComplete(pipelineState)) {
|
|
@@ -836,7 +889,7 @@ async function _handleNextInner(projectDir) {
|
|
|
836
889
|
handoff_status: { valid: true, missing: [], warnings: ['Resuming dev as Build Team'] },
|
|
837
890
|
gate_status: { canAdvance: true, reason: 'Build Team formation (Article XXI)' },
|
|
838
891
|
model_info: resolveAgentModel(agent, projectDir),
|
|
839
|
-
context_bracket: estimateContextBracket(completedAgents.length,
|
|
892
|
+
context_bracket: estimateContextBracket(completedAgents.length, runtimePipeline.length),
|
|
840
893
|
pipeline_progress: getPipelineProgress(pipelineState),
|
|
841
894
|
session: { language: session.language, project_type: session.project_type || session.project?.type, execution_mode: session.execution_mode, user_level: session.user_level || 'auto' },
|
|
842
895
|
status_summary: `Forming Build Team: dev + qa-implementation.`,
|
|
@@ -858,7 +911,7 @@ async function _handleNextInner(projectDir) {
|
|
|
858
911
|
handoff_status: { valid: true, missing: [], warnings: ['Resuming in-progress agent'] },
|
|
859
912
|
gate_status: { canAdvance: true, reason: 'Agent already in progress' },
|
|
860
913
|
model_info: modelInfo,
|
|
861
|
-
context_bracket: estimateContextBracket(completedAgents.length,
|
|
914
|
+
context_bracket: estimateContextBracket(completedAgents.length, runtimePipeline.length),
|
|
862
915
|
pipeline_progress: getPipelineProgress(pipelineState),
|
|
863
916
|
session: { language: session.language, project_type: session.project_type || session.project?.type, execution_mode: session.execution_mode, user_level: session.user_level || 'auto' },
|
|
864
917
|
status_summary: `Resuming ${agent} (in progress).`,
|
|
@@ -887,7 +940,7 @@ async function _handleNextInner(projectDir) {
|
|
|
887
940
|
handoff_status: { valid: true, missing: [], warnings: [] },
|
|
888
941
|
gate_status: { canAdvance: true, reason: 'First agent in pipeline' },
|
|
889
942
|
model_info: modelInfo,
|
|
890
|
-
context_bracket: estimateContextBracket(0,
|
|
943
|
+
context_bracket: estimateContextBracket(0, runtimePipeline.length),
|
|
891
944
|
pipeline_progress: getPipelineProgress(pipelineState),
|
|
892
945
|
session: { language: session.language, project_type: projectType, execution_mode: session.execution_mode, user_level: session.user_level || 'auto' },
|
|
893
946
|
status_summary: `Starting pipeline with ${firstAgent}.`,
|
|
@@ -927,6 +980,13 @@ async function _handleNextInner(projectDir) {
|
|
|
927
980
|
const agentDef = getAgentDefinition(nextAgent);
|
|
928
981
|
const isInteractive = INTERACTIVE_AGENTS.includes(nextAgent);
|
|
929
982
|
|
|
983
|
+
if (installationV2 && legacyExecutionAgents.has(nextAgent)) {
|
|
984
|
+
return errorResult(
|
|
985
|
+
'Planning reached the v2 execution boundary without a sealed RAIL handoff. Complete or re-run Tasks instead of entering Build/Deploy.',
|
|
986
|
+
'V2_RAIL_HANDOFF_REQUIRED',
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
|
|
930
990
|
// Validate handoff from previous agent
|
|
931
991
|
let handoffStatus;
|
|
932
992
|
try {
|
|
@@ -1011,7 +1071,7 @@ async function _handleNextInner(projectDir) {
|
|
|
1011
1071
|
recordEvent(projectDir, EventType.AGENT_ACTIVATED, nextAgent, { action, phase: agentDef?.phase });
|
|
1012
1072
|
|
|
1013
1073
|
const progress = getPipelineProgress(pipelineState);
|
|
1014
|
-
const bracket = estimateContextBracket(completedAgents.length,
|
|
1074
|
+
const bracket = estimateContextBracket(completedAgents.length, runtimePipeline.length);
|
|
1015
1075
|
|
|
1016
1076
|
const result = {
|
|
1017
1077
|
action,
|
|
@@ -1851,6 +1911,8 @@ async function handleAdvance(projectDir, args) {
|
|
|
1851
1911
|
// the handoff identifier and must enter the project-local RAIL lifecycle.
|
|
1852
1912
|
if (handoffData.rail_handoff) {
|
|
1853
1913
|
const railState = {
|
|
1914
|
+
mode: 'rail',
|
|
1915
|
+
project: { ...session.project, state: 'rail' },
|
|
1854
1916
|
current_agent: 'rail',
|
|
1855
1917
|
last_handoff: agent,
|
|
1856
1918
|
pipeline_position: (session.completed_agents || []).length + 1,
|
|
@@ -1860,12 +1922,28 @@ async function handleAdvance(projectDir, args) {
|
|
|
1860
1922
|
};
|
|
1861
1923
|
const saved = await updateSession(projectDir, railState);
|
|
1862
1924
|
if (saved && saved.saved === false) return errorResult(`Session update failed: ${saved.error}`, 'SESSION_WRITE_FAILED');
|
|
1925
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, session);
|
|
1926
|
+
try {
|
|
1927
|
+
writeSessionLock(projectDir, 'rail', {
|
|
1928
|
+
phase: 'rail', mode: session.execution_mode || 'interactive',
|
|
1929
|
+
position: runtimePipeline.length, total: runtimePipeline.length, progress: 100,
|
|
1930
|
+
});
|
|
1931
|
+
updateClaudeMd(projectDir, {
|
|
1932
|
+
currentAgent: 'rail',
|
|
1933
|
+
progress: { progress: 100, completedCount: runtimePipeline.length, totalAgents: runtimePipeline.length },
|
|
1934
|
+
});
|
|
1935
|
+
} catch { /* non-fatal: the canonical session state has already been persisted */ }
|
|
1863
1936
|
return {
|
|
1864
1937
|
advanced: true,
|
|
1865
1938
|
agent_completed: agent,
|
|
1866
1939
|
score,
|
|
1867
1940
|
rail_ready: true,
|
|
1868
1941
|
rail_handoff: handoffData.rail_handoff,
|
|
1942
|
+
pipeline_progress: {
|
|
1943
|
+
phase: 'rail', progress: 100, completedCount: runtimePipeline.length,
|
|
1944
|
+
totalAgents: runtimePipeline.length, completedAgents: [...(session.completed_agents || []), agent],
|
|
1945
|
+
currentAgent: 'rail', nextAgent: null,
|
|
1946
|
+
},
|
|
1869
1947
|
next: {
|
|
1870
1948
|
action: 'rail_execute',
|
|
1871
1949
|
handoff_id: handoffData.rail_handoff.handoff.handoff_id,
|
|
@@ -2277,8 +2355,10 @@ async function handleStatus(projectDir) {
|
|
|
2277
2355
|
}
|
|
2278
2356
|
|
|
2279
2357
|
// Build model map for all agents
|
|
2358
|
+
const runtimePipeline = getRuntimeAgentPipeline(projectDir, session);
|
|
2359
|
+
const runtimeAgentNames = new Set(runtimePipeline.map(({ name }) => name));
|
|
2280
2360
|
const agentModels = {};
|
|
2281
|
-
for (const agentDef of
|
|
2361
|
+
for (const agentDef of runtimePipeline) {
|
|
2282
2362
|
agentModels[agentDef.name] = resolveAgentModel(agentDef.name, projectDir);
|
|
2283
2363
|
}
|
|
2284
2364
|
|
|
@@ -2309,9 +2389,9 @@ async function handleStatus(projectDir) {
|
|
|
2309
2389
|
handoff_history: handoffHistory,
|
|
2310
2390
|
deviation_count: (session.deviations || []).length,
|
|
2311
2391
|
backlog: session.backlog || [],
|
|
2312
|
-
agents: session.agents || {},
|
|
2392
|
+
agents: Object.fromEntries(Object.entries(session.agents || {}).filter(([name]) => runtimeAgentNames.has(name))),
|
|
2313
2393
|
agent_models: agentModels,
|
|
2314
|
-
context_bracket: estimateContextBracket((session.completed_agents || []).length,
|
|
2394
|
+
context_bracket: estimateContextBracket((session.completed_agents || []).length, runtimePipeline.length),
|
|
2315
2395
|
context: {
|
|
2316
2396
|
model: activeModel,
|
|
2317
2397
|
provider: activeProvider,
|
|
@@ -2434,15 +2514,25 @@ async function handleExit(projectDir, args) {
|
|
|
2434
2514
|
}
|
|
2435
2515
|
|
|
2436
2516
|
async function handleProviders(projectDir) {
|
|
2517
|
+
const artifact = loadRuntimeInstallationV2(projectDir);
|
|
2518
|
+
if (artifact) {
|
|
2519
|
+
const { session } = loadSession(projectDir);
|
|
2520
|
+
const planningAgentModels = {};
|
|
2521
|
+
for (const { name } of getRuntimeAgentPipeline(projectDir, session)) {
|
|
2522
|
+
planningAgentModels[name] = resolveAgentModel(name, projectDir);
|
|
2523
|
+
}
|
|
2524
|
+
return {
|
|
2525
|
+
...describeRuntimeInstallationV2(artifact),
|
|
2526
|
+
planning_agent_models: planningAgentModels,
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2437
2530
|
const agentModels = {};
|
|
2438
2531
|
for (const agentDef of AGENT_PIPELINE) {
|
|
2439
2532
|
agentModels[agentDef.name] = resolveAgentModel(agentDef.name, projectDir);
|
|
2440
2533
|
}
|
|
2441
2534
|
|
|
2442
|
-
const
|
|
2443
|
-
const enabledProviders = artifact
|
|
2444
|
-
? artifact.installation.enabled_providers.map(({ provider_id, harness_id }) => ({ provider_id, harness_id }))
|
|
2445
|
-
: [...new Set(Object.values(agentModels).map(({ provider }) => provider).filter(Boolean))].map((harness_id) => ({ harness_id }));
|
|
2535
|
+
const enabledProviders = [...new Set(Object.values(agentModels).map(({ provider }) => provider).filter(Boolean))].map((harness_id) => ({ harness_id }));
|
|
2446
2536
|
|
|
2447
2537
|
return {
|
|
2448
2538
|
enabled_providers: enabledProviders,
|