@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.
- package/.prodify/AGENTS.md +56 -0
- package/.prodify/README.md +10 -0
- package/.prodify/artifacts/01-understand.md +28 -0
- package/.prodify/artifacts/02-diagnose.md +26 -0
- package/.prodify/artifacts/03-architecture.md +30 -0
- package/.prodify/artifacts/04-plan.md +35 -0
- package/.prodify/artifacts/05-refactor.md +24 -0
- package/.prodify/artifacts/06-validate.md +17 -0
- package/.prodify/artifacts/README.md +6 -0
- package/.prodify/artifacts/architecture_spec.md +29 -0
- package/.prodify/artifacts/artifact-validation-design.md +276 -0
- package/.prodify/artifacts/cli-command-design.md +299 -0
- package/.prodify/artifacts/completed-steps-tracking.md +201 -0
- package/.prodify/artifacts/diagnostic_report.md +45 -0
- package/.prodify/artifacts/hardening-patch-summary.md +57 -0
- package/.prodify/artifacts/hardening-verification-report.md +48 -0
- package/.prodify/artifacts/implementation_summary.md +19 -0
- package/.prodify/artifacts/improvement-evaluation-spec.md +148 -0
- package/.prodify/artifacts/next-step-resolver-design.md +570 -0
- package/.prodify/artifacts/orientation_map.md +32 -0
- package/.prodify/artifacts/persona-removal-audit.md +106 -0
- package/.prodify/artifacts/planning-alignment-report.md +189 -0
- package/.prodify/artifacts/refactor-plan-template-hardening.md +83 -0
- package/.prodify/artifacts/refactor-validate-loop-design.md +231 -0
- package/.prodify/artifacts/refactor_plan.md +21 -0
- package/.prodify/artifacts/refactor_plan.strict-example.md +31 -0
- package/.prodify/artifacts/run-state-design.md +292 -0
- package/.prodify/artifacts/run-summary-spec.md +149 -0
- package/.prodify/artifacts/run_state.json +14 -0
- package/.prodify/artifacts/sample-repo-test-plan.md +129 -0
- package/.prodify/artifacts/status-output-spec.md +349 -0
- package/.prodify/artifacts/step-selection-design.md +251 -0
- package/.prodify/artifacts/task-dispatcher-design.md +266 -0
- package/.prodify/artifacts/task-header-audit.md +42 -0
- package/.prodify/artifacts/task-log-enhancement-spec.md +264 -0
- package/.prodify/artifacts/task-protocol-hardening-plan.md +68 -0
- package/.prodify/artifacts/task-self-validation-spec.md +171 -0
- package/.prodify/artifacts/task_log.json +160 -0
- package/.prodify/artifacts/template-usage-audit.md +20 -0
- package/.prodify/artifacts/validation_report.md +22 -0
- package/.prodify/contracts/README.md +3 -0
- package/.prodify/contracts/architecture.contract.json +42 -0
- package/.prodify/contracts/diagnose.contract.json +42 -0
- package/.prodify/contracts/plan.contract.json +42 -0
- package/.prodify/contracts/refactor.contract.json +45 -0
- package/.prodify/contracts/understand.contract.json +42 -0
- package/.prodify/contracts/validate.contract.json +52 -0
- package/.prodify/contracts-src/README.md +4 -0
- package/.prodify/contracts-src/architecture.contract.md +29 -0
- package/.prodify/contracts-src/diagnose.contract.md +29 -0
- package/.prodify/contracts-src/plan.contract.md +29 -0
- package/.prodify/contracts-src/refactor.contract.md +32 -0
- package/.prodify/contracts-src/understand.contract.md +29 -0
- package/.prodify/contracts-src/validate.contract.md +35 -0
- package/.prodify/metrics/README.md +4 -0
- package/.prodify/planning.md +13 -0
- package/.prodify/project.md +15 -0
- package/.prodify/rules/01-global-operating-rules.md +21 -0
- package/.prodify/rules/02-analysis-discipline.md +17 -0
- package/.prodify/rules/03-diagnosis-severity-rules.md +42 -0
- package/.prodify/rules/04-architecture-rules.md +27 -0
- package/.prodify/rules/05-planning-rules.md +23 -0
- package/.prodify/rules/06-refactor-rules.md +20 -0
- package/.prodify/rules/07-validation-rules.md +25 -0
- package/.prodify/rules/08-output-format-rules.md +20 -0
- package/.prodify/rules/09-template-usage-rules.md +11 -0
- package/.prodify/rules/10-artifact-flow-and-orchestration-rules.md +40 -0
- package/.prodify/rules/README.md +3 -0
- package/.prodify/rules/example-rule.md +4 -0
- package/.prodify/runtime-commands.md +57 -0
- package/.prodify/skills/README.md +8 -0
- package/.prodify/skills/domain/react-frontend.skill.json +34 -0
- package/.prodify/skills/domain/typescript-backend.skill.json +34 -0
- package/.prodify/skills/quality-policy/maintainability-review.skill.json +25 -0
- package/.prodify/skills/quality-policy/security-hardening.skill.json +32 -0
- package/.prodify/skills/quality-policy/test-hardening.skill.json +23 -0
- package/.prodify/skills/registry.json +16 -0
- package/.prodify/skills/stage-method/architecture-method.skill.json +22 -0
- package/.prodify/skills/stage-method/codebase-scanning.skill.json +22 -0
- package/.prodify/skills/stage-method/diagnosis-method.skill.json +22 -0
- package/.prodify/skills/stage-method/planning-method.skill.json +22 -0
- package/.prodify/skills/stage-method/refactoring-method.skill.json +22 -0
- package/.prodify/skills/stage-method/validation-method.skill.json +22 -0
- package/.prodify/state.json +30 -0
- package/.prodify/tasks/01-understand.md +83 -0
- package/.prodify/tasks/02-diagnose.md +67 -0
- package/.prodify/tasks/03-architecture.md +70 -0
- package/.prodify/tasks/04-plan.md +71 -0
- package/.prodify/tasks/05-refactor.md +61 -0
- package/.prodify/tasks/06-validate.md +69 -0
- package/.prodify/tasks/README.md +3 -0
- package/.prodify/tasks/example-task.md +13 -0
- package/.prodify/templates/01-understand.template.md +18 -0
- package/.prodify/templates/02-diagnose.template.md +18 -0
- package/.prodify/templates/03-architecture.template.md +18 -0
- package/.prodify/templates/04-plan.template.md +22 -0
- package/.prodify/templates/05-refactor.template.md +19 -0
- package/.prodify/templates/06-validate.template.md +16 -0
- package/.prodify/templates/README.md +3 -0
- package/.prodify/templates/architecture_spec.template.md +29 -0
- package/.prodify/templates/diagnostic_report.template.md +45 -0
- package/.prodify/templates/example.template.md +5 -0
- package/.prodify/templates/implementation_summary.template.md +19 -0
- package/.prodify/templates/orientation_map.template.md +32 -0
- package/.prodify/templates/refactor_plan.template.md +24 -0
- package/.prodify/templates/validation_report.template.md +22 -0
- package/.prodify/version.json +5 -0
- package/AGENTS.md +305 -0
- package/LICENSE +201 -0
- package/README.md +118 -0
- package/assets/presets/default/canonical/AGENTS.md +54 -0
- package/assets/presets/default/canonical/artifacts/README.md +6 -0
- package/assets/presets/default/canonical/contracts-src/README.md +4 -0
- package/assets/presets/default/canonical/contracts-src/architecture.contract.md +56 -0
- package/assets/presets/default/canonical/contracts-src/diagnose.contract.md +49 -0
- package/assets/presets/default/canonical/contracts-src/plan.contract.md +42 -0
- package/assets/presets/default/canonical/contracts-src/refactor.contract.md +54 -0
- package/assets/presets/default/canonical/contracts-src/understand.contract.md +56 -0
- package/assets/presets/default/canonical/contracts-src/validate.contract.md +64 -0
- package/assets/presets/default/canonical/metrics/README.md +4 -0
- package/assets/presets/default/canonical/planning.md +13 -0
- package/assets/presets/default/canonical/project.md +15 -0
- package/assets/presets/default/canonical/rules/README.md +3 -0
- package/assets/presets/default/canonical/rules/example-rule.md +4 -0
- package/assets/presets/default/canonical/runtime-commands.md +57 -0
- package/assets/presets/default/canonical/skills/README.md +8 -0
- package/assets/presets/default/canonical/skills/domain/react-frontend.skill.json +34 -0
- package/assets/presets/default/canonical/skills/domain/typescript-backend.skill.json +34 -0
- package/assets/presets/default/canonical/skills/quality-policy/maintainability-review.skill.json +25 -0
- package/assets/presets/default/canonical/skills/quality-policy/security-hardening.skill.json +32 -0
- package/assets/presets/default/canonical/skills/quality-policy/test-hardening.skill.json +23 -0
- package/assets/presets/default/canonical/skills/registry.json +16 -0
- package/assets/presets/default/canonical/skills/stage-method/architecture-method.skill.json +22 -0
- package/assets/presets/default/canonical/skills/stage-method/codebase-scanning.skill.json +22 -0
- package/assets/presets/default/canonical/skills/stage-method/diagnosis-method.skill.json +22 -0
- package/assets/presets/default/canonical/skills/stage-method/planning-method.skill.json +22 -0
- package/assets/presets/default/canonical/skills/stage-method/refactoring-method.skill.json +22 -0
- package/assets/presets/default/canonical/skills/stage-method/validation-method.skill.json +22 -0
- package/assets/presets/default/canonical/state.json +30 -0
- package/assets/presets/default/canonical/tasks/README.md +3 -0
- package/assets/presets/default/canonical/tasks/example-task.md +13 -0
- package/assets/presets/default/canonical/templates/README.md +3 -0
- package/assets/presets/default/canonical/templates/example.template.md +5 -0
- package/assets/presets/default/preset.json +5 -0
- package/dist/cli.js +53 -0
- package/dist/commands/doctor.js +16 -0
- package/dist/commands/init.js +30 -0
- package/dist/commands/install.js +27 -0
- package/dist/commands/setup-agent.js +23 -0
- package/dist/commands/status.js +28 -0
- package/dist/commands/sync.js +29 -0
- package/dist/commands/update.js +18 -0
- package/dist/contracts/compiled-schema.js +37 -0
- package/dist/contracts/compiler.js +83 -0
- package/dist/contracts/freshness.js +52 -0
- package/dist/contracts/index.js +5 -0
- package/dist/contracts/parser.js +201 -0
- package/dist/contracts/schema.js +138 -0
- package/dist/contracts/source-schema.js +111 -0
- package/dist/core/agent-runtime.js +36 -0
- package/dist/core/agent-setup.js +111 -0
- package/dist/core/doctor.js +155 -0
- package/dist/core/errors.js +19 -0
- package/dist/core/flow-state.js +262 -0
- package/dist/core/fs.js +50 -0
- package/dist/core/install.js +44 -0
- package/dist/core/managed-files.js +106 -0
- package/dist/core/paths.js +56 -0
- package/dist/core/preset-validation.js +43 -0
- package/dist/core/prompt-builder.js +63 -0
- package/dist/core/repo-context.js +77 -0
- package/dist/core/repo-root.js +55 -0
- package/dist/core/skill-resolution.js +123 -0
- package/dist/core/state.js +220 -0
- package/dist/core/status.js +293 -0
- package/dist/core/sync.js +63 -0
- package/dist/core/targets.js +48 -0
- package/dist/core/upgrade.js +57 -0
- package/dist/core/validation.js +138 -0
- package/dist/core/version-checks.js +35 -0
- package/dist/generators/claude.js +14 -0
- package/dist/generators/codex.js +14 -0
- package/dist/generators/copilot.js +29 -0
- package/dist/generators/header.js +13 -0
- package/dist/generators/opencode.js +14 -0
- package/dist/generators/shared.js +37 -0
- package/dist/index.js +9 -0
- package/dist/legacy/targets.js +55 -0
- package/dist/presets/default.js +3 -0
- package/dist/presets/loader.js +34 -0
- package/dist/presets/version.js +18 -0
- package/dist/scoring/model.js +262 -0
- package/dist/skills/loader.js +40 -0
- package/dist/skills/schema.js +159 -0
- package/dist/types.js +1 -0
- package/docs/canonical-prodify-layout.md +87 -0
- package/docs/claude-support.md +22 -0
- package/docs/cli-doctor-spec.md +52 -0
- package/docs/cli-init-spec.md +70 -0
- package/docs/cli-install-agent-spec.md +48 -0
- package/docs/cli-sync-spec.md +40 -0
- package/docs/codex-support.md +24 -0
- package/docs/compatibility-targets.md +59 -0
- package/docs/copilot-support.md +30 -0
- package/docs/default-preset.md +47 -0
- package/docs/generated-file-headers.md +45 -0
- package/docs/generation-rules.md +94 -0
- package/docs/idempotency-guarantees.md +31 -0
- package/docs/managed-file-detection.md +45 -0
- package/docs/manual-edit-conflicts.md +37 -0
- package/docs/opencode-support.md +27 -0
- package/docs/ownership-rules.md +39 -0
- package/docs/path-resolution-rules.md +40 -0
- package/docs/preset-structure.md +49 -0
- package/docs/skill-system.md +67 -0
- package/docs/versioning-and-upgrade-strategy.md +40 -0
- package/package.json +22 -0
- package/src/README.md +11 -0
- package/src/cli.ts +61 -0
- package/src/commands/doctor.ts +20 -0
- package/src/commands/init.ts +37 -0
- package/src/commands/setup-agent.ts +28 -0
- package/src/commands/status.ts +34 -0
- package/src/commands/update.ts +23 -0
- package/src/contracts/README.md +10 -0
- package/src/contracts/compiled-schema.ts +42 -0
- package/src/contracts/compiler.ts +111 -0
- package/src/contracts/freshness.ts +58 -0
- package/src/contracts/index.ts +11 -0
- package/src/contracts/parser.ts +253 -0
- package/src/contracts/source-schema.ts +141 -0
- package/src/core/agent-runtime.ts +53 -0
- package/src/core/agent-setup.ts +147 -0
- package/src/core/doctor.ts +171 -0
- package/src/core/errors.ts +28 -0
- package/src/core/flow-state.ts +333 -0
- package/src/core/fs.ts +59 -0
- package/src/core/paths.ts +63 -0
- package/src/core/preset-validation.ts +47 -0
- package/src/core/prompt-builder.ts +73 -0
- package/src/core/repo-context.ts +93 -0
- package/src/core/repo-root.ts +74 -0
- package/src/core/skill-resolution.ts +151 -0
- package/src/core/state.ts +264 -0
- package/src/core/status.ts +372 -0
- package/src/core/targets.ts +53 -0
- package/src/core/upgrade.ts +66 -0
- package/src/core/validation.ts +233 -0
- package/src/core/version-checks.ts +40 -0
- package/src/index.ts +13 -0
- package/src/presets/default.ts +7 -0
- package/src/presets/loader.ts +46 -0
- package/src/presets/version.ts +31 -0
- package/src/scoring/model.ts +332 -0
- package/src/skills/loader.ts +58 -0
- package/src/skills/schema.ts +197 -0
- package/src/types.ts +329 -0
- package/tests/integration/cli-flows.test.js +347 -0
- package/tests/unit/agent-setup.test.js +81 -0
- package/tests/unit/cli.test.js +28 -0
- package/tests/unit/contracts.test.js +61 -0
- package/tests/unit/helpers.js +28 -0
- package/tests/unit/paths.test.js +52 -0
- package/tests/unit/preset-loader.test.js +37 -0
- package/tests/unit/scoring.test.js +65 -0
- package/tests/unit/self-hosted-workspace.test.js +22 -0
- package/tests/unit/skills.test.js +115 -0
- package/tests/unit/state-and-flow.test.js +120 -0
- package/tests/unit/targets.test.js +13 -0
- package/tests/unit/validation.test.js +73 -0
- package/tests/unit/version.test.js +24 -0
- package/tsconfig.json +23 -0
- 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
|
+
}
|