pi-harness-runtime 1.1.349 → 1.1.351

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.
Files changed (128) hide show
  1. package/README.md +3 -0
  2. package/package.json +1 -1
  3. package/packages/a2a-adapter/package.json +1 -1
  4. package/packages/agent-policy/package.json +1 -1
  5. package/packages/architecture-generator/package.json +1 -1
  6. package/packages/auth/package.json +1 -1
  7. package/packages/autonomous-refactor/package.json +1 -1
  8. package/packages/autonomous-runtime/package.json +1 -1
  9. package/packages/cache-strategy/package.json +1 -1
  10. package/packages/capability-registry/package.json +1 -1
  11. package/packages/checkpoint/package.json +1 -1
  12. package/packages/cli-plugin-sdk/package.json +1 -1
  13. package/packages/clipboard/package.json +1 -1
  14. package/packages/clipboard-plugin/package.json +1 -1
  15. package/packages/code-generation/package.json +1 -1
  16. package/packages/code-review/package.json +1 -1
  17. package/packages/codex-adapter/package.json +1 -1
  18. package/packages/codex-watcher/package.json +1 -1
  19. package/packages/config-capture/package.json +1 -1
  20. package/packages/connection-runtime/package.json +1 -1
  21. package/packages/context-compiler/package.json +1 -1
  22. package/packages/context-discovery/package.json +1 -1
  23. package/packages/context-manager/package.json +1 -1
  24. package/packages/contracts/dist/delegation-assessor.d.ts +27 -0
  25. package/packages/contracts/dist/delegation-assessor.js +210 -0
  26. package/packages/contracts/dist/delegation-store.d.ts +35 -0
  27. package/packages/contracts/dist/delegation-store.js +172 -0
  28. package/packages/contracts/dist/delegation.d.ts +142 -0
  29. package/packages/contracts/dist/delegation.js +33 -0
  30. package/packages/contracts/dist/index.d.ts +5 -0
  31. package/packages/contracts/dist/index.js +5 -0
  32. package/packages/contracts/dist/scope-discovery.d.ts +65 -0
  33. package/packages/contracts/dist/scope-discovery.js +247 -0
  34. package/packages/contracts/dist/work-partitioner.d.ts +57 -0
  35. package/packages/contracts/dist/work-partitioner.js +165 -0
  36. package/packages/contracts/package.json +1 -1
  37. package/packages/contracts/src/delegation-assessor.ts +268 -0
  38. package/packages/contracts/src/delegation-store.ts +204 -0
  39. package/packages/contracts/src/delegation.ts +174 -0
  40. package/packages/contracts/src/index.ts +5 -0
  41. package/packages/contracts/src/scope-discovery.ts +352 -0
  42. package/packages/contracts/src/work-partitioner.ts +251 -0
  43. package/packages/contracts/test/delegation.test.ts +350 -0
  44. package/packages/cookie-sanitizer/package.json +1 -1
  45. package/packages/cost-optimizer/package.json +1 -1
  46. package/packages/dependency-analyzer/package.json +1 -1
  47. package/packages/django-plugin/package.json +1 -1
  48. package/packages/doc-generator/package.json +1 -1
  49. package/packages/durable-review/package.json +1 -1
  50. package/packages/e2e-tester/package.json +1 -1
  51. package/packages/evaluation-engine/package.json +1 -1
  52. package/packages/evaluation-runner/package.json +1 -1
  53. package/packages/event-bus/package.json +1 -1
  54. package/packages/event-sink/package.json +1 -1
  55. package/packages/event-store/package.json +1 -1
  56. package/packages/experience-replay/package.json +1 -1
  57. package/packages/feedback-collector/package.json +1 -1
  58. package/packages/file-copy-helper/package.json +1 -1
  59. package/packages/framework-detector/package.json +1 -1
  60. package/packages/framework-plugin-sdk/package.json +1 -1
  61. package/packages/frappe-plugin/package.json +1 -1
  62. package/packages/generic-web-plugin/package.json +1 -1
  63. package/packages/health-monitor/package.json +1 -1
  64. package/packages/intent-analyzer/package.json +1 -1
  65. package/packages/jev-judge/package.json +1 -1
  66. package/packages/knowledge-graph/package.json +1 -1
  67. package/packages/knowledge-retrieval/package.json +1 -1
  68. package/packages/laravel-plugin/package.json +1 -1
  69. package/packages/learning-engine/package.json +1 -1
  70. package/packages/mcp-adapter/package.json +1 -1
  71. package/packages/memory-engine/package.json +1 -1
  72. package/packages/milestone-manager/package.json +1 -1
  73. package/packages/model-registry/package.json +1 -1
  74. package/packages/nextjs-plugin/package.json +1 -1
  75. package/packages/notification/package.json +1 -1
  76. package/packages/observability/package.json +1 -1
  77. package/packages/okf-indexer/package.json +1 -1
  78. package/packages/paperclip-integration/package.json +1 -1
  79. package/packages/performance-optimizer/package.json +1 -1
  80. package/packages/permission-mode/package.json +1 -1
  81. package/packages/privilege-broker/package.json +1 -1
  82. package/packages/project-analyzer/package.json +1 -1
  83. package/packages/project-bootstrap/package.json +1 -1
  84. package/packages/projection-engine/package.json +1 -1
  85. package/packages/prompt-compiler/package.json +1 -1
  86. package/packages/prompt-versioning/package.json +1 -1
  87. package/packages/provider-adapter-sdk/package.json +1 -1
  88. package/packages/provider-router/package.json +1 -1
  89. package/packages/provider-selector/package.json +1 -1
  90. package/packages/providers/package.json +1 -1
  91. package/packages/qdrant-skills/package.json +1 -1
  92. package/packages/quota-manager/package.json +1 -1
  93. package/packages/rate-limiter/package.json +1 -1
  94. package/packages/react-vite-plugin/package.json +1 -1
  95. package/packages/relay/package.json +1 -1
  96. package/packages/release-manager/package.json +1 -1
  97. package/packages/requirement-compiler/package.json +1 -1
  98. package/packages/runtime/package.json +1 -1
  99. package/packages/scheduler/package.json +1 -1
  100. package/packages/scheduler-adapter/package.json +1 -1
  101. package/packages/session/package.json +1 -1
  102. package/packages/session-api/package.json +1 -1
  103. package/packages/session-export/package.json +1 -1
  104. package/packages/shared-context/package.json +1 -1
  105. package/packages/skill-mcp-client/package.json +1 -1
  106. package/packages/skill-registry/package.json +1 -1
  107. package/packages/skills/package.json +1 -1
  108. package/packages/sprint-planner/package.json +1 -1
  109. package/packages/subscription-engine/package.json +1 -1
  110. package/packages/task-compiler/package.json +1 -1
  111. package/packages/telegram/package.json +1 -1
  112. package/packages/tencentdb-memory/package.json +1 -1
  113. package/packages/tencentdb-sync/package.json +1 -1
  114. package/packages/test-data-generator/package.json +1 -1
  115. package/packages/test-generator/package.json +1 -1
  116. package/packages/todo-bd-sync/package.json +1 -1
  117. package/packages/token-estimation/package.json +1 -1
  118. package/packages/token-optimizer/package.json +1 -1
  119. package/packages/trajectory/package.json +1 -1
  120. package/packages/tui/package.json +1 -1
  121. package/packages/types/package.json +1 -1
  122. package/packages/voice-api/package.json +1 -1
  123. package/packages/webmcp-tester/package.json +1 -1
  124. package/packages/wiki/package.json +1 -1
  125. package/packages/workflow-events/package.json +1 -1
  126. package/packages/workspace-scanner/package.json +1 -1
  127. package/packages/worktree/package.json +1 -1
  128. package/packages/write-review/package.json +1 -1
