@urielsh/prodify 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 (273) hide show
  1. package/.prodify/AGENTS.md +56 -0
  2. package/.prodify/README.md +10 -0
  3. package/.prodify/artifacts/01-understand.md +28 -0
  4. package/.prodify/artifacts/02-diagnose.md +26 -0
  5. package/.prodify/artifacts/03-architecture.md +30 -0
  6. package/.prodify/artifacts/04-plan.md +35 -0
  7. package/.prodify/artifacts/05-refactor.md +24 -0
  8. package/.prodify/artifacts/06-validate.md +17 -0
  9. package/.prodify/artifacts/README.md +6 -0
  10. package/.prodify/artifacts/architecture_spec.md +29 -0
  11. package/.prodify/artifacts/artifact-validation-design.md +276 -0
  12. package/.prodify/artifacts/cli-command-design.md +299 -0
  13. package/.prodify/artifacts/completed-steps-tracking.md +201 -0
  14. package/.prodify/artifacts/diagnostic_report.md +45 -0
  15. package/.prodify/artifacts/hardening-patch-summary.md +57 -0
  16. package/.prodify/artifacts/hardening-verification-report.md +48 -0
  17. package/.prodify/artifacts/implementation_summary.md +19 -0
  18. package/.prodify/artifacts/improvement-evaluation-spec.md +148 -0
  19. package/.prodify/artifacts/next-step-resolver-design.md +570 -0
  20. package/.prodify/artifacts/orientation_map.md +32 -0
  21. package/.prodify/artifacts/persona-removal-audit.md +106 -0
  22. package/.prodify/artifacts/planning-alignment-report.md +189 -0
  23. package/.prodify/artifacts/refactor-plan-template-hardening.md +83 -0
  24. package/.prodify/artifacts/refactor-validate-loop-design.md +231 -0
  25. package/.prodify/artifacts/refactor_plan.md +21 -0
  26. package/.prodify/artifacts/refactor_plan.strict-example.md +31 -0
  27. package/.prodify/artifacts/run-state-design.md +292 -0
  28. package/.prodify/artifacts/run-summary-spec.md +149 -0
  29. package/.prodify/artifacts/run_state.json +14 -0
  30. package/.prodify/artifacts/sample-repo-test-plan.md +129 -0
  31. package/.prodify/artifacts/status-output-spec.md +349 -0
  32. package/.prodify/artifacts/step-selection-design.md +251 -0
  33. package/.prodify/artifacts/task-dispatcher-design.md +266 -0
  34. package/.prodify/artifacts/task-header-audit.md +42 -0
  35. package/.prodify/artifacts/task-log-enhancement-spec.md +264 -0
  36. package/.prodify/artifacts/task-protocol-hardening-plan.md +68 -0
  37. package/.prodify/artifacts/task-self-validation-spec.md +171 -0
  38. package/.prodify/artifacts/task_log.json +160 -0
  39. package/.prodify/artifacts/template-usage-audit.md +20 -0
  40. package/.prodify/artifacts/validation_report.md +22 -0
  41. package/.prodify/contracts/README.md +3 -0
  42. package/.prodify/contracts/architecture.contract.json +42 -0
  43. package/.prodify/contracts/diagnose.contract.json +42 -0
  44. package/.prodify/contracts/plan.contract.json +42 -0
  45. package/.prodify/contracts/refactor.contract.json +45 -0
  46. package/.prodify/contracts/understand.contract.json +42 -0
  47. package/.prodify/contracts/validate.contract.json +52 -0
  48. package/.prodify/contracts-src/README.md +4 -0
  49. package/.prodify/contracts-src/architecture.contract.md +29 -0
  50. package/.prodify/contracts-src/diagnose.contract.md +29 -0
  51. package/.prodify/contracts-src/plan.contract.md +29 -0
  52. package/.prodify/contracts-src/refactor.contract.md +32 -0
  53. package/.prodify/contracts-src/understand.contract.md +29 -0
  54. package/.prodify/contracts-src/validate.contract.md +35 -0
  55. package/.prodify/metrics/README.md +4 -0
  56. package/.prodify/planning.md +13 -0
  57. package/.prodify/project.md +15 -0
  58. package/.prodify/rules/01-global-operating-rules.md +21 -0
  59. package/.prodify/rules/02-analysis-discipline.md +17 -0
  60. package/.prodify/rules/03-diagnosis-severity-rules.md +42 -0
  61. package/.prodify/rules/04-architecture-rules.md +27 -0
  62. package/.prodify/rules/05-planning-rules.md +23 -0
  63. package/.prodify/rules/06-refactor-rules.md +20 -0
  64. package/.prodify/rules/07-validation-rules.md +25 -0
  65. package/.prodify/rules/08-output-format-rules.md +20 -0
  66. package/.prodify/rules/09-template-usage-rules.md +11 -0
  67. package/.prodify/rules/10-artifact-flow-and-orchestration-rules.md +40 -0
  68. package/.prodify/rules/README.md +3 -0
  69. package/.prodify/rules/example-rule.md +4 -0
  70. package/.prodify/runtime-commands.md +57 -0
  71. package/.prodify/skills/README.md +8 -0
  72. package/.prodify/skills/domain/react-frontend.skill.json +34 -0
  73. package/.prodify/skills/domain/typescript-backend.skill.json +34 -0
  74. package/.prodify/skills/quality-policy/maintainability-review.skill.json +25 -0
  75. package/.prodify/skills/quality-policy/security-hardening.skill.json +32 -0
  76. package/.prodify/skills/quality-policy/test-hardening.skill.json +23 -0
  77. package/.prodify/skills/registry.json +16 -0
  78. package/.prodify/skills/stage-method/architecture-method.skill.json +22 -0
  79. package/.prodify/skills/stage-method/codebase-scanning.skill.json +22 -0
  80. package/.prodify/skills/stage-method/diagnosis-method.skill.json +22 -0
  81. package/.prodify/skills/stage-method/planning-method.skill.json +22 -0
  82. package/.prodify/skills/stage-method/refactoring-method.skill.json +22 -0
  83. package/.prodify/skills/stage-method/validation-method.skill.json +22 -0
  84. package/.prodify/state.json +30 -0
  85. package/.prodify/tasks/01-understand.md +83 -0
  86. package/.prodify/tasks/02-diagnose.md +67 -0
  87. package/.prodify/tasks/03-architecture.md +70 -0
  88. package/.prodify/tasks/04-plan.md +71 -0
  89. package/.prodify/tasks/05-refactor.md +61 -0
  90. package/.prodify/tasks/06-validate.md +69 -0
  91. package/.prodify/tasks/README.md +3 -0
  92. package/.prodify/tasks/example-task.md +13 -0
  93. package/.prodify/templates/01-understand.template.md +18 -0
  94. package/.prodify/templates/02-diagnose.template.md +18 -0
  95. package/.prodify/templates/03-architecture.template.md +18 -0
  96. package/.prodify/templates/04-plan.template.md +22 -0
  97. package/.prodify/templates/05-refactor.template.md +19 -0
  98. package/.prodify/templates/06-validate.template.md +16 -0
  99. package/.prodify/templates/README.md +3 -0
  100. package/.prodify/templates/architecture_spec.template.md +29 -0
  101. package/.prodify/templates/diagnostic_report.template.md +45 -0
  102. package/.prodify/templates/example.template.md +5 -0
  103. package/.prodify/templates/implementation_summary.template.md +19 -0
  104. package/.prodify/templates/orientation_map.template.md +32 -0
  105. package/.prodify/templates/refactor_plan.template.md +24 -0
  106. package/.prodify/templates/validation_report.template.md +22 -0
  107. package/.prodify/version.json +5 -0
  108. package/AGENTS.md +305 -0
  109. package/LICENSE +201 -0
  110. package/README.md +118 -0
  111. package/assets/presets/default/canonical/AGENTS.md +54 -0
  112. package/assets/presets/default/canonical/artifacts/README.md +6 -0
  113. package/assets/presets/default/canonical/contracts-src/README.md +4 -0
  114. package/assets/presets/default/canonical/contracts-src/architecture.contract.md +56 -0
  115. package/assets/presets/default/canonical/contracts-src/diagnose.contract.md +49 -0
  116. package/assets/presets/default/canonical/contracts-src/plan.contract.md +42 -0
  117. package/assets/presets/default/canonical/contracts-src/refactor.contract.md +54 -0
  118. package/assets/presets/default/canonical/contracts-src/understand.contract.md +56 -0
  119. package/assets/presets/default/canonical/contracts-src/validate.contract.md +64 -0
  120. package/assets/presets/default/canonical/metrics/README.md +4 -0
  121. package/assets/presets/default/canonical/planning.md +13 -0
  122. package/assets/presets/default/canonical/project.md +15 -0
  123. package/assets/presets/default/canonical/rules/README.md +3 -0
  124. package/assets/presets/default/canonical/rules/example-rule.md +4 -0
  125. package/assets/presets/default/canonical/runtime-commands.md +57 -0
  126. package/assets/presets/default/canonical/skills/README.md +8 -0
  127. package/assets/presets/default/canonical/skills/domain/react-frontend.skill.json +34 -0
  128. package/assets/presets/default/canonical/skills/domain/typescript-backend.skill.json +34 -0
  129. package/assets/presets/default/canonical/skills/quality-policy/maintainability-review.skill.json +25 -0
  130. package/assets/presets/default/canonical/skills/quality-policy/security-hardening.skill.json +32 -0
  131. package/assets/presets/default/canonical/skills/quality-policy/test-hardening.skill.json +23 -0
  132. package/assets/presets/default/canonical/skills/registry.json +16 -0
  133. package/assets/presets/default/canonical/skills/stage-method/architecture-method.skill.json +22 -0
  134. package/assets/presets/default/canonical/skills/stage-method/codebase-scanning.skill.json +22 -0
  135. package/assets/presets/default/canonical/skills/stage-method/diagnosis-method.skill.json +22 -0
  136. package/assets/presets/default/canonical/skills/stage-method/planning-method.skill.json +22 -0
  137. package/assets/presets/default/canonical/skills/stage-method/refactoring-method.skill.json +22 -0
  138. package/assets/presets/default/canonical/skills/stage-method/validation-method.skill.json +22 -0
  139. package/assets/presets/default/canonical/state.json +30 -0
  140. package/assets/presets/default/canonical/tasks/README.md +3 -0
  141. package/assets/presets/default/canonical/tasks/example-task.md +13 -0
  142. package/assets/presets/default/canonical/templates/README.md +3 -0
  143. package/assets/presets/default/canonical/templates/example.template.md +5 -0
  144. package/assets/presets/default/preset.json +5 -0
  145. package/dist/cli.js +53 -0
  146. package/dist/commands/doctor.js +16 -0
  147. package/dist/commands/init.js +30 -0
  148. package/dist/commands/install.js +27 -0
  149. package/dist/commands/setup-agent.js +23 -0
  150. package/dist/commands/status.js +28 -0
  151. package/dist/commands/sync.js +29 -0
  152. package/dist/commands/update.js +18 -0
  153. package/dist/contracts/compiled-schema.js +37 -0
  154. package/dist/contracts/compiler.js +83 -0
  155. package/dist/contracts/freshness.js +52 -0
  156. package/dist/contracts/index.js +5 -0
  157. package/dist/contracts/parser.js +201 -0
  158. package/dist/contracts/schema.js +138 -0
  159. package/dist/contracts/source-schema.js +111 -0
  160. package/dist/core/agent-runtime.js +36 -0
  161. package/dist/core/agent-setup.js +111 -0
  162. package/dist/core/doctor.js +155 -0
  163. package/dist/core/errors.js +19 -0
  164. package/dist/core/flow-state.js +262 -0
  165. package/dist/core/fs.js +50 -0
  166. package/dist/core/install.js +44 -0
  167. package/dist/core/managed-files.js +106 -0
  168. package/dist/core/paths.js +56 -0
  169. package/dist/core/preset-validation.js +43 -0
  170. package/dist/core/prompt-builder.js +63 -0
  171. package/dist/core/repo-context.js +77 -0
  172. package/dist/core/repo-root.js +55 -0
  173. package/dist/core/skill-resolution.js +123 -0
  174. package/dist/core/state.js +220 -0
  175. package/dist/core/status.js +293 -0
  176. package/dist/core/sync.js +63 -0
  177. package/dist/core/targets.js +48 -0
  178. package/dist/core/upgrade.js +57 -0
  179. package/dist/core/validation.js +138 -0
  180. package/dist/core/version-checks.js +35 -0
  181. package/dist/generators/claude.js +14 -0
  182. package/dist/generators/codex.js +14 -0
  183. package/dist/generators/copilot.js +29 -0
  184. package/dist/generators/header.js +13 -0
  185. package/dist/generators/opencode.js +14 -0
  186. package/dist/generators/shared.js +37 -0
  187. package/dist/index.js +9 -0
  188. package/dist/legacy/targets.js +55 -0
  189. package/dist/presets/default.js +3 -0
  190. package/dist/presets/loader.js +34 -0
  191. package/dist/presets/version.js +18 -0
  192. package/dist/scoring/model.js +262 -0
  193. package/dist/skills/loader.js +40 -0
  194. package/dist/skills/schema.js +159 -0
  195. package/dist/types.js +1 -0
  196. package/docs/canonical-prodify-layout.md +87 -0
  197. package/docs/claude-support.md +22 -0
  198. package/docs/cli-doctor-spec.md +52 -0
  199. package/docs/cli-init-spec.md +70 -0
  200. package/docs/cli-install-agent-spec.md +48 -0
  201. package/docs/cli-sync-spec.md +40 -0
  202. package/docs/codex-support.md +24 -0
  203. package/docs/compatibility-targets.md +59 -0
  204. package/docs/copilot-support.md +30 -0
  205. package/docs/default-preset.md +47 -0
  206. package/docs/generated-file-headers.md +45 -0
  207. package/docs/generation-rules.md +94 -0
  208. package/docs/idempotency-guarantees.md +31 -0
  209. package/docs/managed-file-detection.md +45 -0
  210. package/docs/manual-edit-conflicts.md +37 -0
  211. package/docs/opencode-support.md +27 -0
  212. package/docs/ownership-rules.md +39 -0
  213. package/docs/path-resolution-rules.md +40 -0
  214. package/docs/preset-structure.md +49 -0
  215. package/docs/skill-system.md +67 -0
  216. package/docs/versioning-and-upgrade-strategy.md +40 -0
  217. package/package.json +22 -0
  218. package/src/README.md +11 -0
  219. package/src/cli.ts +61 -0
  220. package/src/commands/doctor.ts +20 -0
  221. package/src/commands/init.ts +37 -0
  222. package/src/commands/setup-agent.ts +28 -0
  223. package/src/commands/status.ts +34 -0
  224. package/src/commands/update.ts +23 -0
  225. package/src/contracts/README.md +10 -0
  226. package/src/contracts/compiled-schema.ts +42 -0
  227. package/src/contracts/compiler.ts +111 -0
  228. package/src/contracts/freshness.ts +58 -0
  229. package/src/contracts/index.ts +11 -0
  230. package/src/contracts/parser.ts +253 -0
  231. package/src/contracts/source-schema.ts +141 -0
  232. package/src/core/agent-runtime.ts +53 -0
  233. package/src/core/agent-setup.ts +147 -0
  234. package/src/core/doctor.ts +171 -0
  235. package/src/core/errors.ts +28 -0
  236. package/src/core/flow-state.ts +333 -0
  237. package/src/core/fs.ts +59 -0
  238. package/src/core/paths.ts +63 -0
  239. package/src/core/preset-validation.ts +47 -0
  240. package/src/core/prompt-builder.ts +73 -0
  241. package/src/core/repo-context.ts +93 -0
  242. package/src/core/repo-root.ts +74 -0
  243. package/src/core/skill-resolution.ts +151 -0
  244. package/src/core/state.ts +264 -0
  245. package/src/core/status.ts +372 -0
  246. package/src/core/targets.ts +53 -0
  247. package/src/core/upgrade.ts +66 -0
  248. package/src/core/validation.ts +233 -0
  249. package/src/core/version-checks.ts +40 -0
  250. package/src/index.ts +13 -0
  251. package/src/presets/default.ts +7 -0
  252. package/src/presets/loader.ts +46 -0
  253. package/src/presets/version.ts +31 -0
  254. package/src/scoring/model.ts +332 -0
  255. package/src/skills/loader.ts +58 -0
  256. package/src/skills/schema.ts +197 -0
  257. package/src/types.ts +329 -0
  258. package/tests/integration/cli-flows.test.js +347 -0
  259. package/tests/unit/agent-setup.test.js +81 -0
  260. package/tests/unit/cli.test.js +28 -0
  261. package/tests/unit/contracts.test.js +61 -0
  262. package/tests/unit/helpers.js +28 -0
  263. package/tests/unit/paths.test.js +52 -0
  264. package/tests/unit/preset-loader.test.js +37 -0
  265. package/tests/unit/scoring.test.js +65 -0
  266. package/tests/unit/self-hosted-workspace.test.js +22 -0
  267. package/tests/unit/skills.test.js +115 -0
  268. package/tests/unit/state-and-flow.test.js +120 -0
  269. package/tests/unit/targets.test.js +13 -0
  270. package/tests/unit/validation.test.js +73 -0
  271. package/tests/unit/version.test.js +24 -0
  272. package/tsconfig.json +23 -0
  273. package/urielsh-prodify-0.1.0.tgz +0 -0
