vigthoria-cli 1.13.18 → 1.13.22

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 (185) hide show
  1. package/completions/_vigthoria +49 -0
  2. package/completions/vigthoria.bash +6 -0
  3. package/completions/vigthoria.fish +41 -0
  4. package/dist/commands/auth.d.ts +1 -0
  5. package/dist/commands/auth.js +84 -135
  6. package/dist/commands/background.d.ts +0 -2
  7. package/dist/commands/background.js +26 -34
  8. package/dist/commands/bridge.js +45 -41
  9. package/dist/commands/cancel.d.ts +1 -0
  10. package/dist/commands/cancel.js +22 -16
  11. package/dist/commands/chat.d.ts +5 -42
  12. package/dist/commands/chat.js +462 -1122
  13. package/dist/commands/coding-registration.d.ts +4 -0
  14. package/dist/commands/coding-registration.js +24 -0
  15. package/dist/commands/config.js +32 -42
  16. package/dist/commands/conversation-registration.d.ts +4 -0
  17. package/dist/commands/conversation-registration.js +122 -0
  18. package/dist/commands/deploy.d.ts +8 -2
  19. package/dist/commands/deploy.js +92 -90
  20. package/dist/commands/device.d.ts +1 -2
  21. package/dist/commands/device.js +37 -21
  22. package/dist/commands/doctor-registration.d.ts +4 -0
  23. package/dist/commands/doctor-registration.js +200 -0
  24. package/dist/commands/edit.js +22 -33
  25. package/dist/commands/explain.js +7 -10
  26. package/dist/commands/fork.d.ts +1 -2
  27. package/dist/commands/fork.js +72 -22
  28. package/dist/commands/game.d.ts +1 -1
  29. package/dist/commands/game.js +17 -6
  30. package/dist/commands/generate.js +7 -9
  31. package/dist/commands/history.js +11 -7
  32. package/dist/commands/hub.d.ts +2 -2
  33. package/dist/commands/hub.js +34 -35
  34. package/dist/commands/legion.d.ts +0 -1
  35. package/dist/commands/legion.js +62 -79
  36. package/dist/commands/music.d.ts +1 -2
  37. package/dist/commands/music.js +62 -27
  38. package/dist/commands/platform-registration.d.ts +4 -0
  39. package/dist/commands/platform-registration.js +45 -0
  40. package/dist/commands/preview.d.ts +0 -1
  41. package/dist/commands/preview.js +82 -35
  42. package/dist/commands/product-run-registration.d.ts +4 -0
  43. package/dist/commands/product-run-registration.js +490 -0
  44. package/dist/commands/replay.d.ts +1 -2
  45. package/dist/commands/replay.js +15 -11
  46. package/dist/commands/repo.d.ts +14 -7
  47. package/dist/commands/repo.js +245 -196
  48. package/dist/commands/review.js +9 -12
  49. package/dist/commands/security.d.ts +1 -2
  50. package/dist/commands/security.js +12 -6
  51. package/dist/commands/update-registration.d.ts +3 -0
  52. package/dist/commands/update-registration.js +338 -0
  53. package/dist/commands/v4-registration.d.ts +4 -0
  54. package/dist/commands/v4-registration.js +24 -0
  55. package/dist/commands/v4.d.ts +1 -1
  56. package/dist/commands/v4.js +46 -8
  57. package/dist/commands/wallet.d.ts +1 -3
  58. package/dist/commands/wallet.js +18 -45
  59. package/dist/commands/workflow.d.ts +2 -0
  60. package/dist/commands/workflow.js +52 -39
  61. package/dist/index.js +122 -1498
  62. package/dist/utils/agent-stream-state.d.ts +27 -0
  63. package/dist/utils/agent-stream-state.js +93 -0
  64. package/dist/utils/agentRoute.d.ts +2 -1
  65. package/dist/utils/agentRoute.js +22 -9
  66. package/dist/utils/agentRunOutcome.d.ts +16 -0
  67. package/dist/utils/agentRunOutcome.js +37 -2
  68. package/dist/utils/api-client-factory.d.ts +8 -0
  69. package/dist/utils/api-client-factory.js +8 -0
  70. package/dist/utils/api.d.ts +45 -269
  71. package/dist/utils/api.js +664 -3210
  72. package/dist/utils/auth-session.d.ts +41 -0
  73. package/dist/utils/auth-session.js +224 -0
  74. package/dist/utils/brain-hub-client.d.ts +0 -4
  75. package/dist/utils/brain-hub-client.js +6 -3
  76. package/dist/utils/bridge-client.js +2 -0
  77. package/dist/utils/capability-health-service.d.ts +48 -0
  78. package/dist/utils/capability-health-service.js +64 -0
  79. package/dist/utils/chat-prompt-policy.d.ts +18 -0
  80. package/dist/utils/chat-prompt-policy.js +61 -0
  81. package/dist/utils/chat-tool-call-parser.d.ts +11 -0
  82. package/dist/utils/chat-tool-call-parser.js +71 -0
  83. package/dist/utils/cli-state.d.ts +22 -4
  84. package/dist/utils/cli-state.js +105 -47
  85. package/dist/utils/code-operations-service.d.ts +104 -0
  86. package/dist/utils/code-operations-service.js +837 -0
  87. package/dist/utils/codebase-indexer.d.ts +1 -0
  88. package/dist/utils/codebase-indexer.js +28 -8
  89. package/dist/utils/command-contract.d.ts +61 -0
  90. package/dist/utils/command-contract.js +149 -0
  91. package/dist/utils/command-policy.d.ts +10 -0
  92. package/dist/utils/command-policy.js +54 -0
  93. package/dist/utils/config.d.ts +13 -5
  94. package/dist/utils/config.js +227 -99
  95. package/dist/utils/context-ranker.js +11 -2
  96. package/dist/utils/context-state.d.ts +39 -0
  97. package/dist/utils/context-state.js +52 -0
  98. package/dist/utils/deckEvents.d.ts +0 -5
  99. package/dist/utils/deckEvents.js +3 -2
  100. package/dist/utils/desktop-bridge-client.js +2 -0
  101. package/dist/utils/direct-output-policy.d.ts +3 -0
  102. package/dist/utils/direct-output-policy.js +76 -0
  103. package/dist/utils/durable-json.d.ts +57 -0
  104. package/dist/utils/durable-json.js +319 -0
  105. package/dist/utils/fastAgentRouter.d.ts +6 -7
  106. package/dist/utils/fastAgentRouter.js +21 -30
  107. package/dist/utils/files.js +21 -13
  108. package/dist/utils/frontend-preview-service.d.ts +76 -0
  109. package/dist/utils/frontend-preview-service.js +482 -0
  110. package/dist/utils/goaEvents.d.ts +0 -4
  111. package/dist/utils/goaEvents.js +5 -2
  112. package/dist/utils/logger.d.ts +2 -1
  113. package/dist/utils/logger.js +27 -20
  114. package/dist/utils/mcp-context-client.d.ts +24 -0
  115. package/dist/utils/mcp-context-client.js +58 -0
  116. package/dist/utils/model-governance.d.ts +18 -0
  117. package/dist/utils/model-governance.js +75 -0
  118. package/dist/utils/model-transport-service.d.ts +44 -0
  119. package/dist/utils/model-transport-service.js +111 -0
  120. package/dist/utils/mutation-journal.d.ts +42 -0
  121. package/dist/utils/mutation-journal.js +387 -0
  122. package/dist/utils/network-policy.d.ts +24 -0
  123. package/dist/utils/network-policy.js +202 -0
  124. package/dist/utils/operator-client.d.ts +45 -0
  125. package/dist/utils/operator-client.js +159 -0
  126. package/dist/utils/post-write-validator.js +7 -9
  127. package/dist/utils/preview-screenshot-adapter.d.ts +13 -0
  128. package/dist/utils/preview-screenshot-adapter.js +36 -0
  129. package/dist/utils/process-policy.d.ts +23 -0
  130. package/dist/utils/process-policy.js +284 -0
  131. package/dist/utils/project-memory.d.ts +13 -3
  132. package/dist/utils/project-memory.js +70 -17
  133. package/dist/utils/prompt-workspace-resolver.d.ts +14 -0
  134. package/dist/utils/prompt-workspace-resolver.js +64 -0
  135. package/dist/utils/release-install.d.ts +11 -0
  136. package/dist/utils/release-install.js +155 -0
  137. package/dist/utils/release-policy.d.ts +64 -0
  138. package/dist/utils/release-policy.js +293 -0
  139. package/dist/utils/requestIntent.js +22 -3
  140. package/dist/utils/runtime-capability.d.ts +8 -0
  141. package/dist/utils/runtime-capability.js +16 -0
  142. package/dist/utils/secret-policy.d.ts +20 -0
  143. package/dist/utils/secret-policy.js +160 -0
  144. package/dist/utils/session.d.ts +34 -2
  145. package/dist/utils/session.js +354 -110
  146. package/dist/utils/tool-approval-service.d.ts +17 -0
  147. package/dist/utils/tool-approval-service.js +78 -0
  148. package/dist/utils/tool-capability-providers.d.ts +57 -0
  149. package/dist/utils/tool-capability-providers.js +57 -0
  150. package/dist/utils/tools.d.ts +2 -23
  151. package/dist/utils/tools.js +216 -508
  152. package/dist/utils/update-policy.d.ts +18 -0
  153. package/dist/utils/update-policy.js +137 -0
  154. package/dist/utils/v3-agent-client.d.ts +40 -0
  155. package/dist/utils/v3-agent-client.js +165 -0
  156. package/dist/utils/v3-workspace-service.d.ts +28 -0
  157. package/dist/utils/v3-workspace-service.js +279 -0
  158. package/dist/utils/vigflow-client.d.ts +95 -0
  159. package/dist/utils/vigflow-client.js +105 -0
  160. package/dist/utils/workspace-boundary.d.ts +45 -0
  161. package/dist/utils/workspace-boundary.js +377 -0
  162. package/dist/utils/workspace-brain-service.d.ts +2 -0
  163. package/dist/utils/workspace-brain-service.js +11 -1
  164. package/dist/utils/workspace-cache.js +37 -15
  165. package/dist/utils/workspace-stream.js +35 -10
  166. package/install.ps1 +86 -143
  167. package/install.sh +76 -81
  168. package/package.json +44 -9
  169. package/release-policy.json +43 -0
  170. package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +1 -1
  171. package/scripts/release/generate-completions.mjs +24 -0
  172. package/scripts/release/install-release.mjs +10 -0
  173. package/scripts/release/publish-cli-release.mjs +116 -0
  174. package/scripts/release/publish-cli-release.sh +2 -70
  175. package/scripts/release/resolve-release-manifest.mjs +26 -0
  176. package/scripts/release/test-balanced-model-live.sh +42 -0
  177. package/scripts/release/validate-live-service-gates.sh +90 -0
  178. package/scripts/release/validate-no-go-gates.sh +135 -172
  179. package/scripts/release/verify-runtime-consistency.mjs +4 -1
  180. package/dist/commands/index.d.ts +0 -12
  181. package/dist/commands/index.js +0 -194
  182. package/dist/commands/update.d.ts +0 -9
  183. package/dist/commands/update.js +0 -301
  184. package/dist/utils/templateInstantPath.d.ts +0 -18
  185. package/dist/utils/templateInstantPath.js +0 -228
