@polymorphism-tech/morph-spec 8.44.0 → 8.46.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/CLAUDE.md +11 -9
- package/README.md +10 -10
- package/bin/morph-spec.js +11 -13
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +2 -4
- package/docs/QUICKSTART.md +6 -6
- package/framework/CLAUDE.md +6 -8
- package/framework/MORPH.md +39 -45
- package/framework/agents.json +8 -9
- package/framework/commands/morph-apply.md +1 -3
- package/framework/commands/morph-hotfix.md +1 -1
- package/framework/commands/morph-proposal.md +2 -2
- package/framework/docs/CLI.md +15 -14
- package/framework/evals/review-checklist.md +90 -0
- package/framework/evals/trace-schema.md +2 -12
- package/framework/hooks/README.md +2 -3
- package/framework/hooks/claude-code/core/heavy-gate.js +1 -1
- package/framework/hooks/claude-code/core/protect-spec-files.js +2 -2
- package/framework/hooks/claude-code/core/telemetry-log.js +2 -2
- package/framework/hooks/claude-code/core/trace-autogen.js +1 -22
- package/framework/hooks/claude-code/core/validate-completion.js +3 -56
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/build-check.js +1 -1
- package/framework/hooks/shared/comment-scanner.js +1 -1
- package/framework/hooks/shared/phase-utils.js +0 -5
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/phases.json +4 -6
- package/framework/rubrics/backend.json +1 -1
- package/framework/rubrics/default.json +1 -1
- package/framework/rubrics/frontend.json +1 -1
- package/framework/rules/morph-workflow.md +6 -6
- package/framework/schemas/config.schema.json +4 -0
- package/framework/schemas/feature.schema.json +5 -29
- package/framework/schemas/tasks.schema.json +6 -2
- package/framework/skills/README.md +1 -2
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +145 -246
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +5 -3
- package/framework/skills/core/morph-implement/SKILL.md +101 -201
- package/framework/skills/core/morph-machine/SKILL.md +3 -3
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +171 -287
- package/framework/skills/core/morph-proposal/SKILL.md +4 -5
- package/framework/skills/core/morph-review/SKILL.md +122 -430
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +2 -2
- package/framework/skills/core/morph-uiux/SKILL.md +2 -3
- package/framework/standards/STANDARDS.json +10 -10
- package/framework/standards/ai-agents/agent-archetypes.md +1 -1
- package/framework/standards/ai-agents/agent-session.md +1 -1
- package/framework/standards/ai-agents/agent-spec.md +1 -1
- package/framework/standards/ai-agents/batching.md +1 -1
- package/framework/standards/ai-agents/context-providers.md +1 -1
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +1 -1
- package/framework/standards/ai-agents/cost-and-budget.md +1 -1
- package/framework/standards/ai-agents/durable-workflows-hitl.md +1 -1
- package/framework/standards/ai-agents/guardrails.md +1 -1
- package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
- package/framework/standards/ai-agents/mcp-server.md +1 -1
- package/framework/standards/ai-agents/mcp-tools.md +1 -1
- package/framework/standards/ai-agents/media-pipeline.md +1 -1
- package/framework/standards/ai-agents/media-video.md +1 -1
- package/framework/standards/ai-agents/middleware-patterns.md +1 -1
- package/framework/standards/ai-agents/modalities-image-gen.md +1 -1
- package/framework/standards/ai-agents/modalities-speech-to-text.md +1 -1
- package/framework/standards/ai-agents/modalities-text-to-speech.md +1 -1
- package/framework/standards/ai-agents/modalities-vision.md +1 -1
- package/framework/standards/ai-agents/multi-agent-patterns.md +1 -1
- package/framework/standards/ai-agents/observability-patterns.md +3 -3
- package/framework/standards/ai-agents/production.md +2 -2
- package/framework/standards/ai-agents/prompt-sources.md +1 -1
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +1 -1
- package/framework/standards/ai-agents/service-tier-flex.md +1 -1
- package/framework/standards/ai-agents/setup.md +1 -1
- package/framework/standards/ai-agents/structured-output.md +1 -1
- package/framework/standards/ai-agents/sweet-spot.md +1 -1
- package/framework/standards/ai-agents/testing-ai.md +1 -1
- package/framework/standards/ai-agents/tool-adapters.md +1 -1
- package/framework/standards/ai-agents/vector-data-extensions.md +1 -1
- package/framework/standards/ai-agents/workflows.md +1 -1
- package/framework/templates/CLAUDE.md.core.template +1 -1
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/README.md +1 -1
- package/framework/templates/REGISTRY.json +0 -81
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/docs/spec.md +19 -205
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +2 -2
- package/src/commands/e2e/e2e.js +1 -1
- package/src/commands/project/heavy.js +1 -1
- package/src/commands/project/status.js +3 -3
- package/src/commands/state/approve.js +7 -49
- package/src/commands/state/gate-check.js +16 -106
- package/src/commands/state/gate-decision.js +1 -1
- package/src/commands/state/report-check.js +42 -17
- package/src/commands/validation/mutate.js +1 -1
- package/src/commands/validation/scout-check.js +28 -0
- package/src/commands/validation/validate-feature.js +5 -32
- package/src/commands/validation/verify.js +98 -48
- package/src/core/paths/output-schema.js +0 -2
- package/src/core/state/state-manager.js +1 -2
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/lib/format.js +5 -0
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/FeatureDetail.jsx +16 -22
- package/src/dashboard/app/pages/Features.jsx +7 -7
- package/src/dashboard/app/pages/PhasePipeline.jsx +1 -1
- package/src/dashboard/app/pages/Rubrics.jsx +7 -11
- package/src/dashboard/scanner/docs-scanner.js +1 -2
- package/src/dashboard/scanner/features-scanner.js +3 -4
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/agents/output-collector.js +0 -1
- package/src/lib/ci/ci-verify.js +118 -0
- package/src/lib/ci/github-ci.js +192 -0
- package/src/lib/ci/workflow-scaffold.js +122 -0
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/evaluator-report.js +52 -334
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/handoff-generator.js +4 -5
- package/src/lib/installers/memory-installer.js +2 -2
- package/src/lib/mutation/manifest.js +8 -2
- package/src/lib/mutation/report.js +5 -3
- package/src/lib/mutation/runner.js +9 -7
- package/src/lib/risk-detector.js +60 -122
- package/src/lib/scout/scout-check.js +293 -0
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/tasks-json-parser.js +7 -5
- package/src/lib/tasks/test-nodes.js +1 -1
- package/src/lib/tasks/test-runner.js +1 -1
- package/src/lib/telemetry/verify-event.js +3 -2
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/reuse/reuse-validator.js +6 -8
- package/src/lib/validators/verify-runner.js +1 -1
- package/src/scripts/setup-infra.js +1 -1
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/agents-installer.js +5 -9
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/hooks-installer.js +3 -10
- package/src/utils/skills-installer.js +1 -1
- package/framework/evals/proof-rubrics/README.md +0 -76
- package/framework/evals/proof-rubrics/eval-de-modelo.md +0 -80
- package/framework/evals/proof-rubrics/fiacao.md +0 -54
- package/framework/evals/proof-rubrics/guard-cego.md +0 -52
- package/framework/evals/proof-rubrics/media-claims.md +0 -109
- package/framework/evals/proof-rubrics/mutation-proof.md +0 -107
- package/framework/evals/proof-rubrics/observabilidade-genai.md +0 -119
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +0 -48
- package/framework/evals/rubrics/README.md +0 -45
- package/framework/evals/rubrics/architecture.md +0 -103
- package/framework/evals/rubrics/code-quality.md +0 -98
- package/framework/evals/rubrics/condensed.md +0 -57
- package/framework/evals/rubrics/contracts.md +0 -67
- package/framework/evals/rubrics/test-coverage.md +0 -99
- package/framework/evals/scenarios/dotnet-crud.yaml +0 -42
- package/framework/evals/scenarios/nextjs-auth.yaml +0 -38
- package/framework/evals/suites/standard.yaml +0 -5
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/hooks/claude-code/core/post-edit-typecheck.js +0 -127
- package/framework/skills/core/morph-eval/SKILL.md +0 -64
- package/framework/templates/.idea/morph-templates.xml +0 -92
- package/framework/templates/.vscode/morph-templates.code-snippets +0 -186
- package/framework/templates/docs/clarifications.md +0 -253
- package/framework/templates/docs/onboarding.md +0 -122
- package/framework/templates/docs/schema-analysis.md +0 -119
- package/framework/templates/docs/user-stories.md +0 -34
- package/src/commands/state/score.js +0 -147
|
@@ -4,7 +4,7 @@ import { getFeature, updateFeature } from '../../core/state/state-manager.js';
|
|
|
4
4
|
import { runVerify, readTask, VerifyUsageError } from '../../lib/validators/verify-runner.js';
|
|
5
5
|
import { resolvePrimaryRoot } from '../project/worktree.js';
|
|
6
6
|
import { resolveFeatureTree } from '../../lib/worktree/feature-truth.js';
|
|
7
|
-
import { canonicalPath } from '../../lib/tasks/test-runner.js';
|
|
7
|
+
import { canonicalPath, readMorphConfig } from '../../lib/tasks/test-runner.js';
|
|
8
8
|
import { getHeadSha } from '../../lib/git/default-branch.js';
|
|
9
9
|
import { EVAL_RUNNER } from '../../lib/tasks/eval-node.js';
|
|
10
10
|
import { buildVerifyEvent, recordVerifyEvent, findRepeatedVerify } from '../../lib/telemetry/verify-event.js';
|
|
@@ -12,6 +12,7 @@ import { treeFingerprint } from '../../lib/git/tree-fingerprint.js';
|
|
|
12
12
|
import { HeavyBusyError } from '../../lib/heavy/gate.js';
|
|
13
13
|
import { afterHeavyRun } from '../../lib/heavy/cleanup.js';
|
|
14
14
|
import { readHeavyConfig } from '../../../framework/hooks/shared/heavy-config.js';
|
|
15
|
+
import { runCiVerify, CiUsageError } from '../../lib/ci/ci-verify.js';
|
|
15
16
|
|
|
16
17
|
/** ✓ pass · ✗ fail · – skip */
|
|
17
18
|
function statusIcon(status) {
|
|
@@ -190,6 +191,54 @@ function evalsStatusOf(result) {
|
|
|
190
191
|
*/
|
|
191
192
|
const PARTIAL_RUN_FLAGS = [['filter', 'filtered'], ['skipTests', 'skip-tests'], ['skipBuild', 'skip-build']];
|
|
192
193
|
|
|
194
|
+
const CI_EXCLUSIVE_FLAGS = [
|
|
195
|
+
['filter', '--filter'], ['skipTests', '--skip-tests'], ['skipBuild', '--skip-build'], ['skipE2e', '--skip-e2e'],
|
|
196
|
+
['freshE2e', '--fresh-e2e'], ['linux', '--linux'], ['recordBaseline', '--record-baseline'], ['refreshCache', '--refresh-cache'],
|
|
197
|
+
['noPersist', '--no-persist'],
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
async function runLocalVerify(featureName, taskId, options) {
|
|
201
|
+
try {
|
|
202
|
+
return await runVerify(process.cwd(), featureName, taskId || null, {
|
|
203
|
+
rubric: options.rubric,
|
|
204
|
+
timeout: options.timeout,
|
|
205
|
+
skipTests: options.skipTests,
|
|
206
|
+
skipBuild: options.skipBuild,
|
|
207
|
+
skipE2e: options.skipE2e,
|
|
208
|
+
freshE2e: options.freshE2e,
|
|
209
|
+
filter: options.filter,
|
|
210
|
+
recordBaseline: options.recordBaseline,
|
|
211
|
+
refreshCache: options.refreshCache,
|
|
212
|
+
linux: options.linux,
|
|
213
|
+
linuxImage: options.linuxImage,
|
|
214
|
+
// Task scope: switch the recorte off (#87). At feature scope nothing is
|
|
215
|
+
// ever narrowed, so the flag is a documented no-op there, not an error.
|
|
216
|
+
full: options.full,
|
|
217
|
+
});
|
|
218
|
+
} catch (err) {
|
|
219
|
+
// A wrong invocation is exit 2, like an unknown feature or task — never a
|
|
220
|
+
// verdict. `--filter` that selects nothing must not print green (or red):
|
|
221
|
+
// there is no verification to report, only a command to fix.
|
|
222
|
+
if (err instanceof VerifyUsageError) {
|
|
223
|
+
console.error(chalk.red(`\n❌ ${err.message}\n`));
|
|
224
|
+
process.exit(2);
|
|
225
|
+
}
|
|
226
|
+
// Ocupado não é veredito: nada foi verificado, então não há stamp nem
|
|
227
|
+
// evento, e o exit 3 nunca é "vermelho".
|
|
228
|
+
if (err instanceof HeavyBusyError) {
|
|
229
|
+
if (options.json) {
|
|
230
|
+
const holders = err.holders.map(({ pid, label, feature, node, since }) => ({ pid, label, feature, node, since }));
|
|
231
|
+
console.log(JSON.stringify({
|
|
232
|
+
status: 'busy', persisted: false, busy: { reason: err.reason, holders, freeGb: err.freeGb, waitedMs: err.waitedMs },
|
|
233
|
+
}, null, 2));
|
|
234
|
+
}
|
|
235
|
+
console.error(chalk.yellow(`\n⏳ verify não rodou: ${err.message}. Não é vermelho — a fila já esperou o prazo dela: não repita em laço — siga sem esta rodada e avise o usuário (\`morph-spec heavy status\` mostra quem segura os slots).\n`));
|
|
236
|
+
process.exit(3);
|
|
237
|
+
}
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
193
242
|
/**
|
|
194
243
|
* `morph-spec verify <feature> [task]` — the deterministic code-before-judge
|
|
195
244
|
* gate: build + tests + validators, BEFORE the LLM eval. See verify-runner.js
|
|
@@ -203,8 +252,7 @@ const PARTIAL_RUN_FLAGS = [['filter', 'filtered'], ['skipTests', 'skip-tests'],
|
|
|
203
252
|
* paths to it — never a verdict, because a verdict about nothing is worse
|
|
204
253
|
* than a refusal:
|
|
205
254
|
* - unknown feature, or unknown task id (the task's `group` decides the
|
|
206
|
-
* rubric, so it is a hard usage error here
|
|
207
|
-
* `morph-spec score` gives for the same situation);
|
|
255
|
+
* rubric, so it is a hard usage error here);
|
|
208
256
|
* - `--filter` that matches no declared node (a filtered-to-empty run is
|
|
209
257
|
* green and proves nothing);
|
|
210
258
|
* - `--record-baseline` with nowhere to write (no `config.json`), or with a
|
|
@@ -224,6 +272,14 @@ export async function verifyCommand(featureName, taskId, options = {}) {
|
|
|
224
272
|
process.exit(2);
|
|
225
273
|
}
|
|
226
274
|
|
|
275
|
+
if (options.ci) {
|
|
276
|
+
const conflict = taskId ? `a task ${taskId} (o loop por task é local)` : CI_EXCLUSIVE_FLAGS.find(([flag]) => options[flag])?.[1];
|
|
277
|
+
if (conflict) {
|
|
278
|
+
console.error(chalk.red(`\n❌ --ci roda a suíte inteira da feature no CI; não combina com ${conflict}\n`));
|
|
279
|
+
process.exit(2);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
227
283
|
// The runner's own reader (one reader of tasks.json for verify, #87): null
|
|
228
284
|
// means tasks.json or the task is missing, and both are this usage error.
|
|
229
285
|
if (taskId) {
|
|
@@ -233,51 +289,36 @@ export async function verifyCommand(featureName, taskId, options = {}) {
|
|
|
233
289
|
}
|
|
234
290
|
}
|
|
235
291
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
refreshCache: options.refreshCache,
|
|
251
|
-
linux: options.linux,
|
|
252
|
-
linuxImage: options.linuxImage,
|
|
253
|
-
// Task scope: switch the recorte off (#87). At feature scope nothing is
|
|
254
|
-
// ever narrowed, so the flag is a documented no-op there, not an error.
|
|
255
|
-
full: options.full,
|
|
256
|
-
});
|
|
257
|
-
} catch (err) {
|
|
258
|
-
// A wrong invocation is exit 2, like an unknown feature or task — never a
|
|
259
|
-
// verdict. `--filter` that selects nothing must not print green (or red):
|
|
260
|
-
// there is no verification to report, only a command to fix.
|
|
261
|
-
if (err instanceof VerifyUsageError) {
|
|
262
|
-
console.error(chalk.red(`\n❌ ${err.message}\n`));
|
|
263
|
-
process.exit(2);
|
|
264
|
-
}
|
|
265
|
-
// Ocupado não é veredito: nada foi verificado, então não há stamp nem
|
|
266
|
-
// evento, e o exit 3 diz "tente de novo", nunca "vermelho".
|
|
267
|
-
if (err instanceof HeavyBusyError) {
|
|
268
|
-
if (options.json) {
|
|
269
|
-
const holders = err.holders.map(({ pid, label, feature, node, since }) => ({ pid, label, feature, node, since }));
|
|
270
|
-
console.log(JSON.stringify({
|
|
271
|
-
status: 'busy', persisted: false, busy: { reason: err.reason, holders, freeGb: err.freeGb, waitedMs: err.waitedMs },
|
|
272
|
-
}, null, 2));
|
|
292
|
+
let ci = null;
|
|
293
|
+
if (options.ci) {
|
|
294
|
+
try {
|
|
295
|
+
const outcome = await runCiVerify(process.cwd(), featureName, readMorphConfig(process.cwd()), {
|
|
296
|
+
log: (line) => console.error(chalk.gray(` ${line}`)),
|
|
297
|
+
});
|
|
298
|
+
if (outcome.mode === 'ci') {
|
|
299
|
+
ci = outcome;
|
|
300
|
+
} else if (outcome.mode === 'pending') {
|
|
301
|
+
if (options.json) console.log(JSON.stringify({ status: 'pending', persisted: false, reason: outcome.reason }, null, 2));
|
|
302
|
+
console.error(chalk.yellow(`\n⏳ ${outcome.reason}. Não é vermelho e não há stamp: não repita em laço — siga e deixe o gate-check decidir.\n`));
|
|
303
|
+
process.exit(3);
|
|
304
|
+
} else {
|
|
305
|
+
console.error(chalk.yellow(`\n↪ CI indisponível (${outcome.reason}) — verify local.\n`));
|
|
273
306
|
}
|
|
274
|
-
|
|
275
|
-
|
|
307
|
+
} catch (err) {
|
|
308
|
+
if (err instanceof CiUsageError) {
|
|
309
|
+
console.error(chalk.red(`\n❌ ${err.message}\n`));
|
|
310
|
+
process.exit(2);
|
|
311
|
+
}
|
|
312
|
+
throw err;
|
|
276
313
|
}
|
|
277
|
-
throw err;
|
|
278
314
|
}
|
|
279
315
|
|
|
280
|
-
|
|
316
|
+
// Taken before the run: it is the tree the run is about to read.
|
|
317
|
+
const fingerprint = treeFingerprint(process.cwd());
|
|
318
|
+
|
|
319
|
+
const result = ci ? ci.result : await runLocalVerify(featureName, taskId, options);
|
|
320
|
+
|
|
321
|
+
const cleanup = ci ? { status: 'skipped', reason: 'ci' } : afterHeavyRun({
|
|
281
322
|
projectPath: process.cwd(),
|
|
282
323
|
config: readHeavyConfig(process.cwd()),
|
|
283
324
|
scope: taskId ? 'task' : 'feature',
|
|
@@ -330,9 +371,10 @@ export async function verifyCommand(featureName, taskId, options = {}) {
|
|
|
330
371
|
status: result.status,
|
|
331
372
|
nodes: nodeStatuses(result),
|
|
332
373
|
e2eReason: result.nodes.e2e.status === 'skip' ? (result.nodes.e2e.reason ?? null) : null,
|
|
333
|
-
sha: getHeadSha(process.cwd()),
|
|
374
|
+
sha: ci ? ci.run.headSha : getHeadSha(process.cwd()),
|
|
334
375
|
ts: now,
|
|
335
376
|
scope: taskId ? `task:${taskId}` : 'feature',
|
|
377
|
+
...(ci ? { source: 'ci', ciRun: ci.run.url } : {}),
|
|
336
378
|
};
|
|
337
379
|
await updateFeature(featureName, 'verification', stamp);
|
|
338
380
|
}
|
|
@@ -342,9 +384,9 @@ export async function verifyCommand(featureName, taskId, options = {}) {
|
|
|
342
384
|
let repeatOf = null;
|
|
343
385
|
try {
|
|
344
386
|
const cwd = process.cwd();
|
|
345
|
-
if (!taskId && persist) repeatOf = findRepeatedVerify(cwd, { feature: featureName, task: null, scope: result.scope, fingerprint });
|
|
387
|
+
if (!taskId && persist && !ci) repeatOf = findRepeatedVerify(cwd, { feature: featureName, task: null, scope: result.scope, fingerprint });
|
|
346
388
|
const tree = resolve(cwd).replace(/\\/g, '/') === resolvePrimaryRoot(cwd) ? 'root' : 'worktree';
|
|
347
|
-
recordVerifyEvent(cwd, buildVerifyEvent(result, { sha: getHeadSha(cwd), tree, persisted: persist, reason, fingerprint }));
|
|
389
|
+
recordVerifyEvent(cwd, buildVerifyEvent(result, { sha: ci ? ci.run.headSha : getHeadSha(cwd), tree, persisted: persist, reason, fingerprint, source: ci ? 'ci' : 'local' }));
|
|
348
390
|
} catch { /* telemetry never changes the verdict */ }
|
|
349
391
|
|
|
350
392
|
// The refusal always goes to stderr, so it survives --json (whose stdout has
|
|
@@ -356,10 +398,18 @@ export async function verifyCommand(featureName, taskId, options = {}) {
|
|
|
356
398
|
}
|
|
357
399
|
|
|
358
400
|
if (options.json) {
|
|
359
|
-
const output = {
|
|
401
|
+
const output = {
|
|
402
|
+
...result, persisted: persist, ...(persist ? {} : { reason }), repeatOf, cleanup,
|
|
403
|
+
...(ci ? { source: 'ci', ciRun: { id: ci.run.databaseId, url: ci.run.url, sha: ci.run.headSha }, workflowCreated: ci.created } : {}),
|
|
404
|
+
};
|
|
360
405
|
console.log(JSON.stringify(output, null, 2));
|
|
361
406
|
} else {
|
|
362
407
|
console.log(formatVerifyResult(result));
|
|
408
|
+
if (ci) {
|
|
409
|
+
console.log(chalk.cyan(`fonte: CI ${ci.run.url}`));
|
|
410
|
+
if (result.status === 'fail') console.log(chalk.gray(` log das falhas: gh run view ${ci.run.databaseId} --log-failed`));
|
|
411
|
+
console.log('');
|
|
412
|
+
}
|
|
363
413
|
if (cleanup.status !== 'skipped') {
|
|
364
414
|
const mark = cleanup.status === 'ran' ? chalk.green('✓') : chalk.yellow('⚠');
|
|
365
415
|
console.log(chalk.gray(`${mark} dotnet build-server shutdown: ${cleanup.status}${cleanup.reason ? ` (${cleanup.reason})` : ''}\n`));
|
|
@@ -46,7 +46,6 @@ export const OUTPUT_SCHEMA = {
|
|
|
46
46
|
|
|
47
47
|
// 2-plan/
|
|
48
48
|
spec: { filename: 'spec.md', phaseDir: '2-plan', phase: 'plan', protected: true, approvalGate: 'plan' },
|
|
49
|
-
mandate: { filename: 'mandate.md', phaseDir: '2-plan', phase: 'plan', protected: true, approvalGate: 'plan' },
|
|
50
49
|
tasks: { filename: 'tasks.json', phaseDir: '2-plan', phase: 'plan', protected: true, approvalGate: 'plan', mutableFields: ['status', 'outputs', 'notes'] },
|
|
51
50
|
decisions: { filename: 'decisions.md', phaseDir: '2-plan', phase: 'plan', protected: false },
|
|
52
51
|
// Veredito REUSAR/ESTENDER/CRIAR por conceito que a feature introduz, com a
|
|
@@ -55,7 +54,6 @@ export const OUTPUT_SCHEMA = {
|
|
|
55
54
|
// como decisions.md: é registro vivo — o implementador que descobre um alvo
|
|
56
55
|
// melhor no meio da task precisa poder anotar, e congelá-lo transformaria a
|
|
57
56
|
// correção num bloqueio de gate.
|
|
58
|
-
reuseMap: { filename: 'reuse-map.md', phaseDir: '2-plan', phase: 'plan', protected: false },
|
|
59
57
|
// N files, one per system use case — the behaviour layer the plan distils
|
|
60
58
|
// BEFORE spec.md/tasks.json. Deliberately NOT protected: editing a use case
|
|
61
59
|
// after Gate 2 is the supported way to change behaviour and re-run implement;
|
|
@@ -581,7 +581,6 @@ export async function createFeature(featureName, options = {}) {
|
|
|
581
581
|
review: { approved: false, timestamp: null, approvedBy: null }
|
|
582
582
|
},
|
|
583
583
|
gateDecisions: {},
|
|
584
|
-
taskScores: {},
|
|
585
584
|
tasks: {
|
|
586
585
|
total: 0,
|
|
587
586
|
completed: 0,
|
|
@@ -782,7 +781,7 @@ function findClosestMatch(inputType, validTypes) {
|
|
|
782
781
|
/**
|
|
783
782
|
* Mark output as created
|
|
784
783
|
* @param {string} featureName - Feature name
|
|
785
|
-
* @param {string} outputType - Output type (proposal, spec,
|
|
784
|
+
* @param {string} outputType - Output type (proposal, spec, tasks, etc.)
|
|
786
785
|
*/
|
|
787
786
|
export async function markOutput(featureName, outputType) {
|
|
788
787
|
await ensureFeature(featureName);
|