@planu/cli 4.11.0 → 4.11.2
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/CHANGELOG.md +16 -0
- package/dist/engine/cascade-hooks/registry.js +0 -2
- package/dist/engine/challenge-scenarios-loader.d.ts +3 -3
- package/dist/engine/compliance-injector.d.ts +3 -3
- package/dist/engine/dashboard/kanban-logic.d.ts +1 -1
- package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +1 -1
- package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +1 -1
- package/dist/engine/elicitation/answer-extractor.d.ts +1 -4
- package/dist/engine/elicitation/answer-extractor.js +197 -68
- package/dist/engine/elicitation/decision-gap-detector.js +59 -79
- package/dist/engine/elicitation/index.d.ts +0 -1
- package/dist/engine/elicitation/index.js +0 -1
- package/dist/engine/elicitation/question-grounding-gate.js +83 -34
- package/dist/engine/evidence-gates/lifecycle-gate.js +27 -14
- package/dist/engine/evidence-index/index-builder.js +7 -2
- package/dist/engine/frontmatter-sha/frozen-fields.d.ts +1 -1
- package/dist/engine/handoff-artifacts/schemas/red-tests-handoff.d.ts +2 -2
- package/dist/engine/handoff-artifacts/schemas.d.ts +22 -22
- package/dist/engine/human-summary.js +3 -3
- package/dist/engine/implementation-contract/common.d.ts +1 -1
- package/dist/engine/keyword-matcher/stopwords.d.ts +2 -2
- package/dist/engine/provider-adapters/adapters/claude.d.ts +1 -1
- package/dist/engine/provider-adapters/adapters/gemini.d.ts +1 -1
- package/dist/engine/provider-adapters/adapters/gpt4.d.ts +1 -1
- package/dist/engine/provider-adapters/adapters/markdown.d.ts +1 -1
- package/dist/engine/safety/atomic-write-file.d.ts +1 -1
- package/dist/engine/safety/cross-process-lock.d.ts +1 -1
- package/dist/engine/safety/path-sanitizer.d.ts +1 -1
- package/dist/engine/security-analyzer/profile-detector.js +48 -16
- package/dist/engine/spec-format/copula-blacklist.d.ts +2 -2
- package/dist/engine/spec-format/metadata-value-policy.d.ts +20 -20
- package/dist/engine/text-signal-boundaries.js +45 -12
- package/dist/engine/universal-rules/rules/planu-modes.js +0 -2
- package/dist/engine/well-known/manifest-schema.d.ts +33 -33
- package/dist/engine/workers/schema.d.ts +3 -3
- package/dist/hosts/claude-code/ux/mcp-resources.d.ts +4 -4
- package/dist/hosts/codex/rest-shim.d.ts +1 -1
- package/dist/native/lightweight-command-catalog.d.ts +30 -30
- package/dist/server/openapi-spec.d.ts +132 -132
- package/dist/tools/challenge-spec/event-challenge-scenarios.js +8 -27
- package/dist/tools/challenge-spec/resilience-challenge-scenarios-a.js +16 -32
- package/dist/tools/challenge-spec/resilience-challenge-scenarios-b.js +15 -20
- package/dist/tools/challenge-spec/scenario-collector.d.ts +13 -0
- package/dist/tools/challenge-spec/scenario-collector.js +86 -0
- package/dist/tools/challenge-spec/scenarios-data.js +10 -9
- package/dist/tools/challenge-spec/scenarios-failure.js +38 -54
- package/dist/tools/challenge-spec/scenarios-scale.js +14 -15
- package/dist/tools/challenge-spec/scenarios-security.d.ts +1 -1
- package/dist/tools/challenge-spec/scenarios-security.js +18 -11
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +31 -5
- package/dist/tools/challenge-spec/scenarios-utils.js +102 -6
- package/dist/tools/challenge-spec/security-challenge-scenarios.d.ts +1 -1
- package/dist/tools/challenge-spec/security-challenge-scenarios.js +20 -25
- package/dist/tools/challenge-spec.js +39 -118
- package/dist/tools/compliance-gate-handler.d.ts +1 -1
- package/dist/tools/create-spec.js +4 -24
- package/dist/tools/delete-first/suggest-deletions.d.ts +1 -1
- package/dist/tools/generate-batch-script.d.ts +2 -2
- package/dist/tools/init-project/rules-generator.js +0 -1
- package/dist/tools/oauth-handler.d.ts +1 -1
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/render-spec-for-provider.d.ts +2 -2
- package/dist/tools/scan-orphan-spec-refs.d.ts +6 -6
- package/dist/tools/schemas/agents.d.ts +7 -7
- package/dist/tools/schemas/analysis.d.ts +11 -11
- package/dist/tools/schemas/delete.d.ts +5 -5
- package/dist/tools/schemas/github.d.ts +4 -4
- package/dist/tools/schemas/ide-config.d.ts +12 -12
- package/dist/tools/schemas/infra.d.ts +9 -9
- package/dist/tools/schemas/lifecycle.d.ts +50 -50
- package/dist/tools/schemas/llm-provider-schemas.d.ts +7 -7
- package/dist/tools/schemas/plugins-schemas.d.ts +12 -12
- package/dist/tools/schemas/project-graph.d.ts +6 -6
- package/dist/tools/schemas/rbac.d.ts +2 -2
- package/dist/tools/schemas/registry.d.ts +3 -3
- package/dist/tools/schemas/runtime-security.d.ts +2 -2
- package/dist/tools/schemas/session.d.ts +2 -2
- package/dist/tools/schemas/spec.d.ts +15 -15
- package/dist/tools/schemas/token-intelligence.d.ts +6 -6
- package/dist/tools/schemas/token-optimization.d.ts +2 -2
- package/dist/tools/schemas/workers-schema.d.ts +4 -4
- package/dist/tools/skill-bootstrap-handler.d.ts +7 -7
- package/dist/tools/tool-registry/deprecated-stubs.d.ts +1 -1
- package/dist/tools/triage-request.d.ts +3 -3
- package/dist/tools/update-status/file-sync.d.ts +1 -1
- package/dist/tools/update-status/file-sync.js +10 -45
- package/dist/tools/update-status/index.js +28 -27
- package/dist/tools/update-status/response-builder.d.ts +1 -1
- package/dist/tools/update-status/response-builder.js +11 -19
- package/dist/tools/update-status/transition-guard.js +1 -1
- package/dist/tools/update-status-actions.d.ts +0 -1
- package/dist/tools/update-status-actions.js +10 -26
- package/dist/tools/update-status-convention-gate.d.ts +1 -6
- package/dist/tools/update-status-convention-gate.js +9 -33
- package/dist/types/docs.d.ts +0 -4
- package/dist/types/env.d.ts +0 -4
- package/dist/types/estimation.d.ts +0 -2
- package/dist/types/multi-teammate-review.d.ts +4 -4
- package/dist/types/plugin-install.d.ts +7 -7
- package/package.json +21 -18
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/src/i18n/messages/en.json +0 -72
- package/src/i18n/messages/es.json +0 -72
- package/src/i18n/messages/pt.json +0 -72
- package/dist/config/elicitation-dimensions.json +0 -51
- package/dist/engine/actuals-estimator.d.ts +0 -14
- package/dist/engine/actuals-estimator.js +0 -64
- package/dist/engine/cascade-hooks/hooks/living-specs.hook.d.ts +0 -3
- package/dist/engine/cascade-hooks/hooks/living-specs.hook.js +0 -19
- package/dist/engine/elicitation/option-builder.d.ts +0 -9
- package/dist/engine/elicitation/option-builder.js +0 -85
- package/dist/engine/progress-writer.d.ts +0 -10
- package/dist/engine/progress-writer.js +0 -63
- package/dist/tools/update-status/mode-hints.d.ts +0 -4
- package/dist/tools/update-status/mode-hints.js +0 -24
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"id": "target",
|
|
4
|
-
"headerKey": "questions.target.header",
|
|
5
|
-
"questionKey": "questions.target.question",
|
|
6
|
-
"suppressWhen": "hasTarget",
|
|
7
|
-
"optionSet": "target",
|
|
8
|
-
"multiSelect": false
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"id": "payment_provider",
|
|
12
|
-
"headerKey": "questions.payment.providerHeader",
|
|
13
|
-
"questionKey": "questions.payment.providerQuestion",
|
|
14
|
-
"requiresSignal": "hasBilling",
|
|
15
|
-
"suppressWhen": "namedProvider",
|
|
16
|
-
"optionSet": "payment_provider",
|
|
17
|
-
"multiSelect": false
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"id": "billing_model",
|
|
21
|
-
"headerKey": "questions.payment.modelHeader",
|
|
22
|
-
"questionKey": "questions.payment.modelQuestion",
|
|
23
|
-
"requiresSignal": "hasBilling",
|
|
24
|
-
"optionSet": "billing_model",
|
|
25
|
-
"multiSelect": false
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"id": "scope",
|
|
29
|
-
"headerKey": "questions.scope.header",
|
|
30
|
-
"questionKey": "questions.scope.question",
|
|
31
|
-
"suppressWhen": "hasScope",
|
|
32
|
-
"optionSet": "scope",
|
|
33
|
-
"multiSelect": false
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"id": "database",
|
|
37
|
-
"headerKey": "questions.database.header",
|
|
38
|
-
"questionKey": "questions.database.question",
|
|
39
|
-
"requiresSignal": "hasDatabase",
|
|
40
|
-
"optionSet": "database",
|
|
41
|
-
"multiSelect": true
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"id": "uiType",
|
|
45
|
-
"headerKey": "questions.uiType.header",
|
|
46
|
-
"questionKey": "questions.uiType.question",
|
|
47
|
-
"requiresSignal": "hasUi",
|
|
48
|
-
"optionSet": "uiType",
|
|
49
|
-
"multiSelect": false
|
|
50
|
-
}
|
|
51
|
-
]
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Actuals, Estimation } from '../types/index.js';
|
|
2
|
-
/** Returns true when all token/cost actuals are zero (agent did not provide them). */
|
|
3
|
-
export declare function actualsAreMissing(actuals: Actuals): boolean;
|
|
4
|
-
/**
|
|
5
|
-
* Auto-fills zero token/cost fields in actuals using the spec's estimation data.
|
|
6
|
-
* Marks the result with `estimated: true` so reports can distinguish real vs auto values.
|
|
7
|
-
*/
|
|
8
|
-
export declare function autoFillActuals(actuals: Actuals, estimation: Estimation): Actuals;
|
|
9
|
-
/**
|
|
10
|
-
* Creates a default Actuals object from the spec's estimation when the agent
|
|
11
|
-
* did not provide actuals at all. Token/cost fields are auto-estimated.
|
|
12
|
-
*/
|
|
13
|
-
export declare function createDefaultActuals(estimation: Estimation): Actuals;
|
|
14
|
-
//# sourceMappingURL=actuals-estimator.d.ts.map
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// Rough tokens consumed per dev-hour of Claude Code work (empirical approximation)
|
|
2
|
-
const OPUS_TOKENS_PER_DEV_HOUR = 25_000;
|
|
3
|
-
const SONNET_TOKENS_PER_DEV_HOUR = 45_000;
|
|
4
|
-
// Blended input+output cost per token (Anthropic 2026 pricing)
|
|
5
|
-
const OPUS_COST_PER_TOKEN = 0.00004; // ~$40/1M blended
|
|
6
|
-
const SONNET_COST_PER_TOKEN = 0.000008; // ~$8/1M blended
|
|
7
|
-
/** Returns true when all token/cost actuals are zero (agent did not provide them). */
|
|
8
|
-
export function actualsAreMissing(actuals) {
|
|
9
|
-
return actuals.tokensOpus === 0 && actuals.tokensSonnet === 0 && actuals.apiCostUsd === 0;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Auto-fills zero token/cost fields in actuals using the spec's estimation data.
|
|
13
|
-
* Marks the result with `estimated: true` so reports can distinguish real vs auto values.
|
|
14
|
-
*/
|
|
15
|
-
export function autoFillActuals(actuals, estimation) {
|
|
16
|
-
if (!actualsAreMissing(actuals)) {
|
|
17
|
-
return actuals;
|
|
18
|
-
}
|
|
19
|
-
const hours = actuals.devHours > 0 ? actuals.devHours : estimation.devHours;
|
|
20
|
-
let tokensOpus = 0;
|
|
21
|
-
let tokensSonnet = 0;
|
|
22
|
-
if (estimation.recommendedModel === 'opus') {
|
|
23
|
-
tokensOpus = Math.round(hours * OPUS_TOKENS_PER_DEV_HOUR);
|
|
24
|
-
}
|
|
25
|
-
else if (estimation.recommendedModel === 'sonnet') {
|
|
26
|
-
tokensSonnet = Math.round(hours * SONNET_TOKENS_PER_DEV_HOUR);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
// mixed: 40% opus, 60% sonnet
|
|
30
|
-
tokensOpus = Math.round(hours * OPUS_TOKENS_PER_DEV_HOUR * 0.4);
|
|
31
|
-
tokensSonnet = Math.round(hours * SONNET_TOKENS_PER_DEV_HOUR * 0.6);
|
|
32
|
-
}
|
|
33
|
-
const apiCostUsd = tokensOpus * OPUS_COST_PER_TOKEN + tokensSonnet * SONNET_COST_PER_TOKEN;
|
|
34
|
-
const humanCostUsd = actuals.humanCostUsd > 0 ? actuals.humanCostUsd : hours * estimation.hourlyRate;
|
|
35
|
-
const totalCostUsd = apiCostUsd + humanCostUsd;
|
|
36
|
-
return {
|
|
37
|
-
...actuals,
|
|
38
|
-
tokensOpus,
|
|
39
|
-
tokensSonnet,
|
|
40
|
-
apiCostUsd: parseFloat(apiCostUsd.toFixed(4)),
|
|
41
|
-
humanCostUsd: parseFloat(humanCostUsd.toFixed(4)),
|
|
42
|
-
totalCostUsd: parseFloat(totalCostUsd.toFixed(4)),
|
|
43
|
-
estimated: true,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Creates a default Actuals object from the spec's estimation when the agent
|
|
48
|
-
* did not provide actuals at all. Token/cost fields are auto-estimated.
|
|
49
|
-
*/
|
|
50
|
-
export function createDefaultActuals(estimation) {
|
|
51
|
-
const base = {
|
|
52
|
-
devHours: estimation.devHours,
|
|
53
|
-
reviewHours: estimation.reviewHours,
|
|
54
|
-
tokensOpus: 0,
|
|
55
|
-
tokensSonnet: 0,
|
|
56
|
-
apiCostUsd: 0,
|
|
57
|
-
humanCostUsd: estimation.humanCostUsd,
|
|
58
|
-
totalCostUsd: 0,
|
|
59
|
-
completedAt: new Date().toISOString(),
|
|
60
|
-
notes: '',
|
|
61
|
-
};
|
|
62
|
-
return autoFillActuals(base, estimation);
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=actuals-estimator.js.map
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
async function handler(ctx) {
|
|
2
|
-
const { specId, projectPath } = ctx;
|
|
3
|
-
if (!projectPath) {
|
|
4
|
-
return;
|
|
5
|
-
}
|
|
6
|
-
await import('../../living-specs/index.js')
|
|
7
|
-
.then(({ reconcileSpec }) => reconcileSpec(specId, projectPath))
|
|
8
|
-
.catch((err) => {
|
|
9
|
-
console.error('[planu] living-specs auto-reconcile failed:', err);
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
export const livingSpecsHook = {
|
|
13
|
-
id: 'living-specs',
|
|
14
|
-
triggers: ['implementing', 'done'],
|
|
15
|
-
requiresProjectPath: true,
|
|
16
|
-
label: 'Auto-reconcile living specs on implementing/done (SPEC-330)',
|
|
17
|
-
handler,
|
|
18
|
-
};
|
|
19
|
-
//# sourceMappingURL=living-specs.hook.js.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { ProjectKnowledge, InteractiveOption } from '../../types/index.js';
|
|
2
|
-
/** Payment provider options — puts DNA-detected provider first when found. */
|
|
3
|
-
export declare function buildPaymentProviderOptions(knowledge: ProjectKnowledge | null): InteractiveOption[];
|
|
4
|
-
export declare function buildBillingModelOptions(): InteractiveOption[];
|
|
5
|
-
export declare function buildTargetOptions(): InteractiveOption[];
|
|
6
|
-
export declare function buildScopeOptions(): InteractiveOption[];
|
|
7
|
-
export declare function buildDatabaseOptions(): InteractiveOption[];
|
|
8
|
-
export declare function buildUiTypeOptions(): InteractiveOption[];
|
|
9
|
-
//# sourceMappingURL=option-builder.d.ts.map
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// src/engine/elicitation/option-builder.ts
|
|
2
|
-
// SPEC-624: Builds InteractiveOption lists from project DNA instead of hardcoded arrays.
|
|
3
|
-
import { t } from '../../i18n/index.js';
|
|
4
|
-
const DNA_PROVIDERS = ['stripe', 'paypal', 'paddle', 'braintree', 'adyen'];
|
|
5
|
-
function capitalize(s) {
|
|
6
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
7
|
-
}
|
|
8
|
-
/** Payment provider options — puts DNA-detected provider first when found. */
|
|
9
|
-
export function buildPaymentProviderOptions(knowledge) {
|
|
10
|
-
const stack = knowledge?.stack ?? [];
|
|
11
|
-
const services = (knowledge?.externalServices ?? []).map((s) => s.toLowerCase());
|
|
12
|
-
const detected = DNA_PROVIDERS.filter((p) => stack.some((s) => s.toLowerCase().includes(p)) || services.some((s) => s.includes(p)));
|
|
13
|
-
const [firstProvider, ...restProviders] = detected;
|
|
14
|
-
if (firstProvider !== undefined) {
|
|
15
|
-
const firstLabel = `${capitalize(firstProvider)} (Recommended)`;
|
|
16
|
-
const rest = restProviders.slice(0, 2).map((p) => ({
|
|
17
|
-
label: capitalize(p),
|
|
18
|
-
description: t(`questions.payment.${p}Desc`),
|
|
19
|
-
}));
|
|
20
|
-
return [
|
|
21
|
-
{ label: firstLabel, description: t(`questions.payment.${firstProvider}Desc`) },
|
|
22
|
-
...rest,
|
|
23
|
-
{ label: t('questions.payment.other'), description: t('questions.payment.otherDesc') },
|
|
24
|
-
].slice(0, 4);
|
|
25
|
-
}
|
|
26
|
-
return [
|
|
27
|
-
{ label: t('questions.payment.stripe'), description: t('questions.payment.stripeDesc') },
|
|
28
|
-
{ label: t('questions.payment.paypal'), description: t('questions.payment.paypalDesc') },
|
|
29
|
-
{ label: t('questions.payment.paddle'), description: t('questions.payment.paddleDesc') },
|
|
30
|
-
{ label: t('questions.payment.other'), description: t('questions.payment.otherDesc') },
|
|
31
|
-
];
|
|
32
|
-
}
|
|
33
|
-
export function buildBillingModelOptions() {
|
|
34
|
-
return [
|
|
35
|
-
{ label: t('questions.payment.oneTime'), description: t('questions.payment.oneTimeDesc') },
|
|
36
|
-
{ label: t('questions.payment.recurring'), description: t('questions.payment.recurringDesc') },
|
|
37
|
-
{
|
|
38
|
-
label: t('questions.payment.usageBased'),
|
|
39
|
-
description: t('questions.payment.usageBasedDesc'),
|
|
40
|
-
},
|
|
41
|
-
{ label: t('questions.payment.freemium'), description: t('questions.payment.freemiumDesc') },
|
|
42
|
-
];
|
|
43
|
-
}
|
|
44
|
-
export function buildTargetOptions() {
|
|
45
|
-
return [
|
|
46
|
-
{ label: t('questions.target.frontend'), description: t('questions.target.frontendDesc') },
|
|
47
|
-
{ label: t('questions.target.backend'), description: t('questions.target.backendDesc') },
|
|
48
|
-
{ label: t('questions.target.fullstack'), description: t('questions.target.fullstackDesc') },
|
|
49
|
-
{ label: t('questions.target.infra'), description: t('questions.target.infraDesc') },
|
|
50
|
-
];
|
|
51
|
-
}
|
|
52
|
-
export function buildScopeOptions() {
|
|
53
|
-
return [
|
|
54
|
-
{ label: t('questions.scope.feature'), description: t('questions.scope.featureDesc') },
|
|
55
|
-
{ label: t('questions.scope.crossModule'), description: t('questions.scope.crossModuleDesc') },
|
|
56
|
-
{ label: t('questions.scope.trivial'), description: t('questions.scope.trivialDesc') },
|
|
57
|
-
{
|
|
58
|
-
label: t('questions.scope.architectural'),
|
|
59
|
-
description: t('questions.scope.architecturalDesc'),
|
|
60
|
-
},
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
export function buildDatabaseOptions() {
|
|
64
|
-
return [
|
|
65
|
-
{ label: t('questions.database.none'), description: t('questions.database.noneDesc') },
|
|
66
|
-
{ label: t('questions.database.schema'), description: t('questions.database.schemaDesc') },
|
|
67
|
-
{ label: t('questions.database.rls'), description: t('questions.database.rlsDesc') },
|
|
68
|
-
{ label: t('questions.database.rpc'), description: t('questions.database.rpcDesc') },
|
|
69
|
-
];
|
|
70
|
-
}
|
|
71
|
-
export function buildUiTypeOptions() {
|
|
72
|
-
return [
|
|
73
|
-
{
|
|
74
|
-
label: t('questions.uiType.newComponent'),
|
|
75
|
-
description: t('questions.uiType.newComponentDesc'),
|
|
76
|
-
},
|
|
77
|
-
{ label: t('questions.uiType.modify'), description: t('questions.uiType.modifyDesc') },
|
|
78
|
-
{
|
|
79
|
-
label: t('questions.uiType.serverAction'),
|
|
80
|
-
description: t('questions.uiType.serverActionDesc'),
|
|
81
|
-
},
|
|
82
|
-
{ label: t('questions.uiType.noUi'), description: t('questions.uiType.noUiDesc') },
|
|
83
|
-
];
|
|
84
|
-
}
|
|
85
|
-
//# sourceMappingURL=option-builder.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Spec } from '../types/index.js';
|
|
2
|
-
/**
|
|
3
|
-
* Generate initial ## Progress content for a newly created spec.
|
|
4
|
-
*/
|
|
5
|
-
export declare function generateProgressContent(spec: Spec): string;
|
|
6
|
-
/**
|
|
7
|
-
* Generate updated ## Progress content reflecting a status change.
|
|
8
|
-
*/
|
|
9
|
-
export declare function generateProgressUpdate(spec: Spec, previousStatus: string, existingContent: string): string;
|
|
10
|
-
//# sourceMappingURL=progress-writer.d.ts.map
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate initial ## Progress content for a newly created spec.
|
|
3
|
-
*/
|
|
4
|
-
export function generateProgressContent(spec) {
|
|
5
|
-
const sections = [
|
|
6
|
-
{ title: 'Progress', content: buildHeader(spec) },
|
|
7
|
-
{ title: 'Status History', content: buildStatusHistory(spec) },
|
|
8
|
-
{ title: 'Metrics', content: buildMetrics(spec) },
|
|
9
|
-
];
|
|
10
|
-
return sections.map((s) => `## ${s.title}\n\n${s.content}`).join('\n\n---\n\n');
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Generate updated ## Progress content reflecting a status change.
|
|
14
|
-
*/
|
|
15
|
-
export function generateProgressUpdate(spec, previousStatus, existingContent) {
|
|
16
|
-
const timestamp = new Date().toISOString();
|
|
17
|
-
const entry = `| ${timestamp} | ${previousStatus} → ${spec.status} |`;
|
|
18
|
-
if (existingContent.includes('| Timestamp')) {
|
|
19
|
-
return existingContent.replace(/((?:\|[^\n]*\n)+)/, `$1${entry}\n`);
|
|
20
|
-
}
|
|
21
|
-
return generateProgressContent(spec);
|
|
22
|
-
}
|
|
23
|
-
function buildHeader(spec) {
|
|
24
|
-
const lines = [
|
|
25
|
-
`**Spec:** ${spec.id}`,
|
|
26
|
-
`**Title:** ${spec.title}`,
|
|
27
|
-
`**Status:** ${spec.status}`,
|
|
28
|
-
`**Created:** ${spec.createdAt}`,
|
|
29
|
-
`**Last Updated:** ${spec.updatedAt}`,
|
|
30
|
-
'',
|
|
31
|
-
`**Difficulty:** ${spec.difficulty} | **Risk:** ${spec.risk}`,
|
|
32
|
-
`**Target:** ${spec.target} | **Scope:** ${spec.scope}`,
|
|
33
|
-
];
|
|
34
|
-
if (spec.gitBranch) {
|
|
35
|
-
lines.push(`**Branch:** \`${spec.gitBranch}\``);
|
|
36
|
-
}
|
|
37
|
-
return lines.join('\n');
|
|
38
|
-
}
|
|
39
|
-
function buildStatusHistory(spec) {
|
|
40
|
-
return [
|
|
41
|
-
'| Timestamp | Transition |',
|
|
42
|
-
'|-----------|-----------|',
|
|
43
|
-
`| ${spec.createdAt} | → ${spec.status} |`,
|
|
44
|
-
].join('\n');
|
|
45
|
-
}
|
|
46
|
-
function buildMetrics(spec) {
|
|
47
|
-
const est = spec.estimation;
|
|
48
|
-
const lines = [
|
|
49
|
-
'| Metric | Estimated | Actual |',
|
|
50
|
-
'|--------|-----------|--------|',
|
|
51
|
-
`| Dev Hours | ${String(est.devHours)} | - |`,
|
|
52
|
-
`| Review Hours | ${String(est.reviewHours)} | - |`,
|
|
53
|
-
`| Total Cost (USD) | $${String(est.totalCostUsd)} | - |`,
|
|
54
|
-
];
|
|
55
|
-
if (spec.actuals) {
|
|
56
|
-
const act = spec.actuals;
|
|
57
|
-
lines[2] = `| Dev Hours | ${String(est.devHours)} | ${String(act.devHours)} |`;
|
|
58
|
-
lines[3] = `| Review Hours | ${String(est.reviewHours)} | ${String(act.reviewHours)} |`;
|
|
59
|
-
lines[4] = `| Total Cost (USD) | $${String(est.totalCostUsd)} | $${String(act.totalCostUsd)} |`;
|
|
60
|
-
}
|
|
61
|
-
return lines.join('\n');
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=progress-writer.js.map
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ModeSuggestion } from '../../types/index.js';
|
|
2
|
-
/** Returns the suggested Claude Code permission mode for a given spec status, or undefined for unknown statuses. */
|
|
3
|
-
export declare function getSuggestedMode(newStatus: string): ModeSuggestion | undefined;
|
|
4
|
-
//# sourceMappingURL=mode-hints.d.ts.map
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// tools/update-status/mode-hints.ts — Map spec status to suggested Claude Code permission mode
|
|
2
|
-
// SPEC-494: Claude Code mode hints per spec phase
|
|
3
|
-
const MODE_MAP = {
|
|
4
|
-
draft: 'default',
|
|
5
|
-
review: 'default',
|
|
6
|
-
approved: 'plan',
|
|
7
|
-
implementing: 'acceptEdits',
|
|
8
|
-
done: 'default',
|
|
9
|
-
discarded: 'default',
|
|
10
|
-
};
|
|
11
|
-
const MODE_HINTS = {
|
|
12
|
-
default: 'Spec is in an early phase — Claude will ask before each change.',
|
|
13
|
-
plan: 'Spec is approved. Use `/mode plan` to prevent accidental edits while reviewing the implementation plan.',
|
|
14
|
-
acceptEdits: 'Spec is the contract — safe to auto-accept file edits. Use `/mode acceptEdits`. Bash commands still ask for approval.',
|
|
15
|
-
};
|
|
16
|
-
/** Returns the suggested Claude Code permission mode for a given spec status, or undefined for unknown statuses. */
|
|
17
|
-
export function getSuggestedMode(newStatus) {
|
|
18
|
-
const mode = MODE_MAP[newStatus];
|
|
19
|
-
if (mode === undefined) {
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
return { mode, hint: MODE_HINTS[mode] ?? '' };
|
|
23
|
-
}
|
|
24
|
-
//# sourceMappingURL=mode-hints.js.map
|