@@ -0,0 +1,27 @@
1
+ import type { Ora } from './logger.js';
2
+ export interface AgentStreamStateDependencies {
3
+ isJsonOutput(): boolean;
4
+ idleTimeoutMs(): number;
5
+ }
6
+ /** Owns the mutable lifecycle and deduplication state for one rendered agent stream. */
7
+ export declare class AgentStreamState {
8
+ private readonly dependencies;
9
+ iterationCount: number;
10
+ toolCallCount: number;
11
+ lastActivity: number;
12
+ streamingStarted: boolean;
13
+ streamedAnswerBuffer: string;
14
+ streamedAnswerDisplayed: boolean;
15
+ suppressThinkingStream: boolean;
16
+ startSeen: boolean;
17
+ readonly seenToolCalls: Set<string>;
18
+ readonly seenToolResults: Set<string>;
19
+ private idleWatchInterval;
20
+ private idleNoticeShown;
21
+ constructor(dependencies: AgentStreamStateDependencies);
22
+ reset(): void;
23
+ noteActivity(): void;
24
+ startIdleWatch(spinner: Ora | null): void;
25
+ stopIdleWatch(): void;
26
+ sanitizeVisibleText(text: string): string;
27
+ }
@@ -0,0 +1,93 @@
1
+ import chalk from 'chalk';
2
+ /** Owns the mutable lifecycle and deduplication state for one rendered agent stream. */
3
+ export class AgentStreamState {
4
+ dependencies;
5
+ iterationCount = 0;
6
+ toolCallCount = 0;
7
+ lastActivity = Date.now();
8
+ streamingStarted = false;
9
+ streamedAnswerBuffer = '';
10
+ streamedAnswerDisplayed = false;
11
+ suppressThinkingStream = false;
12
+ startSeen = false;
13
+ seenToolCalls = new Set();
14
+ seenToolResults = new Set();
15
+ idleWatchInterval = null;
16
+ idleNoticeShown = false;
17
+ constructor(dependencies) {
18
+ this.dependencies = dependencies;
19
+ }
20
+ reset() {
21
+ this.iterationCount = 0;
22
+ this.toolCallCount = 0;
23
+ this.lastActivity = Date.now();
24
+ this.streamingStarted = false;
25
+ this.streamedAnswerBuffer = '';
26
+ this.streamedAnswerDisplayed = false;
27
+ this.suppressThinkingStream = false;
28
+ this.startSeen = false;
29
+ this.seenToolCalls.clear();
30
+ this.seenToolResults.clear();
31
+ this.idleNoticeShown = false;
32
+ }
33
+ noteActivity() { this.lastActivity = Date.now(); }
34
+ startIdleWatch(spinner) {
35
+ this.stopIdleWatch();
36
+ if (this.dependencies.isJsonOutput() || !spinner)
37
+ return;
38
+ this.idleWatchInterval = setInterval(() => {
39
+ const idleMs = Date.now() - this.lastActivity;
40
+ if (idleMs < 15_000) {
41
+ this.idleNoticeShown = false;
42
+ return;
43
+ }
44
+ if (this.idleNoticeShown)
45
+ return;
46
+ this.idleNoticeShown = true;
47
+ if (spinner.isSpinning)
48
+ spinner.stop();
49
+ const seconds = Math.round(idleMs / 1000);
50
+ const timeoutSeconds = Math.round(this.dependencies.idleTimeoutMs() / 1000);
51
+ process.stderr.write(chalk.yellow(` [Wait] Model still working (${seconds}s) — this can legitimately take a while for large tasks. `
52
+ + (timeoutSeconds > 0
53
+ ? `Only complete silence (~${timeoutSeconds}s with zero bytes received) will trigger an auto-recover/retry — active progress is never interrupted.\n`
54
+ : '\n')));
55
+ spinner.start();
56
+ spinner.text = 'Waiting for model response...';
57
+ }, 5_000);
58
+ }
59
+ stopIdleWatch() {
60
+ if (this.idleWatchInterval)
61
+ clearInterval(this.idleWatchInterval);
62
+ this.idleWatchInterval = null;
63
+ this.idleNoticeShown = false;
64
+ }
65
+ sanitizeVisibleText(text) {
66
+ let output = String(text || '').replace(/<\/think>/gi, '</thinking>').replace(/<think>/gi, '<thinking>').replace(/<\/redacted_thinking>/gi, '</thinking>');
67
+ if (!output)
68
+ return '';
69
+ if (this.suppressThinkingStream) {
70
+ const closeIndex = output.search(/<\/thinking>/i);
71
+ if (closeIndex < 0)
72
+ return '';
73
+ output = output.slice(closeIndex).replace(/^<\/thinking>/i, '');
74
+ this.suppressThinkingStream = false;
75
+ }
76
+ output = output.replace(/<thinking>[\s\S]*?<\/thinking>/gi, '');
77
+ if (/<thinking>/i.test(output)) {
78
+ output = output.replace(/<thinking>[\s\S]*$/i, '');
79
+ this.suppressThinkingStream = true;
80
+ }
81
+ return output
82
+ .replace(/```json\s*\[\s*\{[\s\S]*?"tool"[\s\S]*?\}\s*\]\s*```/gi, '')
83
+ .replace(/```json\s*\{[\s\S]*?"tool"[\s\S]*?\}\s*```/gi, '')
84
+ .replace(/^\s*(?:json\s*)?\[\s*\{[\s\S]*?"tool"[\s\S]*$/gim, '')
85
+ .replace(/^\s*(?:list_dir|read_file|write_file|edit_file|glob|grep|bash)\s*$/gim, '')
86
+ .replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
87
+ .replace(/<tool_code>[\s\S]*?<\/tool_code>/gi, '')
88
+ .replace(/<read_file>\s*<path>[\s\S]*?<\/path>\s*<\/read_file>/gi, '')
89
+ .replace(/<(?:grep|list_directory|search_files|glob|tool_result)\b[\s\S]*?<\/(?:grep|list_directory|search_files|glob|tool_result)>/gi, '')
90
+ .replace(/bootstrap discovery completed\s*[—-]\s*inspect the most relevant files next\.?/gi, '')
91
+ .replace(/\n{3,}/g, '\n\n');
92
+ }
93
+ }
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Unified agent routing: regex (instant) → optional Balanced 4B → V3 execution hints.
2
+ * Unified agent routing: regex → optional semantic classifier → V3 execution hints.
3
+ * The CLI always dispatches through V3; fastPath and taskKind describe server-side handling.
3
4
  */
4
5
  import type { APIClient } from './api.js';
5
6
  import { type AgentRoutePath } from './fastAgentRouter.js';
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Unified agent routing: regex (instant) → optional Balanced 4B → V3 execution hints.
2
+ * Unified agent routing: regex → optional semantic classifier → V3 execution hints.
3
+ * The CLI always dispatches through V3; fastPath and taskKind describe server-side handling.
3
4
  */
4
5
  import { inferAgentTaskType, isTrivialHtmlPageRequest, isAgentContinuePrompt, isAgentRetryPrompt, hasGameIntent, hasWebPageIntent, taskRequiresWorkspaceChanges, stripExecutionShaping, } from './requestIntent.js';
5
6
  import { isFastInferenceRouterAvailable, routeWithBalanced4b, shouldUseBalancedRouter, } from './fastAgentRouter.js';
@@ -26,10 +27,13 @@ function mergeLlmRoute(regexTask, prompt, parsed) {
26
27
  const llmFast = parsed.fast_path ?? parsed.fastPath ?? undefined;
27
28
  const confidence = Number(parsed.confidence) || 0.75;
28
29
  const reason = String(parsed.reason || 'balanced-4b router');
29
- // Regex game/web signals override wrong LLM labels (hello-world → v3-agent bug).
30
- if (isTrivialHtmlPageRequest(prompt) || (hasWebPageIntent(prompt) && !hasGameIntent(prompt) && llmTask === 'game-build')) {
30
+ // Regex signals are authoritative when the small semantic router confuses
31
+ // web-design language such as "desktop canvas" with an actual playable
32
+ // game. Only genuinely trivial pages belong on template-instant; substantial
33
+ // web builds must retain the full V3 planner/executor path.
34
+ if (isTrivialHtmlPageRequest(prompt)) {
31
35
  return {
32
- path: 'template-instant',
36
+ path: 'v3-agent',
33
37
  taskKind: 'web-build',
34
38
  fastPath: 'template-instant',
35
39
  confidence: Math.max(confidence, 0.92),
@@ -37,10 +41,19 @@ function mergeLlmRoute(regexTask, prompt, parsed) {
37
41
  source: 'merged',
38
42
  };
39
43
  }
44
+ if (hasWebPageIntent(prompt) && !hasGameIntent(prompt) && llmTask === 'game-build') {
45
+ return {
46
+ path: 'v3-agent',
47
+ taskKind: 'web-build',
48
+ confidence: Math.max(confidence, 0.96),
49
+ reason: 'authoritative web-build override for false game classification',
50
+ source: 'merged',
51
+ };
52
+ }
40
53
  if (llmPath === 'template-instant' || llmPath === 'html-template' || llmFast === 'template-instant') {
41
54
  if (hasWebPageIntent(prompt) || isTrivialHtmlPageRequest(prompt)) {
42
55
  return {
43
- path: 'template-instant',
56
+ path: 'v3-agent',
44
57
  taskKind: 'web-build',
45
58
  fastPath: 'template-instant',
46
59
  confidence,
@@ -52,7 +65,7 @@ function mergeLlmRoute(regexTask, prompt, parsed) {
52
65
  if (llmPath === 'analysis-only' || llmTask === 'analysis' || llmTask === 'debugging') {
53
66
  if (!taskRequiresWorkspaceChanges(prompt)) {
54
67
  return {
55
- path: 'analysis-only',
68
+ path: 'v3-agent',
56
69
  taskKind: llmTask === 'debugging' ? 'debugging' : 'analysis',
57
70
  confidence,
58
71
  reason,
@@ -103,7 +116,7 @@ export async function resolveAgentRoute(api, prompt) {
103
116
  }
104
117
  if (isTrivialHtmlPageRequest(stripped)) {
105
118
  return {
106
- path: 'template-instant',
119
+ path: 'v3-agent',
107
120
  taskKind: 'web-build',
108
121
  fastPath: 'template-instant',
109
122
  confidence: 1,
@@ -114,7 +127,7 @@ export async function resolveAgentRoute(api, prompt) {
114
127
  const regexTask = inferAgentTaskType(stripped);
115
128
  if (!taskRequiresWorkspaceChanges(stripped) && (regexTask === 'analysis' || regexTask === 'debugging')) {
116
129
  return {
117
- path: 'analysis-only',
130
+ path: 'v3-agent',
118
131
  taskKind: regexTask,
119
132
  confidence: 0.95,
120
133
  reason: 'read-only analysis (regex)',
@@ -124,7 +137,7 @@ export async function resolveAgentRoute(api, prompt) {
124
137
  if (hasGameIntent(stripped) && regexTask === 'game-build') {
125
138
  if (forceTemplateScaffold() || wantsInstantTemplatePath(stripped)) {
126
139
  return {
127
- path: 'template-instant',
140
+ path: 'v3-agent',
128
141
  taskKind: 'game-build',
129
142
  fastPath: 'template-instant',
130
143
  confidence: 0.98,
@@ -27,6 +27,11 @@ export interface TaskSummaryEvent {
27
27
  task_id?: string;
28
28
  id?: string;
29
29
  }
30
+ export interface RunCompleteTaskEvent {
31
+ tasks_total?: number | string;
32
+ tasks_completed?: number | string;
33
+ tasks_failed?: number | string;
34
+ }
30
35
  export interface RunEvaluation {
31
36
  executorSucceeded: boolean;
32
37
  statusHeadline: string;
@@ -35,6 +40,9 @@ export interface RunEvaluation {
35
40
  export declare function createLiveOutcome(): LiveOutcome;
36
41
  export declare function isExecutorTimeoutFailure(liveOutcome: LiveOutcome): boolean;
37
42
  export declare function isInferenceDegradedFailure(liveOutcome: LiveOutcome): boolean;
43
+ /** Reject a planner summary that labels a task completed while its handoff
44
+ * plainly announces more implementation work. */
45
+ export declare function hasUnfinishedTaskHandoff(text: string): boolean;
38
46
  /** Strip model thinking blocks and stray closing tags from user-visible answer text. */
39
47
  export declare function stripAgentThinkingTags(text: string): string;
40
48
  export declare function isGenericFallbackAnswer(text: string): boolean;
@@ -46,6 +54,14 @@ export declare function isSubstantiveAgentAnswer(text: string): boolean;
46
54
  export declare function normalizeAgentAnswerContent(...sources: Array<string | undefined | null>): string;
47
55
  /** Process executor_complete / task summary events from the V3 SSE stream. */
48
56
  export declare function handleTaskEvent(summary: TaskSummaryEvent, liveOutcome: LiveOutcome): void;
57
+ /** Reconcile counters with the authoritative terminal planner event.
58
+ *
59
+ * Some plans contain a synthetic T00 analysis task which is counted in
60
+ * `tasks_total`/`tasks_completed` but intentionally has no executor_complete
61
+ * event. Without this reconciliation the CLI sees only T01..Tn and exits 1
62
+ * after the server truthfully reports every task complete.
63
+ */
64
+ export declare function handleRunCompleteEvent(event: RunCompleteTaskEvent, liveOutcome: LiveOutcome): void;
49
65
  /** Track read/discovery tool usage for analysis-turn accountability. */
50
66
  export declare function noteAnalysisToolUse(toolName: string, liveOutcome: LiveOutcome): void;
51
67
  /**
@@ -45,6 +45,14 @@ export function isInferenceDegradedFailure(liveOutcome) {
45
45
  return isGenericFallbackAnswer(answer)
46
46
  && (liveOutcome.analysisToolsUsed > 0 || liveOutcome.requiresWorkspaceChanges);
47
47
  }
48
+ /** Reject a planner summary that labels a task completed while its handoff
49
+ * plainly announces more implementation work. */
50
+ export function hasUnfinishedTaskHandoff(text) {
51
+ const normalized = stripAgentThinkingTags(String(text || ''));
52
+ if (!normalized)
53
+ return false;
54
+ return /(?:^|\n)\s*T\d+\s*:\s*(?:i\s+(?:still\s+)?need\s+to|let\s+me\s+(?:apply|implement|finish|complete|run|fix|edit|write|verify|check|test|read)|remaining\s+(?:required\s+)?(?:work|changes?|features?|steps?)|not\s+yet\s+(?:implemented|finished|completed|verified)|unable\s+to\s+(?:complete|apply|implement|finish))/im.test(normalized);
55
+ }
48
56
  function looksLikeRawV3EventPayload(text) {
49
57
  const trimmed = String(text || '').trim();
50
58
  if (!/^[{[]/.test(trimmed))
@@ -174,6 +182,31 @@ export function handleTaskEvent(summary, liveOutcome) {
174
182
  }
175
183
  }
176
184
  }
185
+ /** Reconcile counters with the authoritative terminal planner event.
186
+ *
187
+ * Some plans contain a synthetic T00 analysis task which is counted in
188
+ * `tasks_total`/`tasks_completed` but intentionally has no executor_complete
189
+ * event. Without this reconciliation the CLI sees only T01..Tn and exits 1
190
+ * after the server truthfully reports every task complete.
191
+ */
192
+ export function handleRunCompleteEvent(event, liveOutcome) {
193
+ const total = Number(event.tasks_total);
194
+ const completed = Number(event.tasks_completed);
195
+ const failed = Number(event.tasks_failed);
196
+ if (Number.isFinite(total) && total > 0) {
197
+ liveOutcome.tasksTotal = total;
198
+ }
199
+ if (Number.isFinite(completed) && completed >= 0) {
200
+ liveOutcome.tasksSucceeded = Math.max(liveOutcome.tasksSucceeded, completed);
201
+ }
202
+ if (Number.isFinite(failed)
203
+ && failed === 0
204
+ && liveOutcome.tasksTotal > 0
205
+ && liveOutcome.tasksSucceeded >= liveOutcome.tasksTotal) {
206
+ liveOutcome.failedTaskIds.clear();
207
+ liveOutcome.executorFailed = false;
208
+ }
209
+ }
177
210
  const READ_DISCOVERY_TOOLS = new Set([
178
211
  'read_file',
179
212
  'grep',
@@ -200,10 +233,12 @@ export function noteAnalysisToolUse(toolName, liveOutcome) {
200
233
  * When tasks were planned, ALL must succeed — file changes alone never imply victory.
201
234
  */
202
235
  export function evaluateExecutorSuccess(liveOutcome) {
236
+ const unfinishedTaskHandoff = hasUnfinishedTaskHandoff(liveOutcome.answerContent || '');
203
237
  const hasFatalError = liveOutcome.executorFailed
204
238
  || Boolean(liveOutcome.plannerError)
205
239
  || Boolean(liveOutcome.executorError)
206
- || Boolean(liveOutcome.streamAborted);
240
+ || Boolean(liveOutcome.streamAborted)
241
+ || unfinishedTaskHandoff;
207
242
  if (liveOutcome.streamAborted && liveOutcome.tasksTotal > 0) {
208
243
  const partial = liveOutcome.tasksSucceeded > 0;
209
244
  if (isExecutorTimeoutFailure(liveOutcome)) {
@@ -244,7 +279,7 @@ export function evaluateExecutorSuccess(liveOutcome) {
244
279
  const allTasksPassed = liveOutcome.tasksSucceeded === liveOutcome.tasksTotal;
245
280
  const partialTasksPassed = liveOutcome.tasksSucceeded > 0;
246
281
  const failedCount = liveOutcome.failedTaskIds.size;
247
- if (allTasksPassed && failedCount === 0 && !liveOutcome.streamAborted) {
282
+ if (allTasksPassed && failedCount === 0 && !liveOutcome.streamAborted && !unfinishedTaskHandoff) {
248
283
  const qualityOnlyPlannerNote = Boolean(liveOutcome.plannerError)
249
284
  && /Planner-Executor completed:\s*\d+\s*\/\s*\d+\s+tasks succeeded/i.test(String(liveOutcome.plannerError));
250
285
  const recoveredAfterTransientErrors = liveOutcome.executorFailed
@@ -0,0 +1,8 @@
1
+ import { APIClient, type APIClientDependencies } from './api.js';
2
+ import type { Config } from './config.js';
3
+ import type { Logger } from './logger.js';
4
+ /**
5
+ * The sole production construction boundary for the compatibility API facade.
6
+ * Commands keep owning independent clients until their typed ports are extracted.
7
+ */
8
+ export declare function createAPIClient(config: Config, logger: Logger, dependencies?: APIClientDependencies): APIClient;
@@ -0,0 +1,8 @@
1
+ import { APIClient } from './api.js';
2
+ /**
3
+ * The sole production construction boundary for the compatibility API facade.
4
+ * Commands keep owning independent clients until their typed ports are extracted.
5
+ */
6
+ export function createAPIClient(config, logger, dependencies = {}) {
7
+ return new APIClient(config, logger, dependencies);
8
+ }