package/README.md CHANGED
@@ -30,10 +30,13 @@ pi install npm:pi-harness-runtime
30
30
  This runtime works best with these extensions (auto-installed by pi-harness-runtime):
31
31
 
32
32
  ```bash
33
+ pi install npm:pi-subagents # Sub-agent orchestration for large refactors
33
34
  pi install npm:pi-mcp-adapter # MCP protocol adapter for external tools
34
35
  pi install npm:@juicesharp/rpiv-todo # Task tracking with bd sync
35
36
  ```
36
37
 
38
+ The `pi-subagents` extension enables delegation assessment and parallel task execution for large refactoring work (10+ files, 50+ call sites).
39
+
37
40
  Requires Pi v0.37.3+.
38
41
 
39
42
  ### Headless Server Setup (herdr clipboard bridge)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "[BETA] Codex-style /usage status + autonomous coding harness for pi. Not production ready — expect breaking changes.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/a2a-adapter",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "description": "Google Agent-to-Agent (A2A) protocol adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/agent-policy",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Agent policy runtime for pi-harness - enforces mandatory rule delivery and mutation gating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/architecture-generator",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Generate ADR and Mermaid diagrams from project analysis",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/auth",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "pi-harness-runtime — auth",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-refactor",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "description": "Autonomous refactoring engine",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-runtime",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Autonomous Operations Runtime — task inbox, lease management, and worker lifecycle (RFC-0101)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cache-strategy",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "description": "Smart caching with TTL and invalidation strategies (RFC-0022)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/capability-registry",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/checkpoint",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Enhanced checkpoint system with incremental snapshots, diff-based storage, and recovery strategies",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cli-plugin-sdk",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "description": "CLI Plugin SDK for pi-harness — install, list, remove, update, invoke plugins",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard-plugin",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-generation",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Code generation pipeline for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-review",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Automated code review engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/codex-adapter",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "description": "OpenAI Codex provider adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/codex-watcher",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Watches Codex CLI sessions and emits visible messages for PING-PONG monitoring",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/config-capture",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Auto-capture API-fetched configuration values to AGENTS.md",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/connection-runtime",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "description": "Connection management with jittered exponential backoff for pi-harness",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-compiler",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Bounded context selection engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-discovery",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/context-manager",
