@openprd/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.openprd/README.md +82 -0
- package/.openprd/benchmarks/evidence/milvus-io-ai-code-review-gets-better-when-models-debate-claude-vs-gemini-vs-code.md +14 -0
- package/.openprd/benchmarks/evidence/nolanlawson-com-using-ai-to-write-better-code-more-slowly.md +14 -0
- package/.openprd/benchmarks/index.md +37 -0
- package/.openprd/benchmarks/sources.yaml +56 -0
- package/.openprd/config.yaml +50 -0
- package/.openprd/discovery/config.json +21 -0
- package/.openprd/engagements/active/flows.md +30 -0
- package/.openprd/engagements/active/handoff.md +9 -0
- package/.openprd/engagements/active/intake.md +15 -0
- package/.openprd/engagements/active/prd.md +161 -0
- package/.openprd/engagements/active/review.html +61 -0
- package/.openprd/engagements/active/roles.md +21 -0
- package/.openprd/engagements/work-units/wu-20260524015648-6d33ded7.json +23 -0
- package/.openprd/exports/.gitkeep +0 -0
- package/.openprd/knowledge/index.json +7 -0
- package/.openprd/quality/config.json +229 -0
- package/.openprd/reviews/v0001.html +1256 -0
- package/.openprd/schema/diagram-architecture.schema.yaml +49 -0
- package/.openprd/schema/diagram-product-flow.schema.yaml +52 -0
- package/.openprd/schema/prd.schema.yaml +121 -0
- package/.openprd/sessions/.gitkeep +0 -0
- package/.openprd/standards/config.json +88 -0
- package/.openprd/standards/file-manual-template.md +28 -0
- package/.openprd/standards/folder-readme-template.md +28 -0
- package/.openprd/state/.gitkeep +0 -0
- package/.openprd/state/changes.json +12 -0
- package/.openprd/state/current.json +169 -0
- package/.openprd/state/version-index.json +15 -0
- package/.openprd/state/versions/.gitkeep +0 -0
- package/.openprd/state/versions/v0001.json +121 -0
- package/.openprd/state/versions/v0001.md +161 -0
- package/.openprd/templates/agent/intake.md +6 -0
- package/.openprd/templates/agent/prd.md +21 -0
- package/.openprd/templates/b2b/intake.md +6 -0
- package/.openprd/templates/b2b/prd.md +24 -0
- package/.openprd/templates/base/intake.md +18 -0
- package/.openprd/templates/base/prd.md +67 -0
- package/.openprd/templates/company/README.md +10 -0
- package/.openprd/templates/consumer/intake.md +6 -0
- package/.openprd/templates/consumer/prd.md +19 -0
- package/.openprd/templates/diagram/architecture.contract.json +53 -0
- package/.openprd/templates/diagram/product-flow.contract.json +76 -0
- package/.openprd/templates/industry/README.md +16 -0
- package/.openprd/templates/manifest.yaml +27 -0
- package/.openprd/templates/project/README.md +14 -0
- package/.openprd/templates/session/README.md +14 -0
- package/AGENTS.md +44 -0
- package/CONTRIBUTING.md +30 -0
- package/LICENSE +21 -0
- package/README.md +727 -0
- package/README_CN.md +583 -0
- package/SECURITY.md +23 -0
- package/bin/openprd.js +5 -0
- package/docs/assets/openprd-capability-overview-en.png +0 -0
- package/docs/assets/openprd-capability-overview-zh.png +0 -0
- package/docs/assets/openprd-learning-html.png +0 -0
- package/docs/assets/openprd-quality-html.png +0 -0
- package/docs/assets/openprd-review-html.png +0 -0
- package/docs/assets/openprd-scenario-overview.png +0 -0
- package/docs/assets/openprd-scenario-overview.svg +114 -0
- package/docs/assets/openprd-self-evolving-mechanisms-en.png +0 -0
- package/docs/assets/openprd-self-evolving-mechanisms-zh.png +0 -0
- package/docs/assets/openprd-visual-compare-case-study-en.png +0 -0
- package/docs/assets/openprd-visual-compare-case-study-zh.png +0 -0
- package/package.json +59 -0
- package/scripts/openprd-dev-check.mjs +5 -0
- package/scripts/openprd-review-presentation.mjs +82 -0
- package/skills/openprd-benchmark-router/SKILL.md +92 -0
- package/skills/openprd-benchmark-router/agents/openai.yaml +4 -0
- package/skills/openprd-benchmark-router/references/benchmark-sources.md +74 -0
- package/skills/openprd-benchmark-router/references/evaluation-lenses.md +66 -0
- package/skills/openprd-benchmark-router/references/source-policy.md +35 -0
- package/skills/openprd-diagram-review/SKILL.md +91 -0
- package/skills/openprd-diagram-review/agents/openai.yaml +4 -0
- package/skills/openprd-diagram-review/examples/architecture-zh.md +8 -0
- package/skills/openprd-diagram-review/examples/product-flow-zh.md +7 -0
- package/skills/openprd-diagram-review/references/cocoon-patterns.md +17 -0
- package/skills/openprd-diagram-review/references/diagram-contracts.md +126 -0
- package/skills/openprd-diagram-review/references/review-checklist.md +10 -0
- package/skills/openprd-discovery-loop/SKILL.md +196 -0
- package/skills/openprd-discovery-loop/agents/openai.yaml +3 -0
- package/skills/openprd-harness/SKILL.md +179 -0
- package/skills/openprd-harness/agents/openai.yaml +4 -0
- package/skills/openprd-harness/examples/full-workflow-zh.md +9 -0
- package/skills/openprd-harness/references/command-map.md +71 -0
- package/skills/openprd-harness/references/examples.md +26 -0
- package/skills/openprd-harness/references/usage-guide.md +335 -0
- package/skills/openprd-harness/references/workflow-gates.md +51 -0
- package/skills/openprd-learning-review/SKILL.md +75 -0
- package/skills/openprd-learning-review/agents/openai.yaml +4 -0
- package/skills/openprd-learning-review/references/content-contract.md +125 -0
- package/skills/openprd-learning-review/references/ebook-reader.md +46 -0
- package/skills/openprd-learning-review/references/evidence-manifest.md +55 -0
- package/skills/openprd-learning-review/references/genre-library.md +43 -0
- package/skills/openprd-learning-review/references/prompt-engineering.md +71 -0
- package/skills/openprd-learning-review/references/quality-rubric.md +28 -0
- package/skills/openprd-learning-review/references/retrieval-worked-example.md +40 -0
- package/skills/openprd-learning-review/references/style-packs/xianxia-cultivation.prompt.md +67 -0
- package/skills/openprd-quality/SKILL.md +101 -0
- package/skills/openprd-requirement-intake/SKILL.md +76 -0
- package/skills/openprd-requirement-intake/agents/openai.yaml +4 -0
- package/skills/openprd-requirement-intake/references/prd-template-lenses.md +105 -0
- package/skills/openprd-requirement-intake/references/routing-rubric.md +64 -0
- package/skills/openprd-router/SKILL.md +40 -0
- package/skills/openprd-shared/SKILL.md +142 -0
- package/skills/openprd-shared/agents/openai.yaml +4 -0
- package/skills/openprd-shared/references/language-and-review.md +50 -0
- package/skills/openprd-shared/references/operating-rules.md +65 -0
- package/skills/openprd-shared/references/skill-architecture.md +70 -0
- package/skills/openprd-standards/SKILL.md +79 -0
- package/skills/openprd-standards/agents/openai.yaml +4 -0
- package/src/agent-integration.js +1717 -0
- package/src/benchmark.js +873 -0
- package/src/cli/args.js +460 -0
- package/src/cli/print.js +1423 -0
- package/src/codex-hook-runner-template.mjs +2422 -0
- package/src/dev-standards.js +372 -0
- package/src/diagram-core.js +1047 -0
- package/src/diagram-workspace.js +262 -0
- package/src/discovery.js +709 -0
- package/src/fleet.js +531 -0
- package/src/fs-utils.js +83 -0
- package/src/growth.js +545 -0
- package/src/html-artifacts.js +3803 -0
- package/src/knowledge.js +668 -0
- package/src/language-policy.js +142 -0
- package/src/learning-review.js +1655 -0
- package/src/loop.js +1290 -0
- package/src/openprd.js +1136 -0
- package/src/openspec/change-lifecycle.js +359 -0
- package/src/openspec/change-validate.js +248 -0
- package/src/openspec/constants.js +12 -0
- package/src/openspec/execute.js +300 -0
- package/src/openspec/generate.js +692 -0
- package/src/openspec/paths.js +111 -0
- package/src/openspec/tasks.js +352 -0
- package/src/prd-core.js +656 -0
- package/src/quality-html-artifact.js +1414 -0
- package/src/quality-learning.js +658 -0
- package/src/quality.js +1262 -0
- package/src/review-presentation.js +240 -0
- package/src/run-harness.js +1470 -0
- package/src/self-update.js +329 -0
- package/src/session-binding.js +140 -0
- package/src/source-inventory.js +224 -0
- package/src/standards.js +914 -0
- package/src/time.js +33 -0
- package/src/visual-compare.js +216 -0
- package/src/work-unit-migration.js +232 -0
- package/src/work-unit.js +88 -0
- package/src/workspace-core.js +1706 -0
- package/src/workspace-registry.js +162 -0
- package/src/workspace-workflow.js +1797 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { appendJsonl, cjoin, exists, readJson, readJsonl } from './fs-utils.js';
|
|
5
|
+
import { timestamp } from './time.js';
|
|
6
|
+
|
|
7
|
+
const OPENPRD_WORKSPACE_MARKER = '.openprd';
|
|
8
|
+
const OPENPRD_HARNESS_MANIFEST = cjoin('.openprd', 'harness', 'install-manifest.json');
|
|
9
|
+
const OPENPRD_WORKSPACE_REGISTRY = cjoin('registry', 'workspaces.jsonl');
|
|
10
|
+
|
|
11
|
+
function normalizeToolsArray(value) {
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
return value
|
|
14
|
+
.map((item) => String(item).trim())
|
|
15
|
+
.filter(Boolean);
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === 'string') {
|
|
18
|
+
return value
|
|
19
|
+
.split(',')
|
|
20
|
+
.map((item) => item.trim())
|
|
21
|
+
.filter(Boolean);
|
|
22
|
+
}
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeWorkspaceRegistryEntry(entry) {
|
|
27
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const workspaceRoot = entry.workspaceRoot ? path.resolve(String(entry.workspaceRoot)) : null;
|
|
31
|
+
if (!workspaceRoot) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const realpath = entry.realpath ? path.resolve(String(entry.realpath)) : workspaceRoot;
|
|
35
|
+
const manifestPath = entry.manifestPath
|
|
36
|
+
? path.resolve(String(entry.manifestPath))
|
|
37
|
+
: cjoin(workspaceRoot, OPENPRD_HARNESS_MANIFEST);
|
|
38
|
+
const lastUpdatedAt = entry.lastUpdatedAt ?? entry.generatedAt ?? entry.recordedAt ?? null;
|
|
39
|
+
const firstRegisteredAt = entry.firstRegisteredAt ?? entry.recordedAt ?? lastUpdatedAt;
|
|
40
|
+
return {
|
|
41
|
+
version: 1,
|
|
42
|
+
workspaceRoot,
|
|
43
|
+
realpath,
|
|
44
|
+
workspaceName: entry.workspaceName ?? path.basename(workspaceRoot),
|
|
45
|
+
manifestPath,
|
|
46
|
+
openprdVersion: entry.openprdVersion ?? null,
|
|
47
|
+
tools: normalizeToolsArray(entry.tools),
|
|
48
|
+
hookProfile: entry.hookProfile ? String(entry.hookProfile) : null,
|
|
49
|
+
initializedAt: entry.initializedAt ?? lastUpdatedAt,
|
|
50
|
+
lastUpdatedAt,
|
|
51
|
+
firstRegisteredAt,
|
|
52
|
+
lastRegisteredAt: entry.lastRegisteredAt ?? entry.recordedAt ?? lastUpdatedAt,
|
|
53
|
+
lastAction: entry.lastAction ?? entry.action ?? null,
|
|
54
|
+
manifestPresent: entry.manifestPresent !== false,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveOpenPrdHome(options = {}) {
|
|
59
|
+
return path.resolve(
|
|
60
|
+
options.openprdHome
|
|
61
|
+
?? process.env.OPENPRD_HOME
|
|
62
|
+
?? cjoin(os.homedir(), '.openprd'),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function workspaceRegistryFilePath(options = {}) {
|
|
67
|
+
return cjoin(resolveOpenPrdHome(options), OPENPRD_WORKSPACE_REGISTRY);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function buildWorkspaceRegistrySnapshot(projectRoot, options = {}) {
|
|
71
|
+
const workspaceRoot = path.resolve(projectRoot);
|
|
72
|
+
const realpath = await fs.realpath(workspaceRoot).catch(() => workspaceRoot);
|
|
73
|
+
const manifestPath = cjoin(workspaceRoot, OPENPRD_HARNESS_MANIFEST);
|
|
74
|
+
const manifest = options.manifest ?? await readJson(manifestPath).catch(() => null);
|
|
75
|
+
const recordedAt = options.recordedAt ?? timestamp();
|
|
76
|
+
|
|
77
|
+
return normalizeWorkspaceRegistryEntry({
|
|
78
|
+
workspaceRoot,
|
|
79
|
+
realpath,
|
|
80
|
+
workspaceName: path.basename(workspaceRoot),
|
|
81
|
+
manifestPath,
|
|
82
|
+
openprdVersion: options.openprdVersion ?? manifest?.openprdVersion ?? null,
|
|
83
|
+
tools: normalizeToolsArray(options.tools ?? manifest?.tools),
|
|
84
|
+
hookProfile: options.hookProfile ?? manifest?.hooks?.profile ?? null,
|
|
85
|
+
initializedAt: manifest?.generatedAt ?? recordedAt,
|
|
86
|
+
lastUpdatedAt: manifest?.generatedAt ?? recordedAt,
|
|
87
|
+
lastRegisteredAt: recordedAt,
|
|
88
|
+
lastAction: options.action ?? manifest?.action ?? 'detected',
|
|
89
|
+
manifestPresent: manifest !== null,
|
|
90
|
+
recordedAt,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function readWorkspaceRegistry(options = {}) {
|
|
95
|
+
const home = resolveOpenPrdHome(options);
|
|
96
|
+
const registryPath = workspaceRegistryFilePath({ openprdHome: home });
|
|
97
|
+
const events = await readJsonl(registryPath).catch(() => []);
|
|
98
|
+
const currentByKey = new Map();
|
|
99
|
+
for (const event of events) {
|
|
100
|
+
const entry = normalizeWorkspaceRegistryEntry(event);
|
|
101
|
+
if (!entry) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
currentByKey.set(entry.realpath || entry.workspaceRoot, entry);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const entries = Array.from(currentByKey.values())
|
|
108
|
+
.sort((left, right) => left.workspaceRoot.localeCompare(right.workspaceRoot));
|
|
109
|
+
|
|
110
|
+
const staleEntries = [];
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
const workspaceExists = await exists(entry.workspaceRoot);
|
|
113
|
+
const markerExists = workspaceExists && await exists(cjoin(entry.workspaceRoot, OPENPRD_WORKSPACE_MARKER));
|
|
114
|
+
if (!markerExists) {
|
|
115
|
+
staleEntries.push({
|
|
116
|
+
...entry,
|
|
117
|
+
reason: workspaceExists ? 'missing-openprd-marker' : 'missing-path',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
home,
|
|
124
|
+
registryPath,
|
|
125
|
+
totalEvents: events.length,
|
|
126
|
+
entries,
|
|
127
|
+
staleEntries,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function upsertWorkspaceRegistryEntry(projectRoot, options = {}) {
|
|
132
|
+
const registry = await readWorkspaceRegistry(options);
|
|
133
|
+
const snapshot = await buildWorkspaceRegistrySnapshot(projectRoot, options);
|
|
134
|
+
const existing = registry.entries.find((entry) => entry.realpath === snapshot.realpath || entry.workspaceRoot === snapshot.workspaceRoot) ?? null;
|
|
135
|
+
const recordedAt = options.recordedAt ?? timestamp();
|
|
136
|
+
const entry = {
|
|
137
|
+
...existing,
|
|
138
|
+
...snapshot,
|
|
139
|
+
version: 1,
|
|
140
|
+
initializedAt: existing?.initializedAt ?? snapshot.initializedAt ?? recordedAt,
|
|
141
|
+
firstRegisteredAt: existing?.firstRegisteredAt ?? recordedAt,
|
|
142
|
+
lastRegisteredAt: recordedAt,
|
|
143
|
+
lastUpdatedAt: snapshot.lastUpdatedAt ?? existing?.lastUpdatedAt ?? recordedAt,
|
|
144
|
+
lastAction: snapshot.lastAction ?? existing?.lastAction ?? 'detected',
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
await appendJsonl(registry.registryPath, entry);
|
|
148
|
+
return {
|
|
149
|
+
home: registry.home,
|
|
150
|
+
registryPath: registry.registryPath,
|
|
151
|
+
entry,
|
|
152
|
+
status: existing ? 'updated' : 'created',
|
|
153
|
+
knownTotal: existing ? registry.entries.length : registry.entries.length + 1,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export {
|
|
158
|
+
readWorkspaceRegistry,
|
|
159
|
+
resolveOpenPrdHome,
|
|
160
|
+
upsertWorkspaceRegistryEntry,
|
|
161
|
+
workspaceRegistryFilePath,
|
|
162
|
+
};
|