@mgiles/perk 3.2.0 → 3.3.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/README.md +5 -0
- package/extension/authoring/gist/draft.ts +198 -0
- package/extension/authoring/gist/prose.ts +46 -0
- package/extension/authoring/gist/review.ts +133 -0
- package/extension/authoring/gist/save.ts +118 -0
- package/extension/authoring/objective/draft.ts +345 -0
- package/extension/{factories/objectiveDreamReport.ts → authoring/objective/dreamReportGate.ts} +74 -131
- package/extension/authoring/objective/planning.ts +124 -0
- package/extension/authoring/objective/prose.ts +103 -0
- package/extension/authoring/objective/review.ts +128 -0
- package/extension/authoring/objective/save.ts +224 -0
- package/extension/authoring/plan/draft.ts +84 -0
- package/extension/authoring/plan/prose.ts +41 -0
- package/extension/authoring/plan/review.ts +269 -0
- package/extension/authoring/plan/save.ts +256 -0
- package/extension/authoring/plan/source.ts +82 -0
- package/extension/authoring/refinement/context.ts +468 -0
- package/extension/authoring/refinement/draft.ts +261 -0
- package/extension/authoring/refinement/prose.ts +79 -0
- package/extension/authoring/refinement/review.ts +111 -0
- package/extension/authoring/refinement/save.ts +119 -0
- package/extension/authoring/review/approvalGate.ts +34 -0
- package/extension/authoring/review/draftContext.ts +68 -0
- package/extension/codeReview/automated.ts +352 -0
- package/extension/codeReview/submission.ts +229 -0
- package/extension/delivery/address.ts +295 -0
- package/extension/delivery/ci.ts +355 -0
- package/extension/delivery/commitCompact.ts +93 -0
- package/extension/delivery/conflictResolution.ts +247 -0
- package/extension/delivery/ready.ts +193 -0
- package/extension/delivery/stackConflict.ts +361 -0
- package/extension/delivery/stackObjective.ts +16 -0
- package/extension/delivery/stackReconcile.ts +165 -0
- package/extension/delivery/submit.ts +171 -0
- package/extension/index.ts +365 -380
- package/extension/learning/analystWave.ts +324 -0
- package/extension/learning/audit.ts +667 -0
- package/extension/learning/capture.ts +92 -0
- package/extension/learning/containment.ts +104 -0
- package/extension/{waves/dreamWave.ts → learning/dream.ts} +112 -94
- package/extension/learning/dreamAnalysis.ts +435 -0
- package/extension/{waves/dreamReducerWave.ts → learning/dreamReducer.ts} +46 -41
- package/extension/{waves → learning}/dreamReport.ts +35 -31
- package/extension/learning/harvest.ts +491 -0
- package/extension/learning/prose.ts +66 -0
- package/extension/learning/routing.ts +79 -0
- package/extension/pi/v1/bashScanTimeout.ts +64 -0
- package/extension/{doors/prReview.ts → pi/v1/codeReview/automated.ts} +215 -311
- package/extension/{doors/prReviewBrowser.ts → pi/v1/codeReview/browser.ts} +53 -33
- package/extension/{doors/hunkHandoff.ts → pi/v1/codeReview/checkout.ts} +12 -8
- package/extension/{doors/reviewWaveTools.ts → pi/v1/codeReview/reviewWave.ts} +146 -114
- package/extension/{doors/stackReviewBrowser.ts → pi/v1/codeReview/stack.ts} +62 -29
- package/extension/pi/v1/codeReview/submit.ts +354 -0
- package/extension/{doors/prReviewTerminal.ts → pi/v1/codeReview/terminal.ts} +32 -27
- package/extension/pi/v1/contextEvidence.ts +80 -0
- package/extension/pi/v1/contextInjection.ts +207 -0
- package/extension/{doors → pi/v1/delivery}/address.ts +154 -267
- package/extension/pi/v1/delivery/ci.ts +570 -0
- package/extension/pi/v1/delivery/commitCompact.ts +201 -0
- package/extension/pi/v1/delivery/conflictResolverEngine.ts +425 -0
- package/extension/{doors → pi/v1/delivery}/land.ts +123 -61
- package/extension/pi/v1/delivery/ready.ts +322 -0
- package/extension/pi/v1/delivery/stackConflictResolver.ts +172 -0
- package/extension/pi/v1/delivery/stackDrive.ts +120 -0
- package/extension/pi/v1/delivery/stackLand.ts +223 -0
- package/extension/pi/v1/delivery/stackRecover.ts +265 -0
- package/extension/pi/v1/delivery/stackStatus.ts +237 -0
- package/extension/pi/v1/delivery/stackSync.ts +658 -0
- package/extension/pi/v1/delivery/submit.ts +389 -0
- package/extension/pi/v1/delivery/submitConflict.ts +186 -0
- package/extension/pi/v1/draftReview.ts +431 -0
- package/extension/{doors → pi/v1}/draftReviewWaveTools.ts +141 -151
- package/extension/pi/v1/gist.ts +794 -0
- package/extension/pi/v1/learning/audit.ts +186 -0
- package/extension/pi/v1/learning/dream.ts +207 -0
- package/extension/{doors/learnFactory.ts → pi/v1/learning/factory.ts} +18 -65
- package/extension/{doors/harvestWaveTools.ts → pi/v1/learning/harvest.ts} +46 -100
- package/extension/pi/v1/learning/learn.ts +585 -0
- package/extension/pi/v1/lifecycleGates.ts +127 -0
- package/extension/{factories → pi/v1}/objective.ts +53 -33
- package/extension/pi/v1/objectiveAuthoring.ts +672 -0
- package/extension/pi/v1/objectiveDreamGate.ts +160 -0
- package/extension/{factories/objectivePlan.ts → pi/v1/objectivePlanning.ts} +328 -533
- package/extension/pi/v1/objectiveRefinement.ts +1320 -0
- package/extension/pi/v1/objectiveReview.ts +451 -0
- package/extension/{doors → pi/v1}/objectiveReviewBrowser.ts +259 -172
- package/extension/pi/v1/plan.ts +812 -0
- package/extension/pi/v1/planReview.ts +820 -0
- package/extension/{doors → pi/v1}/planReviewBrowser.ts +228 -152
- package/extension/{doors/annotationPush.ts → pi/v1/providers/annotations.ts} +158 -89
- package/extension/pi/v1/providers/plannotator.ts +487 -0
- package/extension/{doors → pi/v1/providers}/plannotatorHandoff.ts +73 -27
- package/extension/pi/v1/providers/selection.ts +43 -0
- package/extension/{adapters/planAdapterTombell.ts → pi/v1/providers/tombell.ts} +43 -72
- package/extension/pi/v1/review.ts +538 -0
- package/extension/pi/v1/reviewOutcome.ts +9 -0
- package/extension/pi/v1/scoutWave.ts +318 -0
- package/extension/{doors → pi/v1}/selfcheck.ts +4 -4
- package/extension/session/branchWorkflowSession.ts +60 -0
- package/extension/session/lifecycle.ts +644 -0
- package/extension/session/lifecycleGates.ts +64 -0
- package/extension/session/saveDestination.ts +87 -0
- package/extension/session/workflowSession.ts +971 -0
- package/extension/substrate/agentScratch.ts +27 -54
- package/extension/substrate/bashScanTimeout.ts +181 -0
- package/extension/substrate/bindingDelivery.ts +38 -30
- package/extension/substrate/bindings.ts +4 -5
- package/extension/substrate/cache.ts +64 -12
- package/extension/substrate/childRestrictions.ts +39 -0
- package/extension/substrate/coldDoor.ts +17 -1
- package/extension/substrate/config.ts +157 -21
- package/extension/substrate/git.ts +88 -6
- package/extension/substrate/modelVisible.ts +53 -0
- package/extension/substrate/prompts.ts +22 -0
- package/extension/substrate/registry.ts +2 -0
- package/extension/substrate/resolverLease.ts +5 -4
- package/extension/substrate/sessionData.ts +85 -152
- package/extension/substrate/toolGating.ts +263 -84
- package/extension/substrate/unifiedDiff.ts +1 -1
- package/extension/substrate/workflowState.ts +178 -163
- package/extension/substrate/worktreeResolverLock.ts +261 -0
- package/extension/surfaces/surfaces.ts +79 -27
- package/extension/waves/adversarialReviewWave.ts +87 -46
- package/extension/waves/blockedReports.ts +59 -0
- package/extension/waves/draftReviewWave.ts +42 -42
- package/extension/waves/laneIdentity.ts +77 -0
- package/extension/waves/objectiveExplorerWave.ts +24 -24
- package/extension/waves/prReviewWave.ts +89 -77
- package/extension/waves/reportWave.ts +438 -578
- package/extension/waves/reviewClassifierWave.ts +22 -22
- package/extension/waves/rpcAdapter.ts +100 -15
- package/extension/waves/scoutWave.ts +192 -0
- package/extension/waves/transport.ts +480 -0
- package/extension/worker/sdkAdapter.ts +494 -0
- package/extension/worker/stageExecution.ts +679 -0
- package/extension/workerMain.ts +18 -19
- package/package.json +6 -4
- package/prompts/_fixtures/live.yaml +43 -18
- package/prompts/contexts/adapters/plannotator-gist.md +6 -0
- package/prompts/contexts/adapters/plannotator-objective.md +6 -0
- package/prompts/contexts/adapters/plannotator-plan.md +8 -1
- package/prompts/contexts/adapters/plannotator-refinement.md +22 -0
- package/prompts/contexts/objective-refinement.md +17 -0
- package/prompts/contexts/read-only.md +1 -1
- package/prompts/stages/conflict-resolution-continuation.md +9 -6
- package/prompts/stages/conflict-resolution.md +4 -4
- package/prompts/stages/objective-plan/guidance.md +2 -2
- package/prompts/stages/objective-plan/seed.md +9 -1
- package/prompts/stages/objective-reconcile-ready.md +1 -1
- package/prompts/stages/objective-reconcile.md +1 -1
- package/prompts/stages/objective-refine/seed.md +18 -0
- package/prompts/stages/objective-review-browser.md +4 -4
- package/prompts/stages/objective-sync.md +1 -1
- package/prompts/stages/plan-review-browser.md +4 -4
- package/prompts/stages/pr-review-browser/active.md +3 -4
- package/prompts/stages/pr-review-browser/foreign.md +3 -4
- package/prompts/stages/pr-review-terminal/active.md +3 -3
- package/prompts/stages/pr-review-terminal/foreign.md +3 -3
- package/prompts/stages/pr-review.md +3 -3
- package/prompts/stages/stack-review-browser/stack.md +5 -6
- package/shared/README.md +8 -0
- package/shared/bindings.yaml +3 -3
- package/shared/contracts.md +2601 -506
- package/shared/fixtures/issues-table.json +130 -0
- package/shared/registry.yaml +13 -0
- package/shared/schemas/outputs/objective-node-engagement.schema.json +318 -0
- package/shared/schemas/outputs/objective-stack-status.schema.json +6 -1
- package/shared/schemas/outputs/pr-review-context.schema.json +54 -9
- package/shared/schemas/outputs/pr-review-stack-context.schema.json +196 -0
- package/extension/adapters/planAdapterPlannotator.ts +0 -362
- package/extension/doors/auditWaveTools.ts +0 -352
- package/extension/doors/ciExecutor.ts +0 -756
- package/extension/doors/commitCompact.ts +0 -251
- package/extension/doors/dreamWaveTools.ts +0 -489
- package/extension/doors/learn.ts +0 -668
- package/extension/doors/lifecycleGates.ts +0 -207
- package/extension/doors/objectiveStack.ts +0 -1543
- package/extension/doors/prReviewDynamic.ts +0 -276
- package/extension/doors/ready.ts +0 -279
- package/extension/doors/submit.ts +0 -373
- package/extension/doors/submitPrReview.ts +0 -505
- package/extension/factories/gistAuthor.ts +0 -94
- package/extension/factories/gistDraft.ts +0 -265
- package/extension/factories/gistSave.ts +0 -251
- package/extension/factories/implementHere.ts +0 -116
- package/extension/factories/objectiveAuthor.ts +0 -98
- package/extension/factories/objectiveDraft.ts +0 -466
- package/extension/factories/objectiveSave.ts +0 -366
- package/extension/factories/planDraft.ts +0 -140
- package/extension/factories/planMode.ts +0 -205
- package/extension/factories/planReview.ts +0 -1237
- package/extension/factories/planSave.ts +0 -604
- package/extension/factories/planTitle.ts +0 -141
- package/extension/substrate/structuredOutput.ts +0 -202
- package/extension/waves/auditWave.ts +0 -312
- package/extension/waves/harvestWave.ts +0 -399
- package/extension/waves/learnWave.ts +0 -155
- package/extension/waves/memoryAdapter.ts +0 -139
- package/extension/waves/prReviewDynamicWave.ts +0 -777
- package/extension/worker/readOnlySession.ts +0 -294
- package/extension/worker/worker.ts +0 -899
- package/prompts/stages/pr-review-dynamic.md +0 -7
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// Session-lifecycle gates (the interior safety primitive). One reusable dirty-repo guard on
|
|
2
|
-
// session_before_switch / session_before_fork that returns { cancel: true } when an *active perk
|
|
3
|
-
// workflow* has uncommitted changes — so a stage transition never silently orphans work. Plus the
|
|
4
|
-
// guard-only `/implement` command that *enforces* the implement stage's `warm: false` legality (the
|
|
5
|
-
// plan→implement jump requires fresh context; that is the cold door `perk implement`).
|
|
6
|
-
//
|
|
7
|
-
// pi.on("session_before_fork"/"...switch") handlers are fired by extensionRunner.emit({type,...})
|
|
8
|
-
// and their { cancel } result round-trips; the handler's
|
|
9
|
-
// pi.exec("git",["status","--porcelain"],{cwd}) resolves the session cwd.
|
|
10
|
-
|
|
11
|
-
import type {
|
|
12
|
-
ExtensionAPI,
|
|
13
|
-
ExtensionCommandContext,
|
|
14
|
-
ExtensionContext,
|
|
15
|
-
} from "@earendil-works/pi-coding-agent";
|
|
16
|
-
import type { PlanRef } from "../substrate/cache.ts";
|
|
17
|
-
import { registerPerkCommand } from "../substrate/command.ts";
|
|
18
|
-
import { render } from "../substrate/prompts.ts";
|
|
19
|
-
import { type BranchSource, branchOf, rebuildWorkflowState } from "../substrate/workflowState.ts";
|
|
20
|
-
import { report } from "../surfaces/report.ts";
|
|
21
|
-
|
|
22
|
-
// The planning stages whose sessions never legitimately run lifecycle doors. After an approved
|
|
23
|
-
// save, a still-live planning session holds TWO plan identities — the cwd binding (a positioned
|
|
24
|
-
// stacked session's predecessor checkout, read via readPlanRef(ctx.cwd)) and the just-saved plan
|
|
25
|
-
// on active_plan_ref — so a door invocation there could act on the predecessor. At the repo root
|
|
26
|
-
// the same invocation fails confusingly today; the refusal is honest in both shapes.
|
|
27
|
-
const PLANNING_STAGES = new Set(["plan", "objective-plan"]);
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* The planning-stage lifecycle-door refusal (the shared first check of the warm /submit,
|
|
31
|
-
* /address, /land, and /learn doors): when this session's workflow-state `stage` is a planning
|
|
32
|
-
* stage, return the refusal message directing the human at the fresh-session implement door;
|
|
33
|
-
* `null` otherwise (non-planning stages — and stage-less sessions — are unaffected). Fail-CLOSED
|
|
34
|
-
* on an unreadable branch: without the state this guard cannot prove the session is not a
|
|
35
|
-
* positioned planning session (whose cwd binding is the PREDECESSOR — the exact target it
|
|
36
|
-
* protects), so an unreadable read refuses rather than letting the door act.
|
|
37
|
-
*/
|
|
38
|
-
export function planningStageRefusal(ctx: BranchSource, door: string): string | null {
|
|
39
|
-
let stage: string | undefined;
|
|
40
|
-
try {
|
|
41
|
-
stage = rebuildWorkflowState(branchOf(ctx)).stage;
|
|
42
|
-
} catch (error) {
|
|
43
|
-
return (
|
|
44
|
-
`${door} is unavailable: the session's workflow state could not be read ` +
|
|
45
|
-
`(${String(error)}), so this cannot be proven not to be a planning session — ` +
|
|
46
|
-
"retry, or implement the saved plan with `perk impl <N>` in a fresh session."
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
if (stage === undefined || !PLANNING_STAGES.has(stage)) return null;
|
|
50
|
-
return (
|
|
51
|
-
`${door} is unavailable in a planning session (stage ${stage}): a planning session can ` +
|
|
52
|
-
"hold two plan identities (its checkout's own binding and the just-saved plan) — " +
|
|
53
|
-
"implement the saved plan with `perk impl <N>` in a fresh session instead."
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const DIRTY_MESSAGE = "uncommitted changes — commit or stash before switching/forking this stage.";
|
|
58
|
-
const HANDOFF_DIRTY_MESSAGE =
|
|
59
|
-
"uncommitted changes — commit before a fresh-context /implement handoff (the plan is the " +
|
|
60
|
-
"only artifact that crosses the boundary).";
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Pure gate policy: cancel a transition only inside an active perk workflow whose tree is
|
|
64
|
-
* dirty. Kept separate from the `pi.exec` effect so the matrix is unit-testable offline.
|
|
65
|
-
*/
|
|
66
|
-
export function gateDecision(inputs: { active: boolean; dirty: boolean }): { cancel: boolean } {
|
|
67
|
-
return { cancel: inputs.active && inputs.dirty };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** True when this session is linked to a plan (a perk workflow is in progress). */
|
|
71
|
-
function workflowActive(ctx: ExtensionContext): boolean {
|
|
72
|
-
return rebuildWorkflowState(branchOf(ctx)).active_plan_ref != null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* The shared dirty-repo guard for switch/fork. Allows (returns undefined) outside a workflow or on
|
|
77
|
-
* a clean tree; cancels with a loud, fail-safe-headless message on a dirty tree in a workflow. If
|
|
78
|
-
* `git status` itself fails (e.g. not a repo) we allow — this is a hygiene guard, not a validator.
|
|
79
|
-
*/
|
|
80
|
-
async function guardTransition(
|
|
81
|
-
pi: ExtensionAPI,
|
|
82
|
-
ctx: ExtensionContext,
|
|
83
|
-
): Promise<{ cancel: true } | undefined> {
|
|
84
|
-
const active = workflowActive(ctx);
|
|
85
|
-
if (!active) return undefined; // perk does not interfere with non-perk transitions
|
|
86
|
-
const res = await pi.exec("git", ["status", "--porcelain"], { cwd: ctx.cwd });
|
|
87
|
-
const dirty = res.code === 0 && res.stdout.trim().length > 0;
|
|
88
|
-
if (!gateDecision({ active, dirty }).cancel) return undefined;
|
|
89
|
-
report(ctx, "lifecycle", "warning", DIRTY_MESSAGE); // fail-safe-headless: loud, still cancels
|
|
90
|
-
return { cancel: true };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* The per-backend plan-read instruction — the prompt SSOT for "how do I read the saved
|
|
95
|
-
* plan". Byte-identical to `perk/run/launch.py::_plan_read_instruction` (the Python twin); drift in
|
|
96
|
-
* either plane fails the paired parity suites. `github` reads via `gh`; `linear` points at the
|
|
97
|
-
* pi-mono-linear tools with an `open <url>` fallback; any other provider falls back to opening
|
|
98
|
-
* the url.
|
|
99
|
-
*
|
|
100
|
-
* The wording now lives in the canonical templates `prompts/common/plan-read/*.md`, rendered
|
|
101
|
-
* identically by both planes via the shared render seam (contracts.md §8.31); branching stays in
|
|
102
|
-
* code — only the arm chosen and the vars passed differ. Golden-fixture parity (the three
|
|
103
|
-
* `plan-read-*` cases) plus a thin per-arm selection test replace the dedicated substring parity.
|
|
104
|
-
*/
|
|
105
|
-
export function planReadInstruction(provider: string, prId: string, url: string): string {
|
|
106
|
-
if (provider === "github") return render("common/plan-read/github.md", { pr_id: prId, url });
|
|
107
|
-
if (provider === "linear") return render("common/plan-read/linear.md", { pr_id: prId, url });
|
|
108
|
-
return render("common/plan-read/other.md", { pr_id: prId, url });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* The plan-read priming seed for a fresh implement session. The in-session twin of
|
|
113
|
-
* `perk/run/launch.py`'s `_implement_prompt`: carry the plan FORWARD (read it from its canonical
|
|
114
|
-
* source), never summarize it — the plan is the only artifact that crosses the boundary.
|
|
115
|
-
*
|
|
116
|
-
* The wording lives in the canonical template `prompts/stages/implement.md`, rendered by the shared
|
|
117
|
-
* seam (contracts.md §8.31); branching stays in code — only the `read_cmd` var differs. This warm
|
|
118
|
-
* handoff is now byte-identical to the cold/worker primer, so it carries the same "Progress
|
|
119
|
-
* tracking:" tail (the prior shorter near-copy omission is removed).
|
|
120
|
-
*/
|
|
121
|
-
export function implementHandoffPrompt(ref: PlanRef): string {
|
|
122
|
-
const readCmd = planReadInstruction(ref.provider, String(ref.pr_id), ref.url);
|
|
123
|
-
return render("stages/implement.md", {
|
|
124
|
-
provider: ref.provider,
|
|
125
|
-
pr_id: String(ref.pr_id),
|
|
126
|
-
url: ref.url,
|
|
127
|
-
read_cmd: readCmd,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* The warm `/implement`. It still NEVER performs the cross-worktree plan→implement
|
|
133
|
-
* transition (that is structurally the Python cold door's job — no extension session API can change
|
|
134
|
-
* cwd). Outside an impl context it refuses and points at `perk implement`. INSIDE an active
|
|
135
|
-
* impl worktree (read-write + a linked plan-ref) it offers the in-process twin of the cold door: a
|
|
136
|
-
* lossless `ctx.newSession` fresh-context handoff seeded with the plan-read priming (the plan, and
|
|
137
|
-
* the worktree's materialized plan-ref, are the durable state — model-visible output stays capped).
|
|
138
|
-
* Dirty-tree hygiene is gated manually here (belt-and-suspenders: `newSession` is a session-replace,
|
|
139
|
-
* not a fork/switch, so it may bypass the `session_before_*` gate — we refuse on a dirty tree
|
|
140
|
-
* either way), fail-safe-headless.
|
|
141
|
-
*/
|
|
142
|
-
function registerImplementGuard(pi: ExtensionAPI): void {
|
|
143
|
-
registerPerkCommand(pi, "implement", {
|
|
144
|
-
description:
|
|
145
|
-
"Refresh implement context (in-worktree handoff); cross-worktree is `perk implement`.",
|
|
146
|
-
handler: async (_args, ctx) => {
|
|
147
|
-
const state = rebuildWorkflowState(branchOf(ctx));
|
|
148
|
-
const ref = state.active_plan_ref;
|
|
149
|
-
const inImpl = state.mode === "read-write" && ref != null;
|
|
150
|
-
if (!inImpl) {
|
|
151
|
-
report(
|
|
152
|
-
ctx,
|
|
153
|
-
"implement",
|
|
154
|
-
"warning",
|
|
155
|
-
"/implement is cold-only here — run `perk implement` from a shell for fresh context.",
|
|
156
|
-
);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Dirty-tree gate (manual; see the doc comment). Refuse the handoff with uncommitted work.
|
|
161
|
-
const status = await pi.exec("git", ["status", "--porcelain"], { cwd: ctx.cwd });
|
|
162
|
-
if (status.code === 0 && status.stdout.trim().length > 0) {
|
|
163
|
-
report(ctx, "implement", "warning", HANDOFF_DIRTY_MESSAGE);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const commandCtx = ctx as ExtensionCommandContext;
|
|
168
|
-
if (typeof commandCtx.newSession !== "function") {
|
|
169
|
-
report(
|
|
170
|
-
ctx,
|
|
171
|
-
"implement",
|
|
172
|
-
"warning",
|
|
173
|
-
"a fresh-context /implement handoff needs an interactive session.",
|
|
174
|
-
);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const prompt = implementHandoffPrompt(ref as PlanRef);
|
|
179
|
-
const parentSession = ctx.sessionManager.getSessionFile() ?? undefined;
|
|
180
|
-
const result = await commandCtx.newSession({
|
|
181
|
-
parentSession,
|
|
182
|
-
withSession: async (fresh) => {
|
|
183
|
-
await fresh.sendUserMessage(prompt);
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Verify + cap model-visible output (the full state lives in the worktree + the plan issue).
|
|
188
|
-
if (result.cancelled) {
|
|
189
|
-
report(ctx, "implement", "info", "/implement handoff cancelled — staying in this session.");
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
report(
|
|
193
|
-
ctx,
|
|
194
|
-
"implement",
|
|
195
|
-
"info",
|
|
196
|
-
`fresh implement session started for plan #${(ref as PlanRef).pr_id} — the plan is carried forward, not summarized.`,
|
|
197
|
-
);
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** Register the dirty-repo lifecycle gate (switch + fork) and the guard-only `/implement`. */
|
|
203
|
-
export function registerLifecycleGates(pi: ExtensionAPI): void {
|
|
204
|
-
pi.on("session_before_fork", async (_event, ctx) => guardTransition(pi, ctx));
|
|
205
|
-
pi.on("session_before_switch", async (_event, ctx) => guardTransition(pi, ctx));
|
|
206
|
-
registerImplementGuard(pi);
|
|
207
|
-
}
|