3
- "version": "1.1.349",
3
+ "version": "1.1.351",
4
4
  "description": "Context Window Manager — prevents model context overflow via compaction and resume prompts (RFC-0010)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Delegation Assessor
3
+ *
4
+ * Assesses whether work should be delegated to sub-agents based on scope.
5
+ */
6
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
7
+ import type { ScopeFacts, DelegationDecision, DelegationTriggerConfig, ExtensionCapability } from "./delegation.js";
8
+ /**
9
+ * Discover extension capabilities for delegation
10
+ */
11
+ export declare function discoverDelegationCapability(pi: ExtensionAPI): Promise<ExtensionCapability | null>;
12
+ /**
13
+ * Estimate scope from file analysis
14
+ */
15
+ export declare function estimateScope(_pi: ExtensionAPI, patterns: string[]): Promise<ScopeFacts>;
16
+ /**
17
+ * Make deterministic assessment without Jev
18
+ */
19
+ export declare function makeDeterministicAssessment(facts: ScopeFacts, capability: ExtensionCapability | null): DelegationDecision;
20
+ /**
21
+ * Assess delegation need
22
+ */
23
+ export declare function assessDelegation(pi: ExtensionAPI, facts: ScopeFacts, config?: DelegationTriggerConfig): Promise<DelegationDecision | null>;
24
+ /**
25
+ * Validate assessment is still valid
26
+ */
27
+ export declare function isAssessmentStale(decision: DelegationDecision, currentFacts: ScopeFacts, originalFacts: ScopeFacts): boolean;
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Delegation Assessor
3
+ *
4
+ * Assesses whether work should be delegated to sub-agents based on scope.
5
+ */
6
+ import { shouldTriggerAssessment } from "./delegation.js";
7
+ /**
8
+ * Sub-agent extension names to check for
9
+ */
10
+ const SUBAGENT_EXTENSIONS = [
11
+ "pi-subagents",
12
+ "@earendil-works/pi-subagents",
13
+ "subagent",
14
+ "spawn",
15
+ "delegate",
16
+ ];
17
+ /**
18
+ * Tool names that indicate sub-agent capability
19
+ */
20
+ const SUBAGENT_TOOLS = [
21
+ "subagent",
22
+ "spawn",
23
+ "delegate",
24
+ "run_subagent",
25
+ "run_agent",
26
+ ];
27
+ /**
28
+ * Discover extension capabilities for delegation
29
+ */
30
+ export async function discoverDelegationCapability(pi) {
31
+ // Get all available tools
32
+ const allTools = pi.getAllTools();
33
+ const toolNames = allTools.map((t) => t.name);
34
+ const activeTools = pi.getActiveTools();
35
+ // Check for sub-agent tools
36
+ const hasSubagentTool = SUBAGENT_TOOLS.some((tool) => toolNames.includes(tool) || activeTools.includes(tool));
37
+ // Check for subagent extension registration
38
+ // The extension might register tools under different names
39
+ const possibleCapabilities = [];
40
+ // Verify by attempting a capability check
41
+ // If subagent tools exist, assume capability
42
+ if (hasSubagentTool) {
43
+ return {
44
+ name: "subagent-extension",
45
+ supportsSubagents: true,
46
+ supportsWorkIsolation: true, // Assume based on tool presence
47
+ supportsCancellation: true,
48
+ availableTools: activeTools.filter((t) => SUBAGENT_TOOLS.some((st) => t.includes(st))),
49
+ verified: true,
50
+ };
51
+ }
52
+ // Check if pi-subagents skill is mentioned in available tools
53
+ const subagentMentioned = toolNames.some((t) => t.includes("subagent") || t.includes("spawn"));
54
+ if (subagentMentioned) {
55
+ return {
56
+ name: "pi-subagents",
57
+ supportsSubagents: true,
58
+ supportsWorkIsolation: true,
59
+ supportsCancellation: true,
60
+ availableTools: toolNames.filter((t) => t.includes("subagent")),
61
+ verified: false, // Not verified - just mentioned
62
+ };
63
+ }
64
+ return null;
65
+ }
66
+ /**
67
+ * Estimate scope from file analysis
68
+ */
69
+ export async function estimateScope(_pi, patterns) {
70
+ // TODO: Implement actual file discovery
71
+ // For now, return placeholder
72
+ return {
73
+ estimatedFiles: patterns.length,
74
+ observedFiles: 0,
75
+ estimatedCallSites: 0,
76
+ observedCallSites: 0,
77
+ independentComponents: 1,
78
+ tightlyCoupled: false,
79
+ isMechanical: true,
80
+ isComplex: false,
81
+ fileTypes: {},
82
+ fingerprint: "",
83
+ };
84
+ }
85
+ /**
86
+ * Make deterministic assessment without Jev
87
+ */
88
+ export function makeDeterministicAssessment(facts, capability) {
89
+ // No capability - must use single agent
90
+ if (!capability?.verified) {
91
+ return {
92
+ strategy: "unavailable",
93
+ reason: "No verified sub-agent capability available",
94
+ workGroups: [],
95
+ validationExpectations: "Parent handles all validation",
96
+ confidence: "high",
97
+ jevUsed: false,
98
+ reassessmentTriggers: ["Extension becomes available"],
99
+ };
100
+ }
101
+ // Small scope - single agent
102
+ if (facts.observedFiles < 5 && facts.observedCallSites < 20) {
103
+ return {
104
+ strategy: "single_agent",
105
+ reason: "Small scope - delegation overhead not justified",
106
+ workGroups: [],
107
+ validationExpectations: "Standard parent validation",
108
+ confidence: "high",
109
+ jevUsed: false,
110
+ reassessmentTriggers: [],
111
+ };
112
+ }
113
+ // Mechanical transformation with reliable script
114
+ if (facts.isMechanical && !facts.isComplex) {
115
+ return {
116
+ strategy: "script_only",
117
+ reason: "Mechanical transformation - script approach is reliable",
118
+ workGroups: [],
119
+ validationExpectations: "Script output validation + test run",
120
+ confidence: "high",
121
+ jevUsed: false,
122
+ reassessmentTriggers: ["Transformation proves unreliable"],
123
+ };
124
+ }
125
+ // Multiple independent components
126
+ if (facts.independentComponents >= 2 && !facts.tightlyCoupled) {
127
+ const groups = partitionIntoGroups(facts);
128
+ return {
129
+ strategy: "delegate",
130
+ reason: `${facts.independentComponents} independent components - delegation recommended`,
131
+ workGroups: groups,
132
+ validationExpectations: "Each group validated independently, then integrated",
133
+ confidence: "medium",
134
+ jevUsed: false,
135
+ reassessmentTriggers: ["Scope expands significantly", "Component coupling discovered"],
136
+ };
137
+ }
138
+ // Tightly coupled - sequential or single agent
139
+ if (facts.tightlyCoupled) {
140
+ return {
141
+ strategy: "script_then_delegate",
142
+ reason: "Coupled components - script shared parts, delegate isolated changes",
143
+ workGroups: [],
144
+ validationExpectations: "Script validates shared API, delegate validates components",
145
+ confidence: "medium",
146
+ jevUsed: false,
147
+ reassessmentTriggers: ["Coupling reduced after refactoring"],
148
+ };
149
+ }
150
+ // Default - single agent with monitoring
151
+ return {
152
+ strategy: "single_agent",
153
+ reason: "Default to single agent for bounded scope",
154
+ workGroups: [],
155
+ validationExpectations: "Parent validates all changes",
156
+ confidence: "low",
157
+ jevUsed: false,
158
+ reassessmentTriggers: ["Scope exceeds threshold"],
159
+ };
160
+ }
161
+ /**
162
+ * Partition work into groups
163
+ */
164
+ function partitionIntoGroups(facts) {
165
+ const groups = [];
166
+ const filesPerGroup = Math.ceil(facts.observedFiles / facts.independentComponents);
167
+ for (let i = 0; i < facts.independentComponents; i++) {
168
+ groups.push({
169
+ groupId: `group-${i + 1}`,
170
+ description: `Component ${i + 1} of ${facts.independentComponents}`,
171
+ ownedPaths: [], // TODO: Populate with actual files
172
+ isMechanical: facts.isMechanical,
173
+ status: "pending",
174
+ });
175
+ }
176
+ return groups;
177
+ }
178
+ /**
179
+ * Assess delegation need
180
+ */
181
+ export async function assessDelegation(pi, facts, config = { minFiles: 10, minCallSites: 50, minIndependentComponents: 2, assessOnDiscovery: true }) {
182
+ // Check if assessment should trigger
183
+ if (!shouldTriggerAssessment(facts, config)) {
184
+ return null; // No assessment needed
185
+ }
186
+ // Discover capability
187
+ const capability = await discoverDelegationCapability(pi);
188
+ // Make deterministic assessment
189
+ return makeDeterministicAssessment(facts, capability);
190
+ }
191
+ /**
192
+ * Validate assessment is still valid
193
+ */
194
+ export function isAssessmentStale(decision, currentFacts, originalFacts) {
195
+ // Scope significantly expanded
196
+ if (currentFacts.observedFiles > originalFacts.observedFiles * 1.5) {
197
+ return true;
198
+ }
199
+ // New coupling discovered
200
+ if (currentFacts.tightlyCoupled && !originalFacts.tightlyCoupled) {
201
+ return true;
202
+ }
203
+ // Reassessment triggers
204
+ return decision.reassessmentTriggers.some((trigger) => {
205
+ if (trigger.includes("scope expands")) {
206
+ return currentFacts.observedFiles > originalFacts.observedFiles * 1.5;
207
+ }
208
+ return false;
209
+ });
210
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Delegation Store
3
+ *
4
+ * Durable storage for delegation receipts.
5
+ * Stores in ignored harness state directory.
6
+ */
7
+ import type { DelegationReceipt } from "./delegation.js";
8
+ /**
9
+ * Save delegation receipt
10
+ */
11
+ export declare function saveDelegationReceipt(receipt: DelegationReceipt): void;
12
+ /**
13
+ * Load delegation receipt
14
+ */
15
+ export declare function loadDelegationReceipt(workspacePath: string, taskId: string): DelegationReceipt | null;
16
+ /**
17
+ * Delete delegation receipt
18
+ */
19
+ export declare function deleteDelegationReceipt(workspacePath: string, taskId: string): void;
20
+ /**
21
+ * List all receipts for a workspace
22
+ */
23
+ export declare function listDelegationReceipts(workspacePath: string): DelegationReceipt[];
24
+ /**
25
+ * Update receipt status
26
+ */
27
+ export declare function updateReceiptStatus(workspacePath: string, taskId: string, status: DelegationReceipt["status"], updates?: Partial<DelegationReceipt>): DelegationReceipt | null;
28
+ /**
29
+ * Check if receipt exists for task
30
+ */
31
+ export declare function hasReceipt(workspacePath: string, taskId: string): boolean;
32
+ /**
33
+ * Compact receipt for storage after compaction
34
+ */
35
+ export declare function compactReceipt(receipt: DelegationReceipt): DelegationReceipt;
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Delegation Store
3
+ *
4
+ * Durable storage for delegation receipts.
5
+ * Stores in ignored harness state directory.
6
+ */
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
8
+ import { join } from "path";
9
+ /**
10
+ * Store directory path
11
+ */
12
+ const STORE_DIR = join(process.env.HOME || "/home/frappe", ".pi-harness-runtime", "delegation-state");
13
+ /**
14
+ * Ensure store directory exists
15
+ */
16
+ function ensureStoreDir() {
17
+ if (!existsSync(STORE_DIR)) {
18
+ mkdirSync(STORE_DIR, { recursive: true });
19
+ }
20
+ }
21
+ /**
22
+ * Get receipt file path for workspace + task
23
+ */
24
+ function getReceiptPath(workspacePath, taskId) {
25
+ // Sanitize path for use as filename
26
+ const safePath = workspacePath.replace(/[^a-zA-Z0-9_-]/g, "_").slice(-100);
27
+ const safeTask = taskId.replace(/[^a-zA-Z0-9_-]/g, "_");
28
+ return join(STORE_DIR, `${safePath}__${safeTask}.json`);
29
+ }
30
+ /**
31
+ * Save delegation receipt
32
+ */
33
+ export function saveDelegationReceipt(receipt) {
34
+ ensureStoreDir();
35
+ const path = getReceiptPath(receipt.workspacePath, receipt.parentTaskId);
36
+ // Atomic write: write to temp, then rename
37
+ const tempPath = path + ".tmp";
38
+ writeFileSync(tempPath, JSON.stringify(receipt, null, 2), "utf8");
39
+ // Rename is atomic on POSIX
40
+ try {
41
+ const { renameSync } = require("fs");
42
+ renameSync(tempPath, path);
43
+ }
44
+ catch {
45
+ // Fallback: just move the file
46
+ try {
47
+ writeFileSync(path, JSON.stringify(receipt, null, 2), "utf8");
48
+ }
49
+ catch {
50
+ // Ignore write errors
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Load delegation receipt
56
+ */
57
+ export function loadDelegationReceipt(workspacePath, taskId) {
58
+ const path = getReceiptPath(workspacePath, taskId);
59
+ if (!existsSync(path)) {
60
+ return null;
61
+ }
62
+ try {
63
+ const content = readFileSync(path, "utf8");
64
+ const receipt = JSON.parse(content);
65
+ // Validate version
66
+ if (receipt.version !== 1) {
67
+ // Future migration logic would go here
68
+ return null;
69
+ }
70
+ return receipt;
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ /**
77
+ * Delete delegation receipt
78
+ */
79
+ export function deleteDelegationReceipt(workspacePath, taskId) {
80
+ const path = getReceiptPath(workspacePath, taskId);
81
+ if (existsSync(path)) {
82
+ try {
83
+ const { unlinkSync } = require("fs");
84
+ unlinkSync(path);
85
+ }
86
+ catch {
87
+ // Ignore delete errors
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * List all receipts for a workspace
93
+ */
94
+ export function listDelegationReceipts(workspacePath) {
95
+ ensureStoreDir();
96
+ const receipts = [];
97
+ try {
98
+ const { readdirSync } = require("fs");
99
+ const files = readdirSync(STORE_DIR);
100
+ const safePathPrefix = workspacePath.replace(/[^a-zA-Z0-9_-]/g, "_").slice(-100) + "__";
101
+ for (const file of files) {
102
+ if (!file.startsWith(safePathPrefix) || !file.endsWith(".json")) {
103
+ continue;
104
+ }
105
+ try {
106
+ const content = readFileSync(join(STORE_DIR, file), "utf8");
107
+ const receipt = JSON.parse(content);
108
+ if (receipt.workspacePath === workspacePath) {
109
+ receipts.push(receipt);
110
+ }
111
+ }
112
+ catch {
113
+ // Skip invalid files
114
+ }
115
+ }
116
+ }
117
+ catch {
118
+ // Directory doesn't exist or not readable
119
+ }
120
+ return receipts;
121
+ }
122
+ /**
123
+ * Update receipt status
124
+ */
125
+ export function updateReceiptStatus(workspacePath, taskId, status, updates) {
126
+ const receipt = loadDelegationReceipt(workspacePath, taskId);
127
+ if (!receipt) {
128
+ return null;
129
+ }
130
+ const updated = {
131
+ ...receipt,
132
+ ...updates,
133
+ status,
134
+ updatedAt: Date.now(),
135
+ };
136
+ saveDelegationReceipt(updated);
137
+ return updated;
138
+ }
139
+ /**
140
+ * Check if receipt exists for task
141
+ */
142
+ export function hasReceipt(workspacePath, taskId) {
143
+ const path = getReceiptPath(workspacePath, taskId);
144
+ return existsSync(path);
145
+ }
146
+ /**
147
+ * Compact receipt for storage after compaction
148
+ */
149
+ export function compactReceipt(receipt) {
150
+ return {
151
+ version: receipt.version,
152
+ workspacePath: receipt.workspacePath,
153
+ sessionId: receipt.sessionId,
154
+ parentTaskId: receipt.parentTaskId,
155
+ scopeFingerprint: receipt.scopeFingerprint,
156
+ decision: {
157
+ strategy: receipt.decision.strategy,
158
+ reason: receipt.decision.reason,
159
+ workGroups: receipt.decision.workGroups.filter((g) => g.status === "pending" || g.status === "dispatched" || g.status === "running"),
160
+ validationExpectations: receipt.decision.validationExpectations,
161
+ confidence: receipt.decision.confidence,
162
+ jevUsed: receipt.decision.jevUsed,
163
+ reassessmentTriggers: receipt.decision.reassessmentTriggers,
164
+ },
165
+ createdAt: receipt.createdAt,
166
+ updatedAt: Date.now(),
167
+ status: receipt.status,
168
+ childIds: receipt.childIds,
169
+ pendingValidation: receipt.pendingValidation,
170
+ userConstraints: receipt.userConstraints,
171
+ };
172
+ }