@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.
Files changed (154) hide show
  1. package/.openprd/README.md +82 -0
  2. package/.openprd/benchmarks/evidence/milvus-io-ai-code-review-gets-better-when-models-debate-claude-vs-gemini-vs-code.md +14 -0
  3. package/.openprd/benchmarks/evidence/nolanlawson-com-using-ai-to-write-better-code-more-slowly.md +14 -0
  4. package/.openprd/benchmarks/index.md +37 -0
  5. package/.openprd/benchmarks/sources.yaml +56 -0
  6. package/.openprd/config.yaml +50 -0
  7. package/.openprd/discovery/config.json +21 -0
  8. package/.openprd/engagements/active/flows.md +30 -0
  9. package/.openprd/engagements/active/handoff.md +9 -0
  10. package/.openprd/engagements/active/intake.md +15 -0
  11. package/.openprd/engagements/active/prd.md +161 -0
  12. package/.openprd/engagements/active/review.html +61 -0
  13. package/.openprd/engagements/active/roles.md +21 -0
  14. package/.openprd/engagements/work-units/wu-20260524015648-6d33ded7.json +23 -0
  15. package/.openprd/exports/.gitkeep +0 -0
  16. package/.openprd/knowledge/index.json +7 -0
  17. package/.openprd/quality/config.json +229 -0
  18. package/.openprd/reviews/v0001.html +1256 -0
  19. package/.openprd/schema/diagram-architecture.schema.yaml +49 -0
  20. package/.openprd/schema/diagram-product-flow.schema.yaml +52 -0
  21. package/.openprd/schema/prd.schema.yaml +121 -0
  22. package/.openprd/sessions/.gitkeep +0 -0
  23. package/.openprd/standards/config.json +88 -0
  24. package/.openprd/standards/file-manual-template.md +28 -0
  25. package/.openprd/standards/folder-readme-template.md +28 -0
  26. package/.openprd/state/.gitkeep +0 -0
  27. package/.openprd/state/changes.json +12 -0
  28. package/.openprd/state/current.json +169 -0
  29. package/.openprd/state/version-index.json +15 -0
  30. package/.openprd/state/versions/.gitkeep +0 -0
  31. package/.openprd/state/versions/v0001.json +121 -0
  32. package/.openprd/state/versions/v0001.md +161 -0
  33. package/.openprd/templates/agent/intake.md +6 -0
  34. package/.openprd/templates/agent/prd.md +21 -0
  35. package/.openprd/templates/b2b/intake.md +6 -0
  36. package/.openprd/templates/b2b/prd.md +24 -0
  37. package/.openprd/templates/base/intake.md +18 -0
  38. package/.openprd/templates/base/prd.md +67 -0
  39. package/.openprd/templates/company/README.md +10 -0
  40. package/.openprd/templates/consumer/intake.md +6 -0
  41. package/.openprd/templates/consumer/prd.md +19 -0
  42. package/.openprd/templates/diagram/architecture.contract.json +53 -0
  43. package/.openprd/templates/diagram/product-flow.contract.json +76 -0
  44. package/.openprd/templates/industry/README.md +16 -0
  45. package/.openprd/templates/manifest.yaml +27 -0
  46. package/.openprd/templates/project/README.md +14 -0
  47. package/.openprd/templates/session/README.md +14 -0
  48. package/AGENTS.md +44 -0
  49. package/CONTRIBUTING.md +30 -0
  50. package/LICENSE +21 -0
  51. package/README.md +727 -0
  52. package/README_CN.md +583 -0
  53. package/SECURITY.md +23 -0
  54. package/bin/openprd.js +5 -0
  55. package/docs/assets/openprd-capability-overview-en.png +0 -0
  56. package/docs/assets/openprd-capability-overview-zh.png +0 -0
  57. package/docs/assets/openprd-learning-html.png +0 -0
  58. package/docs/assets/openprd-quality-html.png +0 -0
  59. package/docs/assets/openprd-review-html.png +0 -0
  60. package/docs/assets/openprd-scenario-overview.png +0 -0
  61. package/docs/assets/openprd-scenario-overview.svg +114 -0
  62. package/docs/assets/openprd-self-evolving-mechanisms-en.png +0 -0
  63. package/docs/assets/openprd-self-evolving-mechanisms-zh.png +0 -0
  64. package/docs/assets/openprd-visual-compare-case-study-en.png +0 -0
  65. package/docs/assets/openprd-visual-compare-case-study-zh.png +0 -0
  66. package/package.json +59 -0
  67. package/scripts/openprd-dev-check.mjs +5 -0
  68. package/scripts/openprd-review-presentation.mjs +82 -0
  69. package/skills/openprd-benchmark-router/SKILL.md +92 -0
  70. package/skills/openprd-benchmark-router/agents/openai.yaml +4 -0
  71. package/skills/openprd-benchmark-router/references/benchmark-sources.md +74 -0
  72. package/skills/openprd-benchmark-router/references/evaluation-lenses.md +66 -0
  73. package/skills/openprd-benchmark-router/references/source-policy.md +35 -0
  74. package/skills/openprd-diagram-review/SKILL.md +91 -0
  75. package/skills/openprd-diagram-review/agents/openai.yaml +4 -0
  76. package/skills/openprd-diagram-review/examples/architecture-zh.md +8 -0
  77. package/skills/openprd-diagram-review/examples/product-flow-zh.md +7 -0
  78. package/skills/openprd-diagram-review/references/cocoon-patterns.md +17 -0
  79. package/skills/openprd-diagram-review/references/diagram-contracts.md +126 -0
  80. package/skills/openprd-diagram-review/references/review-checklist.md +10 -0
  81. package/skills/openprd-discovery-loop/SKILL.md +196 -0
  82. package/skills/openprd-discovery-loop/agents/openai.yaml +3 -0
  83. package/skills/openprd-harness/SKILL.md +179 -0
  84. package/skills/openprd-harness/agents/openai.yaml +4 -0
  85. package/skills/openprd-harness/examples/full-workflow-zh.md +9 -0
  86. package/skills/openprd-harness/references/command-map.md +71 -0
  87. package/skills/openprd-harness/references/examples.md +26 -0
  88. package/skills/openprd-harness/references/usage-guide.md +335 -0
  89. package/skills/openprd-harness/references/workflow-gates.md +51 -0
  90. package/skills/openprd-learning-review/SKILL.md +75 -0
  91. package/skills/openprd-learning-review/agents/openai.yaml +4 -0
  92. package/skills/openprd-learning-review/references/content-contract.md +125 -0
  93. package/skills/openprd-learning-review/references/ebook-reader.md +46 -0
  94. package/skills/openprd-learning-review/references/evidence-manifest.md +55 -0
  95. package/skills/openprd-learning-review/references/genre-library.md +43 -0
  96. package/skills/openprd-learning-review/references/prompt-engineering.md +71 -0
  97. package/skills/openprd-learning-review/references/quality-rubric.md +28 -0
  98. package/skills/openprd-learning-review/references/retrieval-worked-example.md +40 -0
  99. package/skills/openprd-learning-review/references/style-packs/xianxia-cultivation.prompt.md +67 -0
  100. package/skills/openprd-quality/SKILL.md +101 -0
  101. package/skills/openprd-requirement-intake/SKILL.md +76 -0
  102. package/skills/openprd-requirement-intake/agents/openai.yaml +4 -0
  103. package/skills/openprd-requirement-intake/references/prd-template-lenses.md +105 -0
  104. package/skills/openprd-requirement-intake/references/routing-rubric.md +64 -0
  105. package/skills/openprd-router/SKILL.md +40 -0
  106. package/skills/openprd-shared/SKILL.md +142 -0
  107. package/skills/openprd-shared/agents/openai.yaml +4 -0
  108. package/skills/openprd-shared/references/language-and-review.md +50 -0
  109. package/skills/openprd-shared/references/operating-rules.md +65 -0
  110. package/skills/openprd-shared/references/skill-architecture.md +70 -0
  111. package/skills/openprd-standards/SKILL.md +79 -0
  112. package/skills/openprd-standards/agents/openai.yaml +4 -0
  113. package/src/agent-integration.js +1717 -0
  114. package/src/benchmark.js +873 -0
  115. package/src/cli/args.js +460 -0
  116. package/src/cli/print.js +1423 -0
  117. package/src/codex-hook-runner-template.mjs +2422 -0
  118. package/src/dev-standards.js +372 -0
  119. package/src/diagram-core.js +1047 -0
  120. package/src/diagram-workspace.js +262 -0
  121. package/src/discovery.js +709 -0
  122. package/src/fleet.js +531 -0
  123. package/src/fs-utils.js +83 -0
  124. package/src/growth.js +545 -0
  125. package/src/html-artifacts.js +3803 -0
  126. package/src/knowledge.js +668 -0
  127. package/src/language-policy.js +142 -0
  128. package/src/learning-review.js +1655 -0
  129. package/src/loop.js +1290 -0
  130. package/src/openprd.js +1136 -0
  131. package/src/openspec/change-lifecycle.js +359 -0
  132. package/src/openspec/change-validate.js +248 -0
  133. package/src/openspec/constants.js +12 -0
  134. package/src/openspec/execute.js +300 -0
  135. package/src/openspec/generate.js +692 -0
  136. package/src/openspec/paths.js +111 -0
  137. package/src/openspec/tasks.js +352 -0
  138. package/src/prd-core.js +656 -0
  139. package/src/quality-html-artifact.js +1414 -0
  140. package/src/quality-learning.js +658 -0
  141. package/src/quality.js +1262 -0
  142. package/src/review-presentation.js +240 -0
  143. package/src/run-harness.js +1470 -0
  144. package/src/self-update.js +329 -0
  145. package/src/session-binding.js +140 -0
  146. package/src/source-inventory.js +224 -0
  147. package/src/standards.js +914 -0
  148. package/src/time.js +33 -0
  149. package/src/visual-compare.js +216 -0
  150. package/src/work-unit-migration.js +232 -0
  151. package/src/work-unit.js +88 -0
  152. package/src/workspace-core.js +1706 -0
  153. package/src/workspace-registry.js +162 -0
  154. 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
+ };