@entelligentsia/forgecli 1.0.10 → 1.0.20
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 +191 -0
- package/dist/CHANGELOG-forge-plugin.md +211 -0
- package/dist/bin/forge.js +0 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -1
- package/dist/extensions/forgecli/context-governor-compaction.d.ts +83 -0
- package/dist/extensions/forgecli/context-governor-compaction.js +302 -0
- package/dist/extensions/forgecli/context-governor-compaction.js.map +1 -0
- package/dist/extensions/forgecli/context-governor.d.ts +173 -0
- package/dist/extensions/forgecli/context-governor.js +618 -0
- package/dist/extensions/forgecli/context-governor.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/component.d.ts +105 -0
- package/dist/extensions/forgecli/dashboard/component.js +861 -0
- package/dist/extensions/forgecli/dashboard/component.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/register.d.ts +2 -0
- package/dist/extensions/forgecli/dashboard/register.js +31 -0
- package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/theme.d.ts +27 -0
- package/dist/extensions/forgecli/dashboard/theme.js +91 -0
- package/dist/extensions/forgecli/dashboard/theme.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/view-model.d.ts +35 -0
- package/dist/extensions/forgecli/dashboard/view-model.js +54 -0
- package/dist/extensions/forgecli/dashboard/view-model.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.js +126 -7
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js +2 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- package/dist/extensions/forgecli/forge-commands.js +1 -0
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +53 -0
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +20 -1
- package/dist/extensions/forgecli/forge-subagent.js +23 -7
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.js +3 -1
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +3 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +37 -3
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/index.js +38 -1
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/lib/halt-advisor.d.ts +59 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js +113 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -0
- package/dist/extensions/forgecli/migration-engine.js +25 -12
- package/dist/extensions/forgecli/migration-engine.js.map +1 -1
- package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +26 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js +213 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -0
- package/dist/extensions/forgecli/orchestrator-tree.d.ts +96 -0
- package/dist/extensions/forgecli/orchestrator-tree.js +390 -0
- package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -0
- package/dist/extensions/forgecli/project-orientation.js +12 -8
- package/dist/extensions/forgecli/project-orientation.js.map +1 -1
- package/dist/extensions/forgecli/regenerate.d.ts +16 -0
- package/dist/extensions/forgecli/regenerate.js +110 -0
- package/dist/extensions/forgecli/regenerate.js.map +1 -1
- package/dist/extensions/forgecli/run-sprint.d.ts +3 -1
- package/dist/extensions/forgecli/run-sprint.js +34 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +66 -1
- package/dist/extensions/forgecli/run-task.js +323 -12
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.d.ts +4 -1
- package/dist/extensions/forgecli/thread-switcher.js +118 -762
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/viewport-events.js +32 -0
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/forge-payload/.base-pack/commands/fix-bug.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-sprint.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-task.md +1 -1
- package/dist/forge-payload/.base-pack/personas/architect.md +1 -1
- package/dist/forge-payload/.base-pack/personas/bug-fixer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/collator.md +3 -3
- package/dist/forge-payload/.base-pack/personas/engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/librarian.md +1 -1
- package/dist/forge-payload/.base-pack/personas/orchestrator.md +1 -1
- package/dist/forge-payload/.base-pack/personas/product-manager.md +1 -1
- package/dist/forge-payload/.base-pack/personas/qa-engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/supervisor.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +11 -2
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +6 -7
- package/dist/forge-payload/.base-pack/workflows/architect_review_sprint_completion.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_intake.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_plan.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/collator_agent.md +4 -6
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +5 -6
- package/dist/forge-payload/.base-pack/workflows/enhance.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +15 -7
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +12 -6
- package/dist/forge-payload/.base-pack/workflows/review_code.md +12 -11
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +12 -11
- package/dist/forge-payload/.base-pack/workflows/sprint_retrospective.md +3 -3
- package/dist/forge-payload/.base-pack/workflows/triage.md +12 -9
- package/dist/forge-payload/.base-pack/workflows/update_implementation.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/update_plan.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/validate_task.md +9 -9
- package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +490 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-sprint.js +416 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +608 -0
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/config.schema.json +2 -3
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/event.schema.json +16 -0
- package/dist/forge-payload/.schemas/migrations.json +359 -18
- package/dist/forge-payload/commands/health.md +29 -0
- package/dist/forge-payload/commands/rebuild.md +143 -15
- package/dist/forge-payload/commands/update.md +28 -27
- package/dist/forge-payload/hooks/preflight-session.cjs +99 -0
- package/dist/forge-payload/init/phases/phase-3-materialize.md +18 -5
- package/dist/forge-payload/integrity.json +7 -6
- package/dist/forge-payload/meta/fragments/tool-discipline.md +1 -1
- package/dist/forge-payload/meta/personas/meta-architect.md +1 -1
- package/dist/forge-payload/meta/personas/meta-bug-fixer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-collator.md +7 -7
- package/dist/forge-payload/meta/personas/meta-engineer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-orchestrator.md +1 -1
- package/dist/forge-payload/meta/personas/meta-supervisor.md +1 -1
- package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +11 -2
- package/dist/forge-payload/meta/workflows/meta-approve.md +6 -7
- package/dist/forge-payload/meta/workflows/meta-bug-triage.md +12 -9
- package/dist/forge-payload/meta/workflows/meta-collate.md +5 -7
- package/dist/forge-payload/meta/workflows/meta-commit.md +5 -6
- package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +35 -11
- package/dist/forge-payload/meta/workflows/meta-implement.md +15 -7
- package/dist/forge-payload/meta/workflows/meta-migrate.md +13 -14
- package/dist/forge-payload/meta/workflows/meta-new-sprint.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +138 -39
- package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +12 -6
- package/dist/forge-payload/meta/workflows/meta-retro.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-retrospective.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +12 -11
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +12 -11
- package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-update-implementation.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-update-plan.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-validate.md +9 -9
- package/dist/forge-payload/schemas/config.schema.json +2 -3
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/event.schema.json +16 -0
- package/dist/forge-payload/schemas/structure-manifest.json +75 -73
- package/dist/forge-payload/skills/refresh-kb-links/SKILL.md +14 -7
- package/dist/forge-payload/tools/banners.cjs +29 -10
- package/dist/forge-payload/tools/check-structure.cjs +88 -7
- package/dist/forge-payload/tools/collate.cjs +48 -2
- package/dist/forge-payload/tools/manage-config.cjs +5 -7
- package/dist/forge-payload/tools/parse-gates.cjs +73 -1
- package/dist/forge-payload/tools/postflight-gate.cjs +298 -0
- package/dist/forge-payload/tools/preflight-gate.cjs +47 -0
- package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -4
- package/dist/forge-payload/tools/verify-phase.cjs +17 -0
- package/package.json +2 -2
- package/dist/bin/forgecli.d.ts +0 -2
- package/dist/bin/forgecli.js +0 -6
- package/dist/bin/forgecli.js.map +0 -1
- package/dist/extensions/forgecli/config-tui/index.d.ts +0 -5
- package/dist/extensions/forgecli/config-tui/index.js +0 -5
- package/dist/extensions/forgecli/config-tui/index.js.map +0 -1
- package/dist/extensions/forgecli/loaders/persona-skill-loader.d.ts +0 -45
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js +0 -227
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +0 -1
- package/dist/extensions/forgecli/loaders/template-render.d.ts +0 -20
- package/dist/extensions/forgecli/loaders/template-render.js +0 -85
- package/dist/extensions/forgecli/loaders/template-render.js.map +0 -1
- package/dist/extensions/forgecli/loaders/workflow-loader.d.ts +0 -41
- package/dist/extensions/forgecli/loaders/workflow-loader.js +0 -164
- package/dist/extensions/forgecli/loaders/workflow-loader.js.map +0 -1
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +0 -446
- package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +0 -928
- package/dist/forge-payload/.base-pack/workflows/run_sprint.md +0 -225
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// context-governor-compaction.ts — Mechanism E: Forge-aware compaction handler.
|
|
2
|
+
// FORGE-S30-T09
|
|
3
|
+
//
|
|
4
|
+
// Exports:
|
|
5
|
+
// ForgeFactSummary — extracted Forge facts struct
|
|
6
|
+
// ForgeCompactionOptions — options for the compaction factory
|
|
7
|
+
// extractForgeFacts(msgs) — pure extractor (no fs I/O)
|
|
8
|
+
// buildForgeCompactionFactory(opts) — ExtensionFactory builder
|
|
9
|
+
//
|
|
10
|
+
// Design:
|
|
11
|
+
// - Thin module separate from context-governor.ts so it can import ExtensionAPI
|
|
12
|
+
// types (which require the pi pkg) without polluting the pure-logic governor.
|
|
13
|
+
// - extractForgeFacts: line-level pattern matching — no LLM call, provider-neutral,
|
|
14
|
+
// lossless on structured facts.
|
|
15
|
+
// - Warm-tier merge: reads {PHASE}-SUMMARY.json via injected summaryReader
|
|
16
|
+
// (defaults to fs.readFileSync). Best-effort — absent/malformed files silently
|
|
17
|
+
// skipped (IL7).
|
|
18
|
+
// - IL7 fallback: entire session_before_compact handler wrapped in try/catch.
|
|
19
|
+
// On any error, returns undefined — lets pi compact normally with generateSummary.
|
|
20
|
+
// - IL10/Pack 07: only reads summary files, never writes .forge/store/ or summaries.
|
|
21
|
+
// - NOT wired into index.ts/run-task.ts yet — deferred to T07 production integration.
|
|
22
|
+
import * as fs from "node:fs";
|
|
23
|
+
import * as path from "node:path";
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Pattern constants (module-level compile-time constants)
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
/** Matches Forge store IDs in their standard forms:
|
|
28
|
+
* FORGE-S30-T09 (sprint+task)
|
|
29
|
+
* FORGE-S30 (sprint)
|
|
30
|
+
* FORGE-BUG-042 (bug, with category letters + digit suffix)
|
|
31
|
+
* Pattern: FORGE- followed by alternating ALPHANUM segments separated by hyphens.
|
|
32
|
+
* Two variants ordered longest-first so overlapping (sprint+task before sprint) works. */
|
|
33
|
+
const STORE_ID_RE = /FORGE-[A-Z]+\d*-(?:T?\d+|[A-Z]+\d*)|FORGE-[A-Z]+\d*/g;
|
|
34
|
+
/** Matches Markdown checkbox lines. */
|
|
35
|
+
const CHECKBOX_RE = /^\s*[-*]?\s*\[[ xX]\].*$/gm;
|
|
36
|
+
/** Matches status transition patterns:
|
|
37
|
+
* - Arrow: "→ implemented"
|
|
38
|
+
* - store-cli: "update-status task FORGE-S30-T09 status implementing"
|
|
39
|
+
* Using a broad match to capture both forms reliably. */
|
|
40
|
+
const TRANSITION_RE = /(?:→\s*[\w][\w-]*|update-status\s+\S+\s+\S+\s+status\s+[\w][\w-]*)/g;
|
|
41
|
+
/** Matches file reference patterns. */
|
|
42
|
+
const FILE_REF_RE = /(?:engineering\/[^\s"'`,;)]+|\.forge\/[^\s"'`,;)]+|\b[\w./\-]+\.(?:ts|md|cjs|json)\b)/g;
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// extractForgeFacts — pure extractor
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
/**
|
|
47
|
+
* Extract structured Forge facts from an array of message-like objects.
|
|
48
|
+
*
|
|
49
|
+
* Pure function — no fs I/O, no LLM calls, provider-neutral.
|
|
50
|
+
* Accepts any array (unknown[]) to be safe against varying pi message shapes.
|
|
51
|
+
* Text content is extracted from `.content[].text` (assistant messages)
|
|
52
|
+
* and from direct string entries.
|
|
53
|
+
*
|
|
54
|
+
* @param messagesToSummarize Array of message-like objects from preparation.
|
|
55
|
+
* @returns ForgeFactSummary with all extracted patterns.
|
|
56
|
+
*/
|
|
57
|
+
export function extractForgeFacts(messagesToSummarize) {
|
|
58
|
+
const storeIdSet = new Set();
|
|
59
|
+
const acStateLines = [];
|
|
60
|
+
const transitionLineSet = new Set();
|
|
61
|
+
const fileRefSet = new Set();
|
|
62
|
+
const frictionBlocks = [];
|
|
63
|
+
for (const msg of messagesToSummarize) {
|
|
64
|
+
const texts = extractTextContent(msg);
|
|
65
|
+
for (const text of texts) {
|
|
66
|
+
// Store IDs — reset lastIndex before each matchAll
|
|
67
|
+
const storeMatches = text.matchAll(new RegExp(STORE_ID_RE.source, "g"));
|
|
68
|
+
for (const m of storeMatches) {
|
|
69
|
+
storeIdSet.add(m[0]);
|
|
70
|
+
}
|
|
71
|
+
// AC-state checkbox lines
|
|
72
|
+
const checkboxMatches = text.match(new RegExp(CHECKBOX_RE.source, "gm"));
|
|
73
|
+
if (checkboxMatches) {
|
|
74
|
+
for (const line of checkboxMatches) {
|
|
75
|
+
acStateLines.push(line.trim());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Transition lines
|
|
79
|
+
const transitionMatches = text.matchAll(new RegExp(TRANSITION_RE.source, "g"));
|
|
80
|
+
for (const m of transitionMatches) {
|
|
81
|
+
transitionLineSet.add(m[0].trim());
|
|
82
|
+
}
|
|
83
|
+
// File refs
|
|
84
|
+
const fileRefMatches = text.matchAll(new RegExp(FILE_REF_RE.source, "g"));
|
|
85
|
+
for (const m of fileRefMatches) {
|
|
86
|
+
const ref = m[0].trim();
|
|
87
|
+
if (ref.length > 2) {
|
|
88
|
+
fileRefSet.add(ref);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// FRICTION blocks — scan per line
|
|
92
|
+
for (const line of text.split("\n")) {
|
|
93
|
+
if (/\[FRICTION\]|type:friction/i.test(line)) {
|
|
94
|
+
frictionBlocks.push(line.trim());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
storeIds: Array.from(storeIdSet),
|
|
101
|
+
acStateLines,
|
|
102
|
+
transitionLines: Array.from(transitionLineSet),
|
|
103
|
+
fileRefs: Array.from(fileRefSet),
|
|
104
|
+
frictionBlocks,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Extract text strings from a message-like object.
|
|
109
|
+
* Handles assistant messages (content[].text) and plain strings.
|
|
110
|
+
*/
|
|
111
|
+
function extractTextContent(msg) {
|
|
112
|
+
if (typeof msg === "string") {
|
|
113
|
+
return [msg];
|
|
114
|
+
}
|
|
115
|
+
if (typeof msg !== "object" || msg === null) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const msgObj = msg;
|
|
119
|
+
const content = msgObj["content"];
|
|
120
|
+
if (!Array.isArray(content)) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
const texts = [];
|
|
124
|
+
for (const part of content) {
|
|
125
|
+
if (typeof part === "string") {
|
|
126
|
+
texts.push(part);
|
|
127
|
+
}
|
|
128
|
+
else if (typeof part === "object" && part !== null) {
|
|
129
|
+
const p = part;
|
|
130
|
+
if (p["type"] === "text" && typeof p["text"] === "string") {
|
|
131
|
+
texts.push(p["text"]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return texts;
|
|
136
|
+
}
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Warm-tier helpers
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
/** Map phase key to canonical {PHASE}-SUMMARY.json filename. */
|
|
141
|
+
function phaseSummaryFilename(phaseKey) {
|
|
142
|
+
const map = {
|
|
143
|
+
// Real run-task PHASE_PIPELINE keys (`${personaNoun}/${role}`):
|
|
144
|
+
"engineer/plan": "PLAN-SUMMARY.json",
|
|
145
|
+
"supervisor/review-plan": "REVIEW_PLAN-SUMMARY.json",
|
|
146
|
+
"engineer/implement": "IMPLEMENTATION-SUMMARY.json",
|
|
147
|
+
"supervisor/review-code": "CODE_REVIEW-SUMMARY.json",
|
|
148
|
+
"qa-engineer/validate": "VALIDATION-SUMMARY.json",
|
|
149
|
+
"architect/approve": "APPROVE-SUMMARY.json",
|
|
150
|
+
// Legacy design-time keys (test fixtures only):
|
|
151
|
+
"architect/plan": "PLAN-SUMMARY.json",
|
|
152
|
+
"engineer/review": "REVIEW-SUMMARY.json",
|
|
153
|
+
"engineer/code-review": "CODE_REVIEW-SUMMARY.json",
|
|
154
|
+
};
|
|
155
|
+
return map[phaseKey] ?? "{PHASE}-SUMMARY.json";
|
|
156
|
+
}
|
|
157
|
+
/** Default summaryReader: synchronous fs.readFileSync. Returns null on any error. */
|
|
158
|
+
function defaultSummaryReader(filePath) {
|
|
159
|
+
try {
|
|
160
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Read and parse the warm-tier {PHASE}-SUMMARY.json (synchronous).
|
|
168
|
+
* Returns the parsed object or null on any failure (IL7).
|
|
169
|
+
*
|
|
170
|
+
* When summaryReader is provided but cwd/phaseKey/entityId/sprintId are not,
|
|
171
|
+
* calls summaryReader("") — enables test seams that don't need path resolution.
|
|
172
|
+
*/
|
|
173
|
+
function readWarmTierSummary(opts) {
|
|
174
|
+
try {
|
|
175
|
+
let filePath;
|
|
176
|
+
const reader = opts.summaryReader ?? defaultSummaryReader;
|
|
177
|
+
if (opts.cwd && opts.phaseKey && opts.entityId && opts.sprintId) {
|
|
178
|
+
filePath = path.join(opts.cwd, "engineering", "sprints", opts.sprintId, opts.entityId, phaseSummaryFilename(opts.phaseKey));
|
|
179
|
+
}
|
|
180
|
+
else if (opts.summaryReader) {
|
|
181
|
+
// Test seam: summaryReader present but no path context — call with empty string.
|
|
182
|
+
filePath = "";
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const raw = reader(filePath);
|
|
188
|
+
if (!raw)
|
|
189
|
+
return null;
|
|
190
|
+
const parsed = JSON.parse(raw);
|
|
191
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
192
|
+
return null;
|
|
193
|
+
return parsed;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Summary assembly
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
/**
|
|
203
|
+
* Assemble a compact structured summary string from extracted facts
|
|
204
|
+
* and an optional warm-tier summary.
|
|
205
|
+
*/
|
|
206
|
+
function assembleSummary(facts, warmTier) {
|
|
207
|
+
const parts = [];
|
|
208
|
+
// Warm-tier objective (highest information density — prepend).
|
|
209
|
+
if (warmTier?.objective) {
|
|
210
|
+
parts.push(`## Phase Objective\n${warmTier.objective}`);
|
|
211
|
+
}
|
|
212
|
+
// Warm-tier key changes.
|
|
213
|
+
if (warmTier?.key_changes && warmTier.key_changes.length > 0) {
|
|
214
|
+
parts.push(`## Key Changes\n${warmTier.key_changes.map((c) => `- ${c}`).join("\n")}`);
|
|
215
|
+
}
|
|
216
|
+
// Extracted store IDs.
|
|
217
|
+
if (facts.storeIds.length > 0) {
|
|
218
|
+
parts.push(`## Active Store IDs\n${facts.storeIds.join(", ")}`);
|
|
219
|
+
}
|
|
220
|
+
// AC state (checkboxes — capped at 10).
|
|
221
|
+
if (facts.acStateLines.length > 0) {
|
|
222
|
+
const sample = facts.acStateLines.slice(0, 10);
|
|
223
|
+
parts.push(`## Acceptance Criteria State\n${sample.join("\n")}`);
|
|
224
|
+
}
|
|
225
|
+
// Transitions (capped at 5).
|
|
226
|
+
if (facts.transitionLines.length > 0) {
|
|
227
|
+
const sample = facts.transitionLines.slice(0, 5);
|
|
228
|
+
parts.push(`## Status Transitions\n${sample.join("\n")}`);
|
|
229
|
+
}
|
|
230
|
+
// File refs (capped at 10).
|
|
231
|
+
if (facts.fileRefs.length > 0) {
|
|
232
|
+
const sample = facts.fileRefs.slice(0, 10);
|
|
233
|
+
parts.push(`## File References\n${sample.join("\n")}`);
|
|
234
|
+
}
|
|
235
|
+
// FRICTION blocks.
|
|
236
|
+
if (facts.frictionBlocks.length > 0) {
|
|
237
|
+
parts.push(`## FRICTION\n${facts.frictionBlocks.join("\n")}`);
|
|
238
|
+
}
|
|
239
|
+
if (parts.length === 0) {
|
|
240
|
+
return "[Forge context governor — compaction summary — no structured facts extracted]";
|
|
241
|
+
}
|
|
242
|
+
return `[Forge context governor — compaction summary]\n\n${parts.join("\n\n")}`;
|
|
243
|
+
}
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// buildForgeCompactionFactory — ExtensionFactory builder
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
/**
|
|
248
|
+
* Build an ExtensionFactory that registers a session_before_compact handler
|
|
249
|
+
* returning a deterministically-composed CompactionResult.
|
|
250
|
+
*
|
|
251
|
+
* The handler:
|
|
252
|
+
* 1. Validates that event.preparation is present and well-formed.
|
|
253
|
+
* 2. Extracts Forge facts from event.preparation.messagesToSummarize
|
|
254
|
+
* (no LLM call, provider-neutral).
|
|
255
|
+
* 3. Reads the warm-tier {PHASE}-SUMMARY.json if opts provide path context,
|
|
256
|
+
* or invokes opts.summaryReader("") as a test seam.
|
|
257
|
+
* 4. Assembles a compact structured summary string.
|
|
258
|
+
* 5. Returns { compaction: { summary, firstKeptEntryId, tokensBefore } }.
|
|
259
|
+
* 6. Returns undefined on any error (IL7 — lets pi compact normally).
|
|
260
|
+
*
|
|
261
|
+
* Pack 07: reads summary files but never writes .forge/store/.
|
|
262
|
+
* IL10: no pi-mono edits, no dispatch contract changes.
|
|
263
|
+
* NOT wired into index.ts/run-task.ts — deferred to T07 production integration.
|
|
264
|
+
*
|
|
265
|
+
* @param opts ForgeCompactionOptions (default: empty — no warm-tier).
|
|
266
|
+
* @returns ExtensionFactory for passing to DefaultResourceLoader.extensionFactories.
|
|
267
|
+
*/
|
|
268
|
+
export function buildForgeCompactionFactory(opts = {}) {
|
|
269
|
+
return (pi) => {
|
|
270
|
+
pi.on("session_before_compact", (event) => {
|
|
271
|
+
try {
|
|
272
|
+
// Validate preparation is present and has the required pass-through fields.
|
|
273
|
+
const prep = event?.preparation;
|
|
274
|
+
if (!prep || typeof prep !== "object") {
|
|
275
|
+
return undefined; // IL7 — malformed preparation
|
|
276
|
+
}
|
|
277
|
+
const { firstKeptEntryId, tokensBefore, messagesToSummarize } = prep;
|
|
278
|
+
if (typeof firstKeptEntryId !== "string" || typeof tokensBefore !== "number") {
|
|
279
|
+
return undefined; // IL7 — malformed preparation fields
|
|
280
|
+
}
|
|
281
|
+
// Extract Forge facts from message history.
|
|
282
|
+
const msgs = Array.isArray(messagesToSummarize) ? messagesToSummarize : [];
|
|
283
|
+
const facts = extractForgeFacts(msgs);
|
|
284
|
+
// Read warm-tier summary (best-effort, IL7).
|
|
285
|
+
const warmTier = readWarmTierSummary(opts);
|
|
286
|
+
// Assemble summary string.
|
|
287
|
+
const summary = assembleSummary(facts, warmTier);
|
|
288
|
+
const compaction = {
|
|
289
|
+
summary,
|
|
290
|
+
firstKeptEntryId,
|
|
291
|
+
tokensBefore,
|
|
292
|
+
};
|
|
293
|
+
return { compaction };
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// IL7: unexpected error → return undefined, let pi compact normally.
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=context-governor-compaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-governor-compaction.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/context-governor-compaction.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,gBAAgB;AAChB,EAAE;AACF,WAAW;AACX,2DAA2D;AAC3D,iEAAiE;AACjE,yDAAyD;AACzD,iEAAiE;AACjE,EAAE;AACF,UAAU;AACV,kFAAkF;AAClF,kFAAkF;AAClF,sFAAsF;AACtF,oCAAoC;AACpC,6EAA6E;AAC7E,mFAAmF;AACnF,qBAAqB;AACrB,gFAAgF;AAChF,uFAAuF;AACvF,uFAAuF;AACvF,wFAAwF;AAExF,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AA6ElC,8EAA8E;AAC9E,0DAA0D;AAC1D,8EAA8E;AAE9E;;;;;0FAK0F;AAC1F,MAAM,WAAW,GAAG,sDAAsD,CAAC;AAE3E,uCAAuC;AACvC,MAAM,WAAW,GAAG,4BAA4B,CAAC;AAEjD;;;yDAGyD;AACzD,MAAM,aAAa,GAAG,qEAAqE,CAAC;AAE5F,uCAAuC;AACvC,MAAM,WAAW,GAChB,wFAAwF,CAAC;AAE1F,8EAA8E;AAC9E,qCAAqC;AACrC,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,mBAA8B;IAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,KAAK,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,mDAAmD;YACnD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YACxE,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;gBAC9B,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtB,CAAC;YAED,0BAA0B;YAC1B,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;YACzE,IAAI,eAAe,EAAE,CAAC;gBACrB,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;oBACpC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBAChC,CAAC;YACF,CAAC;YAED,mBAAmB;YACnB,MAAM,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YAC/E,KAAK,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC;gBACnC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACpC,CAAC;YAED,YAAY;YACZ,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1E,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxB,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACpB,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACrB,CAAC;YACF,CAAC;YAED,kCAAkC;YAClC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9C,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBAClC,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO;QACN,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;QAChC,YAAY;QACZ,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC;QAC9C,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;QAChC,cAAc;KACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,kBAAkB,CAAC,GAAY;IACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC7C,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,MAAM,GAAG,GAA8B,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACtD,MAAM,CAAC,GAAG,IAA+B,CAAC;YAC1C,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YACvB,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,gEAAgE;AAChE,SAAS,oBAAoB,CAAC,QAAgB;IAC7C,MAAM,GAAG,GAA2B;QACnC,gEAAgE;QAChE,eAAe,EAAE,mBAAmB;QACpC,wBAAwB,EAAE,0BAA0B;QACpD,oBAAoB,EAAE,6BAA6B;QACnD,wBAAwB,EAAE,0BAA0B;QACpD,sBAAsB,EAAE,yBAAyB;QACjD,mBAAmB,EAAE,sBAAsB;QAC3C,gDAAgD;QAChD,gBAAgB,EAAE,mBAAmB;QACrC,iBAAiB,EAAE,qBAAqB;QACxC,sBAAsB,EAAE,0BAA0B;KAClD,CAAC;IACF,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,sBAAsB,CAAC;AAChD,CAAC;AAQD,qFAAqF;AACrF,SAAS,oBAAoB,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACJ,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,IAA4B;IACxD,IAAI,CAAC;QACJ,IAAI,QAAgB,CAAC;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,IAAI,oBAAoB,CAAC;QAE1D,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjE,QAAQ,GAAG,IAAI,CAAC,IAAI,CACnB,IAAI,CAAC,GAAG,EACR,aAAa,EACb,SAAS,EACT,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,QAAQ,EACb,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,CACnC,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC/B,iFAAiF;YACjF,QAAQ,GAAG,EAAE,CAAC;QACf,CAAC;aAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;QACpD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC/D,OAAO,MAAM,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;GAGG;AACH,SAAS,eAAe,CACvB,KAAuB,EACvB,QAAkC;IAElC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,+DAA+D;IAC/D,IAAI,QAAQ,EAAE,SAAS,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,uBAAuB,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,yBAAyB;IACzB,IAAI,QAAQ,EAAE,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,KAAK,CAAC,IAAI,CAAC,mBAAmB,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,uBAAuB;IACvB,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,wCAAwC;IACxC,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,iCAAiC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,6BAA6B;IAC7B,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,0BAA0B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,4BAA4B;IAC5B,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,mBAAmB;IACnB,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,+EAA+E,CAAC;IACxF,CAAC;IAED,OAAO,oDAAoD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,8EAA8E;AAC9E,yDAAyD;AACzD,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAA+B,EAAE;IAC5E,OAAO,CAAC,EAAgB,EAAQ,EAAE;QACjC,EAAE,CAAC,EAAE,CACJ,wBAAwB,EACxB,CAAC,KAAgC,EAA0C,EAAE;YAC5E,IAAI,CAAC;gBACJ,4EAA4E;gBAC5E,MAAM,IAAI,GAAG,KAAK,EAAE,WAOR,CAAC;gBAEb,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACvC,OAAO,SAAS,CAAC,CAAC,8BAA8B;gBACjD,CAAC;gBAED,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,mBAAmB,EAAE,GAAG,IAAI,CAAC;gBAErE,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;oBAC9E,OAAO,SAAS,CAAC,CAAC,qCAAqC;gBACxD,CAAC;gBAED,4CAA4C;gBAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3E,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAEtC,6CAA6C;gBAC7C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAE3C,2BAA2B;gBAC3B,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAEjD,MAAM,UAAU,GAAqB;oBACpC,OAAO;oBACP,gBAAgB;oBAChB,YAAY;iBACZ,CAAC;gBAEF,OAAO,EAAE,UAAU,EAAE,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACR,qEAAqE;gBACrE,OAAO,SAAS,CAAC;YAClB,CAAC;QACF,CAAC,CACD,CAAC;IACH,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { ExtensionContext, ExtensionFactory, ToolCallEvent, ToolCallEventResult, ToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
/**
|
|
4
|
+
* Return type for tool_result pi handlers — matches ToolResultEventResult from
|
|
5
|
+
* @earendil-works/pi-coding-agent (not exported from the package root).
|
|
6
|
+
* Structural equivalence is sufficient for TypeScript assignability.
|
|
7
|
+
*/
|
|
8
|
+
export interface ToolResultEventResult {
|
|
9
|
+
content?: Array<{
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: "image";
|
|
14
|
+
source: unknown;
|
|
15
|
+
}>;
|
|
16
|
+
details?: unknown;
|
|
17
|
+
isError?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Policy for a single persona/phase combination.
|
|
21
|
+
*
|
|
22
|
+
* residentFields — names of task/sprint record fields that are always retained
|
|
23
|
+
* in context (not trimmed by Mechanism A).
|
|
24
|
+
* toolBudgets — per-tool soft token budget caps (keyed by tool name).
|
|
25
|
+
* T04 reads these when deciding how aggressively to trim tool_result content.
|
|
26
|
+
* steerThreshold — fraction of contextWindow at which Mechanism B fires a
|
|
27
|
+
* budget-steer note (0–1; e.g. 0.80 = steer when 80% of window is used).
|
|
28
|
+
*/
|
|
29
|
+
export interface PhasePolicy {
|
|
30
|
+
residentFields: string[];
|
|
31
|
+
toolBudgets: Record<string, number>;
|
|
32
|
+
steerThreshold: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Lookup table keyed by `"${persona}/${phase}"` (e.g. `"architect/plan"`,
|
|
36
|
+
* `"engineer/review"`) plus a `"default"` entry for unknown combinations.
|
|
37
|
+
*/
|
|
38
|
+
export type PhasePolicyTable = Record<string, PhasePolicy>;
|
|
39
|
+
/**
|
|
40
|
+
* Governor interface wired into hook-dispatcher.ts.
|
|
41
|
+
* T03: both methods return undefined/void (no-op). T04 supplies live curation
|
|
42
|
+
* logic via createGovernor.
|
|
43
|
+
*
|
|
44
|
+
* MUST NOT throw — IL7. Any internal failure must return undefined silently.
|
|
45
|
+
*/
|
|
46
|
+
export interface ContextGovernor {
|
|
47
|
+
/**
|
|
48
|
+
* Called after the triage-error block in the tool_result handler.
|
|
49
|
+
* Return a ToolResultEventResult to replace the event content, or undefined
|
|
50
|
+
* to pass through unchanged.
|
|
51
|
+
*/
|
|
52
|
+
applyToolResult(event: ToolResultEvent, ctx: ExtensionContext): ToolResultEventResult | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Called at the tail of the tool_call handler (after all existing guards).
|
|
55
|
+
* Return a ToolCallEventResult to block or modify the call, or undefined/void
|
|
56
|
+
* to pass through unchanged.
|
|
57
|
+
*/
|
|
58
|
+
applyToolCall(event: ToolCallEvent, ctx: ExtensionContext): ToolCallEventResult | void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns a ContextGovernor whose methods are pure pass-throughs.
|
|
62
|
+
* Used as the default in registerHookDispatcher so existing callers that do
|
|
63
|
+
* not pass a governor see zero behavioural change.
|
|
64
|
+
*/
|
|
65
|
+
export declare function createNoOpGovernor(): ContextGovernor;
|
|
66
|
+
/** Fallback context window when neither ctx.model nor modelRegistry can supply one. */
|
|
67
|
+
export declare const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
68
|
+
/**
|
|
69
|
+
* Create a governor backed by the given policy table and model registry.
|
|
70
|
+
*
|
|
71
|
+
* Implements Mechanism A curation rules (T04):
|
|
72
|
+
* Rule 1 — Dedup/reference-ize
|
|
73
|
+
* Rule 2 — Schema-trim (forge_store results)
|
|
74
|
+
* Rule 3 — Span-clamp (bash/grep/find/read results)
|
|
75
|
+
*
|
|
76
|
+
* Implements Mechanism B (T05):
|
|
77
|
+
* Budget meter: per-turn ctx.getContextUsage() → ctx.ui.setStatus("forge:ctx-budget", ...)
|
|
78
|
+
* Steer: one-shot note at policy.steerThreshold, injected via steerFn
|
|
79
|
+
*
|
|
80
|
+
* Implements Mechanism C (T06):
|
|
81
|
+
* Checkpoint-and-shed: forge_store results for summarized entities are evicted
|
|
82
|
+
* and replaced with an eviction pointer; unsummarized material is retained.
|
|
83
|
+
* Shed criterion: summarySentinel(phaseKey, entityId) returns true.
|
|
84
|
+
*
|
|
85
|
+
* @param table Phase-policy table (keyed by "persona/phase").
|
|
86
|
+
* @param _modelRegistry Model registry (fallback contextWindow resolution only).
|
|
87
|
+
* @param steerFn Optional callback injected at construction by registerHookDispatcher.
|
|
88
|
+
* Receives the steer message string; called at most once per governor
|
|
89
|
+
* instance (single-fire invariant). Callers that omit this see no steer.
|
|
90
|
+
* @param summarySentinel Optional read-only probe injected at construction (Mechanism C / T06).
|
|
91
|
+
* Receives (phaseKey, entityId); returns true when a {PHASE}-SUMMARY.json
|
|
92
|
+
* has been durably written for that entity. When true, the forge_store result
|
|
93
|
+
* is replaced with an eviction pointer. Callers that omit this param see no
|
|
94
|
+
* shedding (backwards-compatible; undefined default).
|
|
95
|
+
* The sentinel MUST NOT write to .forge/store/ or the summary itself (Pack 07).
|
|
96
|
+
* Errors inside the sentinel are silently caught and cause retain, not eviction (IL7).
|
|
97
|
+
*
|
|
98
|
+
* contextWindow resolution order (provider-neutral):
|
|
99
|
+
* 1. usage.contextWindow from ctx.getContextUsage() — direct, when available
|
|
100
|
+
* 2. ctx.model?.contextWindow — active model
|
|
101
|
+
* 3. ctx.modelRegistry.find(provider, modelId)?.contextWindow — registry backup
|
|
102
|
+
* 4. DEFAULT_CONTEXT_WINDOW (200_000) — conservative fallback
|
|
103
|
+
* @param compactFn opt callback injected at construction (Mechanism E / T09).
|
|
104
|
+
* Called proactively once when fraction >= policy.steerThreshold,
|
|
105
|
+
* via a single-fire `compactFired` flag distinct from `steerFired`.
|
|
106
|
+
* Callers pass `compactFn = () => session.compact()`. Errors inside
|
|
107
|
+
* compactFn are caught and written to stderr (IL7). Omitting this
|
|
108
|
+
* param is backwards-compatible — no compact trigger fires.
|
|
109
|
+
* @param phaseKey opt construction-time phase key override ("persona/role").
|
|
110
|
+
* Production paths MUST pass this (via buildGovernorFactory) —
|
|
111
|
+
* pi never populates persona/phase on ExtensionContext, so the
|
|
112
|
+
* ctx probe always resolves "default" at runtime. Omitting it
|
|
113
|
+
* preserves the legacy ctx-probe behaviour (test harnesses).
|
|
114
|
+
*/
|
|
115
|
+
export declare function createGovernor(table: PhasePolicyTable, _modelRegistry: ModelRegistry, steerFn?: (message: string) => void, summarySentinel?: (phaseKey: string, entityId: string) => boolean, compactFn?: () => void, phaseKey?: string): ContextGovernor;
|
|
116
|
+
/**
|
|
117
|
+
* Load the built-in phase-policy table.
|
|
118
|
+
*
|
|
119
|
+
* Ships an entry for every governed run-task PHASE_PIPELINE key
|
|
120
|
+
* (`${personaNoun}/${role}` — engineer/plan, supervisor/review-plan,
|
|
121
|
+
* engineer/implement, supervisor/review-code, qa-engineer/validate,
|
|
122
|
+
* architect/approve) plus "default" for any unlisted persona/phase.
|
|
123
|
+
* writeback/commit intentionally stay on "default" — small phases whose
|
|
124
|
+
* git/store output must not be clamped.
|
|
125
|
+
*
|
|
126
|
+
* `read` budgets are deliberately more generous than `bash` — clamping file
|
|
127
|
+
* reads too tightly degrades implement/review quality (the agent cannot see
|
|
128
|
+
* whole files), while bash output (store-cli reads, test logs, greps) is the
|
|
129
|
+
* dominant context bloat observed in the CART-S02-T03 baseline.
|
|
130
|
+
*
|
|
131
|
+
* Legacy design-time keys ("architect/plan", "engineer/review") are retained
|
|
132
|
+
* for existing test fixtures; the pipeline never produces them.
|
|
133
|
+
*
|
|
134
|
+
* Values are conservative design-time decisions; a future task can promote
|
|
135
|
+
* specific fields to project config once per-project tuning evidence exists.
|
|
136
|
+
*/
|
|
137
|
+
export declare function loadDefaultPolicyTable(): PhasePolicyTable;
|
|
138
|
+
/** Options for buildGovernorFactory. */
|
|
139
|
+
export interface GovernorFactoryOptions {
|
|
140
|
+
/**
|
|
141
|
+
* Pipeline phase key, `${personaNoun}/${role}` (e.g. "supervisor/review-code").
|
|
142
|
+
* Known to run-task.ts at dispatch time; injected here because pi never
|
|
143
|
+
* populates persona/phase on ExtensionContext.
|
|
144
|
+
*/
|
|
145
|
+
phaseKey: string;
|
|
146
|
+
/** Project cwd — root containing `.forge/store/` (sentinel reads only). */
|
|
147
|
+
cwd: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Build an ExtensionFactory that registers a fully-wired context governor in a
|
|
151
|
+
* subagent session. Constructed per-phase by run-task.ts (which knows the
|
|
152
|
+
* persona/role) and passed via RunSubagentOptions.extensionFactories —
|
|
153
|
+
* the same injection channel as buildForgeCompactionFactory (Mechanism E).
|
|
154
|
+
*
|
|
155
|
+
* This is the production wiring the original FORGE-S30-T07 integration missed:
|
|
156
|
+
* registerHookDispatcher(pi, …, governor) in index.ts only governs the PARENT
|
|
157
|
+
* session, while every phase runs in an isolated createAgentSession subagent
|
|
158
|
+
* that the parent's hooks never see. The CART-S02-T03 benchmark confirmed the
|
|
159
|
+
* result: zero curation markers across a full FORGE_CTX_GOVERNOR=1 phase.
|
|
160
|
+
*
|
|
161
|
+
* Wiring supplied here:
|
|
162
|
+
* phaseKey — construction-time (Mechanism D policies finally reachable)
|
|
163
|
+
* steerFn — pi.sendUserMessage(msg, { deliverAs: "steer" }) (Mechanism B)
|
|
164
|
+
* summarySentinel — storeSummarySentinel against .forge/store/ (Mechanism C)
|
|
165
|
+
* compactFn — ctx.compact() proactive trigger (Mechanism E)
|
|
166
|
+
*
|
|
167
|
+
* steer uses the session-scoped ExtensionAPI directly; compact rides the
|
|
168
|
+
* ExtensionContext captured at the start of each handler invocation — it only
|
|
169
|
+
* fires synchronously inside applyToolResult, so the captured ctx is always
|
|
170
|
+
* the live one. All callbacks are guarded: failures fall through silently
|
|
171
|
+
* (IL7); the factory never writes to .forge/store/ (Pack 07).
|
|
172
|
+
*/
|
|
173
|
+
export declare function buildGovernorFactory(opts: GovernorFactoryOptions): ExtensionFactory;
|