@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
package/extension/index.ts
CHANGED
|
@@ -1,80 +1,101 @@
|
|
|
1
|
-
// perk Pi extension — the session *interior
|
|
1
|
+
// perk Pi extension — the session *interior*: the composition root.
|
|
2
2
|
//
|
|
3
|
-
// The tier-3 session-state mechanics (contracts.md §8.2/§8.3)
|
|
3
|
+
// The tier-3 session-state mechanics (contracts.md §8.2/§8.3) — claim PERK_RUN_ID on
|
|
4
4
|
// `session_start` (verified-linkage), rebuild `perk:workflow-state` on `session_start` AND
|
|
5
|
-
// `session_tree` (per-field LWW),
|
|
5
|
+
// `session_tree` (per-field LWW), derive a child run_id on fork, reconcile the stage-gated plan
|
|
6
|
+
// linkage — are OWNED by `session/lifecycle.ts` (identity arms + the two-phase startup facts +
|
|
7
|
+
// the navigation facts). This file binds the production ports and keeps the Pi effects visibly
|
|
8
|
+
// ORDERED: gate sync from the pure scope slice → claimed-only refinement import → the post-gate
|
|
9
|
+
// facts → implementation pointer capture → feedback receiver sync → presentation/probe tail.
|
|
6
10
|
|
|
7
11
|
import { existsSync, mkdirSync } from "node:fs";
|
|
8
12
|
import { basename, join } from "node:path";
|
|
9
13
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
14
|
+
import { createDraftReviewWaveState } from "./authoring/review/draftContext.ts";
|
|
15
|
+
import { createHunkFeedbackReceiver, type HunkFeedbackReceiver } from "./hunkFeedback/receiver.ts";
|
|
16
|
+
import { registerBashScanTimeout } from "./pi/v1/bashScanTimeout.ts";
|
|
17
|
+
import { installAutomatedReviewBindings } from "./pi/v1/codeReview/automated.ts";
|
|
18
|
+
import { installPrReviewBrowserBindings } from "./pi/v1/codeReview/browser.ts";
|
|
19
|
+
import { installReviewWaveBindings } from "./pi/v1/codeReview/reviewWave.ts";
|
|
20
|
+
import { installStackReviewBindings } from "./pi/v1/codeReview/stack.ts";
|
|
21
|
+
import { installCuratedSubmissionBindings } from "./pi/v1/codeReview/submit.ts";
|
|
22
|
+
import { installPrReviewTerminalBindings } from "./pi/v1/codeReview/terminal.ts";
|
|
23
|
+
import { installAddressBindings } from "./pi/v1/delivery/address.ts";
|
|
24
|
+
import { installCiBindings } from "./pi/v1/delivery/ci.ts";
|
|
25
|
+
import { installCommitCompactBindings } from "./pi/v1/delivery/commitCompact.ts";
|
|
26
|
+
import {
|
|
27
|
+
type ConflictResolverEngineOptions,
|
|
28
|
+
createConflictResolverEngine,
|
|
29
|
+
} from "./pi/v1/delivery/conflictResolverEngine.ts";
|
|
30
|
+
import { installLandBindings } from "./pi/v1/delivery/land.ts";
|
|
31
|
+
import { installReadyBindings } from "./pi/v1/delivery/ready.ts";
|
|
32
|
+
import { createStackConflictResolver } from "./pi/v1/delivery/stackConflictResolver.ts";
|
|
33
|
+
import { installStackLandBindings } from "./pi/v1/delivery/stackLand.ts";
|
|
34
|
+
import { installStackRecoverBindings } from "./pi/v1/delivery/stackRecover.ts";
|
|
35
|
+
import { installStackStatusBindings } from "./pi/v1/delivery/stackStatus.ts";
|
|
36
|
+
import {
|
|
37
|
+
installStackSyncBindings,
|
|
38
|
+
type StackResolutionDelivery,
|
|
39
|
+
} from "./pi/v1/delivery/stackSync.ts";
|
|
40
|
+
import { installSubmitBindings } from "./pi/v1/delivery/submit.ts";
|
|
41
|
+
import { installSubmitConflictBindings } from "./pi/v1/delivery/submitConflict.ts";
|
|
42
|
+
import { createDraftReviewSlot } from "./pi/v1/draftReview.ts";
|
|
43
|
+
import { registerDraftReviewWaveTools } from "./pi/v1/draftReviewWaveTools.ts";
|
|
44
|
+
import { installGistBindings } from "./pi/v1/gist.ts";
|
|
45
|
+
import { installAuditBindings } from "./pi/v1/learning/audit.ts";
|
|
46
|
+
import { installDreamBindings } from "./pi/v1/learning/dream.ts";
|
|
47
|
+
import { installLearnFactoryBindings } from "./pi/v1/learning/factory.ts";
|
|
48
|
+
import { installHarvestBindings } from "./pi/v1/learning/harvest.ts";
|
|
49
|
+
import { installLearnBindings } from "./pi/v1/learning/learn.ts";
|
|
50
|
+
import { registerLifecycleGates } from "./pi/v1/lifecycleGates.ts";
|
|
51
|
+
import { installObjectiveBindings } from "./pi/v1/objective.ts";
|
|
52
|
+
import { installObjectiveAuthoringBindings } from "./pi/v1/objectiveAuthoring.ts";
|
|
53
|
+
import { installObjectivePlanningBindings } from "./pi/v1/objectivePlanning.ts";
|
|
54
|
+
import {
|
|
55
|
+
importRefinementContextOnClaim,
|
|
56
|
+
installObjectiveRefinementBindings,
|
|
57
|
+
} from "./pi/v1/objectiveRefinement.ts";
|
|
24
58
|
import {
|
|
25
59
|
openObjectiveReviewSurface,
|
|
26
60
|
registerObjectiveReviewBrowser,
|
|
27
|
-
} from "./
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
import { registerImplementHere } from "./factories/implementHere.ts";
|
|
45
|
-
import { registerObjective } from "./factories/objective.ts";
|
|
46
|
-
import { registerObjectiveAuthor } from "./factories/objectiveAuthor.ts";
|
|
47
|
-
import { registerObjectiveDraft } from "./factories/objectiveDraft.ts";
|
|
48
|
-
import { registerObjectivePlan } from "./factories/objectivePlan.ts";
|
|
49
|
-
import { registerObjectiveSave } from "./factories/objectiveSave.ts";
|
|
50
|
-
import { registerPlanDraft } from "./factories/planDraft.ts";
|
|
51
|
-
import { registerPlanMode } from "./factories/planMode.ts";
|
|
52
|
-
import { registerPlanReview } from "./factories/planReview.ts";
|
|
53
|
-
import { registerPlanSave } from "./factories/planSave.ts";
|
|
54
|
-
import { createHunkFeedbackReceiver } from "./hunkFeedback/receiver.ts";
|
|
61
|
+
} from "./pi/v1/objectiveReviewBrowser.ts";
|
|
62
|
+
import { installPlanBindings } from "./pi/v1/plan.ts";
|
|
63
|
+
import { openPlanReviewSurface, registerPlanReviewBrowser } from "./pi/v1/planReviewBrowser.ts";
|
|
64
|
+
import { createAnnotationState, installAnnotationBindings } from "./pi/v1/providers/annotations.ts";
|
|
65
|
+
import { installPlannotatorPlanAdapter } from "./pi/v1/providers/plannotator.ts";
|
|
66
|
+
import { plannotatorPresent } from "./pi/v1/providers/plannotatorHandoff.ts";
|
|
67
|
+
import { installTombellPlanAdapter } from "./pi/v1/providers/tombell.ts";
|
|
68
|
+
import { installScoutWaveBindings } from "./pi/v1/scoutWave.ts";
|
|
69
|
+
import { registerSelfcheck } from "./pi/v1/selfcheck.ts";
|
|
70
|
+
import {
|
|
71
|
+
branchSessionStateStore,
|
|
72
|
+
establishSessionIdentity,
|
|
73
|
+
reflectSessionReadOnlyFloor,
|
|
74
|
+
resolveSessionStartFacts,
|
|
75
|
+
sessionStartToolScope,
|
|
76
|
+
sessionTreeFacts,
|
|
77
|
+
} from "./session/lifecycle.ts";
|
|
55
78
|
import { createAgentScratchProvisioner, registerAgentScratch } from "./substrate/agentScratch.ts";
|
|
56
79
|
import { registerBindingDelivery } from "./substrate/bindingDelivery.ts";
|
|
57
80
|
import {
|
|
58
81
|
atomicWriteFileSync,
|
|
59
82
|
ensureRunScratch,
|
|
83
|
+
listRunIds,
|
|
60
84
|
markHandoffConsumed,
|
|
61
85
|
readHandoff,
|
|
62
86
|
readPlanRef,
|
|
63
87
|
setMarker,
|
|
64
88
|
workflowDir,
|
|
65
89
|
} from "./substrate/cache.ts";
|
|
66
|
-
import {
|
|
90
|
+
import { decodeReadOnlyFloor, isRunnerChild } from "./substrate/childRestrictions.ts";
|
|
91
|
+
import { loadRegistry, type Registry } from "./substrate/registry.ts";
|
|
67
92
|
import { perkVersion, sharedDir, versionStamp } from "./substrate/resources.ts";
|
|
68
93
|
import { mintRunId } from "./substrate/runId.ts";
|
|
69
94
|
import { captureSessionPointer } from "./substrate/sessionPointers.ts";
|
|
70
95
|
import { registerToolGating } from "./substrate/toolGating.ts";
|
|
71
96
|
import {
|
|
72
|
-
appendWorkflowState,
|
|
73
97
|
branchOf,
|
|
74
|
-
decideClaim,
|
|
75
|
-
planRefsEqual,
|
|
76
98
|
rebuildWorkflowState,
|
|
77
|
-
resolveRunStage,
|
|
78
99
|
WORKFLOW_STATE_TYPE,
|
|
79
100
|
type WorkflowState,
|
|
80
101
|
} from "./substrate/workflowState.ts";
|
|
@@ -91,6 +112,7 @@ import {
|
|
|
91
112
|
} from "./surfaces/surfaces.ts";
|
|
92
113
|
import { registerBtw } from "./vendor/btw/btw.ts";
|
|
93
114
|
import { registerWhimsical } from "./vendor/whimsical/whimsical.ts";
|
|
115
|
+
import { createReportWave } from "./waves/reportWave.ts";
|
|
94
116
|
|
|
95
117
|
// Cross-plane proof marker (TS writes via cache.ts; the Python helper reads it — gate check 3).
|
|
96
118
|
const T3_MARKER = "t3-extension-cache-write";
|
|
@@ -124,18 +146,43 @@ function writeT3Sentinel(
|
|
|
124
146
|
}
|
|
125
147
|
}
|
|
126
148
|
|
|
127
|
-
export default function (
|
|
149
|
+
export default function perk(
|
|
150
|
+
pi: ExtensionAPI,
|
|
151
|
+
options: {
|
|
152
|
+
resolverEngine?: Pick<ConflictResolverEngineOptions, "configPath" | "acquire">;
|
|
153
|
+
stackResolutionDelivery?: StackResolutionDelivery;
|
|
154
|
+
/**
|
|
155
|
+
* Construction-only: the hunk feedback receiver factory (default `createHunkFeedbackReceiver`).
|
|
156
|
+
* Constructed ONCE per activation exactly like production; the registered-path suites bind a
|
|
157
|
+
* recording receiver to observe the startup/navigation sync order and inputs.
|
|
158
|
+
*/
|
|
159
|
+
feedbackReceiverFactory?: (pi: ExtensionAPI) => HunkFeedbackReceiver;
|
|
160
|
+
} = {},
|
|
161
|
+
) {
|
|
128
162
|
const version = perkVersion();
|
|
129
163
|
|
|
130
164
|
// The read-only tool-gating primitive. Attaches to perk:workflow-state.mode; synced on
|
|
131
165
|
// both session_start AND session_tree below. enter/exit are the surface the gated stages consume.
|
|
132
|
-
|
|
166
|
+
// The two native-child booleans (§8.3), re-read at every session_start: the runner bit (also the
|
|
167
|
+
// `() => runnerChild` closure every injected authoring/adapter context takes as its fence — the
|
|
168
|
+
// REAL closure, never a constant), and the read-only floor a runner child derives from the
|
|
169
|
+
// report restriction packet — latched for the activation (`||=`) so no later session_start,
|
|
170
|
+
// gate exit, or tree navigation can clear it.
|
|
171
|
+
let runnerChild = false;
|
|
172
|
+
let readOnlyFloor = false;
|
|
173
|
+
const gating = registerToolGating(pi, () => readOnlyFloor);
|
|
174
|
+
|
|
175
|
+
// The bash scan-timeout guard: always on in every perk session — gated or not, runner children
|
|
176
|
+
// included (the slow gitignore-blind scans were observed in read-write sessions too). The gate's
|
|
177
|
+
// `tool_call` hook runs first only because it registers first; a gate block short-circuits
|
|
178
|
+
// before injection matters.
|
|
179
|
+
registerBashScanTimeout(pi);
|
|
133
180
|
|
|
134
181
|
// Run-owned disposable scratch guidance for every eligible write-capable model turn. One
|
|
135
182
|
// activation-scoped provisioner shares retry/warning suppression with the isolated /btw side
|
|
136
183
|
// session; no model tool or process-global temp environment is introduced.
|
|
137
184
|
const agentScratch = createAgentScratchProvisioner();
|
|
138
|
-
registerAgentScratch(pi, agentScratch);
|
|
185
|
+
registerAgentScratch(pi, agentScratch, () => !gating.isActive() && !runnerChild);
|
|
139
186
|
|
|
140
187
|
// Vendored `btw`: a `/btw` human-only side-chat popover backed by an isolated in-memory
|
|
141
188
|
// AgentSession. Takes `gating` for the gate-mirror — its side-session toolset + cache key follow
|
|
@@ -148,46 +195,123 @@ export default function (pi: ExtensionAPI) {
|
|
|
148
195
|
// turn, via the headless-no-op `setWorkingMessage` surfaces seam. Always on, no config toggle.
|
|
149
196
|
registerWhimsical(pi);
|
|
150
197
|
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
|
|
198
|
+
// The draft-review pair's per-activation state: ONE instance serves the `plan_review` wave
|
|
199
|
+
// arm (via the closures below), the two draft-review browser doors, and the
|
|
200
|
+
// `start_draft_review_wave`/`collect_draft_review_wave` tool pair — per activation, never per
|
|
201
|
+
// process (two bound sessions in one process share nothing). Plain object construction, so
|
|
202
|
+
// creating it before any registration is order-safe.
|
|
203
|
+
const draftReviewWave = createDraftReviewWaveState();
|
|
204
|
+
|
|
205
|
+
// The annotation-push per-activation state: ONE instance serves the `push_annotations`
|
|
206
|
+
// installer and every priming door — the PR/stack review doors (review mode) and the
|
|
207
|
+
// plan/objective review doors (plan mode) — per activation, never per process (the
|
|
208
|
+
// `draftReviewWave` threading pattern).
|
|
209
|
+
const annotations = createAnnotationState();
|
|
210
|
+
|
|
211
|
+
// The composition root's ONE per-activation report-wave instance (the `draftReviewWave`
|
|
212
|
+
// threading pattern): the wave owns adapter selection (a fresh rpc adapter per launch over
|
|
213
|
+
// pi's event bus) and pending execution (instance-owned refs), and is threaded into every
|
|
214
|
+
// wave-consuming installer — no installer touches the transport tier. Plain construction, no
|
|
215
|
+
// Pi registration, order-safe.
|
|
216
|
+
const reportWave = createReportWave(pi.events);
|
|
217
|
+
|
|
218
|
+
const conflictResolver = createConflictResolverEngine({
|
|
219
|
+
events: pi.events,
|
|
220
|
+
enginePresent: () => pi.getAllTools().some((tool) => tool.name === "subagent"),
|
|
221
|
+
readOnly: () => gating.isActive(),
|
|
222
|
+
authorized: (request) =>
|
|
223
|
+
request.mode === "pr-rebase"
|
|
224
|
+
? submitConflict.authorized(request)
|
|
225
|
+
: stackConflict.authorized(request),
|
|
226
|
+
...options.resolverEngine,
|
|
227
|
+
});
|
|
228
|
+
const submitConflict = installSubmitConflictBindings(pi, conflictResolver, () =>
|
|
229
|
+
gating.isActive(),
|
|
230
|
+
);
|
|
231
|
+
const stackConflict = createStackConflictResolver(conflictResolver, () => gating.isActive());
|
|
232
|
+
|
|
233
|
+
// The v1 plan installer: perk-owned plan mode (the `/plan` + Ctrl+Alt+P + `--plan` toggle
|
|
234
|
+
// surface over the read-only gate, plus the plan-authoring context injection — this call
|
|
235
|
+
// sits at the frozen hooks-ordering slot the mode surface always held), the
|
|
236
|
+
// `plan_draft`/`plan_save` tools, the `/plan-save` + `/implement-here` commands, and
|
|
237
|
+
// `plan_review` — perk's UNIVERSAL review door (plannotator-selected → the event-bus bridge;
|
|
238
|
+
// ANY other selection → the first-party in-TUI editor review). Takes `gating` to toggle plan
|
|
239
|
+
// mode and to COMPOSE the approval→save seam (auto-save → D1a gate exit) — Invariant 1 holds:
|
|
240
|
+
// the surfaces compose the gate through the seams, never own it. The injected wave-launch
|
|
241
|
+
// deps power the plannotator launch chooser (§8.23): the presence probe + the two door open
|
|
242
|
+
// cores are composed HERE so plan.ts/planReview.ts import nothing from the browser modules
|
|
243
|
+
// (planReviewBrowser.ts/objectiveReviewBrowser.ts — the value-import cycle break:
|
|
244
|
+
// planReviewBrowser.ts value-imports the review arms). `draftReviews` is the ONE
|
|
245
|
+
// per-activation current-review slot + unconfirmed-save latch every review surface shares
|
|
246
|
+
// (§8.23 "Draft-review guards") — in-memory, nothing persisted.
|
|
247
|
+
const draftReviews = createDraftReviewSlot(pi);
|
|
248
|
+
|
|
249
|
+
// The composed `perk` status handle (charter D2): one slot carrying the objective segment +
|
|
250
|
+
// the ref-counted browser-wait activity. Created once here (no hidden module state) and
|
|
251
|
+
// threaded into the objective publisher, the plan installer (the warm plannotator arm) and
|
|
252
|
+
// the browser doors; the footer reads it back via get/subscribe.
|
|
253
|
+
const perkStatus = createPerkStatus();
|
|
254
|
+
|
|
255
|
+
installPlanBindings(pi, gating, draftReviews, () => runnerChild, perkStatus, {
|
|
256
|
+
present: () => plannotatorPresent(pi),
|
|
257
|
+
plan: (ctx, opts) =>
|
|
258
|
+
openPlanReviewSurface(
|
|
259
|
+
pi,
|
|
260
|
+
ctx,
|
|
261
|
+
gating,
|
|
262
|
+
opts,
|
|
263
|
+
draftReviewWave,
|
|
264
|
+
annotations,
|
|
265
|
+
draftReviews,
|
|
266
|
+
perkStatus,
|
|
267
|
+
),
|
|
268
|
+
objective: (ctx, opts) =>
|
|
269
|
+
openObjectiveReviewSurface(
|
|
270
|
+
pi,
|
|
271
|
+
ctx,
|
|
272
|
+
gating,
|
|
273
|
+
opts,
|
|
274
|
+
draftReviewWave,
|
|
275
|
+
annotations,
|
|
276
|
+
draftReviews,
|
|
277
|
+
perkStatus,
|
|
278
|
+
),
|
|
279
|
+
});
|
|
155
280
|
|
|
156
281
|
// The first 3rd-party plan adapter: a perk-owned, injection-only bridge that re-enables
|
|
157
282
|
// `@tombell/pi-plan` as a real plan provider. Always registered, but INERT unless
|
|
158
283
|
// `[providers] plan = "tombell-plan"`; it directs the foreign free-form prose `/plan` surface into
|
|
159
284
|
// perk's canonical `plan_save` → `cache.plan-ref` contract. It needs no `gating` (Invariant 1: the
|
|
160
285
|
// read-only gate stays perk's, engaged by the cold-door launch — the shim never arbitrates tools).
|
|
161
|
-
|
|
286
|
+
installTombellPlanAdapter(pi, () => runnerChild);
|
|
162
287
|
|
|
163
288
|
// The second 3rd-party plan adapter — AUGMENT posture: `@plannotator/pi-extension` contributes
|
|
164
|
-
// its browser plan-review UI while perk's plan surface + gate stay (
|
|
165
|
-
// `--plan`/`Ctrl+Alt+P` under this selection). Always registered, but INERT unless
|
|
166
|
-
// `[providers] plan = "plannotator-plan"`. Injection-only — the `plan_review`
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
registerGistAuthor(pi, gating);
|
|
289
|
+
// its browser plan-review UI while perk's plan surface + gate stay (the plan installer skips
|
|
290
|
+
// only `--plan`/`Ctrl+Alt+P` under this selection). Always registered, but INERT unless
|
|
291
|
+
// `[providers] plan = "plannotator-plan"`. Injection-only — the `plan_review` tool lives in
|
|
292
|
+
// the plan installer (above), which dispatches to this adapter's event-bus bridge when
|
|
293
|
+
// plannotator is selected.
|
|
294
|
+
installPlannotatorPlanAdapter(pi, () => runnerChild);
|
|
295
|
+
|
|
296
|
+
// The v1 objective-authoring installer: the objective-author context hook pair (this call
|
|
297
|
+
// sits at the frozen hooks-ordering slot the injection always held — keyed off (read-only
|
|
298
|
+
// gate AND stage === objective-author); planMode defers to it), plus the
|
|
299
|
+
// `objective_draft`/`objective_save` tools and the `/objective-save` command (registration is
|
|
300
|
+
// name-keyed — only the hooks ordering is frozen).
|
|
301
|
+
installObjectiveAuthoringBindings(pi, gating, draftReviews, () => runnerChild);
|
|
302
|
+
|
|
303
|
+
// The v1 gist installer: the gist-authoring context hook pair (this call sits at the frozen
|
|
304
|
+
// hooks-ordering slot the injection always held; planMode defers to it too), plus the
|
|
305
|
+
// `gist_draft`/`gist_save` tools and the `/gist-save` command (registration is name-keyed —
|
|
306
|
+
// only the hooks ordering is frozen).
|
|
307
|
+
installGistBindings(pi, gating, draftReviews, () => runnerChild);
|
|
308
|
+
|
|
309
|
+
// The v1 objective-refinement installer (contracts.md §8.67/§8.68): the refinement context hook
|
|
310
|
+
// pair (keyed off (read-only gate AND stage === objective-refine); plan mode and the provider
|
|
311
|
+
// adapters defer to it), the ONE model-facing `objective_refinement_draft` tool, the warm
|
|
312
|
+
// `/objective-refine` entry and the human `/objective-refinement-save` failsafe. Registered
|
|
313
|
+
// before the tool snapshots.
|
|
314
|
+
installObjectiveRefinementBindings(pi, gating, draftReviews, () => runnerChild);
|
|
191
315
|
let sharedOk = false;
|
|
192
316
|
try {
|
|
193
317
|
sharedDir();
|
|
@@ -207,11 +331,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
207
331
|
}
|
|
208
332
|
const registryOk = registryStages > 0;
|
|
209
333
|
|
|
210
|
-
// The single-value `perk` status handle (charter D2): one slot carrying the objective
|
|
211
|
-
// segment. Created once here (no hidden module state) and threaded into the objective
|
|
212
|
-
// publisher below; the footer reads it back via get/subscribe.
|
|
213
|
-
const perkStatus = createPerkStatus();
|
|
214
|
-
|
|
215
334
|
// The generic full report-detail entry and the `perk:workflow-state` transition marker. Renderer
|
|
216
335
|
// bodies live in surfaces.ts; registration is wiring through the pre-0.80.4-safe seam. The report
|
|
217
336
|
// family is appended by command-attached sinks; one workflow registration covers every appender.
|
|
@@ -222,13 +341,23 @@ export default function (pi: ExtensionAPI) {
|
|
|
222
341
|
// globals). Synced from session_start/session_tree below; closed on session_shutdown so the
|
|
223
342
|
// consumer lease releases with the session. A stale /reload predecessor instance is retired
|
|
224
343
|
// by the lease fencing (fresh token per same-identity reacquire + verify-before-inject).
|
|
225
|
-
const feedbackReceiver = createHunkFeedbackReceiver(pi);
|
|
226
|
-
pi.on("session_shutdown", async () => {
|
|
344
|
+
const feedbackReceiver = (options.feedbackReceiverFactory ?? createHunkFeedbackReceiver)(pi);
|
|
345
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
346
|
+
submitConflict.shutdown();
|
|
347
|
+
stackConflict.shutdown();
|
|
348
|
+
await conflictResolver.shutdown();
|
|
227
349
|
feedbackReceiver.close();
|
|
350
|
+
// A browser-wait activity cannot outlive the session.
|
|
351
|
+
perkStatus.clearActivity(ctx);
|
|
228
352
|
});
|
|
229
353
|
|
|
230
354
|
pi.on("session_start", async (_event, ctx) => {
|
|
231
|
-
|
|
355
|
+
// Read the two native-child booleans and latch the floor before lifecycle work or tool rebuilds.
|
|
356
|
+
runnerChild = isRunnerChild(process.env);
|
|
357
|
+
readOnlyFloor ||= decodeReadOnlyFloor(runnerChild, process.env.PI_SUBAGENT_EXTENSION_BINDINGS);
|
|
358
|
+
|
|
359
|
+
submitConflict.setContext(ctx);
|
|
360
|
+
stackConflict.setContext(ctx);
|
|
232
361
|
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
233
362
|
const currentSessionId = sessionFile ? basename(sessionFile) : null;
|
|
234
363
|
|
|
@@ -238,225 +367,108 @@ export default function (pi: ExtensionAPI) {
|
|
|
238
367
|
report(ctx, "workflow-state linkage error", "error", message, { alsoLog: true });
|
|
239
368
|
};
|
|
240
369
|
|
|
241
|
-
|
|
242
|
-
state: rebuildWorkflowState(branchEntries()),
|
|
243
|
-
currentSessionId,
|
|
244
|
-
envRunId: process.env.PERK_RUN_ID ?? null,
|
|
245
|
-
cwd: ctx.cwd,
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
// The session-audit exact-vintage stamp (§8.3), recorded by every run-identity arm below
|
|
370
|
+
// The session-audit exact-vintage stamp (§8.3), recorded by every run-identity arm
|
|
249
371
|
// (claim/fork/adopt/mint); undefined on the perkVersion() failure sentinel, which drops the
|
|
250
372
|
// key on serialize and leaves the session on the timestamp-estimate arm.
|
|
251
373
|
const stamp = versionStamp(version);
|
|
252
374
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const data: WorkflowState = {
|
|
280
|
-
run_id: decision.runId,
|
|
281
|
-
pi_session_id: currentSessionId ?? undefined,
|
|
282
|
-
mode: handoff.mode,
|
|
283
|
-
perk_version: stamp,
|
|
284
|
-
// Record the launched stage so the interior can tell e.g. objective-author from plan
|
|
285
|
-
// (both are read-only) and inject the right authoring context (planMode vs objectiveAuthor).
|
|
286
|
-
stage: handoff.stage,
|
|
287
|
-
...(nodeClaim !== undefined ? { objective_node_claim: nodeClaim } : {}),
|
|
288
|
-
};
|
|
289
|
-
const okAppend = appendWorkflowState(pi, ctx, {
|
|
290
|
-
data,
|
|
291
|
-
field: "run_id",
|
|
292
|
-
expected: decision.runId,
|
|
293
|
-
scope: "workflow-state linkage error",
|
|
294
|
-
failure: `read-back failed for run ${decision.runId}`,
|
|
295
|
-
});
|
|
296
|
-
if (!okAppend) {
|
|
297
|
-
// do NOT consume
|
|
298
|
-
} else {
|
|
299
|
-
markHandoffConsumed(ctx.cwd, decision.runId, {
|
|
300
|
-
piSessionId: currentSessionId ?? undefined,
|
|
301
|
-
});
|
|
302
|
-
resolved = data;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
} else if (decision.action === "fork") {
|
|
306
|
-
// Inherited a run_id from a different session file → isolate the child's scratch. A static
|
|
307
|
-
// redirect or filesystem failure is loud but does not prevent the derived workflow identity
|
|
308
|
-
// from settling; later eligible turns retry through the agent-scratch resolver.
|
|
309
|
-
try {
|
|
310
|
-
ensureRunScratch(ctx.cwd, decision.childRunId);
|
|
311
|
-
} catch (error) {
|
|
312
|
-
report(
|
|
313
|
-
ctx,
|
|
314
|
-
"run scratch",
|
|
315
|
-
"warning",
|
|
316
|
-
`could not create fork run root for ${decision.childRunId}: ${String(error)}`,
|
|
317
|
-
{ alsoLog: true },
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
const data: WorkflowState = {
|
|
321
|
-
run_id: decision.childRunId,
|
|
322
|
-
pi_session_id: currentSessionId ?? undefined,
|
|
323
|
-
predecessor: decision.parentRunId,
|
|
324
|
-
mode: decision.state.mode,
|
|
325
|
-
perk_version: stamp,
|
|
326
|
-
};
|
|
327
|
-
pi.appendEntry(WORKFLOW_STATE_TYPE, data);
|
|
328
|
-
resolved = data;
|
|
329
|
-
} else if (decision.action === "adopt") {
|
|
330
|
-
// An env-inherited run id whose handoff was already consumed by a different session: a
|
|
331
|
-
// spawned child (contracts §8.2). Mirror the fork arm — derived child identity, isolated
|
|
332
|
-
// scratch, inherited mode (read-only gating survives) — minus everything that belongs to
|
|
333
|
-
// the launched session: never re-consume the handoff (its pi_session_id keeps the true
|
|
334
|
-
// claimer), no `stage` (no stage impersonation / stage-binding injection), and no
|
|
335
|
-
// implementation/main pointer capture (resolveRunStage stays null for adopt).
|
|
336
|
-
try {
|
|
337
|
-
ensureRunScratch(ctx.cwd, decision.childRunId);
|
|
338
|
-
} catch (error) {
|
|
375
|
+
// The identity lifecycle (claim / fork / adopt / mint / keep) is the named session
|
|
376
|
+
// operation (session/lifecycle.ts owns the arms); this handler binds the production ports
|
|
377
|
+
// and renders the outcome's per-arm problems/warnings with the exact report scopes the
|
|
378
|
+
// arms always used. The strict appends keep reporting read-back failures through the
|
|
379
|
+
// strict-append seam's own loudness channel. The same cwd-bound handoff reader serves the
|
|
380
|
+
// post-gate facts below (ONE handoff authority).
|
|
381
|
+
const identityPorts = {
|
|
382
|
+
readHandoff: (runId: string) => readHandoff(ctx.cwd, runId),
|
|
383
|
+
listRunIds: () => listRunIds(ctx.cwd),
|
|
384
|
+
markHandoffConsumed: (runId: string, opts: { piSessionId?: string }) =>
|
|
385
|
+
markHandoffConsumed(ctx.cwd, runId, opts),
|
|
386
|
+
ensureRunScratch: (runId: string) => {
|
|
387
|
+
ensureRunScratch(ctx.cwd, runId);
|
|
388
|
+
},
|
|
389
|
+
mintRunId,
|
|
390
|
+
versionStamp: stamp,
|
|
391
|
+
};
|
|
392
|
+
const stateStore = branchSessionStateStore(pi, ctx);
|
|
393
|
+
let identity = establishSessionIdentity(stateStore, identityPorts, {
|
|
394
|
+
currentSessionId,
|
|
395
|
+
envRunId: process.env.PERK_RUN_ID ?? null,
|
|
396
|
+
});
|
|
397
|
+
if (readOnlyFloor) {
|
|
398
|
+
const reflected = reflectSessionReadOnlyFloor(stateStore, identity);
|
|
399
|
+
identity = reflected.outcome;
|
|
400
|
+
if (reflected.unexpectedFailure) {
|
|
339
401
|
report(
|
|
340
402
|
ctx,
|
|
341
|
-
"
|
|
342
|
-
"
|
|
343
|
-
|
|
403
|
+
"child restriction",
|
|
404
|
+
"error",
|
|
405
|
+
"could not persist child read-only restriction; in-memory restriction remains active",
|
|
344
406
|
{ alsoLog: true },
|
|
345
407
|
);
|
|
346
408
|
}
|
|
347
|
-
const data: WorkflowState = {
|
|
348
|
-
run_id: decision.childRunId,
|
|
349
|
-
pi_session_id: currentSessionId ?? undefined,
|
|
350
|
-
predecessor: decision.parentRunId,
|
|
351
|
-
mode: decision.mode,
|
|
352
|
-
perk_version: stamp,
|
|
353
|
-
};
|
|
354
|
-
pi.appendEntry(WORKFLOW_STATE_TYPE, data);
|
|
355
|
-
resolved = data;
|
|
356
|
-
} else if (decision.action === "none") {
|
|
357
|
-
// A warm session with no identity mints its own run_id so
|
|
358
|
-
// per-run state (the session data dir) can key off it. No disk artifacts —
|
|
359
|
-
// dirs are the accessor's job; provenance is recorded separately. A failed cold claim above never
|
|
360
|
-
// falls here (claim stays a loud unclaimed error).
|
|
361
|
-
const runId = mintRunId();
|
|
362
|
-
const data: WorkflowState = {
|
|
363
|
-
run_id: runId,
|
|
364
|
-
pi_session_id: currentSessionId ?? undefined,
|
|
365
|
-
perk_version: stamp,
|
|
366
|
-
};
|
|
367
|
-
const okAppend = appendWorkflowState(pi, ctx, {
|
|
368
|
-
data,
|
|
369
|
-
field: "run_id",
|
|
370
|
-
expected: runId,
|
|
371
|
-
scope: "workflow-state linkage error",
|
|
372
|
-
failure: `read-back failed for minted run ${runId}`,
|
|
373
|
-
});
|
|
374
|
-
if (okAppend) {
|
|
375
|
-
resolved = { ...decision.state, ...data };
|
|
376
|
-
minted = true;
|
|
377
|
-
}
|
|
378
409
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
//
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
// Fail-closed on the gate: if the sync throws, leave it as-is (a failed sync
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
? undefined
|
|
394
|
-
: (resolved.stage ?? (decision.action === "fork" ? decision.state.stage : undefined));
|
|
410
|
+
for (const problem of identity.problems) reportError(problem);
|
|
411
|
+
for (const warning of identity.warnings) {
|
|
412
|
+
report(ctx, "run scratch", "warning", warning, { alsoLog: true });
|
|
413
|
+
}
|
|
414
|
+
const decision = identity.decision;
|
|
415
|
+
const minted = identity.arm === "minted";
|
|
416
|
+
|
|
417
|
+
// PHASE 1 — reapply the read-only allowlist + stage scoping from the established identity
|
|
418
|
+
// FIRST, before the fallible post-gate facts below. The scope derivation is pure (no store,
|
|
419
|
+
// handoff, registry, or checkout read), so no read failure can leave the gate unsynced
|
|
420
|
+
// (defense in depth on top of the total cache readers); `resolved.mode` is final once the
|
|
421
|
+
// arms settle. Fail-closed on the gate: if the sync throws, leave it as-is (a failed sync
|
|
422
|
+
// never opens it).
|
|
423
|
+
const toolScope = sessionStartToolScope(identity);
|
|
395
424
|
try {
|
|
396
|
-
gating.syncFromState(
|
|
425
|
+
gating.syncFromState(toolScope.mode, toolScope.stage);
|
|
397
426
|
} catch (error) {
|
|
398
427
|
console.error(`perk: tool-gating sync failed on session_start — ${error}`);
|
|
399
428
|
}
|
|
400
429
|
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
// (
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const runStage = resolveRunStage(decision, ctx.cwd);
|
|
411
|
-
// Registry-missing is permissive when a stage is present, to preserve implement linkage.
|
|
412
|
-
const consumesPlanRef =
|
|
413
|
-
runStage !== null && (registry === null || stageConsumesPlanRef(registry, runStage));
|
|
414
|
-
if (consumesPlanRef) {
|
|
415
|
-
const cachedRef = readPlanRef(ctx.cwd);
|
|
416
|
-
if (cachedRef !== null) {
|
|
417
|
-
if (planRefsEqual(linked, cachedRef)) {
|
|
418
|
-
resolved = { ...resolved, active_plan_ref: linked };
|
|
419
|
-
} else {
|
|
420
|
-
if (
|
|
421
|
-
appendWorkflowState(pi, ctx, {
|
|
422
|
-
data: { active_plan_ref: cachedRef },
|
|
423
|
-
field: "active_plan_ref",
|
|
424
|
-
expected: cachedRef,
|
|
425
|
-
scope: "workflow-state linkage error",
|
|
426
|
-
failure: `plan-ref read-back failed for ${cachedRef.provider}:${cachedRef.pr_id}`,
|
|
427
|
-
equals: planRefsEqual,
|
|
428
|
-
})
|
|
429
|
-
) {
|
|
430
|
-
resolved = { ...resolved, active_plan_ref: cachedRef };
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
} else if (linked !== null) {
|
|
434
|
-
resolved = { ...resolved, active_plan_ref: linked };
|
|
435
|
-
}
|
|
436
|
-
} else if (linked !== null) {
|
|
437
|
-
// Non-consuming stage (or no launched stage): preserve any already-linked ref via LWW,
|
|
438
|
-
// but NEVER read the cache file — the root selector must not leak in.
|
|
439
|
-
resolved = { ...resolved, active_plan_ref: linked };
|
|
430
|
+
// The refinement cold claim's ONE-TIME context import (contracts.md §8.67): only on the
|
|
431
|
+
// actual cold claim of an `objective-refine` handoff (never keep/fork/adopt/mint), after the
|
|
432
|
+
// identity settled and the gate synced. A refusal is loud and leaves the session gated
|
|
433
|
+
// without a usable context (no orphan repair, no reimport on reload).
|
|
434
|
+
if (identity.arm === "claimed" && typeof identity.resolved.run_id === "string") {
|
|
435
|
+
importRefinementContextOnClaim(pi, ctx, {
|
|
436
|
+
runId: identity.resolved.run_id,
|
|
437
|
+
stage: identity.resolved.stage,
|
|
438
|
+
});
|
|
440
439
|
}
|
|
441
440
|
|
|
441
|
+
// PHASE 2 — the post-gate facts (session/lifecycle.ts owns the decision tree): the lazy,
|
|
442
|
+
// stage-gated `cache.plan-ref` → `active_plan_ref` reconciliation (only a launched stage
|
|
443
|
+
// that *consumes* the ref reads the checkout; claim/keep read the handoff, fork/adopt/none
|
|
444
|
+
// never do; one strict verified append, idempotent by (provider, pr_id)), plus the derived
|
|
445
|
+
// implementation-capture and receiver inputs. Called HERE — after the gate and the
|
|
446
|
+
// refinement import — never while constructing gate inputs. A throwing branch/handoff read
|
|
447
|
+
// propagates to Pi's hook error boundary with the gate already synced: unreadability is
|
|
448
|
+
// never turned into confirmed absence, and no later effect runs from guessed facts.
|
|
449
|
+
const facts = resolveSessionStartFacts(
|
|
450
|
+
stateStore,
|
|
451
|
+
{ readHandoff: identityPorts.readHandoff, readPlanRef: () => readPlanRef(ctx.cwd) },
|
|
452
|
+
{ identity, registry, currentSessionId },
|
|
453
|
+
);
|
|
454
|
+
const resolved: WorkflowState = facts.resolved;
|
|
455
|
+
|
|
442
456
|
// Implementation session pointer (contracts.md §8.35): an implement session self-keys its own
|
|
443
457
|
// session file into the shared main checkout so a later/other session resolves it cross-run.
|
|
444
|
-
// The headless worker's inner session lands here too (.main);
|
|
458
|
+
// The headless worker's inner session lands here too (.main); runStage records the matching
|
|
445
459
|
// .worker. A forked implement session inherits the parent's launched stage + threads the
|
|
446
460
|
// inherited parent session id as fork provenance. Best-effort + non-fatal (carrier warns).
|
|
447
461
|
// First-write-wins (`preserveForeign`): this is the corroborated shadowing defect site — the
|
|
448
462
|
// claimer's original capture stays authoritative, and any future shadow vector warns loudly
|
|
449
463
|
// instead of silently corrupting /learn evidence.
|
|
450
|
-
|
|
451
|
-
runStage ?? (decision.action === "fork" ? (decision.state.stage ?? null) : null);
|
|
452
|
-
if (resolved.run_id && implStage === "implement") {
|
|
464
|
+
if (facts.implementationCapture !== null) {
|
|
453
465
|
captureSessionPointer({
|
|
454
466
|
cwd: ctx.cwd,
|
|
455
|
-
runId:
|
|
467
|
+
runId: facts.implementationCapture.runId,
|
|
456
468
|
klass: "implementation",
|
|
457
469
|
site: "main",
|
|
458
470
|
sessionFile,
|
|
459
|
-
parentSessionId:
|
|
471
|
+
parentSessionId: facts.implementationCapture.parentSessionId,
|
|
460
472
|
preserveForeign: true,
|
|
461
473
|
});
|
|
462
474
|
}
|
|
@@ -466,14 +478,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
466
478
|
// outbox. Eligibility (interactive TUI + implement stage + non-adopted + settled identity +
|
|
467
479
|
// plan-ref match against one fresh cache read) is evaluated inside sync; every ineligible
|
|
468
480
|
// shape closes any open inbox. Never throws (the controller contains its own failures).
|
|
469
|
-
feedbackReceiver.sync(ctx, {
|
|
470
|
-
stage: implStage,
|
|
471
|
-
adopted: decision.action === "adopt",
|
|
472
|
-
runId: resolved.run_id ?? null,
|
|
473
|
-
piSessionId: currentSessionId,
|
|
474
|
-
activePlanRef: resolved.active_plan_ref ?? null,
|
|
475
|
-
mode: ctx.mode ?? null,
|
|
476
|
-
});
|
|
481
|
+
feedbackReceiver.sync(ctx, { ...facts.feedback, mode: ctx.mode ?? null });
|
|
477
482
|
|
|
478
483
|
// Soft version-parity drift signal: pi can lazy-install / load a stale `npm:@mgiles/perk`, so the
|
|
479
484
|
// extension actually running may differ from the `perk` CLI that launched it. The local launch
|
|
@@ -538,173 +543,153 @@ export default function (pi: ExtensionAPI) {
|
|
|
538
543
|
|
|
539
544
|
// Non-negotiable: rebuild on branch navigation too, or state goes stale after /tree (§8.3).
|
|
540
545
|
pi.on("session_tree", async (_event, ctx) => {
|
|
546
|
+
stackConflict.setContext(ctx);
|
|
547
|
+
// ONE fresh full-branch rebuild; the navigation facts derive purely from it (no handoff/
|
|
548
|
+
// checkout read, claim, linkage, or capture on navigation — session/lifecycle.ts owns the
|
|
549
|
+
// asymmetry with startup).
|
|
541
550
|
const state = rebuildWorkflowState(branchOf(ctx));
|
|
551
|
+
const facts = sessionTreeFacts(state);
|
|
542
552
|
// Non-negotiable: re-sync the gate + stage scoping on tree navigation too (mode and stage are
|
|
543
553
|
// per-field LWW — the branch-rebuilt stage is the §8.40 key). Fail-closed on the gate.
|
|
544
554
|
try {
|
|
545
|
-
gating.syncFromState(
|
|
555
|
+
gating.syncFromState(facts.toolScope.mode, facts.toolScope.stage);
|
|
546
556
|
} catch (error) {
|
|
547
557
|
console.error(`perk: tool-gating sync failed on session_tree — ${error}`);
|
|
548
558
|
}
|
|
549
|
-
// Re-sync the feedback receiver from the LWW-rebuilt state (§8.58)
|
|
550
|
-
// right here: an env-adopted child's fresh branch carries no
|
|
551
|
-
// alone keeps it inert on tree navigation.
|
|
552
|
-
feedbackReceiver.sync(ctx, {
|
|
553
|
-
stage: state.stage ?? null,
|
|
554
|
-
adopted: false,
|
|
555
|
-
runId: state.run_id ?? null,
|
|
556
|
-
piSessionId: state.pi_session_id ?? null,
|
|
557
|
-
activePlanRef: state.active_plan_ref ?? null,
|
|
558
|
-
mode: ctx.mode ?? null,
|
|
559
|
-
});
|
|
559
|
+
// Re-sync the feedback receiver from the LWW-rebuilt state (§8.58) — gate first, then
|
|
560
|
+
// receiver; `adopted: false` is right here: an env-adopted child's fresh branch carries no
|
|
561
|
+
// stage, so the stage gate alone keeps it inert on tree navigation.
|
|
562
|
+
feedbackReceiver.sync(ctx, { ...facts.feedback, mode: ctx.mode ?? null });
|
|
560
563
|
if (process.env.PERK_SELFCHECK) {
|
|
561
564
|
writeT3Sentinel(ctx.cwd, "tree", state, ctx.mode ?? null);
|
|
562
565
|
}
|
|
563
566
|
});
|
|
564
567
|
|
|
565
|
-
// Warm door: the `plan_save` tool + `/plan-save` command. Takes `gating`:
|
|
566
|
-
// a successful command-path save exits read-only mode (the read-only → read-write boundary).
|
|
567
|
-
registerPlanSave(pi, gating);
|
|
568
|
-
|
|
569
|
-
// The `/implement-here` command: the human-only no-save exit from plan mode (§8.23) —
|
|
570
|
-
// implement the reviewed draft in-session, no issue created. Composes the gate through the
|
|
571
|
-
// implementHereExit seam; no model tool is registered (machine-unreachable by construction).
|
|
572
|
-
registerImplementHere(pi, gating);
|
|
573
|
-
|
|
574
|
-
// The `plan_draft` working-draft file tool. Registered in the factory so it
|
|
575
|
-
// exists before the gate snapshots tools; its name is in READ_ONLY_TOOLS (the structural
|
|
576
|
-
// session-data carve-out), so it survives plan mode.
|
|
577
|
-
registerPlanDraft(pi);
|
|
578
|
-
|
|
579
|
-
// The `objective_draft` working-objective file tool (the plan_draft twin).
|
|
580
|
-
registerObjectiveDraft(pi);
|
|
581
|
-
|
|
582
|
-
// The `gist_draft` working-gist file tool (the third draft carve-out).
|
|
583
|
-
registerGistDraft(pi);
|
|
584
|
-
|
|
585
568
|
// Lifecycle gates: the dirty-repo switch/fork guard + the guard-only `/implement`.
|
|
586
569
|
registerLifecycleGates(pi);
|
|
587
570
|
|
|
588
571
|
// Warm door: the `submit` tool + `/submit` command.
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
// The warm
|
|
592
|
-
// Takes `gating`: the warm ready→reconcile continuation refuses (loudly) to drive
|
|
593
|
-
// ready-time pass into a read-only session (contracts.md §8.66).
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
// Warm
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
//
|
|
602
|
-
// `
|
|
603
|
-
//
|
|
604
|
-
|
|
572
|
+
installSubmitBindings(pi, submitConflict);
|
|
573
|
+
|
|
574
|
+
// The warm ready + handoff bindings: the deliberate draft→ready review gate (submit keeps
|
|
575
|
+
// draft). Takes `gating`: the warm ready→reconcile continuation refuses (loudly) to drive
|
|
576
|
+
// the ready-time pass into a read-only session (contracts.md §8.66).
|
|
577
|
+
installReadyBindings(pi, gating);
|
|
578
|
+
|
|
579
|
+
// Warm bindings: `land` merges + sets pending-learn; the v1 learn installer (the `learn` +
|
|
580
|
+
// `run_learn_wave` tools and the `/learn` command over the `learning/` feature ops) clears it.
|
|
581
|
+
installLandBindings(pi);
|
|
582
|
+
installLearnBindings(pi, reportWave);
|
|
583
|
+
|
|
584
|
+
// The warm stacked-delivery mutating surface (§8.51): the `/objective-sync`/
|
|
585
|
+
// `/objective-recover`/`/objective-land` drives + the four typed stack tools over the
|
|
586
|
+
// `delivery/stackConflict.ts` + `delivery/stackReconcile.ts` feature ops. Takes `gating` for
|
|
587
|
+
// the driving commands' gate-on soft refusal (stack sync/recovery mutates published
|
|
588
|
+
// branches; the stack tools never join READ_ONLY_TOOLS).
|
|
589
|
+
installStackSyncBindings(pi, gating, stackConflict, options.stackResolutionDelivery);
|
|
590
|
+
installStackRecoverBindings(pi, gating);
|
|
591
|
+
installStackLandBindings(pi, gating);
|
|
592
|
+
|
|
593
|
+
// The stacked-delivery status read: the `objective_stack_status` tool + the `/objective-stack`
|
|
594
|
+
// command (read-only end to end — the command works gate-on; the tool stays gate-off).
|
|
595
|
+
installStackStatusBindings(pi);
|
|
605
596
|
|
|
606
597
|
// The warm `/address` review loop: the submit-then-resolve `finalize_address` tool + `/address`
|
|
607
598
|
// command. Classify-then-act (the verbose feedback fetch + classification runs in an isolated
|
|
608
599
|
// spawned child; the parent fixes actionable items and finalizes the committed repairs).
|
|
609
|
-
|
|
600
|
+
installAddressBindings(pi, reportWave, submitConflict);
|
|
610
601
|
|
|
611
602
|
// The warm `/pr-review` door: automated code review in a FRESH, isolated subagent that
|
|
612
603
|
// POSTS its review to the PR (the deliberate departure from /address's read-only-child rule).
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
// The EXPERIMENTAL warm `/pr-review-dynamic` door: the selector-driven sibling — angle
|
|
616
|
-
// selection delegated to a fresh perk.review-angle-selector lane, normalized in
|
|
617
|
-
// module-rendered code; posting shares /pr-review's post_pr_review + clean guard. The
|
|
618
|
-
// baseline /pr-review stays canonical; promotion/retire is a later dogfood's call.
|
|
619
|
-
registerPrReviewDynamic(pi);
|
|
604
|
+
installAutomatedReviewBindings(pi, reportWave);
|
|
620
605
|
|
|
621
606
|
// The warm `submit_pr_review` tool: the human-gated curated-posting surface both review
|
|
622
607
|
// doors ride (contracts §8.4) — neither door registers tools of its own.
|
|
623
|
-
|
|
608
|
+
installCuratedSubmissionBindings(pi);
|
|
624
609
|
|
|
625
610
|
// The flow-scoped review-wave pair (`start_review_wave`/`collect_review_wave`) both human
|
|
626
611
|
// review doors drive: non-blocking adversarial-review launch + the typed collect, flow-scoped
|
|
627
612
|
// via the session's pending-wave guard.
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
613
|
+
installReviewWaveBindings(pi, reportWave);
|
|
614
|
+
installAuditBindings(pi, reportWave);
|
|
615
|
+
installHarvestBindings(pi, reportWave);
|
|
616
|
+
installDreamBindings(pi, reportWave);
|
|
617
|
+
|
|
618
|
+
// The scout launcher (`run_scout_wave`, contracts.md §8.70): the authoring sessions' blocking
|
|
619
|
+
// fan-out of self-contained read-only briefs onto fresh `perk.scout` lanes — one attempt,
|
|
620
|
+
// no retry, reachable in every gated stage except refinement.
|
|
621
|
+
installScoutWaveBindings(pi, reportWave);
|
|
632
622
|
|
|
633
623
|
// The flow-scoped draft-review-wave pair (`start_draft_review_wave`/
|
|
634
624
|
// `collect_draft_review_wave`) the draft-review door drives: non-blocking draft-review
|
|
635
625
|
// launch over the door-primed context + the typed collect.
|
|
636
|
-
registerDraftReviewWaveTools(pi);
|
|
626
|
+
registerDraftReviewWaveTools(pi, draftReviewWave, reportWave);
|
|
637
627
|
|
|
638
628
|
// The door-primed browser annotation tool (`push_annotations`): the browser door primes the
|
|
639
629
|
// surface handle on open and clears it on settle/degrade — the tool refuses outside a
|
|
640
630
|
// door-opened flow.
|
|
641
|
-
|
|
631
|
+
installAnnotationBindings(pi, annotations);
|
|
642
632
|
|
|
643
633
|
// The warm `/pr-review-terminal` door: the terminal review entry — hunk always, no provider
|
|
644
634
|
// dispatch (the command IS the selection); posting rides `submit_pr_review` above.
|
|
645
|
-
|
|
635
|
+
installPrReviewTerminalBindings(pi);
|
|
646
636
|
|
|
647
637
|
// The warm `/pr-review-browser` door: the browser review entry — plannotator always, opened
|
|
648
638
|
// in the background (pre-PR it absorbs the since-base local browser review); posting is the
|
|
649
639
|
// human's own platform-post from the UI, with `submit_pr_review` for request-changes only.
|
|
650
|
-
|
|
640
|
+
installPrReviewBrowserBindings(pi, annotations, perkStatus);
|
|
651
641
|
|
|
652
642
|
// The warm `/stack-review-browser` door + its cold-launch twin (`open_stack_review`): the
|
|
653
643
|
// stacked-PR browser review over the combined base→top diff — one reviewer wave with
|
|
654
644
|
// `stack: true`, then judgment-routed per-PR posting through `submit_pr_review`.
|
|
655
|
-
|
|
656
|
-
registerOpenStackReview(pi);
|
|
645
|
+
installStackReviewBindings(pi, annotations, perkStatus);
|
|
657
646
|
|
|
658
647
|
// The warm `/plan-review-browser` door: the summonable streaming draft review — the
|
|
659
648
|
// plannotator plan-review browser on the working plan draft, draft reviewers streaming
|
|
660
649
|
// phrase-anchored findings in; APPROVE auto-saves via the approvalSave seam, DENY returns a
|
|
661
650
|
// model-mediated revision round.
|
|
662
|
-
registerPlanReviewBrowser(pi, gating);
|
|
651
|
+
registerPlanReviewBrowser(pi, gating, draftReviewWave, annotations, draftReviews, perkStatus);
|
|
663
652
|
|
|
664
653
|
// The warm `/objective-review-browser` door: the summonable streaming objective-draft review
|
|
665
654
|
// — the plannotator plan-review browser on the RENDERED working objective draft, draft
|
|
666
655
|
// reviewers streaming phrase-anchored findings in; APPROVE auto-saves via the
|
|
667
656
|
// objectiveApprovalSave seam, Direct Edits = a model-mediated revise round (never auto-saved).
|
|
668
|
-
registerObjectiveReviewBrowser(
|
|
657
|
+
registerObjectiveReviewBrowser(
|
|
658
|
+
pi,
|
|
659
|
+
gating,
|
|
660
|
+
draftReviewWave,
|
|
661
|
+
annotations,
|
|
662
|
+
draftReviews,
|
|
663
|
+
perkStatus,
|
|
664
|
+
);
|
|
669
665
|
|
|
670
666
|
// The read-only CI executor: the `run_ci` tool + `/ci` command + `--allow-project-ci`
|
|
671
667
|
// flag. Runs the project's `[ci]` named checks deterministically and reports (never fixes/loops).
|
|
672
|
-
|
|
668
|
+
installCiBindings(pi);
|
|
673
669
|
|
|
674
670
|
// The objective substrate: `/objective` set/clear, budget accounting, threshold
|
|
675
671
|
// compaction, all keyed off the now-live `active_objective`. Inert when no objective is active.
|
|
676
672
|
// (The deterministic objective mechanics live in the Python plane: `perk objective …`.)
|
|
677
|
-
|
|
673
|
+
installObjectiveBindings(pi, perkStatus);
|
|
678
674
|
|
|
679
675
|
// The warm `/commit-and-compact` utility door: drive a commit of the work so far, compact once
|
|
680
676
|
// a successful outcome is known, then completion-gate an automatic evidence-first continuation
|
|
681
677
|
// (clean/read-only trees compact immediately; no commit → no compaction or continuation).
|
|
682
678
|
// Human-only — no tool twin.
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
// The warm `objective_save` door: the `objective_save` tool + `/objective-save` command
|
|
686
|
-
// (the objective mirror of plan-save). Takes `gating` for the read-only → read-write boundary.
|
|
687
|
-
registerObjectiveSave(pi, gating);
|
|
688
|
-
|
|
689
|
-
// The warm `gist_save` door: the `gist_save` tool + `/gist-save` command (the gist mirror).
|
|
690
|
-
registerGistSave(pi, gating);
|
|
679
|
+
installCommitCompactBindings(pi, gating);
|
|
691
680
|
|
|
692
681
|
// The objective plan factory's warm transition surface: the `objective_node` bounded
|
|
693
682
|
// tool (delegates to the Python cold door; `status:"done"` requires a completion audit) + the
|
|
694
683
|
// `/objective-plan` command (select the next node and author a bounded plan). The command now
|
|
695
684
|
// enters the read-only gate on invocation (parity with the cold door's `mode: read-only`
|
|
696
685
|
// handoff; exit stays with plan_save / `/plan` off) — hence `gating`.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
// The learned-docs plan factory's warm surface: the `/learn-docs` command gathers open
|
|
700
|
-
// perk:learn issues into an inbox (via the `perk learn docs --gather` cold door) and injects the
|
|
701
|
-
// factory guidance so the model authors a docs/learned consolidation plan (no model tool).
|
|
702
|
-
registerLearnFactoryDoor(pi, DOCS_DOOR);
|
|
686
|
+
installObjectivePlanningBindings(pi, gating, reportWave);
|
|
703
687
|
|
|
704
|
-
// The learn
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
|
|
688
|
+
// The two learn plan factories' warm surfaces: `/learn-docs` gathers open perk:learn issues
|
|
689
|
+
// (via the `perk learn docs --gather` cold door) toward a docs/learned consolidation plan;
|
|
690
|
+
// `/learn-code` gathers pre-stamped SHOULD_BE_CODE issues (via `perk learn code --gather`)
|
|
691
|
+
// toward a code-routing plan. Guidance-injection only (no model tool).
|
|
692
|
+
installLearnFactoryBindings(pi);
|
|
708
693
|
|
|
709
694
|
// Warm-door skill-binding delivery: Mechanism A's `before_agent_start` injection of
|
|
710
695
|
// the launched stage's user-originated bindings (+ the stale-context strip). Mechanism B (the
|