@synergenius/flow-weaver-pack-weaver 0.9.0 → 0.9.4
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/dist/bot/ai-client.d.ts +22 -2
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +168 -20
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/ansi.d.ts +13 -0
- package/dist/bot/ansi.d.ts.map +1 -0
- package/dist/bot/ansi.js +13 -0
- package/dist/bot/ansi.js.map +1 -0
- package/dist/bot/assistant-core.d.ts +25 -0
- package/dist/bot/assistant-core.d.ts.map +1 -0
- package/dist/bot/assistant-core.js +272 -0
- package/dist/bot/assistant-core.js.map +1 -0
- package/dist/bot/assistant-tools.d.ts +10 -0
- package/dist/bot/assistant-tools.d.ts.map +1 -0
- package/dist/bot/assistant-tools.js +324 -0
- package/dist/bot/assistant-tools.js.map +1 -0
- package/dist/bot/audit-logger.d.ts.map +1 -1
- package/dist/bot/audit-logger.js +9 -5
- package/dist/bot/audit-logger.js.map +1 -1
- package/dist/bot/bot-manager.d.ts +49 -0
- package/dist/bot/bot-manager.d.ts.map +1 -0
- package/dist/bot/bot-manager.js +279 -0
- package/dist/bot/bot-manager.js.map +1 -0
- package/dist/bot/child-process-tracker.d.ts +6 -0
- package/dist/bot/child-process-tracker.d.ts.map +1 -0
- package/dist/bot/child-process-tracker.js +35 -0
- package/dist/bot/child-process-tracker.js.map +1 -0
- package/dist/bot/cli-provider.d.ts.map +1 -1
- package/dist/bot/cli-provider.js +13 -8
- package/dist/bot/cli-provider.js.map +1 -1
- package/dist/bot/conversation-store.d.ts +40 -0
- package/dist/bot/conversation-store.d.ts.map +1 -0
- package/dist/bot/conversation-store.js +182 -0
- package/dist/bot/conversation-store.js.map +1 -0
- package/dist/bot/error-classifier.d.ts +27 -0
- package/dist/bot/error-classifier.d.ts.map +1 -0
- package/dist/bot/error-classifier.js +71 -0
- package/dist/bot/error-classifier.js.map +1 -0
- package/dist/bot/error-guide.d.ts +5 -0
- package/dist/bot/error-guide.d.ts.map +1 -0
- package/dist/bot/error-guide.js +5 -0
- package/dist/bot/error-guide.js.map +1 -0
- package/dist/bot/knowledge-store.d.ts +17 -0
- package/dist/bot/knowledge-store.d.ts.map +1 -0
- package/dist/bot/knowledge-store.js +53 -0
- package/dist/bot/knowledge-store.js.map +1 -0
- package/dist/bot/paths.d.ts +11 -0
- package/dist/bot/paths.d.ts.map +1 -0
- package/dist/bot/paths.js +26 -0
- package/dist/bot/paths.js.map +1 -0
- package/dist/bot/retry-utils.d.ts +5 -0
- package/dist/bot/retry-utils.d.ts.map +1 -0
- package/dist/bot/retry-utils.js +5 -0
- package/dist/bot/retry-utils.js.map +1 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +12 -1
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/safety.d.ts +10 -0
- package/dist/bot/safety.d.ts.map +1 -0
- package/dist/bot/safety.js +14 -0
- package/dist/bot/safety.js.map +1 -0
- package/dist/bot/session-state.d.ts.map +1 -1
- package/dist/bot/session-state.js +3 -1
- package/dist/bot/session-state.js.map +1 -1
- package/dist/bot/steering.js +2 -2
- package/dist/bot/steering.js.map +1 -1
- package/dist/bot/step-executor.d.ts +10 -5
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +252 -3
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/system-prompt.d.ts +1 -1
- package/dist/bot/system-prompt.d.ts.map +1 -1
- package/dist/bot/system-prompt.js +69 -43
- package/dist/bot/system-prompt.js.map +1 -1
- package/dist/bot/task-decomposer.d.ts +24 -0
- package/dist/bot/task-decomposer.d.ts.map +1 -0
- package/dist/bot/task-decomposer.js +75 -0
- package/dist/bot/task-decomposer.js.map +1 -0
- package/dist/bot/task-queue.d.ts +17 -4
- package/dist/bot/task-queue.d.ts.map +1 -1
- package/dist/bot/task-queue.js +83 -5
- package/dist/bot/task-queue.js.map +1 -1
- package/dist/bot/terminal-renderer.d.ts +60 -0
- package/dist/bot/terminal-renderer.d.ts.map +1 -0
- package/dist/bot/terminal-renderer.js +204 -0
- package/dist/bot/terminal-renderer.js.map +1 -0
- package/dist/bot/tool-registry.d.ts +24 -0
- package/dist/bot/tool-registry.d.ts.map +1 -0
- package/dist/bot/tool-registry.js +458 -0
- package/dist/bot/tool-registry.js.map +1 -0
- package/dist/bot/types.d.ts +7 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/bot/weaver-tools.d.ts +18 -0
- package/dist/bot/weaver-tools.d.ts.map +1 -0
- package/dist/bot/weaver-tools.js +124 -0
- package/dist/bot/weaver-tools.js.map +1 -0
- package/dist/cli-bridge.d.ts.map +1 -1
- package/dist/cli-bridge.js +5 -1
- package/dist/cli-bridge.js.map +1 -1
- package/dist/cli-handlers.d.ts +13 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +615 -48
- package/dist/cli-handlers.js.map +1 -1
- package/dist/mcp-tools.js +2 -2
- package/dist/mcp-tools.js.map +1 -1
- package/dist/node-types/abort-task.d.ts.map +1 -1
- package/dist/node-types/abort-task.js +4 -3
- package/dist/node-types/abort-task.js.map +1 -1
- package/dist/node-types/agent-execute.d.ts +38 -0
- package/dist/node-types/agent-execute.d.ts.map +1 -0
- package/dist/node-types/agent-execute.js +252 -0
- package/dist/node-types/agent-execute.js.map +1 -0
- package/dist/node-types/bot-report.d.ts +5 -3
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +39 -7
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/build-context.d.ts +3 -3
- package/dist/node-types/build-context.d.ts.map +1 -1
- package/dist/node-types/build-context.js +108 -24
- package/dist/node-types/build-context.js.map +1 -1
- package/dist/node-types/detect-provider.d.ts +2 -2
- package/dist/node-types/detect-provider.d.ts.map +1 -1
- package/dist/node-types/detect-provider.js +3 -1
- package/dist/node-types/detect-provider.js.map +1 -1
- package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
- package/dist/node-types/exec-validate-retry.js +43 -6
- package/dist/node-types/exec-validate-retry.js.map +1 -1
- package/dist/node-types/execute-plan.d.ts.map +1 -1
- package/dist/node-types/execute-plan.js +31 -8
- package/dist/node-types/execute-plan.js.map +1 -1
- package/dist/node-types/execute-target.d.ts.map +1 -1
- package/dist/node-types/execute-target.js +3 -1
- package/dist/node-types/execute-target.js.map +1 -1
- package/dist/node-types/fix-errors.d.ts.map +1 -1
- package/dist/node-types/fix-errors.js +21 -5
- package/dist/node-types/fix-errors.js.map +1 -1
- package/dist/node-types/genesis-observe.d.ts.map +1 -1
- package/dist/node-types/genesis-observe.js +3 -1
- package/dist/node-types/genesis-observe.js.map +1 -1
- package/dist/node-types/genesis-report.js +4 -1
- package/dist/node-types/genesis-report.js.map +1 -1
- package/dist/node-types/git-ops.d.ts.map +1 -1
- package/dist/node-types/git-ops.js +98 -4
- package/dist/node-types/git-ops.js.map +1 -1
- package/dist/node-types/index.d.ts +2 -0
- package/dist/node-types/index.d.ts.map +1 -1
- package/dist/node-types/index.js +2 -0
- package/dist/node-types/index.js.map +1 -1
- package/dist/node-types/load-config.d.ts +2 -2
- package/dist/node-types/load-config.d.ts.map +1 -1
- package/dist/node-types/load-config.js.map +1 -1
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +14 -2
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/node-types/read-workflow.js +8 -2
- package/dist/node-types/read-workflow.js.map +1 -1
- package/dist/node-types/receive-task.d.ts.map +1 -1
- package/dist/node-types/receive-task.js +35 -26
- package/dist/node-types/receive-task.js.map +1 -1
- package/dist/node-types/send-notify.js +2 -1
- package/dist/node-types/send-notify.js.map +1 -1
- package/dist/node-types/validate-gate.d.ts +18 -0
- package/dist/node-types/validate-gate.d.ts.map +1 -0
- package/dist/node-types/validate-gate.js +96 -0
- package/dist/node-types/validate-gate.js.map +1 -0
- package/dist/workflows/genesis-task.d.ts +20 -12
- package/dist/workflows/genesis-task.d.ts.map +1 -1
- package/dist/workflows/genesis-task.js +20 -12
- package/dist/workflows/genesis-task.js.map +1 -1
- package/dist/workflows/weaver-agent.d.ts +35 -0
- package/dist/workflows/weaver-agent.d.ts.map +1 -0
- package/dist/workflows/weaver-agent.js +777 -0
- package/dist/workflows/weaver-agent.js.map +1 -0
- package/dist/workflows/weaver-bot-batch.d.ts +19 -26
- package/dist/workflows/weaver-bot-batch.d.ts.map +1 -1
- package/dist/workflows/weaver-bot-batch.js +1043 -27
- package/dist/workflows/weaver-bot-batch.js.map +1 -1
- package/dist/workflows/weaver-bot.d.ts +21 -35
- package/dist/workflows/weaver-bot.d.ts.map +1 -1
- package/dist/workflows/weaver-bot.js +1119 -36
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +21 -1
- package/package.json +5 -2
- package/src/bot/ai-client.ts +180 -19
- package/src/bot/ansi.ts +12 -0
- package/src/bot/assistant-core.ts +312 -0
- package/src/bot/assistant-tools.ts +318 -0
- package/src/bot/audit-logger.ts +6 -5
- package/src/bot/bot-manager.ts +293 -0
- package/src/bot/child-process-tracker.ts +40 -0
- package/src/bot/cli-provider.ts +13 -8
- package/src/bot/conversation-store.ts +222 -0
- package/src/bot/error-classifier.ts +90 -0
- package/src/bot/error-guide.ts +4 -0
- package/src/bot/knowledge-store.ts +59 -0
- package/src/bot/paths.ts +27 -0
- package/src/bot/retry-utils.ts +4 -0
- package/src/bot/runner.ts +12 -1
- package/src/bot/safety.ts +16 -0
- package/src/bot/session-state.ts +2 -1
- package/src/bot/steering.ts +2 -2
- package/src/bot/step-executor.ts +313 -5
- package/src/bot/system-prompt.ts +70 -47
- package/src/bot/task-decomposer.ts +100 -0
- package/src/bot/task-queue.ts +100 -8
- package/src/bot/terminal-renderer.ts +238 -0
- package/src/bot/tool-registry.ts +477 -0
- package/src/bot/types.ts +8 -0
- package/src/bot/weaver-tools.ts +134 -0
- package/src/cli-bridge.ts +7 -1
- package/src/cli-handlers.ts +624 -48
- package/src/mcp-tools.ts +2 -2
- package/src/node-types/abort-task.ts +5 -4
- package/src/node-types/agent-execute.ts +303 -0
- package/src/node-types/bot-report.ts +40 -9
- package/src/node-types/build-context.ts +112 -25
- package/src/node-types/detect-provider.ts +4 -3
- package/src/node-types/exec-validate-retry.ts +47 -8
- package/src/node-types/execute-plan.ts +32 -8
- package/src/node-types/execute-target.ts +2 -1
- package/src/node-types/fix-errors.ts +20 -5
- package/src/node-types/genesis-observe.ts +2 -1
- package/src/node-types/genesis-report.ts +1 -1
- package/src/node-types/git-ops.ts +93 -4
- package/src/node-types/index.ts +2 -0
- package/src/node-types/load-config.ts +3 -3
- package/src/node-types/plan-task.ts +15 -3
- package/src/node-types/read-workflow.ts +2 -2
- package/src/node-types/receive-task.ts +31 -26
- package/src/node-types/send-notify.ts +1 -1
- package/src/node-types/validate-gate.ts +112 -0
- package/src/workflows/genesis-task.ts +20 -12
- package/src/workflows/weaver-agent.ts +799 -0
- package/src/workflows/weaver-bot-batch.ts +1049 -27
- package/src/workflows/weaver-bot.ts +1123 -36
package/src/mcp-tools.ts
CHANGED
|
@@ -206,8 +206,8 @@ export async function registerMcpTools(mcp: McpServer): Promise<void> {
|
|
|
206
206
|
switch (args.action) {
|
|
207
207
|
case 'add': {
|
|
208
208
|
if (!args.task) return { content: [{ type: 'text', text: 'Error: task instruction required' }] };
|
|
209
|
-
const id = await queue.add({ instruction: args.task as string, priority: 0 });
|
|
210
|
-
return { content: [{ type: 'text', text: `Task added: ${id}` }] };
|
|
209
|
+
const { id, duplicate } = await queue.add({ instruction: args.task as string, priority: 0 });
|
|
210
|
+
return { content: [{ type: 'text', text: duplicate ? `Task already queued (${id})` : `Task added: ${id}` }] };
|
|
211
211
|
}
|
|
212
212
|
case 'list':
|
|
213
213
|
return { content: [{ type: 'text', text: JSON.stringify(await queue.list(), null, 2) }] };
|
|
@@ -13,17 +13,18 @@ import type { WeaverContext } from '../bot/types.js';
|
|
|
13
13
|
*/
|
|
14
14
|
export function weaverAbortTask(ctx: string): { ctx: string } {
|
|
15
15
|
const context = JSON.parse(ctx) as WeaverContext;
|
|
16
|
-
const task = JSON.parse(context.taskJson
|
|
16
|
+
const task = context.taskJson ? JSON.parse(context.taskJson) as { instruction?: string } : {};
|
|
17
|
+
const reason = context.rejectionReason ?? 'no reason given';
|
|
17
18
|
const result = {
|
|
18
19
|
success: false,
|
|
19
20
|
outcome: 'aborted',
|
|
20
|
-
summary: `Task aborted: ${
|
|
21
|
-
instruction: task.instruction,
|
|
21
|
+
summary: `Task aborted: ${reason}`,
|
|
22
|
+
instruction: (task as { instruction?: string }).instruction,
|
|
22
23
|
filesModified: [],
|
|
23
24
|
filesCreated: [],
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
console.log(`\x1b[33m→ Task aborted: ${
|
|
27
|
+
console.log(`\x1b[33m→ Task aborted: ${reason}\x1b[0m`);
|
|
27
28
|
|
|
28
29
|
context.resultJson = JSON.stringify(result);
|
|
29
30
|
context.filesModified = '[]';
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import type { WeaverContext } from '../bot/types.js';
|
|
2
|
+
import {
|
|
3
|
+
runAgentLoop,
|
|
4
|
+
createAnthropicProvider,
|
|
5
|
+
getOrCreateCliSession,
|
|
6
|
+
killAllCliSessions,
|
|
7
|
+
type AgentProvider,
|
|
8
|
+
type AgentMessage,
|
|
9
|
+
type ToolDefinition,
|
|
10
|
+
type StreamEvent,
|
|
11
|
+
type StreamOptions,
|
|
12
|
+
type ToolEvent,
|
|
13
|
+
} from '@synergenius/flow-weaver/agent';
|
|
14
|
+
import { WEAVER_TOOLS, createWeaverExecutor } from '../bot/weaver-tools.js';
|
|
15
|
+
import { auditEmit } from '../bot/audit-logger.js';
|
|
16
|
+
import { withRetry, getErrorGuidance } from '../bot/error-classifier.js';
|
|
17
|
+
import { CostTracker } from '../bot/cost-tracker.js';
|
|
18
|
+
|
|
19
|
+
// Clean up persistent sessions on process exit
|
|
20
|
+
let cleanupRegistered = false;
|
|
21
|
+
function registerCleanup(): void {
|
|
22
|
+
if (cleanupRegistered) return;
|
|
23
|
+
cleanupRegistered = true;
|
|
24
|
+
const cleanup = () => { try { killAllCliSessions(); } catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] session cleanup failed:', err); } };
|
|
25
|
+
process.on('exit', cleanup);
|
|
26
|
+
process.on('SIGTERM', cleanup);
|
|
27
|
+
process.on('SIGINT', cleanup);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Adapter: wraps a persistent CliSession as an AgentProvider.
|
|
32
|
+
* The agent loop sends full message history each iteration;
|
|
33
|
+
* we only forward the latest user/tool messages since the session
|
|
34
|
+
* maintains its own conversation state.
|
|
35
|
+
*/
|
|
36
|
+
class CliSessionProvider implements AgentProvider {
|
|
37
|
+
private sentCount = 0;
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
private session: { ready: boolean; spawn: () => Promise<void>; send: (msg: string, systemPrompt?: string) => AsyncGenerator<StreamEvent> },
|
|
41
|
+
) {}
|
|
42
|
+
|
|
43
|
+
async *stream(
|
|
44
|
+
messages: AgentMessage[],
|
|
45
|
+
_tools: ToolDefinition[],
|
|
46
|
+
options?: StreamOptions,
|
|
47
|
+
): AsyncGenerator<StreamEvent> {
|
|
48
|
+
if (!this.session.ready) await this.session.spawn();
|
|
49
|
+
|
|
50
|
+
// Only send new messages (session has history of previous ones)
|
|
51
|
+
const newMessages = messages.slice(this.sentCount);
|
|
52
|
+
this.sentCount = messages.length;
|
|
53
|
+
|
|
54
|
+
// Format new messages into a prompt string
|
|
55
|
+
const prompt = newMessages
|
|
56
|
+
.map((m) => {
|
|
57
|
+
if (m.role === 'user') return typeof m.content === 'string' ? m.content : JSON.stringify(m.content);
|
|
58
|
+
if (m.role === 'tool') return `Tool result (${m.toolCallId}): ${typeof m.content === 'string' ? m.content : JSON.stringify(m.content)}`;
|
|
59
|
+
return '';
|
|
60
|
+
})
|
|
61
|
+
.filter(Boolean)
|
|
62
|
+
.join('\n');
|
|
63
|
+
|
|
64
|
+
if (!prompt) return;
|
|
65
|
+
|
|
66
|
+
// Only pass system prompt on the first call
|
|
67
|
+
const systemPrompt = this.sentCount <= messages.length ? options?.systemPrompt : undefined;
|
|
68
|
+
yield* this.session.send(prompt, systemPrompt);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Reset for a new task (new conversation context) */
|
|
72
|
+
resetForNewTask(): void {
|
|
73
|
+
this.sentCount = 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Test-only export (tree-shaken in production bundles)
|
|
78
|
+
export { CliSessionProvider };
|
|
79
|
+
|
|
80
|
+
// Re-use StepLogEntry shape from the bot types
|
|
81
|
+
type LocalStepLogEntry = { step: string; status: string; detail: string };
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Tool-use agent execution. Claude drives the entire task via tool calls
|
|
85
|
+
* (validate, read-file, patch-file, run-shell, etc.) in a single continuous
|
|
86
|
+
* conversation. No separate plan or retry loop needed.
|
|
87
|
+
*
|
|
88
|
+
* @flowWeaver nodeType
|
|
89
|
+
* @label Agent Execute
|
|
90
|
+
* @input ctx [order:0] - Weaver context (JSON)
|
|
91
|
+
* @output ctx [order:0] - Weaver context with results (JSON)
|
|
92
|
+
* @output onSuccess [order:-2] - On Success
|
|
93
|
+
* @output onFailure [order:-1] [hidden] - On Failure
|
|
94
|
+
*/
|
|
95
|
+
export async function weaverAgentExecute(
|
|
96
|
+
execute: boolean,
|
|
97
|
+
ctx: string,
|
|
98
|
+
): Promise<{
|
|
99
|
+
onSuccess: boolean; onFailure: boolean;
|
|
100
|
+
ctx: string;
|
|
101
|
+
}> {
|
|
102
|
+
const context = JSON.parse(ctx) as WeaverContext;
|
|
103
|
+
const { env } = context;
|
|
104
|
+
|
|
105
|
+
if (!execute) {
|
|
106
|
+
context.resultJson = JSON.stringify({ success: true, toolCallCount: 0 });
|
|
107
|
+
context.validationResultJson = '[]';
|
|
108
|
+
context.filesModified = '[]';
|
|
109
|
+
context.stepLogJson = '[]';
|
|
110
|
+
context.allValid = true;
|
|
111
|
+
return { onSuccess: true, onFailure: false, ctx: JSON.stringify(context) };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const { providerInfo: pInfo, projectDir } = env;
|
|
115
|
+
const task = JSON.parse(context.taskJson!);
|
|
116
|
+
|
|
117
|
+
// Build system prompt
|
|
118
|
+
let systemPrompt: string;
|
|
119
|
+
try {
|
|
120
|
+
const mod = await import('../bot/system-prompt.js');
|
|
121
|
+
const basePrompt = await mod.buildSystemPrompt();
|
|
122
|
+
let cliCommands: { name: string; description: string; botCompatible?: boolean; options?: { flags: string; arg?: string; description: string }[] }[] = [];
|
|
123
|
+
try {
|
|
124
|
+
const docMeta = await import('@synergenius/flow-weaver/doc-metadata');
|
|
125
|
+
cliCommands = docMeta.CLI_COMMANDS ?? [];
|
|
126
|
+
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] doc-metadata unavailable (older fw):', err); }
|
|
127
|
+
const botPrompt = mod.buildBotSystemPrompt(context.contextBundle, cliCommands, projectDir);
|
|
128
|
+
systemPrompt = basePrompt + '\n\n' + botPrompt;
|
|
129
|
+
} catch (err) {
|
|
130
|
+
if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] system prompt build failed, using fallback:', err);
|
|
131
|
+
systemPrompt = 'You are Weaver, an AI workflow bot. Use the provided tools to complete tasks.';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const taskPrompt = `Task: ${task.instruction}\nProject directory: ${projectDir}\n${task.targets ? 'Target files: ' + task.targets.join(', ') : ''}`;
|
|
135
|
+
|
|
136
|
+
// Create renderer — single source of all terminal output
|
|
137
|
+
const { TerminalRenderer } = await import('../bot/terminal-renderer.js');
|
|
138
|
+
const renderer = new TerminalRenderer({ verbose: !!process.env.WEAVER_VERBOSE });
|
|
139
|
+
|
|
140
|
+
auditEmit('run-start', { task: task.instruction });
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const provider = createProvider(pInfo, projectDir);
|
|
144
|
+
const executor = createWeaverExecutor(projectDir);
|
|
145
|
+
|
|
146
|
+
const filesModified: string[] = [];
|
|
147
|
+
const stepLog: LocalStepLogEntry[] = [];
|
|
148
|
+
const taskStart = Date.now();
|
|
149
|
+
|
|
150
|
+
// Route tool events through renderer + track state
|
|
151
|
+
const onToolEvent = (event: ToolEvent) => {
|
|
152
|
+
renderer.onToolEvent(event);
|
|
153
|
+
|
|
154
|
+
if (event.type === 'tool_call_result') {
|
|
155
|
+
stepLog.push({
|
|
156
|
+
step: event.name,
|
|
157
|
+
status: event.isError ? 'error' : 'ok',
|
|
158
|
+
detail: event.isError ? (event.result ?? '').slice(0, 200) : event.name,
|
|
159
|
+
});
|
|
160
|
+
if ((event.name === 'patch_file' || event.name === 'write_file') && !event.isError && event.args?.file) {
|
|
161
|
+
filesModified.push(event.args.file as string);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const onStreamEvent = (event: StreamEvent) => renderer.onStreamEvent(event);
|
|
167
|
+
|
|
168
|
+
const result = await withRetry(
|
|
169
|
+
() => runAgentLoop(
|
|
170
|
+
provider,
|
|
171
|
+
WEAVER_TOOLS,
|
|
172
|
+
executor,
|
|
173
|
+
[{ role: 'user', content: taskPrompt }],
|
|
174
|
+
{ systemPrompt, maxIterations: 15, onToolEvent, onStreamEvent },
|
|
175
|
+
),
|
|
176
|
+
{
|
|
177
|
+
maxRetries: 3,
|
|
178
|
+
baseDelayMs: 5_000,
|
|
179
|
+
onRetry: (attempt, delay, err) => {
|
|
180
|
+
renderer.warn(`Transient error, retrying in ${delay / 1000}s (attempt ${attempt}/3): ${err.message.slice(0, 80)}`);
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const usage = result.usage;
|
|
186
|
+
const model = pInfo.model ?? 'claude-sonnet-4-6';
|
|
187
|
+
const estimatedCost = CostTracker.estimateCost(model, {
|
|
188
|
+
inputTokens: usage.promptTokens,
|
|
189
|
+
outputTokens: usage.completionTokens,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Post-agent validation gate: don't trust the AI's self-assessment
|
|
193
|
+
const uniqueFiles = [...new Set(filesModified)];
|
|
194
|
+
let validationPassed = result.success;
|
|
195
|
+
if (uniqueFiles.length > 0) {
|
|
196
|
+
try {
|
|
197
|
+
const { weaverValidateGate } = await import('./validate-gate.js');
|
|
198
|
+
const gateCtx: WeaverContext = { ...context, filesModified: JSON.stringify(uniqueFiles) };
|
|
199
|
+
const gateResult = weaverValidateGate(JSON.stringify(gateCtx));
|
|
200
|
+
const gateData = JSON.parse(gateResult.ctx) as WeaverContext;
|
|
201
|
+
if (!gateData.allValid) {
|
|
202
|
+
validationPassed = false;
|
|
203
|
+
renderer.warn('Post-agent validation found errors — task marked as failed');
|
|
204
|
+
}
|
|
205
|
+
context.validationResultJson = gateData.validationResultJson;
|
|
206
|
+
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[agent-execute] validate-gate unavailable, skipping:', err); }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
context.resultJson = JSON.stringify({
|
|
210
|
+
success: validationPassed,
|
|
211
|
+
summary: result.summary,
|
|
212
|
+
toolCallCount: result.toolCallCount,
|
|
213
|
+
usage: { inputTokens: usage.promptTokens, outputTokens: usage.completionTokens, estimatedCost },
|
|
214
|
+
});
|
|
215
|
+
context.filesModified = JSON.stringify(uniqueFiles);
|
|
216
|
+
context.stepLogJson = JSON.stringify(stepLog);
|
|
217
|
+
context.allValid = validationPassed;
|
|
218
|
+
|
|
219
|
+
auditEmit('run-complete', {
|
|
220
|
+
success: validationPassed,
|
|
221
|
+
toolCalls: result.toolCallCount,
|
|
222
|
+
filesModified: uniqueFiles.length,
|
|
223
|
+
tokens: { in: usage.promptTokens, out: usage.completionTokens },
|
|
224
|
+
estimatedCost,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
renderer.taskEnd(validationPassed, {
|
|
228
|
+
toolCalls: result.toolCallCount,
|
|
229
|
+
inputTokens: usage.promptTokens,
|
|
230
|
+
outputTokens: usage.completionTokens,
|
|
231
|
+
estimatedCost,
|
|
232
|
+
filesModified: uniqueFiles.length,
|
|
233
|
+
elapsed: Date.now() - taskStart,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
return { onSuccess: validationPassed, onFailure: !validationPassed, ctx: JSON.stringify(context) };
|
|
237
|
+
} catch (err: unknown) {
|
|
238
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
239
|
+
let errorDetail = msg;
|
|
240
|
+
const guidance = getErrorGuidance(msg);
|
|
241
|
+
if (guidance) errorDetail = `${msg}\n Hint: ${guidance}`;
|
|
242
|
+
renderer.error('Agent error', errorDetail);
|
|
243
|
+
|
|
244
|
+
context.resultJson = JSON.stringify({ success: false, error: msg });
|
|
245
|
+
context.filesModified = '[]';
|
|
246
|
+
context.stepLogJson = '[]';
|
|
247
|
+
context.allValid = false;
|
|
248
|
+
|
|
249
|
+
return { onSuccess: false, onFailure: true, ctx: JSON.stringify(context) };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create an AgentProvider from pack-weaver's ProviderInfo.
|
|
255
|
+
*/
|
|
256
|
+
function createProvider(
|
|
257
|
+
pInfo: { type: string; apiKey?: string; model?: string; maxTokens?: number },
|
|
258
|
+
projectDir?: string,
|
|
259
|
+
): AgentProvider {
|
|
260
|
+
const type = pInfo.type ?? 'auto';
|
|
261
|
+
|
|
262
|
+
// Explicit Anthropic API
|
|
263
|
+
if (type === 'anthropic' && pInfo.apiKey) {
|
|
264
|
+
return createAnthropicProvider({
|
|
265
|
+
apiKey: pInfo.apiKey,
|
|
266
|
+
model: pInfo.model,
|
|
267
|
+
maxTokens: pInfo.maxTokens,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Claude CLI — use persistent session for warm start
|
|
272
|
+
if (type === 'claude-cli') {
|
|
273
|
+
return createSessionProvider(pInfo.model, projectDir);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Auto mode: try Anthropic API key from env, then fall back to Claude CLI
|
|
277
|
+
if (type === 'auto') {
|
|
278
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
279
|
+
return createAnthropicProvider({
|
|
280
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
281
|
+
model: pInfo.model,
|
|
282
|
+
maxTokens: pInfo.maxTokens,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// No API key — use Claude CLI with persistent session
|
|
286
|
+
return createSessionProvider(pInfo.model, projectDir);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
throw new Error(
|
|
290
|
+
`Unsupported provider type: ${type}. Use 'anthropic', 'claude-cli', or 'auto'.`,
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function createSessionProvider(model?: string, projectDir?: string): CliSessionProvider {
|
|
295
|
+
registerCleanup();
|
|
296
|
+
const key = projectDir ?? process.cwd();
|
|
297
|
+
const session = getOrCreateCliSession(key, {
|
|
298
|
+
binPath: 'claude',
|
|
299
|
+
cwd: key,
|
|
300
|
+
model: model ?? 'claude-sonnet-4-6',
|
|
301
|
+
});
|
|
302
|
+
return new CliSessionProvider(session);
|
|
303
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
1
4
|
import type { WeaverContext } from '../bot/types.js';
|
|
5
|
+
import { withFileLock } from '../bot/file-lock.js';
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* Generates the final bot session report. Receives context from any
|
|
5
9
|
* of the three paths: read-only, main execution, or abort.
|
|
10
|
+
* Also marks the queue task as completed or failed.
|
|
6
11
|
*
|
|
7
12
|
* @flowWeaver nodeType
|
|
8
|
-
* @expression
|
|
9
13
|
* @label Bot Report
|
|
10
14
|
* @executeWhen DISJUNCTION
|
|
11
15
|
* @input [mainCtx] [order:0] - Context from main path (JSON, optional)
|
|
@@ -15,20 +19,21 @@ import type { WeaverContext } from '../bot/types.js';
|
|
|
15
19
|
* @output reportJson [order:1] [hidden] - Full report (JSON)
|
|
16
20
|
* @output onFailure [hidden]
|
|
17
21
|
*/
|
|
18
|
-
export function weaverBotReport(
|
|
22
|
+
export async function weaverBotReport(
|
|
23
|
+
execute: boolean,
|
|
19
24
|
mainCtx?: string,
|
|
20
25
|
readCtx?: string,
|
|
21
26
|
abortCtx?: string,
|
|
22
|
-
): { summary: string; reportJson: string } {
|
|
27
|
+
): Promise<{ onSuccess: boolean; onFailure: boolean; summary: string; reportJson: string }> {
|
|
23
28
|
const ctxStr = mainCtx ?? readCtx ?? abortCtx;
|
|
24
29
|
|
|
25
|
-
if (!ctxStr) {
|
|
30
|
+
if (!execute || !ctxStr) {
|
|
26
31
|
const report = { task: {}, path: 'unknown', result: null, filesModified: [], gitResult: null, timestamp: Date.now() };
|
|
27
|
-
return { summary: '', reportJson: JSON.stringify(report) };
|
|
32
|
+
return { onSuccess: true, onFailure: false, summary: '', reportJson: JSON.stringify(report) };
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
const context = JSON.parse(ctxStr) as WeaverContext;
|
|
31
|
-
const task = context.taskJson ? JSON.parse(context.taskJson) as { instruction?: string; mode?: string } : {};
|
|
36
|
+
const task = context.taskJson ? JSON.parse(context.taskJson) as { instruction?: string; mode?: string; queueId?: string } : {};
|
|
32
37
|
const files: string[] = context.filesModified ? JSON.parse(context.filesModified) : [];
|
|
33
38
|
const gitResult = context.gitResultJson ? JSON.parse(context.gitResultJson) : null;
|
|
34
39
|
|
|
@@ -52,8 +57,10 @@ export function weaverBotReport(
|
|
|
52
57
|
parts.push(`Task: ${task.instruction}`);
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
const success = result?.success !== false && pathName !== 'abort';
|
|
61
|
+
|
|
55
62
|
if (result) {
|
|
56
|
-
parts.push(`Outcome: ${result.outcome ?? (
|
|
63
|
+
parts.push(`Outcome: ${result.outcome ?? (success ? 'completed' : 'failed')}`);
|
|
57
64
|
if (result.summary) parts.push(`Summary: ${result.summary}`);
|
|
58
65
|
}
|
|
59
66
|
|
|
@@ -67,6 +74,13 @@ export function weaverBotReport(
|
|
|
67
74
|
|
|
68
75
|
const summary = parts.join(' | ');
|
|
69
76
|
|
|
77
|
+
// Mark queue task as completed or failed
|
|
78
|
+
if (task.queueId) {
|
|
79
|
+
try {
|
|
80
|
+
await markQueueTask(task.queueId, success ? 'completed' : 'failed');
|
|
81
|
+
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[bot-report] queue update failed:', err); }
|
|
82
|
+
}
|
|
83
|
+
|
|
70
84
|
const report = {
|
|
71
85
|
task,
|
|
72
86
|
path: pathName,
|
|
@@ -76,7 +90,24 @@ export function weaverBotReport(
|
|
|
76
90
|
timestamp: Date.now(),
|
|
77
91
|
};
|
|
78
92
|
|
|
79
|
-
console.log(`\n\x1b[1m${
|
|
93
|
+
console.log(`\n\x1b[1m${success ? '\x1b[32m' : '\x1b[31m'}Bot Report: ${summary}\x1b[0m\n`);
|
|
94
|
+
|
|
95
|
+
return { onSuccess: success, onFailure: !success, summary, reportJson: JSON.stringify(report) };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function markQueueTask(id: string, status: 'completed' | 'failed'): Promise<void> {
|
|
99
|
+
const queuePath = path.join(os.homedir(), '.weaver', 'task-queue.ndjson');
|
|
100
|
+
if (!fs.existsSync(queuePath)) return;
|
|
80
101
|
|
|
81
|
-
|
|
102
|
+
await withFileLock(queuePath, () => {
|
|
103
|
+
const content = fs.readFileSync(queuePath, 'utf-8').trim();
|
|
104
|
+
if (!content) return;
|
|
105
|
+
const tasks = content.split('\n').filter(Boolean).map(l => JSON.parse(l));
|
|
106
|
+
const task = tasks.find((t: { id: string }) => t.id === id);
|
|
107
|
+
if (task) {
|
|
108
|
+
task.status = status;
|
|
109
|
+
fs.writeFileSync(queuePath, tasks.map((t: unknown) => JSON.stringify(t)).join('\n') + '\n', 'utf-8');
|
|
110
|
+
console.log(`\x1b[36m→ Queue task ${id}: ${status}\x1b[0m`);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
82
113
|
}
|
|
@@ -4,9 +4,9 @@ import * as path from 'node:path';
|
|
|
4
4
|
import type { WeaverContext } from '../bot/types.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Builds the knowledge bundle the AI needs for planning.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Builds the knowledge bundle the AI needs for planning.
|
|
8
|
+
* Adaptive: for modify tasks, includes only grammar + referenced node types.
|
|
9
|
+
* For create tasks, includes full authoring context + templates.
|
|
10
10
|
*
|
|
11
11
|
* @flowWeaver nodeType
|
|
12
12
|
* @expression
|
|
@@ -21,31 +21,81 @@ export function weaverBuildContext(ctx: string): { ctx: string } {
|
|
|
21
21
|
const task = JSON.parse(context.taskJson!) as { mode?: string; targets?: string[] };
|
|
22
22
|
const sections: string[] = [];
|
|
23
23
|
|
|
24
|
+
if (task.mode === 'modify' && task.targets?.length) {
|
|
25
|
+
// Adaptive context: minimal grammar + target files + referenced node types
|
|
26
|
+
sections.push(...buildModifyContext(projectDir, task.targets));
|
|
27
|
+
} else {
|
|
28
|
+
// Full context for create tasks or unknown modes
|
|
29
|
+
sections.push(...buildFullContext(projectDir, task.mode));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const bundle = sections.join('\n\n---\n\n');
|
|
33
|
+
// Output handled by session renderer; keep a dim line for debugging
|
|
34
|
+
if (process.env.WEAVER_VERBOSE) process.stderr.write(`\x1b[2m Context: ${bundle.length} chars\x1b[0m\n`);
|
|
35
|
+
|
|
36
|
+
context.contextBundle = bundle;
|
|
37
|
+
return { ctx: JSON.stringify(context) };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Minimal context for modify tasks: grammar + annotations + target sources + referenced node types. */
|
|
41
|
+
function buildModifyContext(projectDir: string, targets: string[]): string[] {
|
|
42
|
+
const sections: string[] = [];
|
|
43
|
+
|
|
44
|
+
// Minimal grammar (jsdoc-grammar + advanced-annotations only — skip concepts/scaffold/patterns)
|
|
24
45
|
try {
|
|
25
|
-
const ctxOutput = execFileSync(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
timeout: 30_000,
|
|
29
|
-
|
|
30
|
-
}).trim();
|
|
46
|
+
const ctxOutput = execFileSync(
|
|
47
|
+
'flow-weaver',
|
|
48
|
+
['context', '--topics', 'jsdoc-grammar,advanced-annotations', '--profile', 'assistant'],
|
|
49
|
+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 30_000, cwd: projectDir },
|
|
50
|
+
).trim();
|
|
31
51
|
if (ctxOutput) sections.push(ctxOutput);
|
|
32
|
-
} catch {
|
|
52
|
+
} catch (err) {
|
|
53
|
+
if (process.env.WEAVER_VERBOSE) console.error('[build-context] modify context unavailable:', err);
|
|
33
54
|
sections.push('(flow-weaver context not available)');
|
|
34
55
|
}
|
|
35
56
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
// Target file sources + referenced node type sources
|
|
58
|
+
const includedFiles = new Set<string>();
|
|
59
|
+
for (const target of targets) {
|
|
60
|
+
const filePath = path.isAbsolute(target) ? target : path.resolve(projectDir, target);
|
|
61
|
+
try {
|
|
62
|
+
if (!fs.existsSync(filePath)) continue;
|
|
63
|
+
const source = fs.readFileSync(filePath, 'utf-8');
|
|
64
|
+
sections.push(`## Target: ${target}\n\n\`\`\`typescript\n${source}\n\`\`\``);
|
|
65
|
+
includedFiles.add(filePath);
|
|
66
|
+
|
|
67
|
+
// Extract import paths to find referenced node type files
|
|
68
|
+
const nodeTypeSources = extractReferencedNodeTypes(filePath, source, projectDir);
|
|
69
|
+
for (const [relPath, ntSource] of nodeTypeSources) {
|
|
70
|
+
const absPath = path.resolve(projectDir, relPath);
|
|
71
|
+
if (!includedFiles.has(absPath)) {
|
|
72
|
+
includedFiles.add(absPath);
|
|
73
|
+
sections.push(`## Node Type: ${relPath}\n\n\`\`\`typescript\n${ntSource}\n\`\`\``);
|
|
43
74
|
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
75
|
+
}
|
|
76
|
+
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[build-context] unreadable file:', err); }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return sections;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Full context for create tasks: full authoring preset + templates. */
|
|
83
|
+
function buildFullContext(projectDir: string, mode?: string): string[] {
|
|
84
|
+
const sections: string[] = [];
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const ctxOutput = execFileSync(
|
|
88
|
+
'flow-weaver',
|
|
89
|
+
['context', 'authoring', '--profile', 'assistant'],
|
|
90
|
+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 30_000, cwd: projectDir },
|
|
91
|
+
).trim();
|
|
92
|
+
if (ctxOutput) sections.push(ctxOutput);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
if (process.env.WEAVER_VERBOSE) console.error('[build-context] full context unavailable:', err);
|
|
95
|
+
sections.push('(flow-weaver context not available)');
|
|
46
96
|
}
|
|
47
97
|
|
|
48
|
-
if (
|
|
98
|
+
if (mode === 'create') {
|
|
49
99
|
try {
|
|
50
100
|
const templates = execFileSync('flow-weaver', ['list', 'templates'], {
|
|
51
101
|
encoding: 'utf-8',
|
|
@@ -54,12 +104,49 @@ export function weaverBuildContext(ctx: string): { ctx: string } {
|
|
|
54
104
|
cwd: projectDir,
|
|
55
105
|
}).trim();
|
|
56
106
|
if (templates) sections.push(`## Available Templates\n\n${templates}`);
|
|
57
|
-
} catch {
|
|
107
|
+
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[build-context] templates not available:', err); }
|
|
58
108
|
}
|
|
59
109
|
|
|
60
|
-
|
|
61
|
-
|
|
110
|
+
return sections;
|
|
111
|
+
}
|
|
62
112
|
|
|
63
|
-
|
|
64
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Extract node type file sources referenced by a workflow file's imports.
|
|
115
|
+
* Parses import statements to find relative imports from node-types directories.
|
|
116
|
+
*/
|
|
117
|
+
function extractReferencedNodeTypes(
|
|
118
|
+
filePath: string,
|
|
119
|
+
source: string,
|
|
120
|
+
projectDir: string,
|
|
121
|
+
): Array<[relPath: string, source: string]> {
|
|
122
|
+
const results: Array<[string, string]> = [];
|
|
123
|
+
const dir = path.dirname(filePath);
|
|
124
|
+
|
|
125
|
+
// Match: import { ... } from '../node-types/foo.js' or './node-types/bar'
|
|
126
|
+
const importRegex = /import\s+(?:type\s+)?{[^}]+}\s+from\s+['"]([^'"]+)['"]/g;
|
|
127
|
+
let match: RegExpExecArray | null;
|
|
128
|
+
|
|
129
|
+
while ((match = importRegex.exec(source)) !== null) {
|
|
130
|
+
const importPath = match[1];
|
|
131
|
+
// Only include relative imports that look like node type files
|
|
132
|
+
if (!importPath.startsWith('.') && !importPath.startsWith('/')) continue;
|
|
133
|
+
if (!importPath.includes('node-type') && !importPath.includes('node_type')) continue;
|
|
134
|
+
|
|
135
|
+
// Resolve the import to an absolute path
|
|
136
|
+
let resolved = path.resolve(dir, importPath);
|
|
137
|
+
// Try with .ts extension if no extension
|
|
138
|
+
if (!fs.existsSync(resolved)) {
|
|
139
|
+
if (fs.existsSync(resolved + '.ts')) resolved = resolved + '.ts';
|
|
140
|
+
else if (fs.existsSync(resolved.replace(/\.js$/, '.ts'))) resolved = resolved.replace(/\.js$/, '.ts');
|
|
141
|
+
else continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const ntSource = fs.readFileSync(resolved, 'utf-8');
|
|
146
|
+
const relPath = path.relative(projectDir, resolved);
|
|
147
|
+
results.push([relPath, ntSource]);
|
|
148
|
+
} catch (err) { if (process.env.WEAVER_VERBOSE) console.error('[build-context] unreadable node type:', err); }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return results;
|
|
65
152
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import type {
|
|
2
|
+
import type { BotConfig, WeaverEnv, ProviderInfo } from '../bot/types.js';
|
|
3
3
|
|
|
4
4
|
const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
|
|
5
5
|
|
|
@@ -23,7 +23,7 @@ function whichSafe(cmd: string, cwd: string): string {
|
|
|
23
23
|
* @output env [order:0] - Weaver environment bundle
|
|
24
24
|
* @output onFailure [hidden]
|
|
25
25
|
*/
|
|
26
|
-
export function weaverDetectProvider(projectDir: string, config:
|
|
26
|
+
export function weaverDetectProvider(projectDir: string, config: BotConfig): {
|
|
27
27
|
env: WeaverEnv;
|
|
28
28
|
} {
|
|
29
29
|
const providerSetting = config.provider ?? 'auto';
|
|
@@ -69,7 +69,8 @@ export function weaverDetectProvider(projectDir: string, config: WeaverConfig):
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
const label = providerInfo.model ? `${type} (${providerInfo.model})` : type;
|
|
72
|
-
|
|
72
|
+
// Provider info now shown by session renderer; keep for verbose/debug
|
|
73
|
+
if (process.env.WEAVER_VERBOSE) process.stderr.write(`\x1b[2m Provider: ${label}\x1b[0m\n`);
|
|
73
74
|
|
|
74
75
|
return {
|
|
75
76
|
env: { projectDir, config, providerType: type, providerInfo },
|