prizmkit 1.0.13 → 1.0.15
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/bin/create-prizmkit.js +4 -1
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/claude/command-adapter.js +35 -4
- package/bundled/adapters/claude/rules-adapter.js +6 -58
- package/bundled/adapters/claude/team-adapter.js +2 -2
- package/bundled/adapters/codebuddy/agent-adapter.js +0 -1
- package/bundled/adapters/codebuddy/rules-adapter.js +30 -0
- package/bundled/adapters/shared/frontmatter.js +3 -1
- package/bundled/dev-pipeline/README.md +13 -3
- package/bundled/dev-pipeline/launch-bugfix-daemon.sh +10 -0
- package/bundled/dev-pipeline/launch-daemon.sh +18 -4
- package/bundled/dev-pipeline/lib/common.sh +105 -0
- package/bundled/dev-pipeline/retry-bug.sh +20 -2
- package/bundled/dev-pipeline/retry-feature.sh +20 -2
- package/bundled/dev-pipeline/run-bugfix.sh +57 -57
- package/bundled/dev-pipeline/run.sh +75 -59
- package/bundled/dev-pipeline/scripts/check-session-status.py +47 -2
- package/bundled/dev-pipeline/scripts/cleanup-logs.py +192 -0
- package/bundled/dev-pipeline/scripts/detect-stuck.py +15 -3
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +32 -27
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +23 -23
- package/bundled/dev-pipeline/scripts/update-feature-status.py +50 -2
- package/bundled/dev-pipeline/scripts/utils.py +22 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +18 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +19 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +18 -2
- package/bundled/dev-pipeline/templates/session-status-schema.json +7 -1
- package/bundled/dev-pipeline/tests/__init__.py +0 -0
- package/bundled/dev-pipeline/tests/conftest.py +133 -0
- package/bundled/dev-pipeline/tests/test_check_session.py +127 -0
- package/bundled/dev-pipeline/tests/test_cleanup_logs.py +119 -0
- package/bundled/dev-pipeline/tests/test_detect_stuck.py +207 -0
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +181 -0
- package/bundled/dev-pipeline/tests/test_generate_prompt.py +190 -0
- package/bundled/dev-pipeline/tests/test_init_bugfix_pipeline.py +153 -0
- package/bundled/dev-pipeline/tests/test_init_pipeline.py +241 -0
- package/bundled/dev-pipeline/tests/test_update_bug_status.py +142 -0
- package/bundled/dev-pipeline/tests/test_update_feature_status.py +277 -0
- package/bundled/dev-pipeline/tests/test_utils.py +141 -0
- package/bundled/rules/USAGE.md +153 -0
- package/bundled/rules/_rules-metadata.json +43 -0
- package/bundled/rules/general/prefer-linux-commands.md +9 -0
- package/bundled/rules/prizm/prizm-commit-workflow.md +10 -0
- package/bundled/rules/prizm/prizm-documentation.md +80 -0
- package/bundled/rules/prizm/prizm-progressive-loading.md +11 -0
- package/bundled/skills/_metadata.json +162 -67
- package/bundled/skills/app-planner/SKILL.md +252 -499
- package/bundled/skills/app-planner/assets/evaluation-guide.md +44 -0
- package/bundled/skills/app-planner/scripts/validate-and-generate.py +143 -4
- package/bundled/skills/bug-planner/SKILL.md +58 -13
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +5 -7
- package/bundled/skills/dev-pipeline-launcher/SKILL.md +16 -7
- package/bundled/skills/feature-workflow/SKILL.md +175 -234
- package/bundled/skills/prizm-kit/SKILL.md +17 -31
- package/bundled/skills/{prizmkit-adr-manager → prizmkit-tool-adr-manager}/SKILL.md +6 -7
- package/bundled/skills/{prizmkit-api-doc-generator → prizmkit-tool-api-doc-generator}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-bug-reproducer → prizmkit-tool-bug-reproducer}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-ci-cd-generator → prizmkit-tool-ci-cd-generator}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-db-migration → prizmkit-tool-db-migration}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-dependency-health → prizmkit-tool-dependency-health}/SKILL.md +3 -4
- package/bundled/skills/{prizmkit-deployment-strategy → prizmkit-tool-deployment-strategy}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-error-triage → prizmkit-tool-error-triage}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-log-analyzer → prizmkit-tool-log-analyzer}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-monitoring-setup → prizmkit-tool-monitoring-setup}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-onboarding-generator → prizmkit-tool-onboarding-generator}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-perf-profiler → prizmkit-tool-perf-profiler}/SKILL.md +4 -5
- package/bundled/skills/{prizmkit-security-audit → prizmkit-tool-security-audit}/SKILL.md +3 -4
- package/bundled/skills/{prizmkit-tech-debt-tracker → prizmkit-tool-tech-debt-tracker}/SKILL.md +3 -4
- package/bundled/skills/refactor-skill/SKILL.md +371 -0
- package/bundled/skills/refactor-workflow/SKILL.md +17 -119
- package/bundled/templates/hooks/commit-intent-claude.json +1 -1
- package/bundled/templates/hooks/commit-intent-codebuddy.json +1 -1
- package/bundled/templates/hooks/prizm-pre-commit.sh +58 -0
- package/bundled/templates/hooks/validate-prizm-docs.sh +84 -0
- package/package.json +1 -1
- package/src/detect-platform.js +20 -8
- package/src/external-skills.js +71 -0
- package/src/index.js +66 -8
- package/src/metadata.js +36 -0
- package/src/scaffold.js +200 -31
- package/bundled/skills/prizmkit-bug-fix-workflow/SKILL.md +0 -356
- package/bundled/templates/claude-md-template.md +0 -38
- package/bundled/templates/codebuddy-md-template.md +0 -35
- /package/bundled/skills/{prizmkit-adr-manager → prizmkit-tool-adr-manager}/assets/adr-template.md +0 -0
package/bin/create-prizmkit.js
CHANGED
|
@@ -28,11 +28,14 @@ program
|
|
|
28
28
|
.command('install [directory]')
|
|
29
29
|
.description('Install PrizmKit into a project directory')
|
|
30
30
|
.option('--platform <platform>', 'Target platform: codebuddy, claude, or both')
|
|
31
|
-
.option('--skills <suite>', 'Skill suite: full, core, or
|
|
31
|
+
.option('--skills <suite>', 'Skill suite: full, core, minimal, or recommended:<type> (frontend/backend/fullstack/library)', 'full')
|
|
32
32
|
.option('--team', 'Enable multi-agent team mode (default: true)')
|
|
33
33
|
.option('--no-team', 'Disable multi-agent team mode')
|
|
34
34
|
.option('--pipeline', 'Install dev-pipeline (default: true)')
|
|
35
35
|
.option('--no-pipeline', 'Disable dev-pipeline')
|
|
36
|
+
.option('--rules <preset>', 'Rules preset: recommended, minimal, or none', 'recommended')
|
|
37
|
+
.option('--ai-cli <command>', 'AI CLI executable command (e.g. cbc, claude, claude-internal)')
|
|
38
|
+
.option('--external-skills <names>', 'Comma-separated external skill names to install (e.g. find-skill,uiuxpromax)')
|
|
36
39
|
.option('--non-interactive', 'Skip interactive prompts (requires --platform)')
|
|
37
40
|
.option('--dry-run', 'Show what would be created without making changes')
|
|
38
41
|
.action(async (directory = '.', options) => {
|
package/bundled/VERSION.json
CHANGED
|
@@ -15,6 +15,37 @@ import { existsSync, mkdirSync, cpSync } from 'node:fs';
|
|
|
15
15
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
16
16
|
import path from 'path';
|
|
17
17
|
|
|
18
|
+
const TOOL_SHORTHANDS = new Set([
|
|
19
|
+
'tech_debt_tracker',
|
|
20
|
+
'bug_reproducer',
|
|
21
|
+
'adr_manager',
|
|
22
|
+
'security_audit',
|
|
23
|
+
'dependency_health',
|
|
24
|
+
'ci_cd_generator',
|
|
25
|
+
'deployment_strategy',
|
|
26
|
+
'db_migration',
|
|
27
|
+
'monitoring_setup',
|
|
28
|
+
'error_triage',
|
|
29
|
+
'log_analyzer',
|
|
30
|
+
'perf_profiler',
|
|
31
|
+
'onboarding_generator',
|
|
32
|
+
'api_doc_generator',
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
function toClaudePrizmkitCommand(sub) {
|
|
36
|
+
const normalized = sub.replace(/_/g, '-');
|
|
37
|
+
|
|
38
|
+
if (sub.startsWith('tool_')) {
|
|
39
|
+
return `prizmkit-${normalized}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (TOOL_SHORTHANDS.has(sub)) {
|
|
43
|
+
return `prizmkit-tool-${normalized}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return `prizmkit-${normalized}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
18
49
|
/**
|
|
19
50
|
* Convert a core SKILL.md to Claude Code command.md format.
|
|
20
51
|
* @param {string} skillContent - Content of the core SKILL.md
|
|
@@ -27,7 +58,7 @@ export function convertSkillToCommand(skillContent, skillName) {
|
|
|
27
58
|
// Claude Code command frontmatter only uses description
|
|
28
59
|
// Also convert prizmkit.xxx references in the description field
|
|
29
60
|
let desc = frontmatter.description || `PrizmKit ${skillName} command`;
|
|
30
|
-
desc = desc.replace(/prizmkit\.(\w+)/g, (_m, sub) =>
|
|
61
|
+
desc = desc.replace(/prizmkit\.(\w+)/g, (_m, sub) => `/${toClaudePrizmkitCommand(sub)}`);
|
|
31
62
|
|
|
32
63
|
const claudeFrontmatter = {
|
|
33
64
|
description: desc,
|
|
@@ -53,9 +84,9 @@ export function convertSkillToCommand(skillContent, skillName) {
|
|
|
53
84
|
// Replace prizmkit.xxx with /prizmkit-xxx for Claude Code
|
|
54
85
|
convertedBody = convertedBody.replace(
|
|
55
86
|
/prizmkit\.(\w+)/g,
|
|
56
|
-
(
|
|
57
|
-
// Map
|
|
58
|
-
const commandName =
|
|
87
|
+
(_match, sub) => {
|
|
88
|
+
// Map shorthand references like prizmkit.tech_debt_tracker -> /prizmkit-tool-tech-debt-tracker
|
|
89
|
+
const commandName = toClaudePrizmkitCommand(sub);
|
|
59
90
|
return `\`/${commandName}\``;
|
|
60
91
|
}
|
|
61
92
|
);
|
|
@@ -8,70 +8,18 @@ import { mkdirSync } from 'node:fs';
|
|
|
8
8
|
import { writeFile } from 'node:fs/promises';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
|
|
11
|
-
const RULES = [
|
|
12
|
-
{
|
|
13
|
-
filename: 'prizm-documentation.md',
|
|
14
|
-
content: `---
|
|
15
|
-
description: "PrizmKit documentation rules"
|
|
16
|
-
globs:
|
|
17
|
-
- "**/*.ts"
|
|
18
|
-
- "**/*.tsx"
|
|
19
|
-
- "**/*.js"
|
|
20
|
-
- "**/*.jsx"
|
|
21
|
-
- "**/*.py"
|
|
22
|
-
- "**/*.go"
|
|
23
|
-
- "**/*.rs"
|
|
24
|
-
- "**/*.java"
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
When modifying source files in this project:
|
|
28
|
-
1. Check if \`.prizm-docs/root.prizm\` exists
|
|
29
|
-
2. If it does, read it before making changes to understand project structure
|
|
30
|
-
3. After making changes, update affected \`.prizm-docs/\` files
|
|
31
|
-
4. Follow the Prizm doc format (KEY: value, not prose)
|
|
32
|
-
5. Size limits: L0 = 4KB, L1 = 3KB, L2 = 5KB
|
|
33
|
-
`,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
filename: 'prizm-commit-workflow.md',
|
|
37
|
-
content: `---
|
|
38
|
-
description: "PrizmKit commit workflow rules"
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
Before any git commit in this project:
|
|
42
|
-
1. Update \`.prizm-docs/\` for affected modules
|
|
43
|
-
2. Use Conventional Commits format: type(scope): description
|
|
44
|
-
3. Bug fixes use \`fix()\` prefix, not \`feat()\`
|
|
45
|
-
4. Do NOT create REGISTRY.md entries for bug fixes
|
|
46
|
-
5. Use \`/prizmkit-committer\` command for the complete commit workflow
|
|
47
|
-
`,
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
filename: 'prizm-progressive-loading.md',
|
|
51
|
-
content: `---
|
|
52
|
-
description: "PrizmKit progressive context loading protocol"
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
This project uses PrizmKit's progressive loading protocol:
|
|
56
|
-
- ON SESSION START: Read \`.prizm-docs/root.prizm\` (L0 — project map)
|
|
57
|
-
- ON TASK: Read L1 (\`.prizm-docs/<module>.prizm\`) for relevant modules
|
|
58
|
-
- ON FILE EDIT: Read L2 (\`.prizm-docs/<module>/<submodule>.prizm\`) before modifying
|
|
59
|
-
- NEVER load all .prizm docs at once
|
|
60
|
-
- Arrow notation (->) in .prizm files indicates load pointers
|
|
61
|
-
- DECISIONS and CHANGELOG in .prizm files are append-only
|
|
62
|
-
`,
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
11
|
/**
|
|
67
12
|
* Install PrizmKit rules to the target project's .claude/rules/ directory.
|
|
68
13
|
* @param {string} targetRoot - Target project root
|
|
14
|
+
* @param {Array<{name: string, content: string}>} ruleFiles - Rules to install
|
|
69
15
|
*/
|
|
70
|
-
export async function installRules(targetRoot) {
|
|
16
|
+
export async function installRules(targetRoot, ruleFiles) {
|
|
71
17
|
const rulesDir = path.join(targetRoot, '.claude', 'rules');
|
|
72
18
|
mkdirSync(rulesDir, { recursive: true });
|
|
73
19
|
|
|
74
|
-
for (const rule of
|
|
75
|
-
|
|
20
|
+
for (const rule of ruleFiles) {
|
|
21
|
+
// Use the basename (after /) as the filename
|
|
22
|
+
const baseName = rule.name.includes('/') ? rule.name.split('/').pop() : rule.name;
|
|
23
|
+
await writeFile(path.join(rulesDir, `${baseName}.md`), rule.content);
|
|
76
24
|
}
|
|
77
25
|
}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* - 支持 shutdown 消息终止 teammate
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { mkdirSync
|
|
19
|
-
import { writeFile
|
|
18
|
+
import { mkdirSync } from 'node:fs';
|
|
19
|
+
import { writeFile } from 'node:fs/promises';
|
|
20
20
|
import path from 'path';
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* For CodeBuddy, this is mostly pass-through as the core format matches.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { parseFrontmatter, buildMarkdown } from '../shared/frontmatter.js';
|
|
8
7
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
9
8
|
import { readFile, writeFile, symlink } from 'node:fs/promises';
|
|
10
9
|
import path from 'path';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeBuddy Rules Adapter
|
|
3
|
+
* Installs .codebuddy/rules/*.mdc files for PrizmKit-enabled projects.
|
|
4
|
+
*/
|
|
5
|
+
import { mkdirSync } from 'node:fs';
|
|
6
|
+
import { writeFile } from 'node:fs/promises';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
|
|
9
|
+
export async function installRules(targetRoot, ruleFiles) {
|
|
10
|
+
// ruleFiles: [{ name: 'prizm/prizm-documentation', content: '...' }, ...]
|
|
11
|
+
const rulesDir = path.join(targetRoot, '.codebuddy', 'rules');
|
|
12
|
+
mkdirSync(rulesDir, { recursive: true });
|
|
13
|
+
|
|
14
|
+
for (const rule of ruleFiles) {
|
|
15
|
+
const mdcContent = convertToMdc(rule.content, rule.name);
|
|
16
|
+
// Use the basename (after /) as the filename
|
|
17
|
+
const baseName = rule.name.includes('/') ? rule.name.split('/').pop() : rule.name;
|
|
18
|
+
await writeFile(path.join(rulesDir, `${baseName}.mdc`), mdcContent);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function convertToMdc(mdContent, name) {
|
|
23
|
+
// Strip existing frontmatter from .md, build .mdc frontmatter
|
|
24
|
+
const bodyMatch = mdContent.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
|
25
|
+
const descMatch = mdContent.match(/description:\s*"([^"]+)"/);
|
|
26
|
+
const body = bodyMatch ? bodyMatch[1] : mdContent;
|
|
27
|
+
const description = descMatch ? descMatch[1] : name;
|
|
28
|
+
|
|
29
|
+
return `---\ndescription: ${description}\nalwaysApply: true\nenabled: true\nupdatedAt: ${new Date().toISOString()}\nprovider: \n---\n${body}`;
|
|
30
|
+
}
|
|
@@ -38,9 +38,11 @@ export function parseFrontmatter(content) {
|
|
|
38
38
|
value = value.slice(1, -1);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// Parse numbers
|
|
41
|
+
// Parse numbers (integer or float)
|
|
42
42
|
if (/^\d+$/.test(value)) {
|
|
43
43
|
value = parseInt(value, 10);
|
|
44
|
+
} else if (/^\d+\.\d+$/.test(value)) {
|
|
45
|
+
value = parseFloat(value);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
frontmatter[key] = value;
|
|
@@ -4,7 +4,7 @@ Autonomous development pipeline that drives the `prizm-dev-team` multi-agent tea
|
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
|
-
- Python 3.
|
|
7
|
+
- Python 3.8+
|
|
8
8
|
- [jq](https://jqlang.github.io/jq/) (`brew install jq`)
|
|
9
9
|
- AI CLI in PATH: CodeBuddy (`cbc`) or Claude Code (`claude`)
|
|
10
10
|
- `feature-list.json` generated by the `app-planner` skill
|
|
@@ -31,13 +31,15 @@ python3 dev-pipeline/scripts/init-pipeline.py \
|
|
|
31
31
|
|
|
32
32
|
| Command | Description |
|
|
33
33
|
|---------|-------------|
|
|
34
|
-
| `./run.sh run [feature-list.json]` | Start or resume the pipeline. Processes features sequentially by dependency order. |
|
|
34
|
+
| `./run.sh run [feature-list.json] [options]` | Start or resume the pipeline. Processes features sequentially by dependency order. |
|
|
35
35
|
| `./run.sh status [feature-list.json]` | Display current pipeline status: completed, pending, blocked, failed features. |
|
|
36
36
|
| `./run.sh reset` | Clear all runtime state in `state/`. Pipeline starts fresh on next `run`. |
|
|
37
37
|
| `./run.sh help` | Show usage help. |
|
|
38
38
|
| `./retry-feature.sh <feature-id> [feature-list.json]` | Retry a single failed feature. Runs one session then exits. |
|
|
39
39
|
| `./reset-feature.sh <feature-id> [--clean] [--run]` | Reset a feature to pending. `--clean` deletes artifacts, `--run` auto-retries. |
|
|
40
40
|
|
|
41
|
+
`run.sh` 常用 options:`--resume-phase N`、`--max-retries N`、`--timeout SEC`、`--ai-cli CMD`、`--dry-run`、`--no-reset`。
|
|
42
|
+
|
|
41
43
|
If `feature-list.json` path is omitted, defaults to `.dev-pipeline/feature-list.json` (run.sh) or `feature-list.json` (retry-feature.sh).
|
|
42
44
|
|
|
43
45
|
### Retrying a Failed Feature
|
|
@@ -95,8 +97,12 @@ What is always reset (with or without `--clean`):
|
|
|
95
97
|
| `MAX_RETRIES` | `3` | Maximum retry attempts per feature before marking as failed. |
|
|
96
98
|
| `SESSION_TIMEOUT` | `0` (no limit) | Timeout in seconds per AI CLI session. 0 = no timeout. |
|
|
97
99
|
| `AI_CLI` | auto-detect | AI CLI command name. Auto-detects `cbc` or `claude`. Set to override. |
|
|
100
|
+
| `CODEBUDDY_CLI` | (deprecated) | Legacy alias for `AI_CLI`. Prefer `AI_CLI`. |
|
|
98
101
|
| `HEARTBEAT_INTERVAL` | `30` | Seconds between heartbeat log output while a session is running. |
|
|
99
102
|
| `HEARTBEAT_STALE_THRESHOLD` | `600` | Seconds before a session is considered stale/stuck. |
|
|
103
|
+
| `LOG_CLEANUP_ENABLED` | `1` | Run log cleanup before pipeline execution (`1`=enabled, `0`=disabled). |
|
|
104
|
+
| `LOG_RETENTION_DAYS` | `14` | Delete logs older than N days. |
|
|
105
|
+
| `LOG_MAX_TOTAL_MB` | `1024` | Keep total log size under N MB by deleting oldest logs first. |
|
|
100
106
|
|
|
101
107
|
Example with custom config:
|
|
102
108
|
|
|
@@ -105,6 +111,9 @@ MAX_RETRIES=5 ./dev-pipeline/run.sh run feature-list.json
|
|
|
105
111
|
|
|
106
112
|
# With 2-hour timeout per session
|
|
107
113
|
SESSION_TIMEOUT=7200 ./dev-pipeline/run.sh run feature-list.json
|
|
114
|
+
|
|
115
|
+
# Keep only recent logs and cap total log size
|
|
116
|
+
LOG_RETENTION_DAYS=7 LOG_MAX_TOTAL_MB=512 ./dev-pipeline/run.sh run feature-list.json
|
|
108
117
|
```
|
|
109
118
|
|
|
110
119
|
## How It Works
|
|
@@ -215,6 +224,7 @@ cat dev-pipeline/state/features/F-003/sessions/F-003-*/logs/session.log | less
|
|
|
215
224
|
|
|
216
225
|
- **Ctrl+C** during execution triggers graceful shutdown — current state is saved.
|
|
217
226
|
- **Re-running** `./run.sh run feature-list.json` resumes from where it left off. Completed features are skipped.
|
|
227
|
+
- 如需强制从某一阶段继续,可使用:`./run.sh run feature-list.json --resume-phase 6`(例如直接进入实现阶段)。
|
|
218
228
|
|
|
219
229
|
### Manual Intervention
|
|
220
230
|
|
|
@@ -422,7 +432,7 @@ run-bugfix.sh main loop
|
|
|
422
432
|
│
|
|
423
433
|
├─ AI CLI session # cbc --print -y < prompt (CBC)
|
|
424
434
|
│ │ # claude --print -p "$(cat prompt)" --yes (CC)
|
|
425
|
-
│ └─
|
|
435
|
+
│ └─ bugfix 5-phase workflow
|
|
426
436
|
│ ├─ Phase 1: Triage (Dev agent: classify, assess impact, write fix-plan.md)
|
|
427
437
|
│ ├─ Phase 2: Reproduce (Dev agent: create failing reproduction test)
|
|
428
438
|
│ ├─ Phase 3: Fix (Dev agent: TDD — make reproduction test pass)
|
|
@@ -134,6 +134,16 @@ cmd_start() {
|
|
|
134
134
|
local start_time
|
|
135
135
|
start_time=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
|
136
136
|
|
|
137
|
+
# Rotate log if over 50 MB
|
|
138
|
+
if [[ -f "$LOG_FILE" ]]; then
|
|
139
|
+
local log_bytes
|
|
140
|
+
log_bytes=$(wc -c < "$LOG_FILE" 2>/dev/null | tr -d ' ')
|
|
141
|
+
if [[ "$log_bytes" -gt 52428800 ]]; then
|
|
142
|
+
mv "$LOG_FILE" "${LOG_FILE}.$(date -u '+%Y%m%dT%H%M%S').bak"
|
|
143
|
+
log_info "Log rotated (was $((log_bytes / 1048576))MB): ${LOG_FILE}.bak"
|
|
144
|
+
fi
|
|
145
|
+
fi
|
|
146
|
+
|
|
137
147
|
log_info "Launching bugfix pipeline..."
|
|
138
148
|
log_info "Bug fix list: $bug_list"
|
|
139
149
|
log_info "Log file: $LOG_FILE"
|
|
@@ -160,6 +160,16 @@ cmd_start() {
|
|
|
160
160
|
local start_time
|
|
161
161
|
start_time=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
|
162
162
|
|
|
163
|
+
# Rotate log if over 50 MB
|
|
164
|
+
if [[ -f "$LOG_FILE" ]]; then
|
|
165
|
+
local log_bytes
|
|
166
|
+
log_bytes=$(wc -c < "$LOG_FILE" 2>/dev/null | tr -d ' ')
|
|
167
|
+
if [[ "$log_bytes" -gt 52428800 ]]; then
|
|
168
|
+
mv "$LOG_FILE" "${LOG_FILE}.$(date -u '+%Y%m%dT%H%M%S').bak"
|
|
169
|
+
log_info "Log rotated (was $((log_bytes / 1048576))MB): ${LOG_FILE}.bak"
|
|
170
|
+
fi
|
|
171
|
+
fi
|
|
172
|
+
|
|
163
173
|
# Launch run.sh in background, fully detached
|
|
164
174
|
log_info "Launching pipeline..."
|
|
165
175
|
log_info "Feature list: $feature_list"
|
|
@@ -190,10 +200,11 @@ cmd_start() {
|
|
|
190
200
|
local pipeline_pid=$!
|
|
191
201
|
disown "$pipeline_pid" 2>/dev/null || true
|
|
192
202
|
|
|
193
|
-
# Write PID file
|
|
194
|
-
echo "$pipeline_pid" > "$PID_FILE"
|
|
203
|
+
# Write PID file (atomic)
|
|
204
|
+
echo "$pipeline_pid" > "${PID_FILE}.tmp"
|
|
205
|
+
mv "${PID_FILE}.tmp" "$PID_FILE"
|
|
195
206
|
|
|
196
|
-
# Write start metadata
|
|
207
|
+
# Write start metadata (atomic)
|
|
197
208
|
python3 -c "
|
|
198
209
|
import json, sys, os
|
|
199
210
|
pid, started_at, feature_list, env_overrides, log_file, state_dir = int(sys.argv[1]), sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]
|
|
@@ -204,8 +215,11 @@ data = {
|
|
|
204
215
|
'env_overrides': env_overrides,
|
|
205
216
|
'log_file': log_file
|
|
206
217
|
}
|
|
207
|
-
|
|
218
|
+
target = os.path.join(state_dir, '.pipeline-meta.json')
|
|
219
|
+
tmp = target + '.tmp'
|
|
220
|
+
with open(tmp, 'w') as f:
|
|
208
221
|
json.dump(data, f, indent=2)
|
|
222
|
+
os.replace(tmp, target)
|
|
209
223
|
" "$pipeline_pid" "$start_time" "$feature_list" "$env_overrides" "$LOG_FILE" "$STATE_DIR" 2>/dev/null || true
|
|
210
224
|
|
|
211
225
|
# Wait briefly and verify
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================
|
|
3
|
+
# dev-pipeline/lib/common.sh - Shared shell helpers
|
|
4
|
+
#
|
|
5
|
+
# Shared by feature and bugfix pipeline runners.
|
|
6
|
+
# Provides:
|
|
7
|
+
# - CLI/platform detection
|
|
8
|
+
# - Common color + log helpers
|
|
9
|
+
# - Common dependency checks
|
|
10
|
+
# ============================================================
|
|
11
|
+
|
|
12
|
+
# Colors
|
|
13
|
+
RED='\033[0;31m'
|
|
14
|
+
GREEN='\033[0;32m'
|
|
15
|
+
YELLOW='\033[1;33m'
|
|
16
|
+
BLUE='\033[0;34m'
|
|
17
|
+
MAGENTA='\033[0;35m'
|
|
18
|
+
BOLD='\033[1m'
|
|
19
|
+
NC='\033[0m'
|
|
20
|
+
|
|
21
|
+
log_info() { echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
|
|
22
|
+
log_warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
|
|
23
|
+
log_error() { echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
|
|
24
|
+
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
|
|
25
|
+
|
|
26
|
+
# Detect AI CLI + platform.
|
|
27
|
+
# Priority:
|
|
28
|
+
# AI_CLI env > .prizmkit/config.json > CODEBUDDY_CLI > auto-detect(cbc/claude) > error
|
|
29
|
+
#
|
|
30
|
+
# Exports:
|
|
31
|
+
# CLI_CMD
|
|
32
|
+
# PLATFORM
|
|
33
|
+
# PRIZMKIT_PLATFORM
|
|
34
|
+
prizm_detect_cli_and_platform() {
|
|
35
|
+
if [[ -n "${AI_CLI:-}" ]]; then
|
|
36
|
+
CLI_CMD="$AI_CLI"
|
|
37
|
+
# Read from .prizmkit/config.json if present
|
|
38
|
+
elif [[ -f ".prizmkit/config.json" ]]; then
|
|
39
|
+
_config_ai_cli=$(python3 -c "
|
|
40
|
+
import json, sys
|
|
41
|
+
try:
|
|
42
|
+
with open('.prizmkit/config.json') as f:
|
|
43
|
+
d = json.load(f)
|
|
44
|
+
v = d.get('ai_cli', '')
|
|
45
|
+
if v: print(v)
|
|
46
|
+
except: pass
|
|
47
|
+
" 2>/dev/null || true)
|
|
48
|
+
if [[ -n "$_config_ai_cli" ]]; then
|
|
49
|
+
CLI_CMD="$_config_ai_cli"
|
|
50
|
+
elif [[ -n "${CODEBUDDY_CLI:-}" ]]; then
|
|
51
|
+
CLI_CMD="$CODEBUDDY_CLI"
|
|
52
|
+
elif command -v cbc &>/dev/null; then
|
|
53
|
+
CLI_CMD="cbc"
|
|
54
|
+
elif command -v claude &>/dev/null; then
|
|
55
|
+
CLI_CMD="claude"
|
|
56
|
+
else
|
|
57
|
+
echo "ERROR: No AI CLI found. Install CodeBuddy (cbc) or Claude Code (claude)." >&2
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
elif [[ -n "${CODEBUDDY_CLI:-}" ]]; then
|
|
61
|
+
CLI_CMD="$CODEBUDDY_CLI"
|
|
62
|
+
elif command -v cbc &>/dev/null; then
|
|
63
|
+
CLI_CMD="cbc"
|
|
64
|
+
elif command -v claude &>/dev/null; then
|
|
65
|
+
CLI_CMD="claude"
|
|
66
|
+
else
|
|
67
|
+
echo "ERROR: No AI CLI found. Install CodeBuddy (cbc) or Claude Code (claude)." >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [[ -n "${PRIZMKIT_PLATFORM:-}" ]]; then
|
|
72
|
+
PLATFORM="$PRIZMKIT_PLATFORM"
|
|
73
|
+
elif [[ "$CLI_CMD" == *"claude"* ]]; then
|
|
74
|
+
PLATFORM="claude"
|
|
75
|
+
else
|
|
76
|
+
PLATFORM="codebuddy"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
export CLI_CMD
|
|
80
|
+
export PLATFORM
|
|
81
|
+
export PRIZMKIT_PLATFORM="$PLATFORM"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Common dependency check (jq + python3 + optional CLI in PATH)
|
|
85
|
+
# Args:
|
|
86
|
+
# $1 - cli command (optional)
|
|
87
|
+
prizm_check_common_dependencies() {
|
|
88
|
+
local cli_cmd="${1:-}"
|
|
89
|
+
|
|
90
|
+
if ! command -v jq &>/dev/null; then
|
|
91
|
+
log_error "jq is required but not installed. Install with: brew install jq"
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
if ! command -v python3 &>/dev/null; then
|
|
96
|
+
log_error "python3 is required but not installed."
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [[ -n "$cli_cmd" ]] && ! command -v "$cli_cmd" &>/dev/null; then
|
|
101
|
+
log_warn "AI CLI '$cli_cmd' not found in PATH."
|
|
102
|
+
log_warn "Set AI_CLI environment variable to the correct command."
|
|
103
|
+
log_warn "Continuing anyway (will fail when spawning sessions)..."
|
|
104
|
+
fi
|
|
105
|
+
}
|
|
@@ -24,9 +24,27 @@ SCRIPTS_DIR="$SCRIPT_DIR/scripts"
|
|
|
24
24
|
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
25
25
|
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
26
26
|
|
|
27
|
-
# AI CLI detection
|
|
27
|
+
# AI CLI detection: AI_CLI env > .prizmkit/config.json > CODEBUDDY_CLI > auto-detect
|
|
28
28
|
if [[ -n "${AI_CLI:-}" ]]; then
|
|
29
29
|
CLI_CMD="$AI_CLI"
|
|
30
|
+
elif [[ -f ".prizmkit/config.json" ]]; then
|
|
31
|
+
_config_cli=$(python3 -c "
|
|
32
|
+
import json, sys
|
|
33
|
+
try:
|
|
34
|
+
with open('.prizmkit/config.json') as f:
|
|
35
|
+
d = json.load(f)
|
|
36
|
+
v = d.get('ai_cli', '')
|
|
37
|
+
if v: print(v)
|
|
38
|
+
except: pass
|
|
39
|
+
" 2>/dev/null || true)
|
|
40
|
+
CLI_CMD="${_config_cli:-}"
|
|
41
|
+
if [[ -z "$CLI_CMD" ]]; then
|
|
42
|
+
if [[ -n "${CODEBUDDY_CLI:-}" ]]; then CLI_CMD="$CODEBUDDY_CLI"
|
|
43
|
+
elif command -v cbc &>/dev/null; then CLI_CMD="cbc"
|
|
44
|
+
elif command -v claude &>/dev/null; then CLI_CMD="claude"
|
|
45
|
+
else echo "ERROR: No AI CLI found. Set AI_CLI or configure .prizmkit/config.json" >&2; exit 1
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
30
48
|
elif [[ -n "${CODEBUDDY_CLI:-}" ]]; then
|
|
31
49
|
CLI_CMD="$CODEBUDDY_CLI"
|
|
32
50
|
elif command -v cbc &>/dev/null; then
|
|
@@ -34,7 +52,7 @@ elif command -v cbc &>/dev/null; then
|
|
|
34
52
|
elif command -v claude &>/dev/null; then
|
|
35
53
|
CLI_CMD="claude"
|
|
36
54
|
else
|
|
37
|
-
echo "ERROR: No AI CLI found. Install CodeBuddy (cbc) or Claude Code (claude)." >&2
|
|
55
|
+
echo "ERROR: No AI CLI found. Install CodeBuddy (cbc) or Claude Code (claude), or set AI_CLI." >&2
|
|
38
56
|
exit 1
|
|
39
57
|
fi
|
|
40
58
|
|
|
@@ -24,9 +24,27 @@ SCRIPTS_DIR="$SCRIPT_DIR/scripts"
|
|
|
24
24
|
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
25
25
|
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
26
26
|
|
|
27
|
-
# AI CLI detection: AI_CLI > CODEBUDDY_CLI > auto-detect
|
|
27
|
+
# AI CLI detection: AI_CLI env > .prizmkit/config.json > CODEBUDDY_CLI > auto-detect
|
|
28
28
|
if [[ -n "${AI_CLI:-}" ]]; then
|
|
29
29
|
CLI_CMD="$AI_CLI"
|
|
30
|
+
elif [[ -f ".prizmkit/config.json" ]]; then
|
|
31
|
+
_config_cli=$(python3 -c "
|
|
32
|
+
import json, sys
|
|
33
|
+
try:
|
|
34
|
+
with open('.prizmkit/config.json') as f:
|
|
35
|
+
d = json.load(f)
|
|
36
|
+
v = d.get('ai_cli', '')
|
|
37
|
+
if v: print(v)
|
|
38
|
+
except: pass
|
|
39
|
+
" 2>/dev/null || true)
|
|
40
|
+
CLI_CMD="${_config_cli:-}"
|
|
41
|
+
if [[ -z "$CLI_CMD" ]]; then
|
|
42
|
+
if [[ -n "${CODEBUDDY_CLI:-}" ]]; then CLI_CMD="$CODEBUDDY_CLI"
|
|
43
|
+
elif command -v cbc &>/dev/null; then CLI_CMD="cbc"
|
|
44
|
+
elif command -v claude &>/dev/null; then CLI_CMD="claude"
|
|
45
|
+
else echo "ERROR: No AI CLI found. Set AI_CLI or configure .prizmkit/config.json" >&2; exit 1
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
30
48
|
elif [[ -n "${CODEBUDDY_CLI:-}" ]]; then
|
|
31
49
|
CLI_CMD="$CODEBUDDY_CLI"
|
|
32
50
|
elif command -v cbc &>/dev/null; then
|
|
@@ -34,7 +52,7 @@ elif command -v cbc &>/dev/null; then
|
|
|
34
52
|
elif command -v claude &>/dev/null; then
|
|
35
53
|
CLI_CMD="claude"
|
|
36
54
|
else
|
|
37
|
-
echo "ERROR: No AI CLI found. Install CodeBuddy (cbc) or Claude Code (claude)." >&2
|
|
55
|
+
echo "ERROR: No AI CLI found. Install CodeBuddy (cbc) or Claude Code (claude), or set AI_CLI." >&2
|
|
38
56
|
exit 1
|
|
39
57
|
fi
|
|
40
58
|
|