@davidorex/pi-workflows 0.6.1 → 0.9.0
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/README.md +1 -1
- package/agents/audit-finding-verifier.agent.yaml +40 -0
- package/agents/audit-results-router.agent.yaml +30 -0
- package/agents/gap-resolution-assessor.agent.yaml +40 -0
- package/dist/expression.d.ts.map +1 -1
- package/dist/expression.js +6 -0
- package/dist/expression.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/step-agent.js +1 -1
- package/dist/step-agent.js.map +1 -1
- package/dist/step-block.d.ts +18 -0
- package/dist/step-block.d.ts.map +1 -0
- package/dist/step-block.js +204 -0
- package/dist/step-block.js.map +1 -0
- package/dist/template-validation.d.ts +25 -0
- package/dist/template-validation.d.ts.map +1 -0
- package/dist/template-validation.js +341 -0
- package/dist/template-validation.js.map +1 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-executor.d.ts.map +1 -1
- package/dist/workflow-executor.js +31 -5
- package/dist/workflow-executor.js.map +1 -1
- package/dist/workflow-sdk.d.ts +1 -0
- package/dist/workflow-sdk.d.ts.map +1 -1
- package/dist/workflow-sdk.js +7 -0
- package/dist/workflow-sdk.js.map +1 -1
- package/dist/workflow-spec.d.ts.map +1 -1
- package/dist/workflow-spec.js +106 -0
- package/dist/workflow-spec.js.map +1 -1
- package/package.json +7 -8
- package/schemas/audit-routing-manifest.schema.json +38 -0
- package/schemas/finding-verification.schema.json +34 -0
- package/schemas/resolution-assessment.schema.json +36 -0
- package/skills/pi-workflows/SKILL.md +1 -1
- package/skills/pi-workflows/references/bundled-resources.md +12 -3
- package/templates/audit-finding-verifier/task.md +59 -0
- package/templates/audit-results-router/task.md +37 -0
- package/templates/gap-resolution-assessor/task.md +48 -0
- package/templates/handoff-writer/task.md +16 -6
- package/templates/phase-author/task.md +8 -0
- package/workflows/create-handoff.workflow.yaml +56 -35
- package/workflows/create-phase.workflow.yaml +27 -32
- package/workflows/do-gap.workflow.yaml +47 -27
- package/workflows/fix-audit.workflow.yaml +89 -127
- package/workflows/gap-to-phase.workflow.yaml +47 -42
- package/workflows/plan-from-requirements.workflow.yaml +16 -27
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"required": ["resolved", "verdict", "resolution_summary", "evidence"],
|
|
4
|
+
"properties": {
|
|
5
|
+
"resolved": {
|
|
6
|
+
"type": "boolean",
|
|
7
|
+
"description": "true if the implementation addresses the gap's described root cause"
|
|
8
|
+
},
|
|
9
|
+
"verdict": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"enum": ["resolved", "partially_resolved", "not_resolved", "checks_failed"],
|
|
12
|
+
"description": "Categorical verdict"
|
|
13
|
+
},
|
|
14
|
+
"resolution_summary": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "What was done and why it addresses (or fails to address) the gap — references specific changes"
|
|
17
|
+
},
|
|
18
|
+
"evidence": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": ["claim", "source"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"claim": { "type": "string" },
|
|
25
|
+
"source": { "type": "string", "description": "File path, diff, or test output supporting the claim" }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"description": "Observable evidence supporting the verdict"
|
|
29
|
+
},
|
|
30
|
+
"unresolved_aspects": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"items": { "type": "string" },
|
|
33
|
+
"description": "Specific aspects of the gap that remain unaddressed (empty if fully resolved)"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -78,7 +78,7 @@ Subcommands: `init`, `list`, `run`, `resume`, `validate`, `status`, `help`
|
|
|
78
78
|
</keyboard_shortcuts>
|
|
79
79
|
|
|
80
80
|
<bundled_resources>
|
|
81
|
-
|
|
81
|
+
24 agents, 14 schemas, 14 workflows, 31 templates bundled.
|
|
82
82
|
See references/bundled-resources.md for full inventory.
|
|
83
83
|
</bundled_resources>
|
|
84
84
|
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# Bundled Resources
|
|
2
2
|
|
|
3
|
-
## agents/ (
|
|
3
|
+
## agents/ (24 files)
|
|
4
4
|
|
|
5
5
|
- `agents/architecture-designer.agent.yaml`
|
|
6
6
|
- `agents/architecture-inferrer.agent.yaml`
|
|
7
|
+
- `agents/audit-finding-verifier.agent.yaml`
|
|
7
8
|
- `agents/audit-fixer.agent.yaml`
|
|
9
|
+
- `agents/audit-results-router.agent.yaml`
|
|
8
10
|
- `agents/code-explorer.agent.yaml`
|
|
9
11
|
- `agents/decomposer.agent.yaml`
|
|
10
12
|
- `agents/gap-identifier.agent.yaml`
|
|
13
|
+
- `agents/gap-resolution-assessor.agent.yaml`
|
|
11
14
|
- `agents/handoff-writer.agent.yaml`
|
|
12
15
|
- `agents/investigator.agent.yaml`
|
|
13
16
|
- `agents/pattern-analyzer.agent.yaml`
|
|
@@ -24,16 +27,19 @@
|
|
|
24
27
|
- `agents/synthesizer.agent.yaml`
|
|
25
28
|
- `agents/verifier.agent.yaml`
|
|
26
29
|
|
|
27
|
-
## schemas/ (
|
|
30
|
+
## schemas/ (14 files)
|
|
28
31
|
|
|
32
|
+
- `schemas/audit-routing-manifest.schema.json`
|
|
29
33
|
- `schemas/decomposition-specs.schema.json`
|
|
30
34
|
- `schemas/execution-results.schema.json`
|
|
35
|
+
- `schemas/finding-verification.schema.json`
|
|
31
36
|
- `schemas/investigation-findings.schema.json`
|
|
32
37
|
- `schemas/pattern-analysis.schema.json`
|
|
33
38
|
- `schemas/phase.schema.json`
|
|
34
39
|
- `schemas/plan-breakdown.schema.json`
|
|
35
40
|
- `schemas/quality-analysis.schema.json`
|
|
36
41
|
- `schemas/research-findings.schema.json`
|
|
42
|
+
- `schemas/resolution-assessment.schema.json`
|
|
37
43
|
- `schemas/structure-analysis.schema.json`
|
|
38
44
|
- `schemas/synthesis.schema.json`
|
|
39
45
|
- `schemas/verifier-output.schema.json`
|
|
@@ -55,7 +61,7 @@
|
|
|
55
61
|
- `workflows/self-implement.workflow.yaml`
|
|
56
62
|
- `workflows/typed-analysis.workflow.yaml`
|
|
57
63
|
|
|
58
|
-
## templates/ (
|
|
64
|
+
## templates/ (31 files)
|
|
59
65
|
|
|
60
66
|
- `templates/analyzers/base-analyzer.md`
|
|
61
67
|
- `templates/analyzers/macros.md`
|
|
@@ -67,11 +73,14 @@
|
|
|
67
73
|
- `templates/analyzers/structure.md`
|
|
68
74
|
- `templates/architecture-designer/task.md`
|
|
69
75
|
- `templates/architecture-inferrer/task.md`
|
|
76
|
+
- `templates/audit-finding-verifier/task.md`
|
|
70
77
|
- `templates/audit-fixer/task.md`
|
|
78
|
+
- `templates/audit-results-router/task.md`
|
|
71
79
|
- `templates/decomposer/task.md`
|
|
72
80
|
- `templates/explorer/system.md`
|
|
73
81
|
- `templates/explorer/task.md`
|
|
74
82
|
- `templates/gap-identifier/task.md`
|
|
83
|
+
- `templates/gap-resolution-assessor/task.md`
|
|
75
84
|
- `templates/handoff-writer/task.md`
|
|
76
85
|
- `templates/investigator/task.md`
|
|
77
86
|
- `templates/phase-author/task.md`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Verify whether the following audit findings have been resolved.
|
|
2
|
+
|
|
3
|
+
## Audit Findings
|
|
4
|
+
|
|
5
|
+
{% for finding in audit.findings %}
|
|
6
|
+
### Finding: {{ finding.id }}
|
|
7
|
+
|
|
8
|
+
**Description**: {{ finding.description }}
|
|
9
|
+
**Severity**: {{ finding.severity | default("unspecified") }}
|
|
10
|
+
**Category**: {{ finding.category | default("unspecified") }}
|
|
11
|
+
**Principle**: {{ finding.principle | default("unspecified") }}
|
|
12
|
+
|
|
13
|
+
**Locations**:
|
|
14
|
+
{% for loc in finding.locations %}
|
|
15
|
+
- `{{ loc.file }}` {% if loc.line %}line {{ loc.line }}{% endif %} {% if loc.description %} — {{ loc.description }}{% endif %}
|
|
16
|
+
{% endfor %}
|
|
17
|
+
|
|
18
|
+
{% if finding.fix %}
|
|
19
|
+
**Fix suggestion**: {{ finding.fix.suggestion | default("none") }}
|
|
20
|
+
{% endif %}
|
|
21
|
+
|
|
22
|
+
{% if finding.resolution and finding.resolution.status == 'passed' %}
|
|
23
|
+
*Previously marked as resolved — re-verify.*
|
|
24
|
+
{% endif %}
|
|
25
|
+
---
|
|
26
|
+
{% endfor %}
|
|
27
|
+
|
|
28
|
+
## Implementation Results
|
|
29
|
+
|
|
30
|
+
{% if implementation_results is iterable and implementation_results is not string %}
|
|
31
|
+
{% for result in implementation_results %}
|
|
32
|
+
- {{ result.spec_name | default(result.name | default("task")) }}: {{ result.status | default("unknown") }}
|
|
33
|
+
{% endfor %}
|
|
34
|
+
{% else %}
|
|
35
|
+
```json
|
|
36
|
+
{{ implementation_results | dump(2) }}
|
|
37
|
+
```
|
|
38
|
+
{% endif %}
|
|
39
|
+
|
|
40
|
+
{% if conformance_reference %}
|
|
41
|
+
## Conformance Reference
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{{ conformance_reference | dump(2) }}
|
|
45
|
+
```
|
|
46
|
+
{% endif %}
|
|
47
|
+
|
|
48
|
+
## Instructions
|
|
49
|
+
|
|
50
|
+
For EACH finding above:
|
|
51
|
+
|
|
52
|
+
1. Read the code at the referenced location(s)
|
|
53
|
+
2. Determine if the finding's described issue is addressed
|
|
54
|
+
3. Record your verdict: `passed`, `failed`, or `needs_inspect`
|
|
55
|
+
4. Provide specific evidence (code snippet, file:line reference)
|
|
56
|
+
|
|
57
|
+
Do NOT use grep exit codes as evidence. Read the code and assess whether the issue described in the finding is genuinely resolved.
|
|
58
|
+
|
|
59
|
+
Produce JSON output with a `findings` array containing one entry per finding, plus summary statistics.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Review the audit fix results and produce a routing manifest.
|
|
2
|
+
|
|
3
|
+
## Implementation Results
|
|
4
|
+
|
|
5
|
+
{% if implementation_results is iterable and implementation_results is not string %}
|
|
6
|
+
{% for result in implementation_results %}
|
|
7
|
+
### Task: {{ result.spec_name | default(result.name | default("unnamed")) }}
|
|
8
|
+
|
|
9
|
+
- Status: {{ result.status | default("unknown") }}
|
|
10
|
+
{% if result.decisions %}
|
|
11
|
+
- Decisions: {{ result.decisions | length }}
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% if result.issues %}
|
|
14
|
+
- Issues flagged: {{ result.issues | length }}
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% endfor %}
|
|
17
|
+
{% else %}
|
|
18
|
+
```json
|
|
19
|
+
{{ implementation_results | dump(2) }}
|
|
20
|
+
```
|
|
21
|
+
{% endif %}
|
|
22
|
+
|
|
23
|
+
## Verification Results
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{{ verification | dump(2) }}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Instructions
|
|
30
|
+
|
|
31
|
+
Produce a routing manifest with:
|
|
32
|
+
|
|
33
|
+
1. **decisions** — validated decisions from implementation results (with complete id, description, rationale fields)
|
|
34
|
+
2. **new_gaps** — genuine issues that should be tracked (with stable id, description, status: "open", category, priority)
|
|
35
|
+
3. **summary** — accurate summary of what was completed, what failed, what needs inspection
|
|
36
|
+
|
|
37
|
+
Only include items that are well-formed and represent genuine project artifacts. Do not route items that are missing required fields or describe hypothetical concerns.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Assess whether the implementation resolves this gap.
|
|
2
|
+
|
|
3
|
+
## Gap
|
|
4
|
+
|
|
5
|
+
**ID**: {{ gap.id }}
|
|
6
|
+
**Description**: {{ gap.description }}
|
|
7
|
+
**Category**: {{ gap.category | default("unspecified") }}
|
|
8
|
+
**Priority**: {{ gap.priority | default("unspecified") }}
|
|
9
|
+
|
|
10
|
+
## Investigation Findings
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{{ investigation | dump(2) }}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Implementation Results
|
|
17
|
+
|
|
18
|
+
{% if implementation_results is iterable and implementation_results is not string %}
|
|
19
|
+
{% for result in implementation_results %}
|
|
20
|
+
### Spec: {{ result.spec_name | default("unnamed") }}
|
|
21
|
+
- Status: {{ result.status | default("unknown") }}
|
|
22
|
+
- Files changed: {{ result.files_changed | default([]) | join(", ") }}
|
|
23
|
+
{% if result.commit_hash %}- Commit: {{ result.commit_hash }}{% endif %}
|
|
24
|
+
{% endfor %}
|
|
25
|
+
{% else %}
|
|
26
|
+
```json
|
|
27
|
+
{{ implementation_results | dump(2) }}
|
|
28
|
+
```
|
|
29
|
+
{% endif %}
|
|
30
|
+
|
|
31
|
+
## Check Results
|
|
32
|
+
|
|
33
|
+
- Status: {{ check_results.status }}
|
|
34
|
+
{% if check_results.errors | length > 0 %}
|
|
35
|
+
- Errors:
|
|
36
|
+
{% for err in check_results.errors %}
|
|
37
|
+
- {{ err }}
|
|
38
|
+
{% endfor %}
|
|
39
|
+
{% endif %}
|
|
40
|
+
|
|
41
|
+
## Instructions
|
|
42
|
+
|
|
43
|
+
1. Read the gap description above. Understand what root cause it identifies.
|
|
44
|
+
2. Examine the implementation results — what files were changed and what was the stated work.
|
|
45
|
+
3. Run `git diff HEAD~{{ implementation_results | length | default(1) }}` (or appropriate range) to see actual code changes.
|
|
46
|
+
4. Judge: do the code changes address the root cause described in the gap?
|
|
47
|
+
5. If tests failed or lint errors exist, the gap is NOT resolved regardless of code quality.
|
|
48
|
+
6. Produce your assessment as JSON.
|
|
@@ -2,27 +2,37 @@ Capture a handoff snapshot for the project at `{{ path }}`.
|
|
|
2
2
|
|
|
3
3
|
## Current Project State
|
|
4
4
|
|
|
5
|
-
{% if project_state.
|
|
5
|
+
{% if project_state.blocks_status %}
|
|
6
|
+
### Block Availability
|
|
7
|
+
|
|
8
|
+
| Block | Available |
|
|
9
|
+
|-------|-----------|
|
|
10
|
+
{% for name, available in project_state.blocks_status %}
|
|
11
|
+
| {{ name }} | {{ "yes" if available else "NO — absent" }} |
|
|
12
|
+
{% endfor %}
|
|
13
|
+
{% endif %}
|
|
14
|
+
|
|
15
|
+
{% if project_state.project %}
|
|
6
16
|
### Project
|
|
7
17
|
**{{ project_state.project.name | default("unnamed") }}** — {{ project_state.project.description | default("no description") }}
|
|
8
18
|
Status: {{ project_state.project.status | default("unknown") }}
|
|
9
19
|
{% endif %}
|
|
10
20
|
|
|
11
|
-
{% if project_state.phases
|
|
21
|
+
{% if project_state.phases and project_state.phases | length > 0 %}
|
|
12
22
|
### Phases
|
|
13
23
|
{% for phase in project_state.phases %}
|
|
14
24
|
- Phase {{ phase.number | default(loop.index) }}: {{ phase.name | default("unnamed") }} ({{ phase.status | default("unknown") }})
|
|
15
25
|
{% endfor %}
|
|
16
26
|
{% endif %}
|
|
17
27
|
|
|
18
|
-
{% if project_state.blockSummaries
|
|
28
|
+
{% if project_state.blockSummaries %}
|
|
19
29
|
### Block Summaries
|
|
20
30
|
{% for block in project_state.blockSummaries %}
|
|
21
31
|
- **{{ block.name }}**: {{ block.count | default("?") }} entries
|
|
22
32
|
{% endfor %}
|
|
23
33
|
{% endif %}
|
|
24
34
|
|
|
25
|
-
{% if project_state.gaps
|
|
35
|
+
{% if project_state.gaps %}
|
|
26
36
|
### Open Gaps
|
|
27
37
|
{% for gap in project_state.gaps %}
|
|
28
38
|
{% if gap.status == "open" %}
|
|
@@ -31,14 +41,14 @@ Status: {{ project_state.project.status | default("unknown") }}
|
|
|
31
41
|
{% endfor %}
|
|
32
42
|
{% endif %}
|
|
33
43
|
|
|
34
|
-
{% if project_state.decisions
|
|
44
|
+
{% if project_state.decisions %}
|
|
35
45
|
### Recent Decisions
|
|
36
46
|
{% for decision in project_state.decisions %}
|
|
37
47
|
- {{ decision.id | default("?") }}: {{ decision.description | default(decision.title | default("no description")) }}
|
|
38
48
|
{% endfor %}
|
|
39
49
|
{% endif %}
|
|
40
50
|
|
|
41
|
-
{% if project_state.recentCommits
|
|
51
|
+
{% if project_state.recentCommits %}
|
|
42
52
|
### Recent Commits
|
|
43
53
|
{% for commit in project_state.recentCommits %}
|
|
44
54
|
- `{{ commit.sha | default("?") | truncate(7, true, "") }}` {{ commit.message | default("no message") }}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- Phase {{ phase.number }}: {{ phase.name }} ({{ phase.status }})
|
|
9
9
|
{% endfor %}
|
|
10
10
|
|
|
11
|
+
{% if architecture and architecture.modules %}
|
|
11
12
|
## Current Architecture
|
|
12
13
|
|
|
13
14
|
{% for module in architecture.modules %}
|
|
@@ -20,13 +21,17 @@
|
|
|
20
21
|
{{ loop.index }}. **{{ stage.stage }}**: {{ stage.description }}
|
|
21
22
|
{% endfor %}
|
|
22
23
|
{% endif %}
|
|
24
|
+
{% endif %}
|
|
23
25
|
|
|
26
|
+
{% if conventions and conventions.rules %}
|
|
24
27
|
## Conventions
|
|
25
28
|
|
|
26
29
|
{% for rule in conventions.rules %}
|
|
27
30
|
- {{ rule.id }}: {{ rule.description }} ({{ rule.enforcement }})
|
|
28
31
|
{% endfor %}
|
|
32
|
+
{% endif %}
|
|
29
33
|
|
|
34
|
+
{% if gaps %}
|
|
30
35
|
## Current Gaps
|
|
31
36
|
|
|
32
37
|
{% for gap in gaps %}
|
|
@@ -34,13 +39,16 @@
|
|
|
34
39
|
- [{{ gap.priority }}] {{ gap.id }}: {{ gap.description }}
|
|
35
40
|
{% endif %}
|
|
36
41
|
{% endfor %}
|
|
42
|
+
{% endif %}
|
|
37
43
|
|
|
44
|
+
{% if inventory %}
|
|
38
45
|
## Current Inventory
|
|
39
46
|
|
|
40
47
|
- Step types: {{ inventory.step_types | length }}
|
|
41
48
|
- Agent specs: {{ inventory.agent_specs | length }}
|
|
42
49
|
- Schemas: {{ inventory.schemas | length }}
|
|
43
50
|
- Tests: {{ inventory.test_count }}
|
|
51
|
+
{% endif %}
|
|
44
52
|
|
|
45
53
|
## Instructions
|
|
46
54
|
|
|
@@ -3,52 +3,73 @@ description: Capture current work context for session resume
|
|
|
3
3
|
version: "1"
|
|
4
4
|
|
|
5
5
|
steps:
|
|
6
|
-
load-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const state = {};
|
|
13
|
-
|
|
14
|
-
// Read project identity
|
|
15
|
-
try { state.project = JSON.parse(fs.readFileSync(path.join(projectDir, 'project.json'), 'utf-8')); } catch {}
|
|
6
|
+
load-blocks:
|
|
7
|
+
block:
|
|
8
|
+
read: [project, gaps, decisions, tasks]
|
|
9
|
+
optional: [project, gaps, decisions, tasks]
|
|
10
|
+
output:
|
|
11
|
+
format: json
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}).filter(Boolean);
|
|
23
|
-
} catch { state.phases = []; }
|
|
13
|
+
load-phases:
|
|
14
|
+
block:
|
|
15
|
+
readDir: phases
|
|
16
|
+
output:
|
|
17
|
+
format: json
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
state.decisions = JSON.parse(fs.readFileSync(path.join(projectDir, 'decisions.json'), 'utf-8'));
|
|
31
|
-
} catch {}
|
|
19
|
+
load-git:
|
|
20
|
+
command: |
|
|
21
|
+
node -e "
|
|
22
|
+
const { execSync } = require('child_process');
|
|
23
|
+
const git = {};
|
|
32
24
|
try {
|
|
33
|
-
|
|
34
|
-
} catch {
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
git.recent_commits = execSync('git log --oneline -10', { encoding: 'utf-8' }).trim().split('\n');
|
|
26
|
+
} catch (e) {
|
|
27
|
+
git.recent_commits = [];
|
|
28
|
+
git.commits_error = e.message || 'git log failed';
|
|
29
|
+
}
|
|
37
30
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
console.log(JSON.stringify(
|
|
31
|
+
git.changed_files = execSync('git diff --name-only HEAD~3 2>/dev/null || echo \"\"', { encoding: 'utf-8' }).trim().split('\n').filter(Boolean);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
git.changed_files = [];
|
|
34
|
+
git.files_error = e.message || 'git diff failed';
|
|
35
|
+
}
|
|
36
|
+
console.log(JSON.stringify(git));
|
|
44
37
|
"
|
|
45
38
|
output:
|
|
46
39
|
format: json
|
|
47
40
|
|
|
41
|
+
assemble-state:
|
|
42
|
+
command: |
|
|
43
|
+
node -e "
|
|
44
|
+
const blocks = JSON.parse(process.argv[1]);
|
|
45
|
+
const phases = JSON.parse(process.argv[2]);
|
|
46
|
+
const git = JSON.parse(process.argv[3]);
|
|
47
|
+
console.log(JSON.stringify({
|
|
48
|
+
project: blocks.project,
|
|
49
|
+
phases: phases,
|
|
50
|
+
gaps: blocks.gaps,
|
|
51
|
+
decisions: blocks.decisions,
|
|
52
|
+
tasks: blocks.tasks,
|
|
53
|
+
recentCommits: git.recent_commits || [],
|
|
54
|
+
changedFiles: git.changed_files || [],
|
|
55
|
+
blocks_status: {
|
|
56
|
+
project: blocks.project != null,
|
|
57
|
+
gaps: blocks.gaps != null,
|
|
58
|
+
decisions: blocks.decisions != null,
|
|
59
|
+
tasks: blocks.tasks != null,
|
|
60
|
+
phases: phases.length > 0,
|
|
61
|
+
git_commits: !git.commits_error,
|
|
62
|
+
git_files: !git.files_error
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
" '${{ steps.load-blocks.output | json }}' '${{ steps.load-phases.output | json }}' '${{ steps.load-git.output | json }}'
|
|
66
|
+
output:
|
|
67
|
+
format: json
|
|
68
|
+
|
|
48
69
|
capture:
|
|
49
70
|
agent: handoff-writer
|
|
50
71
|
input:
|
|
51
|
-
project_state: ${{ steps.
|
|
72
|
+
project_state: ${{ steps.assemble-state.output }}
|
|
52
73
|
path: "."
|
|
53
74
|
output:
|
|
54
75
|
format: json
|
|
@@ -11,28 +11,16 @@ input:
|
|
|
11
11
|
description: Unstructured intent from conversation — what needs to be built and why
|
|
12
12
|
|
|
13
13
|
steps:
|
|
14
|
+
load-phases:
|
|
15
|
+
block:
|
|
16
|
+
readDir: phases
|
|
17
|
+
output:
|
|
18
|
+
format: json
|
|
19
|
+
|
|
14
20
|
load-context:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import path from 'path';
|
|
19
|
-
const phasesDir = '.project/phases';
|
|
20
|
-
let phases = [];
|
|
21
|
-
try {
|
|
22
|
-
phases = fs.readdirSync(phasesDir)
|
|
23
|
-
.filter(f => f.endsWith('.json'))
|
|
24
|
-
.map(f => JSON.parse(fs.readFileSync(path.join(phasesDir, f), 'utf8')));
|
|
25
|
-
} catch {}
|
|
26
|
-
let arch = {};
|
|
27
|
-
try { arch = JSON.parse(fs.readFileSync('.project/architecture.json', 'utf8')); } catch {}
|
|
28
|
-
let conv = {};
|
|
29
|
-
try { conv = JSON.parse(fs.readFileSync('.project/conventions.json', 'utf8')); } catch {}
|
|
30
|
-
let gapsData = { gaps: [] };
|
|
31
|
-
try { gapsData = JSON.parse(fs.readFileSync('.project/gaps.json', 'utf8')); } catch {}
|
|
32
|
-
let inv = {};
|
|
33
|
-
try { inv = JSON.parse(fs.readFileSync('.project/inventory.json', 'utf8')); } catch {}
|
|
34
|
-
console.log(JSON.stringify({ phases, architecture: arch, conventions: conv, gaps: gapsData.gaps, inventory: inv }));
|
|
35
|
-
"
|
|
21
|
+
block:
|
|
22
|
+
read: [architecture, conventions, gaps, inventory]
|
|
23
|
+
optional: [architecture, conventions, gaps, inventory]
|
|
36
24
|
output:
|
|
37
25
|
format: json
|
|
38
26
|
|
|
@@ -40,32 +28,39 @@ steps:
|
|
|
40
28
|
agent: phase-author
|
|
41
29
|
input:
|
|
42
30
|
intent: "${{ input.intent }}"
|
|
43
|
-
phases: "${{ steps.load-
|
|
31
|
+
phases: "${{ steps.load-phases.output }}"
|
|
44
32
|
architecture: "${{ steps.load-context.output.architecture }}"
|
|
45
33
|
conventions: "${{ steps.load-context.output.conventions }}"
|
|
46
|
-
gaps: "${{ steps.load-context.output.gaps }}"
|
|
34
|
+
gaps: "${{ steps.load-context.output.gaps.gaps }}"
|
|
47
35
|
inventory: "${{ steps.load-context.output.inventory }}"
|
|
48
36
|
output:
|
|
49
37
|
format: json
|
|
50
38
|
schema: block:phase
|
|
51
39
|
|
|
52
|
-
|
|
40
|
+
compute-phase-path:
|
|
53
41
|
command: |
|
|
54
|
-
node
|
|
55
|
-
import fs from 'fs';
|
|
42
|
+
node -e "
|
|
56
43
|
const phase = JSON.parse(process.argv[1]);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.log(JSON.stringify({ path: filename, phase_number: phase.number, spec_count: phase.specs.length }));
|
|
44
|
+
const num = String(phase.number).padStart(2, '0');
|
|
45
|
+
const name = phase.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-+$/g, '');
|
|
46
|
+
console.log(JSON.stringify({ path: 'phases/' + num + '-' + name }));
|
|
61
47
|
" '${{ steps.author.output | json }}'
|
|
62
48
|
output:
|
|
63
49
|
format: json
|
|
64
50
|
|
|
51
|
+
write-phase:
|
|
52
|
+
block:
|
|
53
|
+
write:
|
|
54
|
+
name: phase
|
|
55
|
+
data: "${{ steps.author.output }}"
|
|
56
|
+
path: "${{ steps.compute-phase-path.output.path }}"
|
|
57
|
+
output:
|
|
58
|
+
format: json
|
|
59
|
+
|
|
65
60
|
completion:
|
|
66
61
|
message: |
|
|
67
|
-
Phase ${{ steps.
|
|
68
|
-
Contains ${{ steps.
|
|
62
|
+
Phase ${{ steps.author.output.number }} created at ${{ steps.write-phase.output.path }}
|
|
63
|
+
Contains ${{ steps.author.output.specs | length }} specs.
|
|
69
64
|
include:
|
|
70
65
|
- steps.author.output.success_criteria
|
|
71
66
|
- steps.author.output.specs
|