@@ -0,0 +1,372 @@
1
+ import fs from 'node:fs/promises';
2
+
3
+ import { loadDefaultPreset } from '../presets/loader.js';
4
+ import { inspectCompiledContracts } from '../contracts/freshness.js';
5
+ import { listConfiguredAgents, readGlobalAgentSetupState } from './agent-setup.js';
6
+ import { detectRuntimeAgentFromEnv } from './agent-runtime.js';
7
+ import { pathExists } from './fs.js';
8
+ import { getResumeDecision } from './flow-state.js';
9
+ import { resolveStageSkills } from './skill-resolution.js';
10
+ import { resolveCanonicalPath, resolveRepoPath, REQUIRED_CANONICAL_PATHS } from './paths.js';
11
+ import { readRuntimeState, RUNTIME_STATUS } from './state.js';
12
+ import { inspectVersionStatus } from './version-checks.js';
13
+ import { buildBootstrapPrompt, hasManualBootstrapGuidance } from './prompt-builder.js';
14
+ import { getRuntimeProfile } from './targets.js';
15
+ import type {
16
+ RuntimeProfileName,
17
+ RuntimeStateBlock,
18
+ StatusReport,
19
+ VersionInspection,
20
+ VersionMetadata
21
+ } from '../types.js';
22
+
23
+ function describeCanonicalHealth(missingPaths: string[]): string {
24
+ if (missingPaths.length === 0) {
25
+ return 'healthy';
26
+ }
27
+
28
+ return `missing ${missingPaths.join(', ')}`;
29
+ }
30
+
31
+ function hasStageValidationFailure(report: StatusReport): boolean {
32
+ return report.runtimeState?.runtime.current_state === 'failed'
33
+ || report.runtimeState?.runtime.last_validation_result === 'fail';
34
+ }
35
+
36
+ function describeWorkspaceHealth(report: StatusReport): string {
37
+ if (!report.initialized) {
38
+ return 'not initialized';
39
+ }
40
+
41
+ const issues = [];
42
+ if (!report.canonicalOk) {
43
+ issues.push(`canonical files: ${describeCanonicalHealth(report.canonicalMissing)}`);
44
+ }
45
+ if (report.versionStatus.status !== 'current') {
46
+ issues.push(`version/schema: ${report.versionStatus.status}`);
47
+ }
48
+ if (report.runtimeStateError) {
49
+ issues.push('runtime state unreadable');
50
+ }
51
+ if (!report.manualBootstrapReady) {
52
+ issues.push('bootstrap guidance incomplete');
53
+ }
54
+
55
+ return issues.length === 0 ? 'healthy' : `repair required (${issues.join('; ')})`;
56
+ }
57
+
58
+ function describeContractFreshness(report: StatusReport): string {
59
+ if (!report.contractInventory) {
60
+ return 'unavailable';
61
+ }
62
+
63
+ if (report.contractInventory.ok) {
64
+ return `${report.contractInventory.compiledCount} compiled, synchronized`;
65
+ }
66
+
67
+ const parts = [];
68
+ if (report.contractInventory.missingCompiledStages.length > 0) {
69
+ parts.push(`missing compiled: ${report.contractInventory.missingCompiledStages.join(', ')}`);
70
+ }
71
+ if (report.contractInventory.staleStages.length > 0) {
72
+ parts.push(`stale: ${report.contractInventory.staleStages.join(', ')}`);
73
+ }
74
+ if (report.contractInventory.invalidStages.length > 0) {
75
+ parts.push(`invalid: ${report.contractInventory.invalidStages.join(', ')}`);
76
+ }
77
+
78
+ return parts.join('; ') || 'invalid';
79
+ }
80
+
81
+ function describeGlobalAgentSetup(report: StatusReport): string {
82
+ return report.configuredAgents.length === 0 ? 'none configured' : report.configuredAgents.join(', ');
83
+ }
84
+
85
+ function describeSkillStage(report: StatusReport): string {
86
+ return report.stageSkillResolution?.stage ?? 'unavailable';
87
+ }
88
+
89
+ function describeConsideredSkills(report: StatusReport): string {
90
+ if (!report.stageSkillResolution) {
91
+ return 'unavailable';
92
+ }
93
+
94
+ if (report.stageSkillResolution.considered_skills.length === 0) {
95
+ return 'none';
96
+ }
97
+
98
+ return report.stageSkillResolution.considered_skills
99
+ .map((skill) => `${skill.id} [${skill.reason}]`)
100
+ .join(', ');
101
+ }
102
+
103
+ function describeActiveSkills(report: StatusReport): string {
104
+ if (!report.stageSkillResolution) {
105
+ return 'unavailable';
106
+ }
107
+
108
+ const activeSkills = report.stageSkillResolution.considered_skills.filter((skill) => skill.active);
109
+ if (activeSkills.length === 0) {
110
+ return 'none';
111
+ }
112
+
113
+ return activeSkills.map((skill) => `${skill.id} [${skill.reason}]`).join(', ');
114
+ }
115
+
116
+ function describeVersion(versionStatus: VersionInspection, presetMetadata: VersionMetadata): string {
117
+ if (versionStatus.status === 'current') {
118
+ return `current (${presetMetadata.name}@${presetMetadata.version}, schema ${presetMetadata.schemaVersion})`;
119
+ }
120
+
121
+ if (versionStatus.status === 'outdated' && versionStatus.current) {
122
+ return `outdated (${versionStatus.current.presetName}@${versionStatus.current.presetVersion}, schema ${versionStatus.current.schemaVersion})`;
123
+ }
124
+
125
+ if (versionStatus.status === 'malformed') {
126
+ return 'malformed';
127
+ }
128
+
129
+ return 'missing';
130
+ }
131
+
132
+ function describeRuntime(runtime: RuntimeStateBlock | null): string {
133
+ if (!runtime) {
134
+ return 'unavailable';
135
+ }
136
+
137
+ if (runtime.status === RUNTIME_STATUS.NOT_BOOTSTRAPPED) {
138
+ return 'not bootstrapped';
139
+ }
140
+
141
+ const stage = runtime.current_stage ?? runtime.pending_stage ?? 'none';
142
+ const task = runtime.current_task_id ?? (runtime.pending_stage ? `${runtime.pending_stage} pending` : 'none');
143
+ return `${runtime.current_state} at ${stage} (${task})`;
144
+ }
145
+
146
+ function describeStageValidation(report: StatusReport): string {
147
+ const runtime = report.runtimeState?.runtime ?? null;
148
+ if (!runtime) {
149
+ return 'unavailable';
150
+ }
151
+
152
+ if (runtime.current_state === 'failed' || runtime.last_validation_result === 'fail') {
153
+ const stage = runtime.failure_metadata?.stage ?? runtime.current_stage ?? null;
154
+ const reason = runtime.failure_metadata?.reason ?? runtime.blocked_reason ?? 'stage outputs failed contract validation';
155
+ return `failed${stage ? ` at ${stage}` : ''}: ${reason}`;
156
+ }
157
+
158
+ if (!runtime.last_validation) {
159
+ return 'not run yet';
160
+ }
161
+
162
+ return runtime.last_validation.passed
163
+ ? `last pass at ${runtime.last_validation.stage} (contract ${runtime.last_validation.contract_version})`
164
+ : `failed at ${runtime.last_validation.stage}`;
165
+ }
166
+
167
+ async function checkManualBootstrapGuidance(repoRoot: string): Promise<boolean> {
168
+ const agentsPath = resolveCanonicalPath(repoRoot, '.prodify/AGENTS.md');
169
+ if (!(await pathExists(agentsPath))) {
170
+ return false;
171
+ }
172
+
173
+ const content = await fs.readFile(agentsPath, 'utf8');
174
+ return hasManualBootstrapGuidance(content);
175
+ }
176
+
177
+ function deriveNextAction({
178
+ initialized,
179
+ canonicalOk,
180
+ contractsOk,
181
+ configuredAgents,
182
+ versionStatus,
183
+ runtimeState,
184
+ runtimeStateError,
185
+ bootstrapPrompt
186
+ }: {
187
+ initialized: boolean;
188
+ canonicalOk: boolean;
189
+ contractsOk: boolean;
190
+ configuredAgents: RuntimeProfileName[];
191
+ versionStatus: VersionInspection;
192
+ runtimeState: StatusReport['runtimeState'];
193
+ runtimeStateError: Error | null;
194
+ bootstrapPrompt: string;
195
+ }): string {
196
+ if (!initialized) {
197
+ return 'prodify init';
198
+ }
199
+
200
+ if (!canonicalOk || !contractsOk || ['missing', 'malformed', 'outdated'].includes(versionStatus.status)) {
201
+ return 'prodify update';
202
+ }
203
+
204
+ if (runtimeStateError) {
205
+ return 'prodify update';
206
+ }
207
+
208
+ if (!runtimeState || runtimeState.runtime.status === RUNTIME_STATUS.NOT_BOOTSTRAPPED) {
209
+ if (configuredAgents.length === 0) {
210
+ return 'prodify setup-agent <agent>';
211
+ }
212
+
213
+ return `tell your agent: "${bootstrapPrompt}"`;
214
+ }
215
+
216
+ if (runtimeState.runtime.current_state === 'failed' || runtimeState.runtime.last_validation_result === 'fail') {
217
+ return 'rerun or remediate stage outputs';
218
+ }
219
+
220
+ const resume = getResumeDecision(runtimeState);
221
+ if (!resume.resumable) {
222
+ return runtimeState.runtime.status === RUNTIME_STATUS.COMPLETE ? 'none' : 'repair runtime state';
223
+ }
224
+
225
+ return resume.command ?? 'repair runtime state';
226
+ }
227
+
228
+ export async function inspectRepositoryStatus(
229
+ repoRoot: string,
230
+ options: { agent?: string | null } = {}
231
+ ): Promise<StatusReport> {
232
+ const preset = await loadDefaultPreset();
233
+ const prodifyPath = resolveRepoPath(repoRoot, '.prodify');
234
+ const initialized = await pathExists(prodifyPath);
235
+ const configuredAgents = listConfiguredAgents(await readGlobalAgentSetupState({
236
+ allowMissing: true
237
+ }));
238
+ const bootstrapProfile = (
239
+ getRuntimeProfile(options.agent ?? null)?.name
240
+ ?? detectRuntimeAgentFromEnv()
241
+ ?? (configuredAgents.length === 1 ? configuredAgents[0] : 'codex')
242
+ ) as RuntimeProfileName;
243
+ const bootstrapPrompt = buildBootstrapPrompt(bootstrapProfile);
244
+
245
+ if (!initialized) {
246
+ return {
247
+ ok: false,
248
+ initialized: false,
249
+ canonicalOk: false,
250
+ canonicalMissing: [...REQUIRED_CANONICAL_PATHS],
251
+ contractsOk: false,
252
+ contractInventory: null,
253
+ versionStatus: {
254
+ status: 'missing',
255
+ current: null,
256
+ expected: preset.metadata,
257
+ schemaMigrationRequired: false
258
+ },
259
+ configuredAgents,
260
+ runtimeState: null,
261
+ runtimeStateError: null,
262
+ resumable: false,
263
+ manualBootstrapReady: false,
264
+ bootstrapProfile,
265
+ bootstrapPrompt,
266
+ stageSkillResolution: null,
267
+ recommendedNextAction: 'prodify init',
268
+ presetMetadata: preset.metadata
269
+ };
270
+ }
271
+
272
+ const missingPaths = [];
273
+ for (const relativePath of REQUIRED_CANONICAL_PATHS) {
274
+ if (!(await pathExists(resolveCanonicalPath(repoRoot, relativePath)))) {
275
+ missingPaths.push(relativePath);
276
+ }
277
+ }
278
+
279
+ const contractInventory = await inspectCompiledContracts(repoRoot);
280
+ const versionStatus = await inspectVersionStatus(repoRoot, preset.metadata);
281
+ let runtimeState = null;
282
+ let runtimeStateError = null;
283
+ let stageSkillResolution = null;
284
+
285
+ try {
286
+ runtimeState = await readRuntimeState(repoRoot, {
287
+ presetMetadata: preset.metadata
288
+ });
289
+ } catch (error) {
290
+ runtimeStateError = error instanceof Error ? error : new Error(String(error));
291
+ }
292
+
293
+ const manualBootstrapReady = await checkManualBootstrapGuidance(repoRoot);
294
+ const canonicalOk = missingPaths.length === 0;
295
+ if (canonicalOk && contractInventory.ok) {
296
+ const skillStage = runtimeState?.runtime.current_stage
297
+ ?? runtimeState?.runtime.pending_stage
298
+ ?? 'understand';
299
+ stageSkillResolution = await resolveStageSkills(repoRoot, skillStage);
300
+ }
301
+ const resume = runtimeState ? getResumeDecision(runtimeState) : {
302
+ resumable: false,
303
+ command: null,
304
+ reason: runtimeStateError?.message ?? 'runtime unavailable'
305
+ };
306
+ const stageValidationFailed = runtimeState?.runtime.current_state === 'failed'
307
+ || runtimeState?.runtime.last_validation_result === 'fail';
308
+
309
+ return {
310
+ ok: initialized
311
+ && canonicalOk
312
+ && contractInventory.ok
313
+ && versionStatus.status === 'current'
314
+ && !runtimeStateError
315
+ && manualBootstrapReady
316
+ && !stageValidationFailed,
317
+ initialized,
318
+ canonicalOk,
319
+ canonicalMissing: missingPaths,
320
+ contractsOk: contractInventory.ok,
321
+ contractInventory,
322
+ versionStatus,
323
+ configuredAgents,
324
+ runtimeState,
325
+ runtimeStateError,
326
+ resumable: resume.resumable,
327
+ manualBootstrapReady,
328
+ bootstrapProfile,
329
+ bootstrapPrompt,
330
+ stageSkillResolution,
331
+ recommendedNextAction: deriveNextAction({
332
+ initialized,
333
+ canonicalOk,
334
+ contractsOk: contractInventory.ok,
335
+ configuredAgents,
336
+ versionStatus,
337
+ runtimeState,
338
+ runtimeStateError,
339
+ bootstrapPrompt
340
+ }),
341
+ presetMetadata: preset.metadata
342
+ };
343
+ }
344
+
345
+ export function renderStatusReport(report: StatusReport): string {
346
+ const lines = [
347
+ 'Prodify Status',
348
+ `Repository: ${report.initialized ? 'initialized' : 'not initialized'}`,
349
+ `Workspace health: ${describeWorkspaceHealth(report)}`,
350
+ `Canonical files: ${describeCanonicalHealth(report.canonicalMissing)}`,
351
+ `Contract freshness: ${describeContractFreshness(report)}`,
352
+ `Version/schema: ${describeVersion(report.versionStatus, report.presetMetadata)}`,
353
+ 'Repo runtime binding: agent-agnostic',
354
+ `Global agent setup: ${describeGlobalAgentSetup(report)}`,
355
+ `Skill routing stage: ${describeSkillStage(report)}`,
356
+ `Skills considered: ${describeConsideredSkills(report)}`,
357
+ `Skills active: ${describeActiveSkills(report)}`,
358
+ `Execution state: ${describeRuntime(report.runtimeState?.runtime ?? null)}`,
359
+ `Stage validation: ${describeStageValidation(report)}`,
360
+ `Manual bootstrap: ${report.manualBootstrapReady ? 'ready' : 'repair .prodify/AGENTS.md guidance'}`,
361
+ `Bootstrap profile: ${report.bootstrapProfile}`,
362
+ `Bootstrap prompt: ${report.bootstrapPrompt}`,
363
+ `Resumable: ${report.resumable ? 'yes' : 'no'}`,
364
+ `Recommended next action: ${report.recommendedNextAction}`
365
+ ];
366
+
367
+ if (report.runtimeStateError) {
368
+ lines.splice(7, 0, `Runtime state: ${report.runtimeStateError.message}`);
369
+ }
370
+
371
+ return lines.join('\n');
372
+ }
@@ -0,0 +1,53 @@
1
+ import type { RuntimeProfile, RuntimeProfileName } from '../types.js';
2
+ import { isRuntimeProfileName } from './paths.js';
3
+
4
+ export const RUNTIME_PROFILES: Record<RuntimeProfileName, RuntimeProfile> = {
5
+ codex: {
6
+ name: 'codex',
7
+ displayName: 'Codex',
8
+ bootstrapPrompt: 'Read .prodify/AGENTS.md and bootstrap Prodify for this repository.',
9
+ bootstrapSummary: 'Manual bootstrap through .prodify/AGENTS.md.',
10
+ executeCommand: '$prodify-execute',
11
+ resumeCommand: '$prodify-resume',
12
+ nuances: ['Prefer the explicit instruction to read .prodify/AGENTS.md before any repo scan.']
13
+ },
14
+ claude: {
15
+ name: 'claude',
16
+ displayName: 'Claude',
17
+ bootstrapPrompt: 'Read .prodify/AGENTS.md and bootstrap Prodify for this repository. Then use the runtime commands from that file.',
18
+ bootstrapSummary: 'Manual bootstrap from canonical guidance inside .prodify/.',
19
+ executeCommand: '$prodify-execute',
20
+ resumeCommand: '$prodify-resume',
21
+ nuances: ['Keep the flow anchored to .prodify/AGENTS.md instead of relying on root discovery.']
22
+ },
23
+ copilot: {
24
+ name: 'copilot',
25
+ displayName: 'Copilot',
26
+ bootstrapPrompt: 'Read .prodify/AGENTS.md, bootstrap Prodify for this repository, and keep the workflow state under .prodify/.',
27
+ bootstrapSummary: 'Manual bootstrap with explicit .prodify-only state.',
28
+ executeCommand: '$prodify-execute',
29
+ resumeCommand: '$prodify-resume',
30
+ nuances: ['The main flow does not require .github/copilot-instructions.md.']
31
+ },
32
+ opencode: {
33
+ name: 'opencode',
34
+ displayName: 'OpenCode',
35
+ bootstrapPrompt: 'Read .prodify/AGENTS.md and bootstrap Prodify for this repository using the .prodify runtime state.',
36
+ bootstrapSummary: 'Manual bootstrap with runtime state anchored in .prodify/state.json.',
37
+ executeCommand: '$prodify-execute',
38
+ resumeCommand: '$prodify-resume',
39
+ nuances: ['No root-level OpenCode adapter is required for the default flow.']
40
+ }
41
+ };
42
+
43
+ export function listRuntimeProfiles(): RuntimeProfile[] {
44
+ return Object.values(RUNTIME_PROFILES);
45
+ }
46
+
47
+ export function getRuntimeProfile(agent: string | null | undefined): RuntimeProfile | null {
48
+ if (!agent || !isRuntimeProfileName(agent)) {
49
+ return null;
50
+ }
51
+
52
+ return RUNTIME_PROFILES[agent];
53
+ }
@@ -0,0 +1,66 @@
1
+ import fs from 'node:fs/promises';
2
+
3
+ import { writeFileEnsuringDir } from './fs.js';
4
+ import { USER_OWNED_CANONICAL_PATHS, USER_OWNED_CANONICAL_PREFIXES, resolveRepoPath } from './paths.js';
5
+ import { loadDefaultPreset } from '../presets/loader.js';
6
+ import { readRuntimeState, createInitialRuntimeState, normalizeRuntimeState, serializeRuntimeState } from './state.js';
7
+ import { inspectVersionStatus } from './version-checks.js';
8
+ import { synchronizeRuntimeContracts } from '../contracts/compiler.js';
9
+ import type { UpdateSummary } from '../types.js';
10
+
11
+ export async function updateProdifySetup(repoRoot: string): Promise<UpdateSummary> {
12
+ const preset = await loadDefaultPreset();
13
+ const versionStatus = await inspectVersionStatus(repoRoot, preset.metadata);
14
+ const writtenCanonical: string[] = [];
15
+ const preservedCanonical: string[] = [];
16
+
17
+ for (const entry of preset.entries) {
18
+ const targetPath = resolveRepoPath(repoRoot, entry.relativePath);
19
+ const isUserOwned = (USER_OWNED_CANONICAL_PATHS as readonly string[]).includes(entry.relativePath);
20
+ const isUserOwnedByPrefix = (USER_OWNED_CANONICAL_PREFIXES as readonly string[]).some((prefix) => entry.relativePath.startsWith(prefix));
21
+
22
+ if (isUserOwned || isUserOwnedByPrefix) {
23
+ try {
24
+ await fs.access(targetPath);
25
+ preservedCanonical.push(entry.relativePath);
26
+ continue;
27
+ } catch {
28
+ // fall through and create the missing file
29
+ }
30
+ }
31
+
32
+ if (entry.relativePath === '.prodify/state.json') {
33
+ let nextState;
34
+
35
+ try {
36
+ const existingState = await readRuntimeState(repoRoot, {
37
+ presetMetadata: preset.metadata
38
+ });
39
+ nextState = normalizeRuntimeState(existingState, {
40
+ presetMetadata: preset.metadata
41
+ });
42
+ } catch {
43
+ nextState = createInitialRuntimeState({
44
+ presetMetadata: preset.metadata
45
+ });
46
+ }
47
+
48
+ await writeFileEnsuringDir(targetPath, serializeRuntimeState(nextState));
49
+ writtenCanonical.push(entry.relativePath);
50
+ continue;
51
+ }
52
+
53
+ await writeFileEnsuringDir(targetPath, entry.content);
54
+ writtenCanonical.push(entry.relativePath);
55
+ }
56
+
57
+ const compiledContracts = await synchronizeRuntimeContracts(repoRoot);
58
+
59
+ return {
60
+ versionStatus: versionStatus.status,
61
+ schemaMigrationRequired: versionStatus.schemaMigrationRequired,
62
+ writtenCanonicalCount: writtenCanonical.length,
63
+ preservedCanonicalCount: preservedCanonical.length,
64
+ compiledContractCount: compiledContracts.length
65
+ };
66
+ }