cadence-skill-installer 0.2.37 → 0.2.39
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 -0
- package/package.json +1 -1
- package/scripts/install-cadence-skill.mjs +152 -1
- package/skill/scripts/run-prerequisite-gate.py +43 -7
- package/skill/skills/brownfield-documenter/SKILL.md +25 -0
- package/skill/skills/brownfield-documenter/agents/openai.yaml +1 -0
- package/skill/skills/brownfield-intake/SKILL.md +30 -0
- package/skill/skills/brownfield-intake/agents/openai.yaml +1 -0
- package/skill/skills/ideation-updater/SKILL.md +40 -0
- package/skill/skills/ideation-updater/agents/openai.yaml +1 -0
- package/skill/skills/ideator/SKILL.md +39 -0
- package/skill/skills/ideator/agents/openai.yaml +1 -0
- package/skill/skills/planner/SKILL.md +28 -0
- package/skill/skills/planner/agents/openai.yaml +1 -0
- package/skill/skills/prerequisite-gate/SKILL.md +29 -3
- package/skill/skills/prerequisite-gate/agents/openai.yaml +2 -1
- package/skill/skills/project-progress/SKILL.md +62 -7
- package/skill/skills/project-progress/agents/openai.yaml +4 -0
- package/skill/skills/researcher/SKILL.md +83 -4
- package/skill/skills/researcher/agents/openai.yaml +4 -1
- package/skill/skills/scaffold/SKILL.md +27 -0
- package/skill/skills/scaffold/agents/openai.yaml +1 -0
- package/skill/tests/test_run_prerequisite_gate.py +89 -0
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ The installer shows a multi-select prompt (comma-separated choices) so you can i
|
|
|
12
12
|
If a selected tool already has Cadence installed, the installer prints an update notice and warns that files will be overwritten.
|
|
13
13
|
In TTY terminals, selection is a real interactive TUI: use arrow keys (or `j`/`k`) to move, `space` to toggle, `a` to toggle all, and `enter` to confirm.
|
|
14
14
|
The TUI includes color highlighting and a large ASCII `CADANCE` header.
|
|
15
|
+
Before copying skill files, the installer checks for `python3`; if missing, it warns and offers to install Python 3 using a detected system package manager.
|
|
15
16
|
|
|
16
17
|
## Non-interactive examples
|
|
17
18
|
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import readline from "node:readline/promises";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
9
|
import { stdin as input, stdout as output } from "node:process";
|
|
9
10
|
|
|
@@ -106,7 +107,11 @@ function printHelp(binName, installerVersion) {
|
|
|
106
107
|
" --all Install to all supported tools.",
|
|
107
108
|
" --yes Skip confirmation prompt.",
|
|
108
109
|
" --home <path> Override home directory for destination paths.",
|
|
109
|
-
" --help Show this message."
|
|
110
|
+
" --help Show this message.",
|
|
111
|
+
"",
|
|
112
|
+
"Prerequisite:",
|
|
113
|
+
" python3 is required for Cadence workflow scripts. Installer preflight checks",
|
|
114
|
+
" python3 and can offer installation guidance in interactive runs."
|
|
110
115
|
].join("\n") + "\n"
|
|
111
116
|
);
|
|
112
117
|
}
|
|
@@ -154,6 +159,150 @@ function parseArgs(argv) {
|
|
|
154
159
|
return parsed;
|
|
155
160
|
}
|
|
156
161
|
|
|
162
|
+
function isCommandAvailable(command) {
|
|
163
|
+
if (process.platform === "win32") {
|
|
164
|
+
const result = spawnSync("where", [command], { stdio: "ignore" });
|
|
165
|
+
return result.status === 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const result = spawnSync("sh", ["-lc", `command -v ${command}`], { stdio: "ignore" });
|
|
169
|
+
return result.status === 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function withOptionalSudo(command, args) {
|
|
173
|
+
const display = `${command} ${args.join(" ")}`.trim();
|
|
174
|
+
if (process.platform === "win32") {
|
|
175
|
+
return { command, args, display };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
179
|
+
if (isRoot || !isCommandAvailable("sudo")) {
|
|
180
|
+
return { command, args, display };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
command: "sudo",
|
|
185
|
+
args: [command, ...args],
|
|
186
|
+
display: `sudo ${display}`
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function detectPythonInstallCommand() {
|
|
191
|
+
if (process.platform === "darwin") {
|
|
192
|
+
if (isCommandAvailable("brew")) {
|
|
193
|
+
return {
|
|
194
|
+
command: "brew",
|
|
195
|
+
args: ["install", "python"],
|
|
196
|
+
display: "brew install python"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (process.platform === "linux") {
|
|
203
|
+
if (isCommandAvailable("apt-get")) {
|
|
204
|
+
return withOptionalSudo("apt-get", ["install", "-y", "python3"]);
|
|
205
|
+
}
|
|
206
|
+
if (isCommandAvailable("dnf")) {
|
|
207
|
+
return withOptionalSudo("dnf", ["install", "-y", "python3"]);
|
|
208
|
+
}
|
|
209
|
+
if (isCommandAvailable("yum")) {
|
|
210
|
+
return withOptionalSudo("yum", ["install", "-y", "python3"]);
|
|
211
|
+
}
|
|
212
|
+
if (isCommandAvailable("pacman")) {
|
|
213
|
+
return withOptionalSudo("pacman", ["-Sy", "--noconfirm", "python"]);
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (process.platform === "win32") {
|
|
219
|
+
if (isCommandAvailable("winget")) {
|
|
220
|
+
return {
|
|
221
|
+
command: "winget",
|
|
222
|
+
args: ["install", "-e", "--id", "Python.Python.3.12"],
|
|
223
|
+
display: "winget install -e --id Python.Python.3.12"
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
if (isCommandAvailable("choco")) {
|
|
227
|
+
return {
|
|
228
|
+
command: "choco",
|
|
229
|
+
args: ["install", "-y", "python"],
|
|
230
|
+
display: "choco install -y python"
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function confirmPythonInstall(commandDisplay) {
|
|
240
|
+
const rl = readline.createInterface({ input, output });
|
|
241
|
+
try {
|
|
242
|
+
const answer = await rl.question(
|
|
243
|
+
style(
|
|
244
|
+
`Python 3 is required and not detected. Install now using "${commandDisplay}"? [y/N]: `,
|
|
245
|
+
ANSI.bold,
|
|
246
|
+
ANSI.white
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
const normalized = answer.trim().toLowerCase();
|
|
250
|
+
return normalized === "y" || normalized === "yes";
|
|
251
|
+
} finally {
|
|
252
|
+
rl.close();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function ensurePythonInstalled(parsed) {
|
|
257
|
+
if (isCommandAvailable("python3")) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
output.write(
|
|
262
|
+
style(
|
|
263
|
+
"\nWarning: python3 is missing. Cadence workflow scripts require Python 3.\n",
|
|
264
|
+
ANSI.bold,
|
|
265
|
+
ANSI.brightYellow
|
|
266
|
+
)
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const installCommand = detectPythonInstallCommand();
|
|
270
|
+
if (!installCommand) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
"python3 is missing and no supported automatic installer was detected. Install Python 3 manually, then rerun cadence-skill-installer."
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const canPrompt = input.isTTY && output.isTTY && !parsed.yes;
|
|
277
|
+
if (!canPrompt) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
`python3 is missing. Re-run installer interactively to allow automatic installation with: ${installCommand.display}`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const installApproved = await confirmPythonInstall(installCommand.display);
|
|
284
|
+
if (!installApproved) {
|
|
285
|
+
throw new Error("python3 is required. Install Python 3 and rerun cadence-skill-installer.");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
output.write(style(`\nInstalling Python 3 via: ${installCommand.display}\n`, ANSI.bold, ANSI.brightCyan));
|
|
289
|
+
const installResult = spawnSync(installCommand.command, installCommand.args, {
|
|
290
|
+
stdio: "inherit"
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (installResult.error) {
|
|
294
|
+
throw new Error(`Failed to run Python installer command: ${installResult.error.message}`);
|
|
295
|
+
}
|
|
296
|
+
if (installResult.status !== 0) {
|
|
297
|
+
throw new Error("Python installation command failed.");
|
|
298
|
+
}
|
|
299
|
+
if (!isCommandAvailable("python3")) {
|
|
300
|
+
throw new Error("Python installation completed, but python3 is still not detected on PATH.");
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
output.write(style("Python 3 detected. Continuing installation.\n", ANSI.bold, ANSI.brightGreen));
|
|
304
|
+
}
|
|
305
|
+
|
|
157
306
|
async function readInstallerVersion() {
|
|
158
307
|
try {
|
|
159
308
|
const raw = await fs.readFile(PACKAGE_JSON_PATH, "utf8");
|
|
@@ -583,6 +732,8 @@ async function main() {
|
|
|
583
732
|
return;
|
|
584
733
|
}
|
|
585
734
|
|
|
735
|
+
await ensurePythonInstalled(parsed);
|
|
736
|
+
|
|
586
737
|
const homeDir = parsed.home || os.homedir();
|
|
587
738
|
const sourceDir = resolveSourceDir();
|
|
588
739
|
await ensureSourceDir(sourceDir);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
5
5
|
import json
|
|
6
|
-
import shutil
|
|
7
6
|
import subprocess
|
|
8
7
|
import sys
|
|
9
8
|
from pathlib import Path
|
|
@@ -14,6 +13,13 @@ from project_root import resolve_project_root, write_project_root_hint
|
|
|
14
13
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
15
14
|
RESOLVE_SCRIPT = SCRIPT_DIR / "resolve-project-scripts-dir.py"
|
|
16
15
|
ROUTE_GUARD_SCRIPT = SCRIPT_DIR / "assert-workflow-route.py"
|
|
16
|
+
REQUIRED_RUNTIME_ASSETS = (
|
|
17
|
+
"handle-prerequisite-state.py",
|
|
18
|
+
"read-workflow-state.py",
|
|
19
|
+
"set-workflow-item-status.py",
|
|
20
|
+
"finalize-skill-checkpoint.py",
|
|
21
|
+
"workflow_state.py",
|
|
22
|
+
)
|
|
17
23
|
|
|
18
24
|
|
|
19
25
|
def run_command(command):
|
|
@@ -76,6 +82,21 @@ def resolve_scripts_dir(project_root: Path):
|
|
|
76
82
|
return scripts_dir
|
|
77
83
|
|
|
78
84
|
|
|
85
|
+
def assert_runtime_assets(scripts_dir: str):
|
|
86
|
+
scripts_path = Path(scripts_dir)
|
|
87
|
+
missing: list[str] = []
|
|
88
|
+
for asset in REQUIRED_RUNTIME_ASSETS:
|
|
89
|
+
if not (scripts_path / asset).is_file():
|
|
90
|
+
missing.append(asset)
|
|
91
|
+
|
|
92
|
+
if missing:
|
|
93
|
+
print(
|
|
94
|
+
"MISSING_CADENCE_RUNTIME_ASSET:" + ",".join(sorted(missing)),
|
|
95
|
+
file=sys.stderr,
|
|
96
|
+
)
|
|
97
|
+
raise SystemExit(1)
|
|
98
|
+
|
|
99
|
+
|
|
79
100
|
def read_prerequisite_state(scripts_dir, project_root: Path):
|
|
80
101
|
script_path = Path(scripts_dir) / "handle-prerequisite-state.py"
|
|
81
102
|
result = run_command(
|
|
@@ -139,18 +160,33 @@ def main():
|
|
|
139
160
|
scripts_dir = str(scripts_path)
|
|
140
161
|
else:
|
|
141
162
|
scripts_dir = resolve_scripts_dir(project_root)
|
|
163
|
+
assert_runtime_assets(scripts_dir)
|
|
142
164
|
state = read_prerequisite_state(scripts_dir, project_root)
|
|
143
165
|
|
|
144
166
|
if state == "true":
|
|
145
|
-
print(
|
|
167
|
+
print(
|
|
168
|
+
json.dumps(
|
|
169
|
+
{
|
|
170
|
+
"status": "ok",
|
|
171
|
+
"prerequisites_pass": True,
|
|
172
|
+
"source": "cache",
|
|
173
|
+
"runtime_assets": "ok",
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
)
|
|
146
177
|
return
|
|
147
178
|
|
|
148
|
-
if shutil.which("python3") is None:
|
|
149
|
-
print("MISSING_PYTHON3", file=sys.stderr)
|
|
150
|
-
raise SystemExit(1)
|
|
151
|
-
|
|
152
179
|
write_prerequisite_state(scripts_dir, "1", project_root)
|
|
153
|
-
print(
|
|
180
|
+
print(
|
|
181
|
+
json.dumps(
|
|
182
|
+
{
|
|
183
|
+
"status": "ok",
|
|
184
|
+
"prerequisites_pass": True,
|
|
185
|
+
"source": "fresh-check",
|
|
186
|
+
"runtime_assets": "ok",
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
)
|
|
154
190
|
|
|
155
191
|
|
|
156
192
|
if __name__ == "__main__":
|
|
@@ -60,3 +60,28 @@ description: Perform deep evidence-based analysis of an existing codebase and pe
|
|
|
60
60
|
15. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
61
61
|
16. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
62
62
|
17. In normal user-facing updates, report brownfield findings and persisted ideation outcomes without raw command traces or internal routing details unless explicitly requested.
|
|
63
|
+
|
|
64
|
+
## Strict Response Format
|
|
65
|
+
|
|
66
|
+
- If clarification is required before persistence, respond exactly:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
Brownfield documentation in progress:
|
|
70
|
+
|
|
71
|
+
- Missing detail: <single highest-leverage gap>
|
|
72
|
+
- Question: <one focused question>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- On successful persistence, respond exactly in this shape:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Brownfield documentation captured:
|
|
79
|
+
|
|
80
|
+
- Objective: <objective summary>
|
|
81
|
+
- Core outcome: <core outcome summary>
|
|
82
|
+
- Research agenda: blocks=<block_count>, topics=<topic_count>, entities=<entity_count>
|
|
83
|
+
- Payload repairs: <none|count + short description>
|
|
84
|
+
- Checkpoint: brownfield-documenter/documentation-captured (<ok|no_changes>)
|
|
85
|
+
|
|
86
|
+
Start a new chat with a new agent and say "cadence, research my project".
|
|
87
|
+
```
|
|
@@ -6,6 +6,7 @@ interface:
|
|
|
6
6
|
Run scripts/run-skill-entry-gate.py --require-cadence, then use its JSON output for PROJECT_ROOT
|
|
7
7
|
(project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), and push/local-only mode (repo_enabled).
|
|
8
8
|
Never edit .cadence/cadence.json manually.
|
|
9
|
+
Enforce the strict user-facing response templates from skills/brownfield-documenter/SKILL.md.
|
|
9
10
|
Run scripts/run-brownfield-documentation.py --project-root "$PROJECT_ROOT" discover, perform evidence-based
|
|
10
11
|
analysis, then persist with scripts/run-brownfield-documentation.py --project-root "$PROJECT_ROOT" complete --stdin.
|
|
11
12
|
Require a research_agenda with at least one topic, verify with scripts/get-ideation.py, and mention
|
|
@@ -27,3 +27,33 @@ description: Classify project mode (greenfield vs brownfield) and capture a dete
|
|
|
27
27
|
11. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
28
28
|
12. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
29
29
|
13. In normal user-facing updates, report mode decision and baseline outcome without raw command traces or internal routing details unless explicitly requested.
|
|
30
|
+
|
|
31
|
+
## Strict Response Format
|
|
32
|
+
|
|
33
|
+
- If resulting mode is `brownfield`, respond exactly in this shape:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
Brownfield intake result:
|
|
37
|
+
|
|
38
|
+
- Mode: brownfield (source: <mode_source>; detected: <detected_mode>)
|
|
39
|
+
- Repository scale: files=<file_count>, directories=<directory_count>
|
|
40
|
+
- Tooling manifests: <count>
|
|
41
|
+
- CI workflows: <count>
|
|
42
|
+
- Monorepo signal: <yes|no>
|
|
43
|
+
- Checkpoint: brownfield-intake/baseline-captured (<ok|no_changes>)
|
|
44
|
+
|
|
45
|
+
Start a new chat and say "cadence, document my existing project".
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- If resulting mode is `greenfield`, respond exactly in this shape:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
Brownfield intake result:
|
|
52
|
+
|
|
53
|
+
- Mode: greenfield (source: <mode_source>; detected: <detected_mode>)
|
|
54
|
+
- Baseline capture: skipped (clean repository)
|
|
55
|
+
- Checkpoint: brownfield-intake/baseline-captured (<ok|no_changes>)
|
|
56
|
+
- Next step: Continue with ideation.
|
|
57
|
+
|
|
58
|
+
Start a new chat and say "cadence, help define my project".
|
|
59
|
+
```
|
|
@@ -6,6 +6,7 @@ interface:
|
|
|
6
6
|
Run scripts/run-skill-entry-gate.py --require-cadence, then use its JSON output for PROJECT_ROOT
|
|
7
7
|
(project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), and push/local-only mode (repo_enabled).
|
|
8
8
|
Never edit .cadence/cadence.json manually.
|
|
9
|
+
Enforce the strict user-facing response templates from skills/brownfield-intake/SKILL.md.
|
|
9
10
|
Run scripts/run-brownfield-intake.py --project-root "$PROJECT_ROOT" --project-mode auto.
|
|
10
11
|
Do not ask the user to choose mode up front; clean repositories should resolve to greenfield automatically.
|
|
11
12
|
If the user explicitly asks to force a mode, rerun with --project-mode <greenfield|brownfield>.
|
|
@@ -65,3 +65,43 @@ description: Discuss, audit, and update existing project ideation in .cadence/ca
|
|
|
65
65
|
18. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
66
66
|
19. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
67
67
|
20. Ask whether to continue refining another aspect or stop.
|
|
68
|
+
|
|
69
|
+
## Strict Response Format
|
|
70
|
+
|
|
71
|
+
- In discussion-only mode (no persistence), respond exactly in this shape:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
Ideation discussion update:
|
|
75
|
+
|
|
76
|
+
- Focus area: <current focus>
|
|
77
|
+
- Tradeoff summary: <short recommendation or options>
|
|
78
|
+
|
|
79
|
+
Next question: <exactly one question>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- Before persistence, respond exactly in this shape:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
Proposed ideation update:
|
|
86
|
+
|
|
87
|
+
- Add: <fields>
|
|
88
|
+
- Update: <fields>
|
|
89
|
+
- Remove: <fields>
|
|
90
|
+
- Unchanged: <fields>
|
|
91
|
+
- Research impact: blocks=<count>, topics=<count>, entities=<count>
|
|
92
|
+
|
|
93
|
+
Confirmation needed: Persist these ideation updates? (yes/no)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- After successful persistence, respond exactly in this shape:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
Ideation update captured:
|
|
100
|
+
|
|
101
|
+
- Updated fields: <summary>
|
|
102
|
+
- Research agenda: blocks=<block_count>, topics=<topic_count>, entities=<entity_count>
|
|
103
|
+
- Research execution: reset for replanning
|
|
104
|
+
- Checkpoint: ideation-updater/ideation-updated (<ok|no_changes>)
|
|
105
|
+
|
|
106
|
+
Next action: Continue refining another aspect? (yes/no)
|
|
107
|
+
```
|
|
@@ -6,6 +6,7 @@ interface:
|
|
|
6
6
|
Run scripts/run-skill-entry-gate.py --require-cadence, then use its JSON output for PROJECT_ROOT
|
|
7
7
|
(project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), and push/local-only mode (repo_enabled).
|
|
8
8
|
Never edit .cadence/cadence.json manually.
|
|
9
|
+
Enforce the strict user-facing response templates from skills/ideation-updater/SKILL.md.
|
|
9
10
|
Review current ideation, discuss updates, rebuild the full ideation object with synchronized research_agenda,
|
|
10
11
|
then run scripts/prepare-ideation-research.py and scripts/inject-ideation.py from PROJECT_ROOT.
|
|
11
12
|
If the user is starting from scratch, hand off with:
|
|
@@ -86,3 +86,42 @@ description: Guide users from a rough concept to a fully defined project idea th
|
|
|
86
86
|
22. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
87
87
|
23. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
88
88
|
24. If the user requests revisions later, regenerate the payload, rerun `prepare-ideation-research.py`, and rerun `inject-ideation.py` from `PROJECT_ROOT`.
|
|
89
|
+
|
|
90
|
+
## Strict Response Format
|
|
91
|
+
|
|
92
|
+
- During discovery turns (before final confirmation), respond exactly in this shape:
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
Ideation progress:
|
|
96
|
+
|
|
97
|
+
- Understanding update: <one sentence>
|
|
98
|
+
|
|
99
|
+
Next question: <exactly one question>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- When presenting final pre-persistence confirmation, respond exactly in this shape:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
Proposed ideation package:
|
|
106
|
+
|
|
107
|
+
- Objective: <summary>
|
|
108
|
+
- Core outcome: <summary>
|
|
109
|
+
- Audience: <summary>
|
|
110
|
+
- Scope: in=<count>, out=<count>
|
|
111
|
+
- Research agenda: blocks=<block_count>, topics=<topic_count>, entities=<entity_count>
|
|
112
|
+
|
|
113
|
+
Confirmation needed: Persist this ideation package? (yes/no)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- On successful persistence, respond exactly in this shape:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
Ideation captured:
|
|
120
|
+
|
|
121
|
+
- Objective: <summary>
|
|
122
|
+
- Core outcome: <summary>
|
|
123
|
+
- Research agenda: blocks=<block_count>, topics=<topic_count>, entities=<entity_count>
|
|
124
|
+
- Checkpoint: ideator/ideation-completed (<ok|no_changes>)
|
|
125
|
+
|
|
126
|
+
Start a new chat with a new agent and say "cadence, research my project".
|
|
127
|
+
```
|
|
@@ -7,6 +7,7 @@ interface:
|
|
|
7
7
|
output for PROJECT_ROOT (project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), and push/local-only mode
|
|
8
8
|
(repo_enabled).
|
|
9
9
|
Never edit .cadence/cadence.json manually.
|
|
10
|
+
Enforce the strict user-facing response templates from skills/ideator/SKILL.md.
|
|
10
11
|
Ask one question at a time, build an execution-ready ideation object and complete research_agenda,
|
|
11
12
|
then from PROJECT_ROOT rerun route assertion, run scripts/prepare-ideation-research.py,
|
|
12
13
|
and persist with scripts/inject-ideation.py.
|
|
@@ -27,3 +27,31 @@ description: Create a greenfield project roadmap from cadence ideation and resea
|
|
|
27
27
|
9. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
28
28
|
10. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
29
29
|
11. In normal user-facing updates, report roadmap outcomes without raw command traces or internal routing details unless explicitly requested.
|
|
30
|
+
|
|
31
|
+
## Strict Response Format
|
|
32
|
+
|
|
33
|
+
- Before persistence confirmation, respond exactly in this shape:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
Proposed roadmap:
|
|
37
|
+
|
|
38
|
+
- Milestones: <milestone_count>
|
|
39
|
+
- Phases: <phase_count>
|
|
40
|
+
- Detail level: milestone_phase_v1
|
|
41
|
+
- Key assumptions: <count or "none">
|
|
42
|
+
|
|
43
|
+
Confirmation needed: Persist this roadmap? (yes/no)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- After successful persistence, respond exactly in this shape:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
Roadmap captured:
|
|
50
|
+
|
|
51
|
+
- Milestones: <milestone_count>
|
|
52
|
+
- Phases: <phase_count>
|
|
53
|
+
- Detail level: milestone_phase_v1
|
|
54
|
+
- Checkpoint: planner/plan-created (<ok|no_changes>)
|
|
55
|
+
|
|
56
|
+
Next route: <skill_name or "workflow complete">
|
|
57
|
+
```
|
|
@@ -7,6 +7,7 @@ interface:
|
|
|
7
7
|
for PROJECT_ROOT (project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), and push/local-only mode
|
|
8
8
|
(repo_enabled).
|
|
9
9
|
Never edit .cadence/cadence.json manually.
|
|
10
|
+
Enforce the strict user-facing response templates from skills/planner/SKILL.md.
|
|
10
11
|
Gather context with scripts/run-planner.py --project-root "$PROJECT_ROOT" discover, then draft and confirm a
|
|
11
12
|
roadmap containing milestones and phases only (no waves/tasks) using detail_level milestone_phase_v1.
|
|
12
13
|
Persist with scripts/run-planner.py --project-root "$PROJECT_ROOT" complete --stdin.
|
|
@@ -1,21 +1,47 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prerequisite-gate
|
|
3
|
-
description: Run and persist Cadence prerequisite checks
|
|
3
|
+
description: Run and persist Cadence runtime prerequisite checks. Use when Cadence starts work after scaffolding and must confirm required Cadence runtime assets before lifecycle or delivery commands.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Prerequisite Gate
|
|
7
7
|
|
|
8
8
|
1. Run this only after scaffold routing from `skills/scaffold/SKILL.md`.
|
|
9
9
|
- Never manually edit `.cadence/cadence.json`; all Cadence state writes must go through Cadence scripts.
|
|
10
|
+
- Do not run Python interpreter availability checks in this workflow gate; installer-time preflight owns that check.
|
|
10
11
|
2. Run shared skill entry gates once at conversation start:
|
|
11
12
|
- `python3 ../../scripts/run-skill-entry-gate.py --require-cadence`
|
|
12
13
|
- Parse JSON and store `PROJECT_ROOT` from `project_root`, `CADENCE_SCRIPTS_DIR` from `cadence_scripts_dir`, and push mode from `repo_enabled` (`false` means local-only commits).
|
|
13
14
|
3. Run `python3 "$CADENCE_SCRIPTS_DIR/run-prerequisite-gate.py" --project-root "$PROJECT_ROOT" --scripts-dir "$CADENCE_SCRIPTS_DIR"`.
|
|
14
15
|
4. `run-prerequisite-gate.py` performs workflow route assertion internally; if assertion fails, stop and surface the exact error.
|
|
15
|
-
5. If the script reports `
|
|
16
|
-
6. Do not continue Cadence lifecycle or delivery execution while
|
|
16
|
+
5. If the script reports `MISSING_CADENCE_RUNTIME_ASSET:<files>`, stop and ask the user to repair/reinstall Cadence runtime files before continuing.
|
|
17
|
+
6. Do not continue Cadence lifecycle or delivery execution while required runtime assets are missing.
|
|
17
18
|
7. At end of this successful skill conversation, run `cd "$PROJECT_ROOT" && python3 "$CADENCE_SCRIPTS_DIR/finalize-skill-checkpoint.py" --scope prerequisite-gate --checkpoint prerequisites-passed --paths .`.
|
|
18
19
|
8. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
19
20
|
9. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
20
21
|
10. Surface script failures verbatim instead of adding custom fallback logic.
|
|
21
22
|
11. In normal user-facing updates, share the prerequisite outcome without raw command traces or internal routing details unless explicitly requested.
|
|
23
|
+
|
|
24
|
+
## Strict Response Format
|
|
25
|
+
|
|
26
|
+
- If `MISSING_CADENCE_RUNTIME_ASSET:<files>` is returned, respond exactly:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
Prerequisite status:
|
|
30
|
+
|
|
31
|
+
- Cadence runtime assets: missing
|
|
32
|
+
- Cadence prerequisite gate: not passed
|
|
33
|
+
|
|
34
|
+
Action required: repair or reinstall Cadence skill files, then rerun the prerequisite gate.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- On successful prerequisite completion, respond exactly:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Prerequisite gate complete:
|
|
41
|
+
|
|
42
|
+
- Cadence runtime assets: available
|
|
43
|
+
- Cadence prerequisite gate: passed
|
|
44
|
+
- Checkpoint: prerequisite-gate/prerequisites-passed (<ok|no_changes>)
|
|
45
|
+
|
|
46
|
+
Next step: Run project mode and baseline intake.
|
|
47
|
+
```
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Prerequisite Gate"
|
|
3
|
-
short_description: "Run and persist Cadence prerequisite checks
|
|
3
|
+
short_description: "Run and persist Cadence runtime prerequisite checks"
|
|
4
4
|
default_prompt: >-
|
|
5
5
|
Follow skills/prerequisite-gate/SKILL.md for exact gate behavior.
|
|
6
6
|
Run scripts/run-skill-entry-gate.py --require-cadence, then use its JSON output for PROJECT_ROOT
|
|
7
7
|
(project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), and push/local-only mode (repo_enabled).
|
|
8
8
|
Never edit .cadence/cadence.json manually.
|
|
9
|
+
Enforce the strict user-facing response templates from skills/prerequisite-gate/SKILL.md.
|
|
9
10
|
Run scripts/run-prerequisite-gate.py --project-root "$PROJECT_ROOT" --scripts-dir "$CADENCE_SCRIPTS_DIR".
|
|
10
11
|
Finalize from PROJECT_ROOT with scripts/finalize-skill-checkpoint.py --scope prerequisite-gate
|
|
11
12
|
--checkpoint prerequisites-passed --paths . (allow status=no_changes; treat failures as blocking).
|
|
@@ -9,10 +9,19 @@ description: Read and route project lifecycle progress from .cadence/cadence.jso
|
|
|
9
9
|
- `python3 ../../scripts/run-skill-entry-gate.py --require-cadence --include-workflow-state`
|
|
10
10
|
- Parse JSON and store `PROJECT_ROOT` from `project_root`, `CADENCE_SCRIPTS_DIR` from `cadence_scripts_dir`, push mode from `repo_enabled` (`false` means local-only commits), and workflow payload from `workflow_state`.
|
|
11
11
|
- Never manually edit `.cadence/cadence.json`; all Cadence state writes must go through Cadence scripts.
|
|
12
|
-
2. Always report current progress first:
|
|
12
|
+
2. Always report current progress first with route-aware formatting:
|
|
13
13
|
- current phase title
|
|
14
|
-
- completion summary (completed vs total actionable items, percent)
|
|
15
14
|
- what comes next
|
|
15
|
+
- If `workflow_state.route.skill_name` is `researcher` (or `workflow_state.next_item.id` is `task-research`):
|
|
16
|
+
- Run `python3 "$CADENCE_SCRIPTS_DIR/run-research-pass.py" --project-root "$PROJECT_ROOT" status`.
|
|
17
|
+
- Report research progress only from that output:
|
|
18
|
+
- topics complete vs total
|
|
19
|
+
- topics needing follow-up
|
|
20
|
+
- topics pending
|
|
21
|
+
- completed passes vs pending passes
|
|
22
|
+
- next pass id (if present)
|
|
23
|
+
- Do not show global workflow completion counts/percent in this mode unless the user explicitly asks for full workflow metrics.
|
|
24
|
+
- Otherwise, report completion summary (completed vs total actionable items, percent).
|
|
16
25
|
3. Interpret user intent:
|
|
17
26
|
- If the user only asks status, answer with progress and stop.
|
|
18
27
|
- If the user asks to continue or resume, answer with progress and then route using `workflow_state.route.skill_path` from the entry gate payload.
|
|
@@ -21,8 +30,54 @@ description: Read and route project lifecycle progress from .cadence/cadence.jso
|
|
|
21
30
|
- If `route.skill_path` is present, invoke that skill.
|
|
22
31
|
- If route skill is `researcher`, keep execution to one pass per conversation and follow researcher handoff behavior between passes.
|
|
23
32
|
- If no route is present for a non-complete item, ask the user what action they want for that item.
|
|
24
|
-
5. If `run-
|
|
25
|
-
6.
|
|
26
|
-
7.
|
|
27
|
-
8. If `finalize-skill-checkpoint.py`
|
|
28
|
-
9.
|
|
33
|
+
5. If `workflow_state.route.skill_name` is `researcher` and `run-research-pass.py status` fails, surface the script error verbatim and stop.
|
|
34
|
+
6. If `run-skill-entry-gate.py` errors (including workflow read failures), surface the script error verbatim and stop.
|
|
35
|
+
7. At end of this successful skill conversation, run `cd "$PROJECT_ROOT" && python3 "$CADENCE_SCRIPTS_DIR/finalize-skill-checkpoint.py" --scope project-progress --checkpoint progress-checked --paths .`.
|
|
36
|
+
8. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
37
|
+
9. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
38
|
+
10. Do not expose raw workflow IDs, route paths, or execution traces in user-facing replies unless the user explicitly asks for internals.
|
|
39
|
+
|
|
40
|
+
## Strict Response Format
|
|
41
|
+
|
|
42
|
+
- If routing is `researcher`, respond exactly in this shape:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
Research progress:
|
|
46
|
+
|
|
47
|
+
- Current phase: <phase_title>
|
|
48
|
+
- Topics complete: <topic_complete>/<topic_total>
|
|
49
|
+
- Topics needing follow-up: <topic_needs_followup>
|
|
50
|
+
- Topics pending: <topic_pending>
|
|
51
|
+
- Passes complete: <pass_complete>
|
|
52
|
+
- Passes pending: <pass_pending>
|
|
53
|
+
- Next pass: <next_pass_id or "none">
|
|
54
|
+
- Next route: researcher
|
|
55
|
+
|
|
56
|
+
Start a new chat and say "cadence, plan my project".
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- If the user asked to continue/resume and more passes remain, append this exact line:
|
|
60
|
+
- `Start a new chat and say "continue research".`
|
|
61
|
+
|
|
62
|
+
- If routing is not `researcher`, respond exactly in this shape:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Workflow progress:
|
|
66
|
+
|
|
67
|
+
- Current phase: <phase_title>
|
|
68
|
+
- Completion: <completed_actionable_items>/<total_actionable_items> (<completion_percent>%)
|
|
69
|
+
- Next item: <next_item_title>
|
|
70
|
+
- Next route: <route_skill_name or "none">
|
|
71
|
+
|
|
72
|
+
Start a new chat and say "cadence, research my project".
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- If workflow is complete, respond exactly:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Workflow progress:
|
|
79
|
+
|
|
80
|
+
- Current phase: Workflow Complete
|
|
81
|
+
- Completion: 100%
|
|
82
|
+
- Status: All currently tracked workflow items are complete.
|
|
83
|
+
```
|
|
@@ -7,7 +7,11 @@ interface:
|
|
|
7
7
|
PROJECT_ROOT (project_root), CADENCE_SCRIPTS_DIR (cadence_scripts_dir), push/local-only mode (repo_enabled),
|
|
8
8
|
and workflow payload (workflow_state).
|
|
9
9
|
Never edit .cadence/cadence.json manually.
|
|
10
|
+
Enforce the strict user-facing response templates from skills/project-progress/SKILL.md.
|
|
10
11
|
Summarize progress in user-facing terms and for continue/resume requests route via workflow_state.route.
|
|
12
|
+
When workflow_state.route.skill_name is researcher (or next_item.id is task-research), run
|
|
13
|
+
scripts/run-research-pass.py --project-root "$PROJECT_ROOT" status and report only research progress;
|
|
14
|
+
omit global workflow completion counts/percent unless the user explicitly asks for full workflow metrics.
|
|
11
15
|
If routed to researcher and more passes remain, use:
|
|
12
16
|
Start a new chat and say "continue research".
|
|
13
17
|
Finalize from PROJECT_ROOT with scripts/finalize-skill-checkpoint.py --scope project-progress
|
|
@@ -34,7 +34,86 @@ description: Execute ideation research agenda topics through dynamic multi-pass
|
|
|
34
34
|
- Run `python3 "$CADENCE_SCRIPTS_DIR/read-workflow-state.py" --project-root "$PROJECT_ROOT"` and inspect `route.skill_name`.
|
|
35
35
|
- If `route.skill_name` is `planner`, end with this exact handoff line: `Start a new chat and say "plan my project".`
|
|
36
36
|
- If workflow is complete, report that research and currently tracked workflow items are complete.
|
|
37
|
-
10.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
10. Strict user-facing return format is required for all successful runs. Use the exact section order below and fill values from script output (and the just-submitted pass payload where applicable):
|
|
38
|
+
- If `complete` returns `handoff_required=true`, respond exactly in this structure, then stop:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
Pass recorded:
|
|
42
|
+
|
|
43
|
+
- Pass ID: <pass_id>
|
|
44
|
+
- Pass summary: <pass_summary>
|
|
45
|
+
|
|
46
|
+
Topic outcomes:
|
|
47
|
+
|
|
48
|
+
- <topic_id>: <status>; confidence=<confidence>; unresolved_questions=<count>
|
|
49
|
+
- <topic_id>: <status>; confidence=<confidence>; unresolved_questions=<count>
|
|
50
|
+
|
|
51
|
+
Research progress:
|
|
52
|
+
|
|
53
|
+
- Topics complete: <topic_complete>/<topic_total>
|
|
54
|
+
- Topics needing follow-up: <topic_needs_followup>
|
|
55
|
+
- Topics pending: <topic_pending>
|
|
56
|
+
- Passes complete: <pass_complete>
|
|
57
|
+
- Passes pending: <pass_pending>
|
|
58
|
+
- Next pass: <next_pass_id or "none">
|
|
59
|
+
|
|
60
|
+
Start a new chat and say "cadence, continue research".
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- If `complete` returns `research_complete=true` and route advances to planner, respond exactly:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
Pass recorded:
|
|
67
|
+
|
|
68
|
+
- Pass ID: <pass_id>
|
|
69
|
+
- Pass summary: <pass_summary>
|
|
70
|
+
|
|
71
|
+
Research progress:
|
|
72
|
+
|
|
73
|
+
- Topics complete: <topic_complete>/<topic_total>
|
|
74
|
+
- Topics needing follow-up: <topic_needs_followup>
|
|
75
|
+
- Topics pending: <topic_pending>
|
|
76
|
+
- Passes complete: <pass_complete>
|
|
77
|
+
- Passes pending: <pass_pending>
|
|
78
|
+
|
|
79
|
+
Start a new chat and say "cadence, plan my project".
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- If `complete` returns `research_complete=true` and workflow is complete, respond exactly:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
Pass recorded:
|
|
86
|
+
|
|
87
|
+
- Pass ID: <pass_id>
|
|
88
|
+
- Pass summary: <pass_summary>
|
|
89
|
+
|
|
90
|
+
Research progress:
|
|
91
|
+
|
|
92
|
+
- Topics complete: <topic_complete>/<topic_total>
|
|
93
|
+
- Topics needing follow-up: <topic_needs_followup>
|
|
94
|
+
- Topics pending: <topic_pending>
|
|
95
|
+
- Passes complete: <pass_complete>
|
|
96
|
+
- Passes pending: <pass_pending>
|
|
97
|
+
|
|
98
|
+
Research and currently tracked workflow items are complete.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- If `start` returns `research_complete=true`, do not run a pass; respond exactly:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
Research progress:
|
|
105
|
+
|
|
106
|
+
- Topics complete: <topic_complete>/<topic_total>
|
|
107
|
+
- Topics needing follow-up: <topic_needs_followup>
|
|
108
|
+
- Topics pending: <topic_pending>
|
|
109
|
+
- Passes complete: <pass_complete>
|
|
110
|
+
- Passes pending: <pass_pending>
|
|
111
|
+
|
|
112
|
+
Research is already complete.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
11. At end of this successful skill conversation, run `cd "$PROJECT_ROOT" && python3 "$CADENCE_SCRIPTS_DIR/finalize-skill-checkpoint.py" --scope researcher --checkpoint research-pass-recorded --paths .`.
|
|
116
|
+
12. If `finalize-skill-checkpoint.py` returns `status=no_changes`, continue without failure.
|
|
117
|
+
13. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
118
|
+
14. Surface script failures verbatim and do not expose internal command traces unless explicitly requested.
|
|
119
|
+
15. For successful runs, do not add extra prose before or after the strict templates in this file.
|
|
@@ -9,7 +9,10 @@ interface:
|
|
|
9
9
|
Never edit .cadence/cadence.json manually.
|
|
10
10
|
Run exactly one pass per chat: scripts/run-research-pass.py start, research only that pass's topics,
|
|
11
11
|
then persist with scripts/run-research-pass.py complete. Do not run a second pass in the same chat.
|
|
12
|
-
|
|
12
|
+
Enforce the strict user-facing return templates defined in skills/researcher/SKILL.md for every successful run,
|
|
13
|
+
and do not add extra prose outside those templates.
|
|
14
|
+
If more work remains, include the full required response sections and end with:
|
|
15
|
+
Start a new chat and say "continue research".
|
|
13
16
|
If research is complete and route advances to planner, end with:
|
|
14
17
|
Start a new chat and say "plan my project".
|
|
15
18
|
Finalize from PROJECT_ROOT with scripts/finalize-skill-checkpoint.py --scope researcher
|
|
@@ -37,3 +37,30 @@ description: Initialize Cadence project scaffolding for first-time setup. Use wh
|
|
|
37
37
|
13. If `finalize-skill-checkpoint.py` reports an error, stop and surface it verbatim.
|
|
38
38
|
14. Execute scaffold actions serially. Do not run this flow in parallel with other setup gates.
|
|
39
39
|
15. In user-facing replies, summarize only the result. Do not expose internal command lines, skill chains, or execution traces unless explicitly requested.
|
|
40
|
+
|
|
41
|
+
## Strict Response Format
|
|
42
|
+
|
|
43
|
+
- For decision-required turns, respond exactly in this shape:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
Scaffold status:
|
|
47
|
+
|
|
48
|
+
- Project root: <PROJECT_ROOT>
|
|
49
|
+
- Cadence initialized: <yes|no>
|
|
50
|
+
- Repo mode: <remote-enabled|local-only|pending>
|
|
51
|
+
|
|
52
|
+
Decision needed: <one required decision>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- For successful completion, respond exactly in this shape:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
Scaffold complete:
|
|
59
|
+
|
|
60
|
+
- Project root: <PROJECT_ROOT>
|
|
61
|
+
- Cadence state: initialized
|
|
62
|
+
- Repo mode: <remote-enabled|local-only>
|
|
63
|
+
- .cadence git policy: <tracked|ignored>
|
|
64
|
+
- Checkpoint: scaffold/<cadence-tracked|cadence-ignored> (<ok|no_changes>)
|
|
65
|
+
- Next step: Run prerequisite gate.
|
|
66
|
+
```
|
|
@@ -10,6 +10,7 @@ interface:
|
|
|
10
10
|
For .cadence policy updates, run scripts/configure-cadence-gitignore.py with --mode and
|
|
11
11
|
--gitignore-path "$PROJECT_ROOT/.gitignore" only (do not pass --project-root).
|
|
12
12
|
Never edit .cadence/cadence.json manually.
|
|
13
|
+
Enforce the strict user-facing response templates from skills/scaffold/SKILL.md.
|
|
13
14
|
Only rerun repo-status after remote setup to confirm repo_enabled=true; do not run an extra write pass
|
|
14
15
|
just to persist false in local-only mode.
|
|
15
16
|
Finalize with scripts/finalize-skill-checkpoint.py --paths . --project-root "$PROJECT_ROOT" and the scope/checkpoint
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
import tempfile
|
|
5
|
+
import unittest
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
SCRIPTS_DIR = Path(__file__).resolve().parents[1] / "scripts"
|
|
9
|
+
if str(SCRIPTS_DIR) not in sys.path:
|
|
10
|
+
sys.path.insert(0, str(SCRIPTS_DIR))
|
|
11
|
+
|
|
12
|
+
from workflow_state import default_data, set_workflow_item_status
|
|
13
|
+
|
|
14
|
+
RUN_SCRIPT = SCRIPTS_DIR / "run-prerequisite-gate.py"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def build_prerequisite_ready_state() -> dict:
|
|
18
|
+
data = default_data()
|
|
19
|
+
data, found = set_workflow_item_status(
|
|
20
|
+
data,
|
|
21
|
+
item_id="task-scaffold",
|
|
22
|
+
status="complete",
|
|
23
|
+
cadence_dir_exists=True,
|
|
24
|
+
)
|
|
25
|
+
if not found:
|
|
26
|
+
raise RuntimeError("Missing task-scaffold in workflow fixture")
|
|
27
|
+
return data
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RunPrerequisiteGateTests(unittest.TestCase):
|
|
31
|
+
@staticmethod
|
|
32
|
+
def write_cadence_state(project_root: Path) -> None:
|
|
33
|
+
(project_root / ".cadence").mkdir(parents=True, exist_ok=True)
|
|
34
|
+
(project_root / ".cadence" / "cadence.json").write_text(
|
|
35
|
+
json.dumps(build_prerequisite_ready_state(), indent=4) + "\n",
|
|
36
|
+
encoding="utf-8",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def test_passes_and_reports_runtime_assets(self) -> None:
|
|
40
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
41
|
+
project_root = Path(tmp_dir)
|
|
42
|
+
self.write_cadence_state(project_root)
|
|
43
|
+
|
|
44
|
+
result = subprocess.run(
|
|
45
|
+
[
|
|
46
|
+
sys.executable,
|
|
47
|
+
str(RUN_SCRIPT),
|
|
48
|
+
"--project-root",
|
|
49
|
+
str(project_root),
|
|
50
|
+
"--scripts-dir",
|
|
51
|
+
str(SCRIPTS_DIR),
|
|
52
|
+
],
|
|
53
|
+
capture_output=True,
|
|
54
|
+
text=True,
|
|
55
|
+
check=False,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
self.assertEqual(result.returncode, 0, msg=result.stderr or result.stdout)
|
|
59
|
+
payload = json.loads(result.stdout)
|
|
60
|
+
self.assertEqual(payload["status"], "ok")
|
|
61
|
+
self.assertTrue(payload["prerequisites_pass"])
|
|
62
|
+
self.assertEqual(payload["runtime_assets"], "ok")
|
|
63
|
+
self.assertIn(payload["source"], {"fresh-check", "cache"})
|
|
64
|
+
|
|
65
|
+
def test_fails_when_runtime_assets_are_missing(self) -> None:
|
|
66
|
+
with tempfile.TemporaryDirectory() as tmp_dir, tempfile.TemporaryDirectory() as scripts_dir:
|
|
67
|
+
project_root = Path(tmp_dir)
|
|
68
|
+
self.write_cadence_state(project_root)
|
|
69
|
+
|
|
70
|
+
result = subprocess.run(
|
|
71
|
+
[
|
|
72
|
+
sys.executable,
|
|
73
|
+
str(RUN_SCRIPT),
|
|
74
|
+
"--project-root",
|
|
75
|
+
str(project_root),
|
|
76
|
+
"--scripts-dir",
|
|
77
|
+
scripts_dir,
|
|
78
|
+
],
|
|
79
|
+
capture_output=True,
|
|
80
|
+
text=True,
|
|
81
|
+
check=False,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
self.assertNotEqual(result.returncode, 0)
|
|
85
|
+
self.assertIn("MISSING_CADENCE_RUNTIME_ASSET", result.stderr)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
unittest.main()
|