@planu/cli 5.7.4 → 5.7.6
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 +85 -0
- package/README.md +3 -3
- package/dist/.planu-build.json +1 -1
- package/dist/cli/commands/package-handoff.js +30 -5
- package/dist/config/compliance-profiles.json +36 -3
- package/dist/config/environment-schema.json +21 -0
- package/dist/config/hook-templates/planu-session-safeguard.sh +22 -15
- package/dist/config/official-sdd-tools.d.ts +1 -1
- package/dist/config/official-sdd-tools.js +11 -24
- package/dist/config/registries/hosts/codex.json +14 -30
- package/dist/config/registries/hosts/opencode.json +1 -6
- package/dist/config/registries/legacy-guidance.json +26 -0
- package/dist/config/server-instructions.js +0 -21
- package/dist/config/skill-templates/planu-context-assets.md +3 -6
- package/dist/config/skill-templates/planu-implement.md +2 -2
- package/dist/config/skill-templates/planu-multi-teammate-review.md +1 -1
- package/dist/config/skill-templates/planu-release.md +2 -7
- package/dist/config/skill-templates/planu-validate.md +3 -3
- package/dist/config/spec-templates/crud-rest-api/template.json +5 -1
- package/dist/config/spec-templates/file-upload-s3/template.json +5 -1
- package/dist/config/spec-templates/stripe-payments/template.json +5 -1
- package/dist/config/spec-templates/webhook-system/template.json +5 -1
- package/dist/config/subagent-templates/planu-challenger.md +4 -9
- package/dist/config/subagent-templates/planu-spec-implementer.md +2 -4
- package/dist/config/subagent-templates/planu-validator.md +5 -8
- package/dist/config/tool-groups.json +6 -144
- package/dist/engine/ambiguity-scorer.js +40 -1
- package/dist/engine/autopilot/bootstrap.js +1 -1
- package/dist/engine/code-impact-analyzer.js +2 -6
- package/dist/engine/context-orchestrator/index.js +2 -2
- package/dist/engine/convention-scanner/codebase-scanner.js +2 -2
- package/dist/engine/dogfooding/runtime-gap-detector.js +2 -2
- package/dist/engine/evidence-gates/artifact-reader.d.ts +1 -0
- package/dist/engine/evidence-gates/artifact-reader.js +1 -1
- package/dist/engine/evidence-gates/evidence-autofill.d.ts +13 -5
- package/dist/engine/evidence-gates/evidence-autofill.js +106 -43
- package/dist/engine/evidence-gates/lifecycle-gate.js +7 -4
- package/dist/engine/evidence-index/index-builder.js +21 -4
- package/dist/engine/execution/job-runtime.js +1 -1
- package/dist/engine/execution/package-handoff-job-executor.d.ts +22 -0
- package/dist/engine/execution/package-handoff-job-executor.js +490 -0
- package/dist/engine/execution/validate-job-executor.js +20 -8
- package/dist/engine/git/exec-git.d.ts +4 -0
- package/dist/engine/git/exec-git.js +14 -0
- package/dist/engine/handoff-artifacts/implementation-review-reader.js +15 -2
- package/dist/engine/handoff-artifacts/schemas.d.ts +2 -0
- package/dist/engine/handoff-artifacts/schemas.js +1 -0
- package/dist/engine/handoff-format.d.ts +36 -0
- package/dist/engine/handoff-format.js +314 -0
- package/dist/engine/handoff-packager.d.ts +5 -3
- package/dist/engine/handoff-packager.js +89 -32
- package/dist/engine/host-tool-filter.js +20 -49
- package/dist/engine/human-summary.js +14 -3
- package/dist/engine/implementation-contract/common.d.ts +8 -3
- package/dist/engine/implementation-contract/common.js +9 -6
- package/dist/engine/implementation-contract/evaluator.js +4 -6
- package/dist/engine/implementation-contract/renderer.js +18 -23
- package/dist/engine/project-health-checker.js +2 -2
- package/dist/engine/readiness-checker.js +27 -0
- package/dist/engine/reconcile/apply-changes.js +4 -0
- package/dist/engine/reconcile/propagate-mirrors.d.ts +3 -0
- package/dist/engine/reconcile/propagate-mirrors.js +311 -0
- package/dist/engine/self-healing/healer.js +12 -5
- package/dist/engine/self-healing/strategies/lint-fix.d.ts +1 -1
- package/dist/engine/self-healing/strategies/lint-fix.js +4 -1
- package/dist/engine/self-healing/strategies/test-fix.d.ts +4 -3
- package/dist/engine/self-healing/strategies/test-fix.js +32 -14
- package/dist/engine/self-healing/strategies/typescript-fix.d.ts +1 -1
- package/dist/engine/self-healing/strategies/typescript-fix.js +28 -10
- package/dist/engine/session/checkpoint-writer.js +8 -4
- package/dist/engine/session/session-tracker.d.ts +5 -16
- package/dist/engine/session/session-tracker.js +29 -26
- package/dist/engine/session-state/writer.js +3 -11
- package/dist/engine/skill-generator/workflow-skill-generator.d.ts +4 -2
- package/dist/engine/skill-generator/workflow-skill-generator.js +113 -38
- package/dist/engine/spec-format/bdd-parser.d.ts +1 -11
- package/dist/engine/spec-format/bdd-parser.js +40 -11
- package/dist/engine/spec-format/lean-spec-generator.js +30 -10
- package/dist/engine/spec-format/retired-scaffold.d.ts +3 -0
- package/dist/engine/spec-format/retired-scaffold.js +5 -0
- package/dist/engine/spec-format/technical-md-populator.d.ts +1 -0
- package/dist/engine/spec-format/technical-md-populator.js +27 -0
- package/dist/engine/spec-format/unified-spec-builder.d.ts +1 -0
- package/dist/engine/spec-format/unified-spec-builder.js +30 -20
- package/dist/engine/spec-grounding/contract.js +115 -1
- package/dist/engine/spec-migrator/fold-technical.js +60 -19
- package/dist/engine/spec-migrator/placeholder-technical.d.ts +2 -0
- package/dist/engine/spec-migrator/placeholder-technical.js +18 -0
- package/dist/engine/spec-quality/generic-output-gate.js +37 -3
- package/dist/engine/technical-enricher/index.js +4 -1
- package/dist/engine/type-safety-gate.js +3 -11
- package/dist/engine/universal-rules/catalog.js +0 -2
- package/dist/engine/universal-rules/rules/planu-workflow.js +1 -1
- package/dist/engine/validation/durable-validation.d.ts +3 -2
- package/dist/engine/validation/durable-validation.js +106 -40
- package/dist/engine/validation/validation-freshness.d.ts +3 -2
- package/dist/engine/validation/validation-freshness.js +22 -16
- package/dist/engine/validation/validation-worktree.js +34 -0
- package/dist/hosts/claude-code/ux/mcp-prompts.js +8 -8
- package/dist/index.js +3 -17
- package/dist/resources/process.js +38 -65
- package/dist/storage/session-state-store.js +2 -0
- package/dist/tools/challenge-spec/scenarios-utils.js +2 -2
- package/dist/tools/configure-checkpoint-policy.js +3 -3
- package/dist/tools/create-spec-helpers.js +2 -5
- package/dist/tools/create-spec.js +21 -4
- package/dist/tools/facilitate.js +3 -6
- package/dist/tools/git/branch-ops.js +16 -4
- package/dist/tools/github-release-handler.js +1 -20
- package/dist/tools/heal-spec-docs.js +1 -13
- package/dist/tools/init-project/agents-md-writer.js +6 -6
- package/dist/tools/init-project/claude-md-generator.d.ts +0 -1
- package/dist/tools/init-project/claude-md-generator.js +0 -35
- package/dist/tools/init-project/handler.js +24 -49
- package/dist/tools/init-project/legacy-guidance-scanner.d.ts +12 -0
- package/dist/tools/init-project/legacy-guidance-scanner.js +176 -0
- package/dist/tools/init-project/per-client-files-writer.js +5 -5
- package/dist/tools/init-project/planu-workflow-generator.js +2 -13
- package/dist/tools/init-project/portable-index-reconciler.d.ts +21 -1
- package/dist/tools/init-project/portable-index-reconciler.js +66 -0
- package/dist/tools/init-project/rules-generator.d.ts +0 -11
- package/dist/tools/init-project/rules-generator.js +4 -85
- package/dist/tools/init-project/scaffold-writer.d.ts +0 -1
- package/dist/tools/init-project/scaffold-writer.js +1 -12
- package/dist/tools/jobs/handlers.d.ts +0 -6
- package/dist/tools/jobs/handlers.js +13 -40
- package/dist/tools/list-specs.js +6 -21
- package/dist/tools/package-handoff.d.ts +3 -2
- package/dist/tools/package-handoff.js +153 -427
- package/dist/tools/reconcile-session-safeguard-hook.js +22 -15
- package/dist/tools/register-sdd-tools.js +0 -23
- package/dist/tools/register-spec-tools/core-spec-tools.js +18 -27
- package/dist/tools/schemas/index.d.ts +1 -1
- package/dist/tools/schemas/index.js +1 -1
- package/dist/tools/schemas/output-schemas.d.ts +1 -18
- package/dist/tools/schemas/output-schemas.js +1 -11
- package/dist/tools/schemas/package-handoff-output-schema.d.ts +40 -0
- package/dist/tools/schemas/package-handoff-output-schema.js +68 -0
- package/dist/tools/schemas/validate-output-schema.d.ts +1 -2
- package/dist/tools/schemas/validate-output-schema.js +3 -2
- package/dist/tools/session-checkpoint.js +2 -2
- package/dist/tools/skill-registry/index.d.ts +0 -1
- package/dist/tools/skill-registry/index.js +0 -1
- package/dist/tools/sync-spec-state-handler.d.ts +2 -2
- package/dist/tools/sync-spec-state-handler.js +23 -3
- package/dist/tools/tool-registry/core-tools.js +1 -140
- package/dist/tools/tool-registry/group-infra.js +2 -39
- package/dist/tools/tool-registry/group-quality-compliance.js +9 -1
- package/dist/tools/update-status/batch.js +17 -0
- package/dist/tools/update-status/dod-gates.js +14 -1
- package/dist/tools/update-status/done-receipt-verifier.d.ts +22 -0
- package/dist/tools/update-status/done-receipt-verifier.js +56 -26
- package/dist/tools/update-status/evidence-gate.js +10 -21
- package/dist/tools/update-status/file-sync.d.ts +1 -0
- package/dist/tools/update-status/file-sync.js +6 -0
- package/dist/tools/update-status/index.d.ts +6 -0
- package/dist/tools/update-status/index.js +39 -44
- package/dist/tools/update-status-actions.js +2 -7
- package/dist/tools/validate.js +34 -28
- package/dist/transports/oauth-validator.js +12 -1
- package/dist/transports/transport-factory.d.ts +2 -1
- package/dist/transports/transport-factory.js +19 -0
- package/dist/types/common/primitives.d.ts +2 -0
- package/dist/types/durable-job.d.ts +45 -0
- package/dist/types/durable-validation.d.ts +1 -1
- package/dist/types/evidence-autofill.d.ts +13 -1
- package/dist/types/handoff-artifacts.d.ts +2 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/legacy-guidance.d.ts +20 -0
- package/dist/types/legacy-guidance.js +3 -0
- package/dist/types/readiness.d.ts +8 -1
- package/dist/types/reconcile.d.ts +6 -0
- package/dist/types/skill-registry.d.ts +26 -1
- package/dist/types/spec/core.d.ts +5 -0
- package/dist/types/spec/inputs.d.ts +2 -2
- package/dist/types/spec-format.d.ts +11 -1
- package/dist/types/spec-grounding.d.ts +12 -0
- package/dist/types/ssr-migration.d.ts +1 -1
- package/dist/types/transport.d.ts +1 -0
- package/dist/types/validation-receipt.d.ts +27 -0
- package/package.json +3 -2
- package/planu-plugin.json +13 -26
- package/src/i18n/messages/en.json +1 -1
- package/src/i18n/messages/es.json +1 -1
- package/src/i18n/messages/pt.json +1 -1
- package/dist/engine/skill-generator/conventions-hasher.d.ts +0 -7
- package/dist/engine/skill-generator/conventions-hasher.js +0 -24
- package/dist/engine/universal-rules/rules/agent-teams.d.ts +0 -3
- package/dist/engine/universal-rules/rules/agent-teams.js +0 -63
- package/dist/tools/clarify-requirements/multiple-choice.d.ts +0 -30
- package/dist/tools/clarify-requirements/multiple-choice.js +0 -306
- package/dist/tools/clarify-requirements/questions-context.d.ts +0 -9
- package/dist/tools/clarify-requirements/questions-context.js +0 -74
- package/dist/tools/clarify-requirements/questions.d.ts +0 -16
- package/dist/tools/clarify-requirements/questions.js +0 -96
- package/dist/tools/clarify-requirements.d.ts +0 -4
- package/dist/tools/clarify-requirements.js +0 -314
- package/dist/tools/code-graph-handler.d.ts +0 -6
- package/dist/tools/code-graph-handler.js +0 -72
- package/dist/tools/create-rule.d.ts +0 -4
- package/dist/tools/create-rule.js +0 -107
- package/dist/tools/feedback-handler.d.ts +0 -7
- package/dist/tools/feedback-handler.js +0 -150
- package/dist/tools/semantic-search-handler.d.ts +0 -7
- package/dist/tools/semantic-search-handler.js +0 -71
- package/dist/tools/skill-registry/search.d.ts +0 -11
- package/dist/tools/skill-registry/search.js +0 -159
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// tools/init-project/legacy-guidance-scanner.ts — SPEC-1716
|
|
2
|
+
// Neutralizes stale Planu-installed guidance that instructs agents to create
|
|
3
|
+
// legacy standalone technical.md/progress.md files. Fail-closed by tiers:
|
|
4
|
+
// Tier 1 — delimited Planu block markers: rewrite only the block content.
|
|
5
|
+
// Tier 2 — composite fingerprint (allowlisted legacy filename + managed-by
|
|
6
|
+
// header): replace the whole file, backing up the prior content.
|
|
7
|
+
// Tier 3 — contradictory phrase alone: warning only, zero mutation.
|
|
8
|
+
// Malformed markers (opening without closing) also fail closed: warning only.
|
|
9
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { atomicWriteFile } from '../../engine/safety/atomic-write-file.js';
|
|
12
|
+
import { resolveContainedProjectFile } from '../../engine/safety/contained-project-file.js';
|
|
13
|
+
import legacyGuidanceRegistry from '../../config/registries/legacy-guidance.json' with { type: 'json' };
|
|
14
|
+
const REGISTRY = legacyGuidanceRegistry;
|
|
15
|
+
async function resolveScanSurface(projectPath) {
|
|
16
|
+
const files = [...REGISTRY.hostSurfaceFiles];
|
|
17
|
+
for (const { dir, extension } of REGISTRY.hostSurfaceDirectories) {
|
|
18
|
+
let entries;
|
|
19
|
+
try {
|
|
20
|
+
entries = await readdir(join(projectPath, dir), { withFileTypes: true });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
for (const entry of entries) {
|
|
26
|
+
if (entry.isFile() && entry.name.endsWith(extension)) {
|
|
27
|
+
files.push(`${dir}/${entry.name}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return files;
|
|
32
|
+
}
|
|
33
|
+
function containsContradictoryPhrase(text) {
|
|
34
|
+
return REGISTRY.contradictoryPhrases.find((phrase) => text.includes(phrase));
|
|
35
|
+
}
|
|
36
|
+
const OPEN_MARKER_RE = /<!--\s*(planu[\w:-]*)\s*-->/g;
|
|
37
|
+
/**
|
|
38
|
+
* Locate delimited `<!-- planu... --> ... <!-- /planu... -->` (or repeated-tag,
|
|
39
|
+
* as emitted by claude-md-generator.ts wrap()) blocks. Returns `null` when an
|
|
40
|
+
* opening marker has no matching close — the malformed-marker fail-closed case.
|
|
41
|
+
*
|
|
42
|
+
* Uses its own cursor (a fresh RegExp with `re.lastIndex` advanced past each
|
|
43
|
+
* close marker) instead of `matchAll` over the whole string — a repeated-tag
|
|
44
|
+
* close is itself a valid open-marker match, so scanning the string without
|
|
45
|
+
* skipping past it would misread that close as the next block's opener.
|
|
46
|
+
*/
|
|
47
|
+
function findPlanuBlocks(content) {
|
|
48
|
+
const blocks = [];
|
|
49
|
+
const re = new RegExp(OPEN_MARKER_RE.source, 'g');
|
|
50
|
+
let match;
|
|
51
|
+
while ((match = re.exec(content)) !== null) {
|
|
52
|
+
const id = match[1];
|
|
53
|
+
if (id === undefined) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const openEnd = match.index + match[0].length;
|
|
57
|
+
const closeTag = `<!-- /${id} -->`;
|
|
58
|
+
const repeatTag = match[0];
|
|
59
|
+
const closeTagStart = content.indexOf(closeTag, openEnd);
|
|
60
|
+
const repeatTagStart = content.indexOf(repeatTag, openEnd);
|
|
61
|
+
const closeStart = [closeTagStart, repeatTagStart]
|
|
62
|
+
.filter((idx) => idx !== -1)
|
|
63
|
+
.sort((a, b) => a - b)[0];
|
|
64
|
+
if (closeStart === undefined) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const closeLength = closeStart === closeTagStart ? closeTag.length : repeatTag.length;
|
|
68
|
+
blocks.push({ id, openEnd, closeStart });
|
|
69
|
+
re.lastIndex = closeStart + closeLength;
|
|
70
|
+
}
|
|
71
|
+
return blocks;
|
|
72
|
+
}
|
|
73
|
+
async function scanTier1(absPath, relPath, content) {
|
|
74
|
+
const blocks = findPlanuBlocks(content);
|
|
75
|
+
if (blocks === null) {
|
|
76
|
+
return {
|
|
77
|
+
kind: 'warning',
|
|
78
|
+
file: relPath,
|
|
79
|
+
reason: 'malformed Planu block marker: an opening marker has no matching closing marker',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const dirty = blocks.some(({ openEnd, closeStart }) => containsContradictoryPhrase(content.slice(openEnd, closeStart)));
|
|
83
|
+
if (!dirty) {
|
|
84
|
+
return { kind: 'clean' };
|
|
85
|
+
}
|
|
86
|
+
let rewritten = '';
|
|
87
|
+
let cursor = 0;
|
|
88
|
+
for (const { openEnd, closeStart } of blocks) {
|
|
89
|
+
const body = content.slice(openEnd, closeStart);
|
|
90
|
+
rewritten += content.slice(cursor, openEnd);
|
|
91
|
+
rewritten += containsContradictoryPhrase(body) ? `\n${REGISTRY.replacementGuidance}\n` : body;
|
|
92
|
+
cursor = closeStart;
|
|
93
|
+
}
|
|
94
|
+
rewritten += content.slice(cursor);
|
|
95
|
+
await atomicWriteFile(absPath, rewritten);
|
|
96
|
+
return { kind: 'healed', file: relPath };
|
|
97
|
+
}
|
|
98
|
+
async function scanTier2Or3(absPath, relPath, content) {
|
|
99
|
+
const phrase = containsContradictoryPhrase(content);
|
|
100
|
+
if (!phrase) {
|
|
101
|
+
return { kind: 'clean' };
|
|
102
|
+
}
|
|
103
|
+
const strongFingerprint = REGISTRY.legacyFilenameAllowlist.includes(relPath) &&
|
|
104
|
+
REGISTRY.managedByMarkers.some((marker) => content.includes(marker));
|
|
105
|
+
if (!strongFingerprint) {
|
|
106
|
+
return {
|
|
107
|
+
kind: 'warning',
|
|
108
|
+
file: relPath,
|
|
109
|
+
reason: `contains contradictory legacy guidance phrase: "${phrase}"`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
await atomicWriteFile(`${absPath}.planu-backup`, content);
|
|
113
|
+
await atomicWriteFile(absPath, `${REGISTRY.replacementGuidance}\n`);
|
|
114
|
+
return { kind: 'healed', file: relPath };
|
|
115
|
+
}
|
|
116
|
+
async function scanFile(projectPath, relPath) {
|
|
117
|
+
const absPath = join(projectPath, relPath);
|
|
118
|
+
let content;
|
|
119
|
+
try {
|
|
120
|
+
content = await readFile(absPath, 'utf-8');
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return { kind: 'clean' };
|
|
124
|
+
}
|
|
125
|
+
// Fail closed if the surface entry (or an ancestor directory, e.g. a
|
|
126
|
+
// symlinked .claude/rules) resolves outside the project root — never let a
|
|
127
|
+
// mutation follow a symlink off the repo.
|
|
128
|
+
try {
|
|
129
|
+
await resolveContainedProjectFile(projectPath, absPath);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return {
|
|
133
|
+
kind: 'warning',
|
|
134
|
+
file: relPath,
|
|
135
|
+
reason: 'path escapes the project directory (symlink containment check failed)',
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const hasMarkers = OPEN_MARKER_RE.test(content);
|
|
139
|
+
OPEN_MARKER_RE.lastIndex = 0;
|
|
140
|
+
return hasMarkers
|
|
141
|
+
? scanTier1(absPath, relPath, content)
|
|
142
|
+
: scanTier2Or3(absPath, relPath, content);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Scan the bounded set of Planu-installed host guidance surfaces for stale
|
|
146
|
+
* directives that contradict the current spec.md-only contract, and
|
|
147
|
+
* neutralize what can be neutralized fail-closed. Never touches files
|
|
148
|
+
* outside the inventoried scan surface (no repo-wide walk).
|
|
149
|
+
*/
|
|
150
|
+
export async function scanLegacyGuidance(projectPath) {
|
|
151
|
+
const files = await resolveScanSurface(projectPath);
|
|
152
|
+
const healed = [];
|
|
153
|
+
const warnings = [];
|
|
154
|
+
for (const relPath of files) {
|
|
155
|
+
const outcome = await scanFile(projectPath, relPath);
|
|
156
|
+
if (outcome.kind === 'healed') {
|
|
157
|
+
healed.push(outcome.file);
|
|
158
|
+
}
|
|
159
|
+
else if (outcome.kind === 'warning') {
|
|
160
|
+
warnings.push({ file: outcome.file, reason: outcome.reason });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return { healed, warnings };
|
|
164
|
+
}
|
|
165
|
+
/** Records a legacy-guidance scan outcome onto an init_project autopilot summary. */
|
|
166
|
+
export function summarizeLegacyGuidanceScan(collector, scan) {
|
|
167
|
+
if (scan.healed.length > 0) {
|
|
168
|
+
collector.pushOk('legacy-guidance-healed', `Neutralized stale Planu guidance in: ${scan.healed.join(', ')}`);
|
|
169
|
+
}
|
|
170
|
+
if (scan.warnings.length > 0) {
|
|
171
|
+
collector.pushSkipped('legacy-guidance-warnings', `Left untouched (weak fingerprint, needs manual review): ${scan.warnings
|
|
172
|
+
.map((w) => w.file)
|
|
173
|
+
.join(', ')}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=legacy-guidance-scanner.js.map
|
|
@@ -18,13 +18,13 @@ alwaysApply: true
|
|
|
18
18
|
\`\`\`
|
|
19
19
|
facilitate("what to build") → create_spec → challenge_spec → check_readiness
|
|
20
20
|
→ update_status(review) → approve → update_status(approved) → implement
|
|
21
|
-
→ validate (ack) →
|
|
21
|
+
→ validate (ack) → get_job (poll until completed) → inspect job.result → update_status(done)
|
|
22
22
|
\`\`\`
|
|
23
23
|
|
|
24
24
|
## Durable Validation Gate
|
|
25
25
|
|
|
26
|
-
1. Call \`validate\` and capture \`operationId\`, \`projectId\`,
|
|
27
|
-
2.
|
|
26
|
+
1. Call \`validate\` and capture \`operationId\`, \`projectId\`, and \`workspaceId\`
|
|
27
|
+
2. Poll \`get_job\` with those identifiers until terminal
|
|
28
28
|
3. Require \`completed\` and inspect \`job.result.structuredContent\`; stop on \`failed\`, \`dead-letter\`, or \`cancelled\`
|
|
29
29
|
4. Mark done only when the completed result reports \`ready: true\`, \`status: "passing"\`, and passing quality gates
|
|
30
30
|
|
|
@@ -54,7 +54,7 @@ Planu enforces Spec Driven Development — spec first, then implement, then vali
|
|
|
54
54
|
|
|
55
55
|
- Starting a new feature: use \`facilitate()\` or \`create_spec()\`
|
|
56
56
|
- Resuming work: use \`planu_status\` to see what's in progress
|
|
57
|
-
- Finishing work: submit \`validate()\`,
|
|
57
|
+
- Finishing work: submit \`validate()\`, poll \`get_job()\`, inspect \`job.result.structuredContent\`, then use \`update_status(done)\`
|
|
58
58
|
|
|
59
59
|
## Mandatory Workflow
|
|
60
60
|
|
|
@@ -64,7 +64,7 @@ Planu enforces Spec Driven Development — spec first, then implement, then vali
|
|
|
64
64
|
4. \`update_status(specId, "approved")\` — lock the spec
|
|
65
65
|
5. Implement the code
|
|
66
66
|
6. \`validate(specId)\` — submit validation and capture the durable job acknowledgement
|
|
67
|
-
7. \`
|
|
67
|
+
7. \`get_job(operationId, projectId, workspaceId)\` — poll and repeat until terminal
|
|
68
68
|
8. Require \`completed\` and inspect \`job.result.structuredContent\`
|
|
69
69
|
9. \`update_status(specId, "done")\` — mark complete only after a completed passing result
|
|
70
70
|
|
|
@@ -10,7 +10,7 @@ const PLANU_WORKFLOW_CONTENT = `<!-- planu-sdd-workflow -->
|
|
|
10
10
|
### Session Start
|
|
11
11
|
1. Call \`planu_status\` — load active specs and git state
|
|
12
12
|
2. If spec is \`implementing\` → resume it before starting new work
|
|
13
|
-
3. Call \`
|
|
13
|
+
3. Call \`list_specs\` before starting any new task to find related work
|
|
14
14
|
|
|
15
15
|
### For ANY task > 5 minutes
|
|
16
16
|
NEVER write production code without an approved spec.
|
|
@@ -21,22 +21,11 @@ NEVER write production code without an approved spec.
|
|
|
21
21
|
### Session End
|
|
22
22
|
Call \`session_checkpoint\` to save context for the next session.
|
|
23
23
|
|
|
24
|
-
### For Multiple Specs (3+ parallel work)
|
|
25
|
-
When implementing multiple independent specs simultaneously, use Agent Teams:
|
|
26
|
-
1. Call \`plan_team_distribution\` with spec IDs → auto-assigns file ownership
|
|
27
|
-
2. Call \`generate_teammate_prompt\` for each teammate → isolated context per agent
|
|
28
|
-
3. Spawn N Claude Code agents with the generated prompts
|
|
29
|
-
4. Call \`validate_team_results\` after completion → verify merged code
|
|
30
|
-
|
|
31
|
-
Use teams when: 3+ specs ready, estimated effort >8h, monorepo with clear module boundaries.
|
|
32
|
-
Quick ref: parallel work → \`plan_team_distribution\` → teammates → \`validate_team_results\`
|
|
33
|
-
|
|
34
24
|
### Quick reference
|
|
35
25
|
- New feature → \`facilitate("description")\`
|
|
36
26
|
- Check progress → \`planu_status\`
|
|
37
|
-
- Find related work → \`
|
|
27
|
+
- Find related work → \`list_specs\` and scan titles
|
|
38
28
|
- List pending → \`list_specs\` with status filter
|
|
39
|
-
- Parallel work → \`plan_team_distribution\`
|
|
40
29
|
<!-- /planu-sdd-workflow -->`;
|
|
41
30
|
/**
|
|
42
31
|
* Generate the Planu SDD section for CLAUDE.md.
|
|
@@ -1,10 +1,30 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { WorkflowSkillGenerationResult } from '../../types/skill-registry.js';
|
|
2
|
+
import type { FilesystemImportDeps, FilesystemImportFailure, LegacyGuidanceScanResult, PortableIndexReconciliationResult, SkippedLegacyContract } from '../../types/index.js';
|
|
3
|
+
import type { ToolResult } from '../../types/common/primitives.js';
|
|
2
4
|
/** Autopilot-first summary of fatal reconciliation failures: what failed, why, and the next action. */
|
|
3
5
|
export declare function describeReconciliationFailures(failures: FilesystemImportFailure[]): string;
|
|
4
6
|
/** Autopilot-first summary of a successful reconciliation, including any legacy skips. */
|
|
5
7
|
export declare function describeReconciliationSuccess(repositoryFilesChanged: string[], skippedLegacy: SkippedLegacyContract[], strayRepoRemovals?: string[]): string;
|
|
6
8
|
/** Autopilot-first message for a reconciliation outcome, success or fatal-failure. */
|
|
7
9
|
export declare function describeReconciliationOutcome(reconciliation: PortableIndexReconciliationResult, repositoryFilesChanged: string[]): string;
|
|
10
|
+
/**
|
|
11
|
+
* SPEC-1716: Build the already-initialized `init_project` result, folding the
|
|
12
|
+
* legacy-guidance scan's healed paths into the reported repository file changes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildAlreadyInitializedResult(projectId: string, reconciliation: PortableIndexReconciliationResult, legacyMigratedPaths: readonly string[], refreshedAssets: readonly string[], legacyGuidanceScan: LegacyGuidanceScanResult, projectPath: string, skillSync?: WorkflowSkillGenerationResult | null): ToolResult;
|
|
15
|
+
/** The subset of `MigrationRunResult` (migration-runner.ts) needed to report an authorized migration. */
|
|
16
|
+
interface AuthorizedMigrationSummary {
|
|
17
|
+
criticalMigrationFailures: unknown[];
|
|
18
|
+
changedPaths?: string[];
|
|
19
|
+
migrationReportPath: string | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* SPEC-1716: Build the authorized-migration `init_project` result, folding the
|
|
23
|
+
* legacy-guidance scan's healed paths into the reported repository file changes
|
|
24
|
+
* the same way the already-initialized fast path does.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildAuthorizedMigrationResult(projectId: string, projectPath: string, authorizedMigrations: readonly string[], migrationResult: AuthorizedMigrationSummary, legacyGuidanceScan: LegacyGuidanceScanResult): ToolResult;
|
|
8
27
|
/** Rebuild the mutable external index from the repository-owned portable contracts. */
|
|
9
28
|
export declare function reconcilePortableSpecIndex(projectPath: string, projectId: string, deps?: FilesystemImportDeps): Promise<PortableIndexReconciliationResult>;
|
|
29
|
+
export {};
|
|
10
30
|
//# sourceMappingURL=portable-index-reconciler.d.ts.map
|
|
@@ -156,6 +156,72 @@ export function describeReconciliationOutcome(reconciliation, repositoryFilesCha
|
|
|
156
156
|
? describeReconciliationSuccess(repositoryFilesChanged, reconciliation.skippedLegacy, reconciliation.strayRepoRemovals)
|
|
157
157
|
: describeReconciliationFailures(reconciliation.failures);
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* SPEC-1716: Build the already-initialized `init_project` result, folding the
|
|
161
|
+
* legacy-guidance scan's healed paths into the reported repository file changes.
|
|
162
|
+
*/
|
|
163
|
+
export function buildAlreadyInitializedResult(projectId, reconciliation, legacyMigratedPaths, refreshedAssets, legacyGuidanceScan, projectPath, skillSync = null) {
|
|
164
|
+
const repositoryFilesChanged = [...refreshedAssets, ...legacyGuidanceScan.healed];
|
|
165
|
+
const baseText = describeReconciliationOutcome(reconciliation, [...refreshedAssets]);
|
|
166
|
+
const healedGuidanceSuffix = legacyGuidanceScan.healed.length === 0
|
|
167
|
+
? ''
|
|
168
|
+
: ` Healed stale legacy guidance in: ${legacyGuidanceScan.healed.join(', ')}.`;
|
|
169
|
+
const skillSyncSuffix = skillSync === null
|
|
170
|
+
? ''
|
|
171
|
+
: ` Refreshed ${String(skillSync.written.length)} workflow skill(s), left ${String(skillSync.userModified.length)} user-modified skill(s) untouched.`;
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: 'text', text: baseText + healedGuidanceSuffix + skillSyncSuffix }],
|
|
174
|
+
structuredContent: {
|
|
175
|
+
projectId,
|
|
176
|
+
...(reconciliation.failures.length === 0 ? { projectPath } : {}),
|
|
177
|
+
isUpdate: true,
|
|
178
|
+
repositoryFilesChanged,
|
|
179
|
+
authorizedMigrations: [],
|
|
180
|
+
importedSpecIds: reconciliation.importedSpecIds,
|
|
181
|
+
failures: reconciliation.failures,
|
|
182
|
+
skippedLegacy: reconciliation.skippedLegacy,
|
|
183
|
+
strayRepoRemovals: reconciliation.strayRepoRemovals,
|
|
184
|
+
migratedLegacyPaths: legacyMigratedPaths,
|
|
185
|
+
legacyGuidanceHealed: legacyGuidanceScan.healed,
|
|
186
|
+
legacyGuidanceWarnings: legacyGuidanceScan.warnings,
|
|
187
|
+
skillsWritten: skillSync?.written.length ?? 0,
|
|
188
|
+
skillsUserModified: skillSync?.userModified.length ?? 0,
|
|
189
|
+
},
|
|
190
|
+
...(reconciliation.failures.length > 0 ? { isError: true } : {}),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* SPEC-1716: Build the authorized-migration `init_project` result, folding the
|
|
195
|
+
* legacy-guidance scan's healed paths into the reported repository file changes
|
|
196
|
+
* the same way the already-initialized fast path does.
|
|
197
|
+
*/
|
|
198
|
+
export function buildAuthorizedMigrationResult(projectId, projectPath, authorizedMigrations, migrationResult, legacyGuidanceScan) {
|
|
199
|
+
const hasCriticalFailures = migrationResult.criticalMigrationFailures.length > 0;
|
|
200
|
+
const healedGuidanceSuffix = legacyGuidanceScan.healed.length === 0
|
|
201
|
+
? ''
|
|
202
|
+
: ` Healed stale legacy guidance in: ${legacyGuidanceScan.healed.join(', ')}.`;
|
|
203
|
+
const baseText = hasCriticalFailures
|
|
204
|
+
? `Authorized migration completed with ${String(migrationResult.criticalMigrationFailures.length)} blocking issue(s).`
|
|
205
|
+
: 'Authorized planu-spec-format-v1 migration completed.';
|
|
206
|
+
return {
|
|
207
|
+
content: [{ type: 'text', text: baseText + healedGuidanceSuffix }],
|
|
208
|
+
structuredContent: {
|
|
209
|
+
projectId,
|
|
210
|
+
projectPath,
|
|
211
|
+
isUpdate: true,
|
|
212
|
+
authorizedMigrations,
|
|
213
|
+
repositoryFilesChanged: [
|
|
214
|
+
...(migrationResult.changedPaths ?? []),
|
|
215
|
+
...legacyGuidanceScan.healed,
|
|
216
|
+
],
|
|
217
|
+
migrationReportPath: migrationResult.migrationReportPath,
|
|
218
|
+
criticalMigrationFailures: migrationResult.criticalMigrationFailures,
|
|
219
|
+
legacyGuidanceHealed: legacyGuidanceScan.healed,
|
|
220
|
+
legacyGuidanceWarnings: legacyGuidanceScan.warnings,
|
|
221
|
+
},
|
|
222
|
+
...(hasCriticalFailures ? { isError: true } : {}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
159
225
|
/** Rebuild the mutable external index from the repository-owned portable contracts. */
|
|
160
226
|
export async function reconcilePortableSpecIndex(projectPath, projectId, deps = {
|
|
161
227
|
listSpecs: specStore.listSpecs,
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
export declare function generateAgentTeamsRulesContent(): string;
|
|
2
|
-
/**
|
|
3
|
-
* Write .claude/rules/agent-teams.md to the target project.
|
|
4
|
-
* Always overwrites to keep the content up to date.
|
|
5
|
-
*/
|
|
6
|
-
export declare function generateAgentTeamsRules(projectPath: string): Promise<void>;
|
|
7
|
-
/**
|
|
8
|
-
* Write .claude/rules/agent-teams.md only if it does not exist yet.
|
|
9
|
-
* @returns true if the file was created, false if it already existed.
|
|
10
|
-
*/
|
|
11
|
-
export declare function generateAgentTeamsRulesIfMissing(projectPath: string): Promise<boolean>;
|
|
12
1
|
/**
|
|
13
2
|
* Write .claude/rules/planu-workflow.md to the target project.
|
|
14
3
|
* Always overwrites to keep the content up to date.
|
|
@@ -18,12 +18,12 @@ Auto-generated by \`init_project\`. Do not edit manually.
|
|
|
18
18
|
| implementing | work in progress |
|
|
19
19
|
| done | implemented + validated |
|
|
20
20
|
|
|
21
|
-
Flow: \`facilitate → create_spec → challenge_spec → check_readiness → approve → implement → validate (ack) →
|
|
21
|
+
Flow: \`facilitate → create_spec → challenge_spec → check_readiness → approve → implement → validate (ack) → get_job (poll until completed) → inspect job.result → done\`
|
|
22
22
|
|
|
23
23
|
## Durable Validation Gate
|
|
24
24
|
|
|
25
|
-
1. Call \`validate\` and capture \`operationId\`, \`projectId\`,
|
|
26
|
-
2.
|
|
25
|
+
1. Call \`validate\` and capture \`operationId\`, \`projectId\`, and \`workspaceId\` from the acknowledgement.
|
|
26
|
+
2. Poll \`get_job\` with those identifiers. Repeat while state is non-terminal.
|
|
27
27
|
3. Require state \`completed\`, then inspect \`job.result.structuredContent\`. Stop and report \`failed\`, \`dead-letter\`, or \`cancelled\`.
|
|
28
28
|
4. Call \`update_status(done)\` only after the completed result reports \`ready: true\`, \`status: "passing"\`, and passing quality gates.
|
|
29
29
|
|
|
@@ -60,7 +60,7 @@ Any new feature, bug fix, refactor, integration, or task > 5 min.
|
|
|
60
60
|
|------|------|
|
|
61
61
|
| New feature | \`facilitate("what to build")\` |
|
|
62
62
|
| Project status | \`planu_status\` |
|
|
63
|
-
| Find related specs | \`
|
|
63
|
+
| Find related specs | \`list_specs\` and scan titles |
|
|
64
64
|
| List approved work | \`list_specs\` with \`status: approved\` |
|
|
65
65
|
| Mark done | \`update_status\` → \`done\` |
|
|
66
66
|
| Verify | \`validate\` |
|
|
@@ -102,87 +102,6 @@ Set \`CLAUDE_CODE_SUBAGENT_MODEL=haiku\` in \`.env\` for automatic haiku on all
|
|
|
102
102
|
- Keep output < 500 tokens for read operations, < 200 tokens for write confirmations
|
|
103
103
|
- After every tool call: explain what happened in simple terms
|
|
104
104
|
`;
|
|
105
|
-
const AGENT_TEAMS_RULES_PATH = '.claude/rules/agent-teams.md';
|
|
106
|
-
export function generateAgentTeamsRulesContent() {
|
|
107
|
-
return `# Agent Teams (MANDATORY when 3+ specs in parallel)
|
|
108
|
-
|
|
109
|
-
This rule file is auto-generated by Planu \`init_project\`. Do not edit manually — re-run \`init_project\` to update.
|
|
110
|
-
|
|
111
|
-
## When to Use Agent Teams
|
|
112
|
-
|
|
113
|
-
Use Agent Teams when ALL of the following apply:
|
|
114
|
-
- 3+ independent specs are ready to implement simultaneously
|
|
115
|
-
- Estimated total effort > 8h
|
|
116
|
-
- Specs touch different modules/packages (clear file ownership boundaries)
|
|
117
|
-
- Monorepo or multi-layer architecture with well-defined interfaces
|
|
118
|
-
|
|
119
|
-
## File Ownership (MANDATORY)
|
|
120
|
-
|
|
121
|
-
**Two teammates MUST NEVER modify the same file.** This is non-negotiable.
|
|
122
|
-
|
|
123
|
-
- \`plan_team_distribution\` auto-assigns exclusive file ownership per agent
|
|
124
|
-
- Review the distribution before spawning — resolve any conflicts first
|
|
125
|
-
- If two specs require the same shared file, implement them sequentially, not in parallel
|
|
126
|
-
|
|
127
|
-
## Workflow
|
|
128
|
-
|
|
129
|
-
\`\`\`
|
|
130
|
-
1. plan_team_distribution # input: spec IDs → output: file ownership map
|
|
131
|
-
2. generate_teammate_prompt # input: teammate assignment → output: isolated prompt
|
|
132
|
-
3. spawn N agents # claude -p "<prompt>" for each teammate (run in parallel)
|
|
133
|
-
4. validate_team_results # input: projectPath → verifies merged code integrity
|
|
134
|
-
\`\`\`
|
|
135
|
-
|
|
136
|
-
## Available Team Patterns
|
|
137
|
-
|
|
138
|
-
- **implement-and-test** — one agent implements, another writes tests (zero shared files)
|
|
139
|
-
- **full-stack** — frontend and backend agents with a contract-first API boundary
|
|
140
|
-
- **research-then-build** — researcher gathers context first, builder implements after
|
|
141
|
-
- **parallel-specs** — N agents implement N fully independent specs simultaneously
|
|
142
|
-
|
|
143
|
-
## Quick Reference
|
|
144
|
-
|
|
145
|
-
| Goal | Tool |
|
|
146
|
-
|------|------|
|
|
147
|
-
| Plan team distribution | \`plan_team_distribution\` with spec IDs array |
|
|
148
|
-
| Get teammate context | \`generate_teammate_prompt\` with assignment object |
|
|
149
|
-
| Validate merged result | \`validate_team_results\` after all agents complete |
|
|
150
|
-
|
|
151
|
-
## Prohibited Patterns
|
|
152
|
-
|
|
153
|
-
- NEVER spawn teammates without running \`plan_team_distribution\` first
|
|
154
|
-
- NEVER assign the same file to two different teammates
|
|
155
|
-
- NEVER skip \`validate_team_results\` after parallel implementation
|
|
156
|
-
- NEVER use Agent Teams for 1-2 specs — sequential is faster and safer
|
|
157
|
-
`;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Write .claude/rules/agent-teams.md to the target project.
|
|
161
|
-
* Always overwrites to keep the content up to date.
|
|
162
|
-
*/
|
|
163
|
-
export async function generateAgentTeamsRules(projectPath) {
|
|
164
|
-
const rulesPath = join(projectPath, AGENT_TEAMS_RULES_PATH);
|
|
165
|
-
const rulesDir = join(projectPath, '.claude/rules');
|
|
166
|
-
await mkdir(rulesDir, { recursive: true });
|
|
167
|
-
const content = generateAgentTeamsRulesContent();
|
|
168
|
-
assertEnglishOnlyArtifactText(content, 'rule');
|
|
169
|
-
await writeFile(rulesPath, content, 'utf-8');
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Write .claude/rules/agent-teams.md only if it does not exist yet.
|
|
173
|
-
* @returns true if the file was created, false if it already existed.
|
|
174
|
-
*/
|
|
175
|
-
export async function generateAgentTeamsRulesIfMissing(projectPath) {
|
|
176
|
-
const rulesPath = join(projectPath, AGENT_TEAMS_RULES_PATH);
|
|
177
|
-
try {
|
|
178
|
-
await access(rulesPath);
|
|
179
|
-
return false; // already exists
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
await generateAgentTeamsRules(projectPath);
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
105
|
/**
|
|
187
106
|
* Write .claude/rules/planu-workflow.md to the target project.
|
|
188
107
|
* Always overwrites to keep the content up to date.
|
|
@@ -22,7 +22,6 @@ export interface ScaffoldWriteResult {
|
|
|
22
22
|
planuWorkflowInjected: boolean;
|
|
23
23
|
planuHooksConfigured: boolean;
|
|
24
24
|
planuRulesWritten: boolean;
|
|
25
|
-
agentTeamsRulesWritten: boolean;
|
|
26
25
|
modeRulesWritten: boolean;
|
|
27
26
|
responseStyleRulesWritten: boolean;
|
|
28
27
|
compactSkillWritten: boolean;
|
|
@@ -8,7 +8,7 @@ import { runGitSetup } from './git-setup.js';
|
|
|
8
8
|
import { generateAndWriteRules } from './lifecycle-helpers.js';
|
|
9
9
|
import { generatePlanuSection, injectPlanuSection } from './planu-workflow-generator.js';
|
|
10
10
|
import { configurePlanuHooks } from './hooks-configurator.js';
|
|
11
|
-
import { generateWorkflowRulesIfMissing,
|
|
11
|
+
import { generateWorkflowRulesIfMissing, generateModeRulesIfMissing, generateResponseStyleRulesIfMissing, } from './rules-generator.js';
|
|
12
12
|
import { generateCompactSkillIfMissing } from './skills-writer.js';
|
|
13
13
|
import { generateFindSkillsIfMissing } from './find-skills-writer.js';
|
|
14
14
|
import { injectPlanuAutoStage } from '../../engine/git-hook-injector.js';
|
|
@@ -120,16 +120,6 @@ export async function runScaffoldWriter(projectPath, projectId, knowledge, recom
|
|
|
120
120
|
/* best-effort */
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
-
// SPEC-291: Write .claude/rules/agent-teams.md if missing (best-effort)
|
|
124
|
-
let agentTeamsRulesWritten = false;
|
|
125
|
-
if (shouldWriteClaudeAssets) {
|
|
126
|
-
try {
|
|
127
|
-
agentTeamsRulesWritten = await generateAgentTeamsRulesIfMissing(projectPath);
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
/* best-effort */
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
123
|
// SPEC-494: Write .claude/rules/planu-modes.md if missing (best-effort)
|
|
134
124
|
let modeRulesWritten = false;
|
|
135
125
|
if (shouldWriteClaudeAssets) {
|
|
@@ -394,7 +384,6 @@ export async function runScaffoldWriter(projectPath, projectId, knowledge, recom
|
|
|
394
384
|
planuWorkflowInjected,
|
|
395
385
|
planuHooksConfigured,
|
|
396
386
|
planuRulesWritten,
|
|
397
|
-
agentTeamsRulesWritten,
|
|
398
387
|
modeRulesWritten,
|
|
399
388
|
responseStyleRulesWritten,
|
|
400
389
|
compactSkillWritten,
|
|
@@ -4,12 +4,6 @@ export interface JobToolIdentityInput {
|
|
|
4
4
|
projectId: string;
|
|
5
5
|
workspaceId?: string;
|
|
6
6
|
}
|
|
7
|
-
export interface WatchJobToolInput extends JobToolIdentityInput {
|
|
8
|
-
afterCursor?: string;
|
|
9
|
-
timeoutMs?: number;
|
|
10
|
-
}
|
|
11
7
|
export declare function handleGetJob(input: JobToolIdentityInput): Promise<ToolResult>;
|
|
12
|
-
export declare function handleWatchJob(input: WatchJobToolInput): Promise<ToolResult>;
|
|
13
|
-
export declare function handleCancelJob(input: JobToolIdentityInput): Promise<ToolResult>;
|
|
14
8
|
export declare function handleRestartJob(input: JobToolIdentityInput): Promise<ToolResult>;
|
|
15
9
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -52,6 +52,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
52
52
|
});
|
|
53
53
|
import { DurableJobRuntime, publicJobCursor } from '../../engine/execution/job-runtime.js';
|
|
54
54
|
import { scheduleValidateJobExecution } from '../../engine/execution/validate-job-executor.js';
|
|
55
|
+
import { schedulePackageHandoffJobExecution } from '../../engine/execution/package-handoff-job-executor.js';
|
|
55
56
|
import { isValidationReceiptPendingIntent, parseValidationReceiptPendingCheckpoint, } from '../../types/durable-validation.js';
|
|
56
57
|
import { redactText } from '../../security/redactor.js';
|
|
57
58
|
import { getRuntimePolicy } from '../../engine/runtime-policy.js';
|
|
@@ -97,62 +98,34 @@ export function handleGetJob(input) {
|
|
|
97
98
|
__disposeResources(env_1);
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
export
|
|
101
|
+
export function handleRestartJob(input) {
|
|
101
102
|
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
102
103
|
try {
|
|
103
104
|
const runtime = __addDisposableResource(env_2, new DurableJobRuntime(), false);
|
|
104
|
-
const job = await runtime.watch(input);
|
|
105
|
-
const observation = publicJob(runtime, job);
|
|
106
|
-
return result({ schemaVersion: 1, job: observation, cursor: publicJobCursor(observation) });
|
|
107
|
-
}
|
|
108
|
-
catch (e_2) {
|
|
109
|
-
env_2.error = e_2;
|
|
110
|
-
env_2.hasError = true;
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
__disposeResources(env_2);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
export function handleCancelJob(input) {
|
|
117
|
-
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
118
|
-
try {
|
|
119
|
-
const runtime = __addDisposableResource(env_3, new DurableJobRuntime(), false);
|
|
120
|
-
const job = runtime.cancel(input);
|
|
121
|
-
const observation = publicJob(runtime, job);
|
|
122
|
-
return Promise.resolve(result({ schemaVersion: 1, job: observation, cursor: publicJobCursor(observation) }));
|
|
123
|
-
}
|
|
124
|
-
catch (e_3) {
|
|
125
|
-
env_3.error = e_3;
|
|
126
|
-
env_3.hasError = true;
|
|
127
|
-
}
|
|
128
|
-
finally {
|
|
129
|
-
__disposeResources(env_3);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
export function handleRestartJob(input) {
|
|
133
|
-
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
134
|
-
try {
|
|
135
|
-
const runtime = __addDisposableResource(env_4, new DurableJobRuntime(), false);
|
|
136
105
|
const current = runtime.get(input);
|
|
137
106
|
const pending = parseValidationReceiptPendingCheckpoint(current.checkpoint, checkpointLimits());
|
|
138
107
|
if (!pending && isValidationReceiptPendingIntent(current.checkpoint)) {
|
|
139
108
|
throw new Error('[Planu] Invalid validation receipt checkpoint');
|
|
140
109
|
}
|
|
141
110
|
const job = pending ? runtime.restartReceiptPublication(input) : runtime.restart(input);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
111
|
+
const kind = job.payload && typeof job.payload === 'object'
|
|
112
|
+
? job.payload.kind
|
|
113
|
+
: undefined;
|
|
114
|
+
if (kind === 'validate') {
|
|
145
115
|
scheduleValidateJobExecution(job.projectId, job.workspaceId);
|
|
146
116
|
}
|
|
117
|
+
else if (kind === 'package-handoff') {
|
|
118
|
+
schedulePackageHandoffJobExecution(job.projectId, job.workspaceId);
|
|
119
|
+
}
|
|
147
120
|
const observation = publicJob(runtime, job);
|
|
148
121
|
return Promise.resolve(result({ schemaVersion: 1, job: observation, cursor: publicJobCursor(observation) }));
|
|
149
122
|
}
|
|
150
|
-
catch (
|
|
151
|
-
|
|
152
|
-
|
|
123
|
+
catch (e_2) {
|
|
124
|
+
env_2.error = e_2;
|
|
125
|
+
env_2.hasError = true;
|
|
153
126
|
}
|
|
154
127
|
finally {
|
|
155
|
-
__disposeResources(
|
|
128
|
+
__disposeResources(env_2);
|
|
156
129
|
}
|
|
157
130
|
}
|
|
158
131
|
//# sourceMappingURL=handlers.js.map
|