@openprd/cli 0.1.11 → 0.1.19
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/.openprd/changes/adaptive-project-framing/.openprd.yaml +2 -0
- package/.openprd/changes/adaptive-project-framing/design.md +47 -0
- package/.openprd/changes/adaptive-project-framing/proposal.md +35 -0
- package/.openprd/changes/adaptive-project-framing/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/adaptive-project-framing/task-events.jsonl +20 -0
- package/.openprd/changes/adaptive-project-framing/tasks.md +340 -0
- package/.openprd/changes/docs-anti-pollution-and-design-direction-review/.openprd.yaml +2 -0
- package/.openprd/changes/docs-anti-pollution-and-design-direction-review/design.md +34 -0
- package/.openprd/changes/docs-anti-pollution-and-design-direction-review/proposal.md +23 -0
- package/.openprd/changes/docs-anti-pollution-and-design-direction-review/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/docs-anti-pollution-and-design-direction-review/task-events.jsonl +14 -0
- package/.openprd/changes/docs-anti-pollution-and-design-direction-review/tasks.md +238 -0
- package/.openprd/changes/loop-isolated-worktree-commit/.openprd.yaml +2 -0
- package/.openprd/changes/loop-isolated-worktree-commit/design.md +53 -0
- package/.openprd/changes/loop-isolated-worktree-commit/proposal.md +38 -0
- package/.openprd/changes/loop-isolated-worktree-commit/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/loop-isolated-worktree-commit/task-events.jsonl +22 -0
- package/.openprd/changes/loop-isolated-worktree-commit/tasks.md +357 -0
- package/.openprd/changes/openprd/.openprd.yaml +2 -0
- package/.openprd/changes/openprd/design.md +46 -0
- package/.openprd/changes/openprd/proposal.md +36 -0
- package/.openprd/changes/openprd/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/openprd/task-events.jsonl +23 -0
- package/.openprd/changes/openprd/tasks.md +242 -0
- package/.openprd/changes/openprd-generated-change/.openprd.yaml +2 -0
- package/.openprd/changes/openprd-generated-change/design.md +50 -0
- package/.openprd/changes/openprd-generated-change/proposal.md +37 -0
- package/.openprd/changes/openprd-generated-change/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/openprd-generated-change/task-events.jsonl +21 -0
- package/.openprd/changes/openprd-generated-change/tasks.md +357 -0
- package/.openprd/changes/pm-human-in-the-loop/.openprd.yaml +2 -0
- package/.openprd/changes/pm-human-in-the-loop/design.md +38 -0
- package/.openprd/changes/pm-human-in-the-loop/proposal.md +29 -0
- package/.openprd/changes/pm-human-in-the-loop/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/pm-human-in-the-loop/task-events.jsonl +18 -0
- package/.openprd/changes/pm-human-in-the-loop/tasks.md +306 -0
- package/.openprd/changes/test-strategy-router/.openprd.yaml +2 -0
- package/.openprd/changes/test-strategy-router/design.md +65 -0
- package/.openprd/changes/test-strategy-router/proposal.md +45 -0
- package/.openprd/changes/test-strategy-router/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/test-strategy-router/task-events.jsonl +1 -0
- package/.openprd/changes/test-strategy-router/tasks.md +132 -0
- package/.openprd/changes/verify-boundaries-and-historical-refresh/.openprd.yaml +2 -0
- package/.openprd/changes/verify-boundaries-and-historical-refresh/design.md +28 -0
- package/.openprd/changes/verify-boundaries-and-historical-refresh/proposal.md +23 -0
- package/.openprd/changes/verify-boundaries-and-historical-refresh/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/verify-boundaries-and-historical-refresh/task-events.jsonl +11 -0
- package/.openprd/changes/verify-boundaries-and-historical-refresh/tasks.md +66 -0
- package/.openprd/changes/vibe-coding-dev-check/.openprd.yaml +2 -0
- package/.openprd/changes/vibe-coding-dev-check/design.md +37 -0
- package/.openprd/changes/vibe-coding-dev-check/proposal.md +28 -0
- package/.openprd/changes/vibe-coding-dev-check/specs/agent-requirements/spec.md +16 -0
- package/.openprd/changes/vibe-coding-dev-check/task-events.jsonl +18 -0
- package/.openprd/changes/vibe-coding-dev-check/tasks.md +306 -0
- package/.openprd/design/README.md +11 -6
- package/.openprd/design/README_EN.md +4 -1
- package/.openprd/design/active/asset-spec.md +6 -0
- package/.openprd/design/active/direction-plan.md +5 -5
- package/.openprd/design/active/selected-direction.md +2 -0
- package/.openprd/design/anti-slop.md +26 -1
- package/.openprd/design/assets/surface-presets.md +6 -0
- package/.openprd/design/checklists/ui-quality-gate.md +7 -0
- package/.openprd/design/lenses/frontend-lenses.md +28 -0
- package/.openprd/design/recipes/content-experience.md +8 -1
- package/.openprd/design/recipes/operational-tool.md +7 -0
- package/.openprd/design/recipes/product-launch.md +8 -1
- package/.openprd/design/templates/README.md +6 -3
- package/.openprd/design/templates/README_EN.md +6 -3
- package/.openprd/design/templates/ops-dashboard.html +8 -1
- package/.openprd/design/templates/product-launch.html +2 -1
- package/.openprd/design/themes/theme-catalog.json +23 -5
- package/.openprd/engagements/active/prd.md +137 -112
- package/.openprd/standards/config.json +7 -1
- package/AGENTS.md +13 -3
- package/README.md +127 -14
- package/README_EN.md +156 -13
- package/package.json +1 -1
- package/scripts/dev-check-wrapup-copy.mjs +46 -21
- package/skills/openprd-diagram-review/SKILL.md +27 -2
- package/skills/openprd-diagram-review/references/explanation-svg-patterns.md +131 -0
- package/skills/openprd-discovery-loop/SKILL.md +2 -2
- package/skills/openprd-frontend-design/SKILL.md +44 -20
- package/skills/openprd-frontend-design/references/design-asset-contract.md +6 -0
- package/skills/openprd-frontend-design/references/direction-engine.md +29 -4
- package/skills/openprd-harness/SKILL.md +22 -16
- package/skills/openprd-quality/SKILL.md +10 -8
- package/skills/openprd-requirement-intake/SKILL.md +2 -0
- package/skills/openprd-router/SKILL.md +2 -1
- package/skills/openprd-shared/SKILL.md +26 -16
- package/skills/openprd-standards/SKILL.md +4 -2
- package/src/agent-canonical-content.js +810 -0
- package/src/agent-integration.js +258 -777
- package/src/canvas-app-client-app.js +838 -0
- package/src/canvas-app-client-helpers.js +1138 -0
- package/src/canvas-app-styles.js +898 -0
- package/src/canvas-app.html.js +135 -0
- package/src/canvas-binding.js +414 -0
- package/src/canvas-codex-relay.js +430 -0
- package/src/canvas-i18n.js +282 -0
- package/src/canvas-scene.js +377 -0
- package/src/canvas-session-store.js +148 -0
- package/src/canvas-workspace.js +1264 -0
- package/src/cli/args.js +72 -4
- package/src/cli/basic-print.js +3 -0
- package/src/cli/canvas-print.js +106 -0
- package/src/cli/doctor-print.js +20 -0
- package/src/cli/print.js +2 -0
- package/src/cli/quality-commands.js +222 -0
- package/src/cli/quality-print.js +28 -2
- package/src/cli/run-print.js +5 -0
- package/src/cli/workflow-print.js +3 -0
- package/src/codex-app-server-relay.js +251 -0
- package/src/codex-hook-runner-template.mjs +978 -58
- package/src/design-starter-support.js +2 -2
- package/src/design-starter.js +39 -3
- package/src/dev-standards.js +125 -10
- package/src/diagram-core.js +6 -20
- package/src/discovery.js +2 -8
- package/src/docs-compact.js +125 -0
- package/src/execution-strategy.js +1 -1
- package/src/fleet.js +9 -3
- package/src/guide.js +227 -0
- package/src/html-artifacts.js +428 -7
- package/src/knowledge.js +45 -11
- package/src/language-policy.js +63 -3
- package/src/learning-review.js +1 -1
- package/src/loop.js +1 -1
- package/src/openprd.js +68 -131
- package/src/openspec/change-validate.js +2 -2
- package/src/openspec/constants.js +6 -7
- package/src/openspec/execute.js +2 -2
- package/src/openspec/generate.js +318 -102
- package/src/openspec/migration.js +168 -0
- package/src/openspec/paths.js +1 -22
- package/src/prd-core.js +1 -1
- package/src/quality-visual-review.js +257 -14
- package/src/quality.js +46 -8
- package/src/review-presentation.js +60 -0
- package/src/run-harness.js +41 -3
- package/src/session-evidence.js +363 -0
- package/src/standards.js +64 -0
- package/src/test-strategy.js +7 -4
- package/src/visual-compare-centering.js +622 -0
- package/src/visual-compare-core.js +1123 -0
- package/src/visual-compare.js +620 -698
- package/src/workspace-core.js +94 -4
- package/src/workspace-workflow.js +46 -1
package/src/language-policy.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const OPENPRD_FALLBACK_LOCALE = 'zh-CN';
|
|
2
|
+
export const OPENPRD_CONTENT_LOCALE = OPENPRD_FALLBACK_LOCALE;
|
|
2
3
|
|
|
3
4
|
export const OPENPRD_LANGUAGE_POLICY =
|
|
4
|
-
'OpenPrd
|
|
5
|
+
'OpenPrd 用户可见内容以及 Agent 产出的 spec、tasks 和说明文案应跟随用户当前主语言;无法判断时才使用简体中文兜底。PRD、OpenPrd、OpenSpec、API、SDK、CLI、TypeScript、JSON、HTTP、WebSocket、字段 key、命令名、品牌名、产品名和协议名等必要专有名词按原文保留。';
|
|
5
6
|
|
|
6
7
|
export const TBD_ZH = '待补充';
|
|
7
8
|
|
|
8
9
|
const CJK_RE = /[\u3400-\u9fff]/;
|
|
10
|
+
const LATIN_WORD_RE = /[A-Za-z][A-Za-z0-9+_.-]*/g;
|
|
9
11
|
|
|
10
12
|
export function scalarZh(value, fallback = TBD_ZH) {
|
|
11
13
|
if (value === null || value === undefined) {
|
|
@@ -19,14 +21,72 @@ export function hasSimplifiedChinese(value) {
|
|
|
19
21
|
return CJK_RE.test(String(value ?? ''));
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
export function englishWords(value) {
|
|
25
|
+
return String(value ?? '').match(LATIN_WORD_RE) ?? [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isChineseLocale(locale) {
|
|
29
|
+
return normalizeOutputLocale(locale).startsWith('zh');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function normalizeOutputLocale(locale, fallback = OPENPRD_FALLBACK_LOCALE) {
|
|
33
|
+
const text = String(locale ?? '').trim();
|
|
34
|
+
if (!text) {
|
|
35
|
+
return fallback;
|
|
36
|
+
}
|
|
37
|
+
const lower = text.toLowerCase();
|
|
38
|
+
if (lower === 'cn' || lower.startsWith('zh')) {
|
|
39
|
+
return 'zh-CN';
|
|
40
|
+
}
|
|
41
|
+
if (lower.startsWith('en')) {
|
|
42
|
+
return 'en';
|
|
43
|
+
}
|
|
44
|
+
return text;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function detectPrimaryLanguage(values, fallback = OPENPRD_FALLBACK_LOCALE) {
|
|
48
|
+
const text = (Array.isArray(values) ? values : [values])
|
|
49
|
+
.map((value) => String(value ?? ''))
|
|
50
|
+
.join('\n');
|
|
51
|
+
const cjkCount = (text.match(CJK_RE) ?? []).length;
|
|
52
|
+
const latinCount = englishWords(text).length;
|
|
53
|
+
if (cjkCount > 0) {
|
|
54
|
+
return 'zh-CN';
|
|
55
|
+
}
|
|
56
|
+
if (latinCount >= 4) {
|
|
57
|
+
return 'en';
|
|
58
|
+
}
|
|
59
|
+
return normalizeOutputLocale(fallback);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function isEnglishHeavyText(value) {
|
|
63
|
+
const text = String(value ?? '').trim();
|
|
64
|
+
if (!text || hasSimplifiedChinese(text)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return englishWords(text).length >= 4;
|
|
68
|
+
}
|
|
69
|
+
|
|
22
70
|
export function preferSimplifiedChinese(value, fallback = TBD_ZH) {
|
|
23
71
|
const text = scalarZh(value, '');
|
|
24
72
|
return hasSimplifiedChinese(text) ? text : fallback;
|
|
25
73
|
}
|
|
26
74
|
|
|
75
|
+
export function preferUserLanguage(value, locale = OPENPRD_FALLBACK_LOCALE, fallbacks = {}) {
|
|
76
|
+
const text = scalarZh(value, '');
|
|
77
|
+
if (text) {
|
|
78
|
+
return text;
|
|
79
|
+
}
|
|
80
|
+
const normalizedLocale = normalizeOutputLocale(locale);
|
|
81
|
+
if (!isChineseLocale(normalizedLocale) && fallbacks.en) {
|
|
82
|
+
return fallbacks.en;
|
|
83
|
+
}
|
|
84
|
+
return fallbacks.zh ?? fallbacks.default ?? TBD_ZH;
|
|
85
|
+
}
|
|
86
|
+
|
|
27
87
|
export function languagePolicyLines() {
|
|
28
88
|
return [
|
|
29
|
-
'>
|
|
89
|
+
'> 语言规则:用户可见说明、PRD、spec 和 tasks 跟随用户当前主语言;无法判断时才使用简体中文兜底。PRD、OpenPrd、OpenSpec、API、SDK、CLI、TypeScript、JSON、HTTP、WebSocket、字段 key、命令名、品牌名、产品名和协议名等必要专有名词保留原文。',
|
|
30
90
|
'',
|
|
31
91
|
];
|
|
32
92
|
}
|
package/src/learning-review.js
CHANGED
|
@@ -622,7 +622,7 @@ async function buildEvidenceManifest(ws, snapshot, options = {}) {
|
|
|
622
622
|
];
|
|
623
623
|
|
|
624
624
|
if (changeId) {
|
|
625
|
-
const changeRoot = path.join(ws.projectRoot, 'openprd', 'changes', changeId);
|
|
625
|
+
const changeRoot = path.join(ws.projectRoot, '.openprd', 'changes', changeId);
|
|
626
626
|
candidateDefs.push(
|
|
627
627
|
makeEvidenceCandidate({
|
|
628
628
|
id: 'change-proposal',
|
package/src/loop.js
CHANGED
|
@@ -550,7 +550,7 @@ async function syncLoopIsolationArtifacts(sourceRoot, targetRoot, options = {})
|
|
|
550
550
|
LOOP_STATE,
|
|
551
551
|
LOOP_BOOTSTRAP,
|
|
552
552
|
RELEASE_LEDGER,
|
|
553
|
-
options.change ? path.join('openprd', 'changes', options.change) : null,
|
|
553
|
+
options.change ? path.join('.openprd', 'changes', options.change) : null,
|
|
554
554
|
].filter(Boolean);
|
|
555
555
|
for (const relativePath of relativePaths) {
|
|
556
556
|
if (await copyRelativePath(sourceRoot, targetRoot, relativePath, { force: Boolean(options.force) })) {
|
package/src/openprd.js
CHANGED
|
@@ -33,7 +33,8 @@ import { doctorOpenPrdAgentIntegration, setupOpenPrdAgentIntegration, updateOpen
|
|
|
33
33
|
import { finishLoopWorkspace, initLoopWorkspace, nextLoopWorkspace, planLoopWorkspace, promptLoopWorkspace, runLoopWorkspace, statusLoopWorkspace, verifyLoopWorkspace } from './loop.js';
|
|
34
34
|
import { timestamp } from './time.js';
|
|
35
35
|
import { parseCommandArgs, usage } from './cli/args.js';
|
|
36
|
-
import {
|
|
36
|
+
import { runQualityCommand } from './cli/quality-commands.js';
|
|
37
|
+
import { printAcceptedSpecsResult, printAgentIntegrationResult, printBenchmarkResult, printBrainstormResult, printCanvasResult, printCaptureResult, printClarifyResult, printClassifyResult, printDesignStarterResult, printDevelopmentStandardsResult, printDiagramResult, printDiffResult, printDoctorResult, printFleetResult, printFreezeResult, printGrowthResult, printHandoffResult, printHistoryResult, printInitResult, printInterviewResult, printKnowledgeResult, printLearningResult, printLoopResult, printNextResult, printOpenPrdChangeActionResult, printOpenPrdChangesResult, printOpenSpecChangeValidationResult, printOpenSpecDiscoveryResult, printOpenSpecGenerateResult, printOpenSpecTaskResult, printPlaygroundResult, printQualityResult, printReleaseResult, printReviewResult, printRunResult, printSelfUpdateResult, printStandardsResult, printStatus, printSynthesizeResult, printUpgradeResult, printValidation, printVisualCompareResult, printVisualPrepareResult } from './cli/print.js';
|
|
37
38
|
import { cjoin, exists, readJson, writeJson, writeText, writeYaml } from './fs-utils.js';
|
|
38
39
|
import { diagramWorkspace } from './diagram-workspace.js';
|
|
39
40
|
import { createOpenSpecDiscoveryWorkspace } from './discovery.js';
|
|
@@ -64,6 +65,7 @@ import {
|
|
|
64
65
|
import { brainstormWorkspace } from './brainstorm.js';
|
|
65
66
|
import { buildBrainstormPresentationTemplatePayload, brainstormPresentationWorkspace } from './brainstorm-presentation.js';
|
|
66
67
|
import { designStarterWorkspace } from './design-starter.js';
|
|
68
|
+
import { canvasWorkspace } from './canvas-workspace.js';
|
|
67
69
|
import { buildReviewPresentationTemplatePayload, reviewPresentationWorkspace } from './review-presentation.js';
|
|
68
70
|
import { analyzeWorkspaceRegistryHygiene } from './registry-hygiene.js';
|
|
69
71
|
import { syncSessionBindingFromChange } from './session-binding.js';
|
|
@@ -74,6 +76,22 @@ import { captureWorkspace, clarifyWorkspace, classifyWorkspace, computeWorkspace
|
|
|
74
76
|
import { appendDecision, appendProgress, appendVerification, appendWorkflowEvent, buildCurrentStateSnapshot, buildWorkflowTaskGraph, computeWorkspaceDigest, CORE_TEMPLATE_FILES, ensureWorkspaceSkeleton, isSupportedProductType, loadCurrentLaneSnapshot, loadLatestVersionSnapshot, loadWorkspace, migrateWorkspaceSkeleton, normalizeVersionId, persistWorkspaceCurrentState, readVersionIndex, resolveActiveTemplatePack, resolveCurrentProductType, validateWorkspace } from './workspace-core.js';
|
|
75
77
|
import { readWorkspaceRegistry } from './workspace-registry.js';
|
|
76
78
|
|
|
79
|
+
function buildInitTemplatePackGuidance(templatePack, options = {}) {
|
|
80
|
+
const label = formatTemplatePackDisplay(templatePack, { fallback: '通用产品或工程场景' });
|
|
81
|
+
if (options.explicit) {
|
|
82
|
+
return {
|
|
83
|
+
source: 'explicit',
|
|
84
|
+
templatePack,
|
|
85
|
+
message: `已按指定场景模板使用${label}起步;后续需求澄清或场景分类时,仍可按用户确认调整产品场景。`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
source: 'default',
|
|
90
|
+
templatePack,
|
|
91
|
+
message: `未指定场景模板,已使用${label}起步;后续需求澄清或场景分类时,可再锁定为个人消费者、企业服务或 Agent 场景。`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
77
95
|
async function initWorkspace(projectRoot, options) {
|
|
78
96
|
const ws = await ensureWorkspaceSkeleton(projectRoot, options);
|
|
79
97
|
const workspace = await loadWorkspace(projectRoot);
|
|
@@ -131,12 +149,16 @@ async function initWorkspace(projectRoot, options) {
|
|
|
131
149
|
templatePack: currentState.templatePack,
|
|
132
150
|
projectRoot,
|
|
133
151
|
});
|
|
152
|
+
const templatePackGuidance = buildInitTemplatePackGuidance(currentState.templatePack, {
|
|
153
|
+
explicit: Boolean(options.templatePack),
|
|
154
|
+
});
|
|
134
155
|
await appendProgress(workspace, [
|
|
135
156
|
`已初始化工作区: ${workspace.workspaceRoot}。`,
|
|
136
157
|
`场景模板: ${formatTemplatePackDisplay(currentState.templatePack, { fallback: '待确认' })}。`,
|
|
158
|
+
templatePackGuidance.message,
|
|
137
159
|
]);
|
|
138
160
|
|
|
139
|
-
return { ws: workspace, created: ws.created, currentState, standards, quality, growth, agentIntegration };
|
|
161
|
+
return { ws: workspace, created: ws.created, currentState, templatePackGuidance, standards, quality, growth, agentIntegration };
|
|
140
162
|
}
|
|
141
163
|
|
|
142
164
|
async function setupAgentIntegrationWorkspace(projectRoot, options = {}) {
|
|
@@ -171,7 +193,16 @@ async function setupAgentIntegrationWorkspace(projectRoot, options = {}) {
|
|
|
171
193
|
platform: options.platform,
|
|
172
194
|
hookProfile: options.hookProfile,
|
|
173
195
|
});
|
|
174
|
-
return {
|
|
196
|
+
return {
|
|
197
|
+
...agentIntegration,
|
|
198
|
+
ok: agentIntegration.ok && migration.ok,
|
|
199
|
+
initialized: false,
|
|
200
|
+
migration,
|
|
201
|
+
standards,
|
|
202
|
+
quality,
|
|
203
|
+
growth,
|
|
204
|
+
errors: [...(agentIntegration.errors ?? []), ...(migration.errors ?? [])],
|
|
205
|
+
};
|
|
175
206
|
}
|
|
176
207
|
|
|
177
208
|
async function updateAgentIntegrationWorkspace(projectRoot, options = {}) {
|
|
@@ -189,7 +220,15 @@ async function updateAgentIntegrationWorkspace(projectRoot, options = {}) {
|
|
|
189
220
|
platform: options.platform,
|
|
190
221
|
hookProfile: options.hookProfile,
|
|
191
222
|
});
|
|
192
|
-
return {
|
|
223
|
+
return {
|
|
224
|
+
...agentIntegration,
|
|
225
|
+
ok: agentIntegration.ok && migration.ok,
|
|
226
|
+
migration,
|
|
227
|
+
standards,
|
|
228
|
+
quality,
|
|
229
|
+
growth,
|
|
230
|
+
errors: [...(agentIntegration.errors ?? []), ...(migration.errors ?? [])],
|
|
231
|
+
};
|
|
193
232
|
}
|
|
194
233
|
|
|
195
234
|
async function doctorWorkspace(projectRoot, options = {}) {
|
|
@@ -897,138 +936,34 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
897
936
|
return result.ok ? 0 : 1;
|
|
898
937
|
}
|
|
899
938
|
|
|
900
|
-
if (command === '
|
|
901
|
-
const result =
|
|
902
|
-
|
|
903
|
-
: flags.
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
html: flags.html,
|
|
916
|
-
learn: Boolean(flags.learn),
|
|
917
|
-
review: flags.review,
|
|
918
|
-
from: flags.from,
|
|
919
|
-
force: flags.force,
|
|
920
|
-
});
|
|
921
|
-
printQualityResult(result, flags.json);
|
|
922
|
-
return result.ok ? 0 : 1;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
if (command === 'knowledge') {
|
|
926
|
-
const subcommand = positionals[0] ?? 'candidates';
|
|
927
|
-
const firstArgIsProjectPath = !flags.path && positionals.length > 1 && await isDirectoryPath(positionals[1]);
|
|
928
|
-
const knowledgeProjectPath = path.resolve(flags.path ?? (firstArgIsProjectPath ? positionals[1] : process.cwd()));
|
|
929
|
-
let result;
|
|
930
|
-
if (subcommand === 'candidates' || subcommand === 'list') {
|
|
931
|
-
result = await listKnowledgeCandidates(knowledgeProjectPath, {
|
|
932
|
-
status: flags.status ?? 'pending-review',
|
|
933
|
-
});
|
|
934
|
-
} else if (subcommand === 'reject') {
|
|
935
|
-
result = await rejectKnowledgeCandidate(knowledgeProjectPath, {
|
|
936
|
-
id: flags.id ?? positionals[1] ?? null,
|
|
937
|
-
reason: flags.reason ?? flags.notes,
|
|
938
|
-
});
|
|
939
|
-
} else if (subcommand === 'archive') {
|
|
940
|
-
result = await archiveKnowledgeCandidate(knowledgeProjectPath, {
|
|
941
|
-
id: flags.id ?? positionals[1] ?? null,
|
|
942
|
-
reason: flags.reason ?? flags.notes,
|
|
943
|
-
});
|
|
944
|
-
} else if (subcommand === 'restore') {
|
|
945
|
-
result = await restoreKnowledgeCandidate(knowledgeProjectPath, {
|
|
946
|
-
id: flags.id ?? positionals[1] ?? null,
|
|
947
|
-
});
|
|
948
|
-
} else {
|
|
949
|
-
console.log('Usage: openprd knowledge <candidates|reject|archive|restore> [path-or-id] [--status <pending-review|all|rejected|archived|promoted|merged>] [--id <candidate-id>] [--reason <text>] [--json]');
|
|
950
|
-
return 1;
|
|
951
|
-
}
|
|
952
|
-
printKnowledgeResult(result, flags.json);
|
|
953
|
-
return result.ok ? 0 : 1;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
if (command === 'visual-prepare') {
|
|
957
|
-
const result = await visualPrepareWorkspace(projectPath, {
|
|
958
|
-
reference: flags.reference,
|
|
959
|
-
grid: flags.grid,
|
|
960
|
-
boxes: flags.boxes,
|
|
961
|
-
include: flags.include,
|
|
939
|
+
if (command === 'canvas') {
|
|
940
|
+
const result = await canvasWorkspace(projectPath, {
|
|
941
|
+
thread: flags.thread,
|
|
942
|
+
threadTitle: flags.threadTitle,
|
|
943
|
+
conversationTitle: flags.conversationTitle,
|
|
944
|
+
session: flags.session,
|
|
945
|
+
sessionTitle: flags.sessionTitle,
|
|
946
|
+
host: flags.host,
|
|
947
|
+
port: flags.port,
|
|
948
|
+
daemon: flags.daemon,
|
|
949
|
+
stop: flags.stop,
|
|
950
|
+
bridgeOutbox: flags.bridgeOutbox,
|
|
951
|
+
bridgeSent: flags.bridgeSent,
|
|
952
|
+
bridgeFailed: flags.bridgeFailed,
|
|
953
|
+
claim: flags.claim,
|
|
962
954
|
id: flags.id,
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
return result.ok ? 0 : 1;
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
if (command === 'visual-compare') {
|
|
971
|
-
const result = await visualCompareWorkspace(projectPath, {
|
|
972
|
-
reference: flags.reference,
|
|
973
|
-
actual: flags.actual,
|
|
974
|
-
before: flags.before,
|
|
975
|
-
after: flags.after,
|
|
976
|
-
board: flags.board,
|
|
977
|
-
out: flags.out,
|
|
978
|
-
format: flags.format,
|
|
979
|
-
quality: flags.quality,
|
|
980
|
-
maxPanelWidth: flags.maxPanelWidth,
|
|
981
|
-
referenceLabel: flags.referenceLabel,
|
|
982
|
-
actualLabel: flags.actualLabel,
|
|
983
|
-
});
|
|
984
|
-
printVisualCompareResult(result, flags.json);
|
|
985
|
-
return result.ok ? 0 : 1;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
if (command === 'design-starter') {
|
|
989
|
-
const result = await designStarterWorkspace(projectPath, {
|
|
990
|
-
starter: flags.starter,
|
|
991
|
-
out: flags.out,
|
|
992
|
-
title: flags.title,
|
|
993
|
-
brief: flags.brief,
|
|
994
|
-
sections: flags.sections,
|
|
995
|
-
noExternalFacts: flags.noExternalFacts,
|
|
996
|
-
noBrandAssets: flags.noBrandAssets,
|
|
997
|
-
noRealImages: flags.noRealImages,
|
|
998
|
-
force: flags.force,
|
|
955
|
+
reason: flags.reason,
|
|
956
|
+
open: flags.open,
|
|
957
|
+
openTarget: flags.openTarget,
|
|
958
|
+
dryRun: flags.dryRun,
|
|
999
959
|
});
|
|
1000
|
-
|
|
960
|
+
printCanvasResult(result, flags.json);
|
|
1001
961
|
return result.ok ? 0 : 1;
|
|
1002
962
|
}
|
|
1003
963
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
let result;
|
|
1008
|
-
if (flags.init) {
|
|
1009
|
-
result = await initGrowthWorkspace(growthProjectPath);
|
|
1010
|
-
} else if (flags.apply) {
|
|
1011
|
-
result = await applyGrowthCandidateWorkspace(growthProjectPath, { id: flags.id });
|
|
1012
|
-
} else if (flags.reject) {
|
|
1013
|
-
result = await rejectGrowthCandidateWorkspace(growthProjectPath, { id: flags.id, notes: flags.notes });
|
|
1014
|
-
} else if (flags.check) {
|
|
1015
|
-
result = await checkGrowthWorkspace(growthProjectPath);
|
|
1016
|
-
} else {
|
|
1017
|
-
result = await reviewGrowthWorkspace(growthProjectPath);
|
|
1018
|
-
}
|
|
1019
|
-
printGrowthResult(result, flags.json);
|
|
1020
|
-
return result.ok ? 0 : 1;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
if (command === 'dev-check') {
|
|
1024
|
-
const firstArgIsProjectPath = !flags.path && positionals.length > 1 && await isDirectoryPath(positionals[0]);
|
|
1025
|
-
const devProjectPath = path.resolve(flags.path ?? (firstArgIsProjectPath ? positionals[0] : process.cwd()));
|
|
1026
|
-
const files = flags.path
|
|
1027
|
-
? positionals
|
|
1028
|
-
: (firstArgIsProjectPath ? positionals.slice(1) : positionals);
|
|
1029
|
-
const result = await checkDevelopmentStandardsWorkspace(devProjectPath, { files });
|
|
1030
|
-
printDevelopmentStandardsResult(result, flags.json);
|
|
1031
|
-
return result.ok ? 0 : 1;
|
|
964
|
+
const qualityCommandExit = await runQualityCommand(command, { projectPath, flags, positionals });
|
|
965
|
+
if (qualityCommandExit !== null) {
|
|
966
|
+
return qualityCommandExit;
|
|
1032
967
|
}
|
|
1033
968
|
|
|
1034
969
|
if (command === 'benchmark') {
|
|
@@ -1171,6 +1106,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
1171
1106
|
version: flags.version,
|
|
1172
1107
|
digest: flags.digest,
|
|
1173
1108
|
workUnit: flags.workUnit,
|
|
1109
|
+
direction: flags.direction,
|
|
1174
1110
|
});
|
|
1175
1111
|
printReviewResult(result, flags.json);
|
|
1176
1112
|
return result.ok ? 0 : 1;
|
|
@@ -1454,6 +1390,7 @@ export {
|
|
|
1454
1390
|
fleetWorkspace,
|
|
1455
1391
|
backfillWorkUnitsWorkspace,
|
|
1456
1392
|
runWorkspace,
|
|
1393
|
+
canvasWorkspace,
|
|
1457
1394
|
initLoopWorkspace,
|
|
1458
1395
|
planLoopWorkspace,
|
|
1459
1396
|
statusLoopWorkspace,
|
|
@@ -47,7 +47,7 @@ export async function resolveOpenSpecChangeId(projectRoot, requestedChange) {
|
|
|
47
47
|
return changeDirs[0];
|
|
48
48
|
}
|
|
49
49
|
if (changeDirs.length === 0) {
|
|
50
|
-
throw new Error('openprd/changes 下没有找到 OpenPrd change。');
|
|
50
|
+
throw new Error('.openprd/changes 下没有找到 OpenPrd change。');
|
|
51
51
|
}
|
|
52
52
|
throw new Error(`找到多个 OpenPrd change;请传入 --change <id>。已找到: ${changeDirs.join(', ')}`);
|
|
53
53
|
}
|
|
@@ -60,7 +60,7 @@ function extractProposalCapabilities(text) {
|
|
|
60
60
|
return capabilities;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
const SPEC_SECTION_HEADING_RE = /^##\s+(?:(ADDED|MODIFIED|REMOVED)\s+Requirements|(?:新增|修改|移除)需求)\s*$/gim;
|
|
63
|
+
const SPEC_SECTION_HEADING_RE = /^##\s+(?:(ADDED|MODIFIED|REMOVED|NEW|UPDATED|CHANGED)\s+Requirements|(?:新增|修改|移除)需求)\s*$/gim;
|
|
64
64
|
const REQUIREMENT_HEADING_RE = /^###\s+(?:Requirement|需求)[::]\s*(.+)$/gm;
|
|
65
65
|
const SCENARIO_HEADING_RE = /^####\s+(?:Scenario|场景)[::]\s*(.+)$/gm;
|
|
66
66
|
const WHEN_STEP_RE = /^-\s+\*\*(?:WHEN|当)\*\*/im;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
export const OPENPRD_DISCOVERY_DIR = ['.openprd', 'discovery'];
|
|
2
2
|
export const OPENPRD_DISCOVERY_CONFIG_PATH = ['.openprd', 'discovery', 'config.json'];
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
6
|
-
export const
|
|
7
|
-
export const
|
|
8
|
-
export const
|
|
9
|
-
export const OPENPRD_ARCHIVE_CHANGE_ROOT = ['openprd', 'archive', 'changes'];
|
|
3
|
+
export const OPENPRD_CHANGE_ROOT = ['.openprd', 'changes'];
|
|
4
|
+
export const LEGACY_OPENPRD_CHANGE_ROOT = ['openprd', 'changes'];
|
|
5
|
+
export const OPENPRD_ACCEPTED_SPEC_ROOT = ['.openprd', 'specs'];
|
|
6
|
+
export const LEGACY_OPENPRD_ACCEPTED_SPEC_ROOT = ['openprd', 'specs'];
|
|
7
|
+
export const OPENPRD_ARCHIVE_CHANGE_ROOT = ['.openprd', 'archive', 'changes'];
|
|
8
|
+
export const LEGACY_OPENPRD_ARCHIVE_CHANGE_ROOT = ['openprd', 'archive', 'changes'];
|
|
10
9
|
export const OPENSPEC_TASK_MAX_ITEMS_PER_FILE = 25;
|
|
11
10
|
export const OPENSPEC_TASK_FILE_PATTERN = /^tasks(?:-\d{3})?\.md$/;
|
|
12
11
|
export const OPENSPEC_TASK_ID_PATTERN = /^T\d{3}\.\d+$/;
|
package/src/openspec/execute.js
CHANGED
|
@@ -96,9 +96,9 @@ function resolveTaskSelection(state, options = {}) {
|
|
|
96
96
|
|
|
97
97
|
if (!task) {
|
|
98
98
|
if (requestedId) {
|
|
99
|
-
throw new Error(`Unknown
|
|
99
|
+
throw new Error(`Unknown OpenPrd task: ${requestedId}`);
|
|
100
100
|
}
|
|
101
|
-
throw new Error('No ready
|
|
101
|
+
throw new Error('No ready OpenPrd task is available.');
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
return task;
|