@bike4mind/cli 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{package-CMkVxGGC.mjs → package-DNcd24qN.mjs} +1 -1
- package/dist/{tools-QQ6ibgPF.mjs → tools-BhPOnNo3.mjs} +245 -245
- package/package.json +4 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "../package-
|
|
2
|
+
import { t as version } from "../package-DNcd24qN.mjs";
|
|
3
3
|
import { n as compareSemver, r as fetchLatestVersion } from "../updateChecker-D67NPlS5.mjs";
|
|
4
4
|
import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
|
|
5
5
|
import { execSync } from "child_process";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as generateCliTools, G as buildSystemPrompt, J as ReActAgent, N as loadContextFiles, P as PermissionManager, Q as SessionStore, S as ApiClient, T as FallbackLlmBackend, U as setWebSocketToolExecutor, X as CheckpointStore, Y as CustomCommandStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, k as McpManager, m as createCoordinateTaskTool, p as createWriteTodosTool, q as isReadOnlyTool, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-
|
|
2
|
+
import { C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as generateCliTools, G as buildSystemPrompt, J as ReActAgent, N as loadContextFiles, P as PermissionManager, Q as SessionStore, S as ApiClient, T as FallbackLlmBackend, U as setWebSocketToolExecutor, X as CheckpointStore, Y as CustomCommandStore, _ as createAgentDelegateTool, b as createSkillTool, d as createFindDefinitionTool, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, k as McpManager, m as createCoordinateTaskTool, p as createWriteTodosTool, q as isReadOnlyTool, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, y as SubagentOrchestrator } from "../tools-BhPOnNo3.mjs";
|
|
3
3
|
import { n as logger, r as getApiUrl, t as ConfigStore } from "../ConfigStore-C3tokQej.mjs";
|
|
4
4
|
import { t as DEFAULT_SANDBOX_CONFIG } from "../types-LyRNHOiS.mjs";
|
|
5
5
|
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-ChGlxSGQ.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "../package-
|
|
2
|
+
import { t as version } from "../package-DNcd24qN.mjs";
|
|
3
3
|
import { i as forceCheckForUpdate } from "../updateChecker-D67NPlS5.mjs";
|
|
4
4
|
import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
|
|
5
5
|
import { execSync } from "child_process";
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as OAuthClient, A as substituteArguments, B as DEFAULT_THOROUGHNESS, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as generateCliTools, G as buildSystemPrompt, H as registerFeatureModuleTools, I as ALWAYS_DENIED_FOR_AGENTS, J as ReActAgent, K as buildSkillsPromptSection, L as DEFAULT_AGENT_MODEL, M as extractCompactInstructions, N as loadContextFiles, O as isTransientNetworkError, P as PermissionManager, Q as SessionStore, R as DEFAULT_MAX_ITERATIONS, S as ApiClient, T as FallbackLlmBackend, U as setWebSocketToolExecutor, V as clearFeatureModuleTools, W as getPlanModeFilePath, X as CheckpointStore, Y as CustomCommandStore, Z as CommandHistoryStore, _ as createAgentDelegateTool, a as createBlockerTools, at as searchFiles, b as createSkillTool, c as createDecisionStore, d as createFindDefinitionTool, et as hasFileReferences, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as formatFileSize, j as formatStep, k as McpManager, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as searchCommands, o as formatBlockersOutput, ot as warmFileCache, p as createWriteTodosTool, q as isReadOnlyTool, r as formatReviewGatesOutput, rt as mergeCommands, s as createDecisionLogTool, t as createReviewGateStore, tt as processFileReferences, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_RETRY_CONFIG } from "./tools-
|
|
2
|
+
import { $ as OAuthClient, A as substituteArguments, B as DEFAULT_THOROUGHNESS, C as WebSocketToolExecutor, D as ServerLlmBackend, E as WebSocketLlmBackend, F as generateCliTools, G as buildSystemPrompt, H as registerFeatureModuleTools, I as ALWAYS_DENIED_FOR_AGENTS, J as ReActAgent, K as buildSkillsPromptSection, L as DEFAULT_AGENT_MODEL, M as extractCompactInstructions, N as loadContextFiles, O as isTransientNetworkError, P as PermissionManager, Q as SessionStore, R as DEFAULT_MAX_ITERATIONS, S as ApiClient, T as FallbackLlmBackend, U as setWebSocketToolExecutor, V as clearFeatureModuleTools, W as getPlanModeFilePath, X as CheckpointStore, Y as CustomCommandStore, Z as CommandHistoryStore, _ as createAgentDelegateTool, a as createBlockerTools, at as searchFiles, b as createSkillTool, c as createDecisionStore, d as createFindDefinitionTool, et as hasFileReferences, f as createTodoStore, g as BackgroundAgentManager, h as createBackgroundAgentTools, i as createBlockerStore, it as formatFileSize, j as formatStep, k as McpManager, l as formatDecisionsOutput, m as createCoordinateTaskTool, n as createReviewGateTool, nt as searchCommands, o as formatBlockersOutput, ot as warmFileCache, p as createWriteTodosTool, q as isReadOnlyTool, r as formatReviewGatesOutput, rt as mergeCommands, s as createDecisionLogTool, t as createReviewGateStore, tt as processFileReferences, u as createGetFileStructureTool, v as AgentStore, w as WebSocketConnectionManager, x as parseAgentConfig, y as SubagentOrchestrator, z as DEFAULT_RETRY_CONFIG } from "./tools-BhPOnNo3.mjs";
|
|
3
3
|
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-DV5s-qni.mjs";
|
|
4
4
|
import { Ut as validateJupyterKernelName, Wt as validateNotebookPath$1, g as CREDIT_DEDUCT_TRANSACTION_TYPES, i as getEnvironmentName, n as logger, r as getApiUrl, t as ConfigStore, v as ChatModels } from "./ConfigStore-C3tokQej.mjs";
|
|
5
|
-
import { t as version } from "./package-
|
|
5
|
+
import { t as version } from "./package-DNcd24qN.mjs";
|
|
6
6
|
import { t as checkForUpdate } from "./updateChecker-D67NPlS5.mjs";
|
|
7
7
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
8
8
|
import { Box, Static, Text, render, useApp, useInput, usePaste, useStdout } from "ink";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { $ as ProjectEvents, A as GenerateImageToolCallSchema, At as dayjsConfig_default, B as InviteEvents, Bt as sanitizeTelemetryError, C as ElabsEvents, Ct as UnauthorizedError, D as ForbiddenError, Dt as VideoModels, E as FileEvents, Et as VideoGenerationUsageTransaction, F as ImageEditUsageTransaction, Ft as isGPTImage2Model, G as ModalEvents, Gt as buildRateLimitLogEntry, H as KnowledgeType, Ht as settingsMap, I as ImageGenerationUsageTransaction, It as isGPTImageModel, J as OpenAIEmbeddingModel, Jt as parseRateLimitHeaders, K as ModelBackend, Kt as extractSnippetMeta, L as ImageModels, Lt as isZodError, M as GenericCreditDeductTransaction, Mt as getDataLakeTags, N as HTTPError, Nt as getMcpProviderMetadata, O as FriendshipEvents, Ot as XAI_IMAGE_MODELS, P as HttpStatus, Pt as getViewById, Q as ProfileEvents, R as InboxEvents, Rt as obfuscateApiKey, S as DashboardParamsSchema, St as UiNavigationEvents, T as FeedbackEvents, Tt as VIDEO_SIZE_CONSTRAINTS, U as LLMEvents, V as InviteType, Vt as secureParameters, W as MiscEvents, X as Permission, Y as OpenAIImageGenerationInput, Yt as CollectionType, Z as PermissionDeniedError, _ as ChatCompletionCreateInputSchema, _t as TaskScheduleHandler, a as ALERT_THRESHOLDS, at as ReceivedCreditTransaction, b as CompletionApiUsageTransaction, bt as ToolUsageTransaction, c as ApiKeyScope, ct as ResearchModeParamsSchema, d as ArtifactTypeSchema, dt as ResearchTaskType, et as PromptIntentSchema, f as AuthEvents, ft as SessionEvents, gt as TagType, h as BadRequestError, ht as SupportedFabFileMimeTypes, it as RealtimeVoiceUsageTransaction, j as GenericCreditAddTransaction, jt as getAccessibleDataLakes, k as GEMINI_IMAGE_MODELS, kt as b4mLLMTools, l as ApiKeyType, lt as ResearchTaskExecutionType, m as BFL_SAFETY_TOLERANCE, mt as SubscriptionCreditTransaction, n as logger, nt as PurchaseTransaction, o as AiEvents, ot as RechartsChartTypeList, p as BFL_IMAGE_MODELS, pt as SpeechToTextUsageTransaction, q as NotFoundError, qt as isNearLimit, rt as QuestMasterParamsSchema, s as ApiKeyEvents, st as RegInviteEvents, t as ConfigStore, tt as PromptMetaZodSchema, u as AppFileEvents, ut as ResearchTaskPeriodicFrequencyType, v as ChatModels, vt as TextGenerationUsageTransaction, w as FavoriteDocumentType, wt as UnprocessableEntityError, x as CorruptedFileError, xt as TransferCreditTransaction, y as ClaudeArtifactMimeTypes, yt as TooManyRequestsError, z as InternalServerError, zt as resolveNavigationIntents } from "./ConfigStore-C3tokQej.mjs";
|
|
3
3
|
import { a as isUserLockedOut, c as userCanDisableMFA, d as userRequiresMFA, f as verifyBackupCode, i as getLockoutTimeRemaining, l as userEligibleForMFA, n as generateBackupCodes, o as recordFailedAttempt, p as verifyTOTPToken, r as generateTOTPSetup, s as shouldResetFailedAttempts, t as clearFailedAttempts, u as userHasMFAConfigured } from "./utils-PpNti-tY.mjs";
|
|
4
4
|
import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-D8tjkQXE-1HwvsuYT.mjs";
|
|
5
|
-
import { t as version } from "./package-
|
|
5
|
+
import { t as version } from "./package-DNcd24qN.mjs";
|
|
6
6
|
import { execFile, execFileSync, spawn } from "child_process";
|
|
7
7
|
import crypto, { createHash, randomBytes } from "crypto";
|
|
8
8
|
import { existsSync, promises, readFileSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -2994,6 +2994,168 @@ function trimConversationHistory(messages, maxIterations, protectedPrefixCount)
|
|
|
2994
2994
|
const keepFrom = dynamicStart + nudgeIndices[nudgeIndices.length - maxIterations];
|
|
2995
2995
|
messages.splice(dynamicStart, keepFrom - dynamicStart);
|
|
2996
2996
|
}
|
|
2997
|
+
/**
|
|
2998
|
+
* Per-node failure policy.
|
|
2999
|
+
*
|
|
3000
|
+
* `cascade`: if this node fails, all transitive dependents are marked
|
|
3001
|
+
* `cascade_failed` and skipped. (Default.)
|
|
3002
|
+
*
|
|
3003
|
+
* `isolate`: if this node fails, dependents proceed; their dependency
|
|
3004
|
+
* context for this node is null/missing. Used for fan-out research nodes
|
|
3005
|
+
* where one branch failing shouldn't poison the synthesis.
|
|
3006
|
+
*/
|
|
3007
|
+
const FailurePolicySchema = z.enum(["cascade", "isolate"]);
|
|
3008
|
+
const DecomposedTaskSchema = z.object({
|
|
3009
|
+
id: z.string().min(1),
|
|
3010
|
+
description: z.string().min(1),
|
|
3011
|
+
agentType: z.enum([
|
|
3012
|
+
"explore",
|
|
3013
|
+
"plan",
|
|
3014
|
+
"general-purpose",
|
|
3015
|
+
"review",
|
|
3016
|
+
"test"
|
|
3017
|
+
]),
|
|
3018
|
+
dependsOn: z.array(z.string()).default([]),
|
|
3019
|
+
onFailure: FailurePolicySchema.default("cascade")
|
|
3020
|
+
});
|
|
3021
|
+
const DecomposeTaskInputSchema = z.object({ tasks: z.array(DecomposedTaskSchema).min(1, "At least one task is required") });
|
|
3022
|
+
/**
|
|
3023
|
+
* Validate the task graph and return the topological execution levels.
|
|
3024
|
+
*
|
|
3025
|
+
* - All dependency references must point to existing tasks
|
|
3026
|
+
* - No task can depend on itself
|
|
3027
|
+
* - No circular dependencies
|
|
3028
|
+
* - No duplicate task ids
|
|
3029
|
+
*
|
|
3030
|
+
* Throws on any violation. Returns levels (each level's tasks have no
|
|
3031
|
+
* inter-dependencies and can run concurrently).
|
|
3032
|
+
*/
|
|
3033
|
+
function validateAndSort(input) {
|
|
3034
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
3035
|
+
for (const task of input.tasks) {
|
|
3036
|
+
if (tasks.has(task.id)) throw new Error(`Duplicate task id: "${task.id}"`);
|
|
3037
|
+
tasks.set(task.id, task);
|
|
3038
|
+
}
|
|
3039
|
+
for (const [taskId, task] of tasks) for (const depId of task.dependsOn) {
|
|
3040
|
+
if (!tasks.has(depId)) throw new Error(`Task "${taskId}" depends on unknown task "${depId}"`);
|
|
3041
|
+
if (depId === taskId) throw new Error(`Task "${taskId}" cannot depend on itself`);
|
|
3042
|
+
}
|
|
3043
|
+
detectCycles(tasks);
|
|
3044
|
+
return topologicalSort(tasks);
|
|
3045
|
+
}
|
|
3046
|
+
function detectCycles(tasks) {
|
|
3047
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3048
|
+
const inStack = /* @__PURE__ */ new Set();
|
|
3049
|
+
for (const taskId of tasks.keys()) {
|
|
3050
|
+
if (visited.has(taskId)) continue;
|
|
3051
|
+
const stack = [{
|
|
3052
|
+
id: taskId,
|
|
3053
|
+
phase: "enter"
|
|
3054
|
+
}];
|
|
3055
|
+
while (stack.length > 0) {
|
|
3056
|
+
const { id, phase } = stack.pop();
|
|
3057
|
+
if (phase === "exit") {
|
|
3058
|
+
inStack.delete(id);
|
|
3059
|
+
continue;
|
|
3060
|
+
}
|
|
3061
|
+
if (inStack.has(id)) throw new Error(`Circular dependency detected involving task "${id}"`);
|
|
3062
|
+
if (visited.has(id)) continue;
|
|
3063
|
+
visited.add(id);
|
|
3064
|
+
inStack.add(id);
|
|
3065
|
+
stack.push({
|
|
3066
|
+
id,
|
|
3067
|
+
phase: "exit"
|
|
3068
|
+
});
|
|
3069
|
+
const task = tasks.get(id);
|
|
3070
|
+
for (const depId of task.dependsOn) {
|
|
3071
|
+
if (inStack.has(depId)) throw new Error(`Circular dependency detected: "${id}" → "${depId}"`);
|
|
3072
|
+
if (!visited.has(depId)) stack.push({
|
|
3073
|
+
id: depId,
|
|
3074
|
+
phase: "enter"
|
|
3075
|
+
});
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
/**
|
|
3081
|
+
* Kahn's algorithm — group tasks into execution levels.
|
|
3082
|
+
* Tasks within a level have no inter-dependencies.
|
|
3083
|
+
*/
|
|
3084
|
+
function topologicalSort(tasks) {
|
|
3085
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
3086
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
3087
|
+
for (const [taskId, task] of tasks) {
|
|
3088
|
+
inDegree.set(taskId, task.dependsOn.length);
|
|
3089
|
+
for (const depId of task.dependsOn) {
|
|
3090
|
+
const deps = dependents.get(depId) || [];
|
|
3091
|
+
deps.push(taskId);
|
|
3092
|
+
dependents.set(depId, deps);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
const levels = [];
|
|
3096
|
+
let currentLevel = [...tasks.keys()].filter((id) => inDegree.get(id) === 0);
|
|
3097
|
+
while (currentLevel.length > 0) {
|
|
3098
|
+
levels.push(currentLevel);
|
|
3099
|
+
const nextLevel = [];
|
|
3100
|
+
for (const taskId of currentLevel) for (const dependent of dependents.get(taskId) || []) {
|
|
3101
|
+
const newDegree = inDegree.get(dependent) - 1;
|
|
3102
|
+
inDegree.set(dependent, newDegree);
|
|
3103
|
+
if (newDegree === 0) nextLevel.push(dependent);
|
|
3104
|
+
}
|
|
3105
|
+
currentLevel = nextLevel;
|
|
3106
|
+
}
|
|
3107
|
+
return levels;
|
|
3108
|
+
}
|
|
3109
|
+
const DEFAULT_MAX_RESULT_CHARS = 800;
|
|
3110
|
+
/**
|
|
3111
|
+
* Build the final markdown summary + structured result for a DAG execution.
|
|
3112
|
+
*
|
|
3113
|
+
* Shared between the CLI's in-process executor and the web's Lambda-fan-out
|
|
3114
|
+
* executor so the synthesized tool_result that the parent agent sees has
|
|
3115
|
+
* consistent shape across surfaces.
|
|
3116
|
+
*/
|
|
3117
|
+
function buildPipelineResult(taskResults, options = {}) {
|
|
3118
|
+
const maxLen = options.maxResultChars ?? DEFAULT_MAX_RESULT_CHARS;
|
|
3119
|
+
const completed = taskResults.filter((t) => t.status === "completed");
|
|
3120
|
+
const failed = taskResults.filter((t) => t.status === "failed");
|
|
3121
|
+
const cascadeFailed = taskResults.filter((t) => t.status === "cascade_failed");
|
|
3122
|
+
const pending = taskResults.filter((t) => t.status === "pending" || t.status === "running");
|
|
3123
|
+
const success = failed.length === 0 && cascadeFailed.length === 0 && pending.length === 0;
|
|
3124
|
+
const summaryParts = [];
|
|
3125
|
+
if (completed.length > 0) {
|
|
3126
|
+
summaryParts.push(`## Completed Tasks (${completed.length}/${taskResults.length})\n`);
|
|
3127
|
+
for (const task of completed) {
|
|
3128
|
+
summaryParts.push(`### ${task.id}: ${task.description}\n`);
|
|
3129
|
+
summaryParts.push(`*Agent: ${task.agentType}*\n`);
|
|
3130
|
+
if (task.result) {
|
|
3131
|
+
const truncated = task.result.length > maxLen ? task.result.slice(0, maxLen) + "\n...(truncated)" : task.result;
|
|
3132
|
+
summaryParts.push(truncated);
|
|
3133
|
+
}
|
|
3134
|
+
summaryParts.push("");
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
if (failed.length > 0) {
|
|
3138
|
+
summaryParts.push(`## Failed Tasks (${failed.length})\n`);
|
|
3139
|
+
for (const task of failed) {
|
|
3140
|
+
summaryParts.push(`### ${task.id}: ${task.description}\n`);
|
|
3141
|
+
summaryParts.push(`*Agent: ${task.agentType}*\n`);
|
|
3142
|
+
summaryParts.push(`**Error:** ${task.error}\n`);
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
if (cascadeFailed.length > 0) {
|
|
3146
|
+
summaryParts.push(`## Cascade-Failed Tasks (${cascadeFailed.length})\n`);
|
|
3147
|
+
for (const task of cascadeFailed) summaryParts.push(`- ${task.id}: ${task.description} — ${task.error}\n`);
|
|
3148
|
+
}
|
|
3149
|
+
if (pending.length > 0) {
|
|
3150
|
+
summaryParts.push(`## Skipped Tasks (${pending.length})\n`);
|
|
3151
|
+
for (const task of pending) summaryParts.push(`- ${task.id}: ${task.description}\n`);
|
|
3152
|
+
}
|
|
3153
|
+
return {
|
|
3154
|
+
success,
|
|
3155
|
+
taskResults,
|
|
3156
|
+
summary: summaryParts.join("\n")
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
2997
3159
|
String.raw`
|
|
2998
3160
|
const { parentPort } = require('node:worker_threads');
|
|
2999
3161
|
const vm = require('node:vm');
|
|
@@ -12071,7 +12233,7 @@ No markdown, no explanation, no code blocks — just the raw JSON object.`;
|
|
|
12071
12233
|
"Minimize: sum(error^2)"
|
|
12072
12234
|
].join("\n");
|
|
12073
12235
|
//#endregion
|
|
12074
|
-
//#region ../../b4m-core/services/dist/tools-
|
|
12236
|
+
//#region ../../b4m-core/services/dist/tools-CtLkSQLQ.mjs
|
|
12075
12237
|
async function performDeepResearch(context, params, config) {
|
|
12076
12238
|
const maxDepth = config.maxDepth || 7;
|
|
12077
12239
|
const duration = config.duration || 4.5;
|
|
@@ -26154,249 +26316,6 @@ function createBackgroundAgentTools(manager) {
|
|
|
26154
26316
|
];
|
|
26155
26317
|
}
|
|
26156
26318
|
//#endregion
|
|
26157
|
-
//#region src/agents/TaskPipeline.ts
|
|
26158
|
-
/**
|
|
26159
|
-
* Schema for a single decomposed task in the pipeline
|
|
26160
|
-
*/
|
|
26161
|
-
const DecomposedTaskSchema = z.object({
|
|
26162
|
-
/** Unique identifier for this task within the pipeline */
|
|
26163
|
-
id: z.string().min(1),
|
|
26164
|
-
/** Human-readable description of what needs to be done */
|
|
26165
|
-
description: z.string().min(1),
|
|
26166
|
-
/** Which agent type should handle this task */
|
|
26167
|
-
agentType: z.enum([
|
|
26168
|
-
"explore",
|
|
26169
|
-
"plan",
|
|
26170
|
-
"general-purpose",
|
|
26171
|
-
"review",
|
|
26172
|
-
"test"
|
|
26173
|
-
]),
|
|
26174
|
-
/** IDs of tasks that must complete before this one can start */
|
|
26175
|
-
dependsOn: z.array(z.string()).default([])
|
|
26176
|
-
});
|
|
26177
|
-
/**
|
|
26178
|
-
* Schema for the decompose_task tool input
|
|
26179
|
-
*/
|
|
26180
|
-
const DecomposeTaskInputSchema = z.object({ tasks: z.array(DecomposedTaskSchema).min(1, "At least one task is required") });
|
|
26181
|
-
/**
|
|
26182
|
-
* TaskPipeline builds and executes a DAG of tasks with dependency ordering.
|
|
26183
|
-
*
|
|
26184
|
-
* Tasks are executed in topological order. Independent tasks at the same
|
|
26185
|
-
* level can be executed in parallel via the executor callback.
|
|
26186
|
-
*/
|
|
26187
|
-
var TaskPipeline = class {
|
|
26188
|
-
constructor(input) {
|
|
26189
|
-
this.tasks = /* @__PURE__ */ new Map();
|
|
26190
|
-
for (const task of input.tasks) this.tasks.set(task.id, {
|
|
26191
|
-
...task,
|
|
26192
|
-
status: "pending"
|
|
26193
|
-
});
|
|
26194
|
-
this.validate();
|
|
26195
|
-
this.executionOrder = this.topologicalSort();
|
|
26196
|
-
}
|
|
26197
|
-
/**
|
|
26198
|
-
* Get the number of tasks in the pipeline
|
|
26199
|
-
*/
|
|
26200
|
-
get size() {
|
|
26201
|
-
return this.tasks.size;
|
|
26202
|
-
}
|
|
26203
|
-
/**
|
|
26204
|
-
* Get the execution levels (groups of tasks that can run in parallel)
|
|
26205
|
-
*/
|
|
26206
|
-
getExecutionLevels() {
|
|
26207
|
-
return this.executionOrder;
|
|
26208
|
-
}
|
|
26209
|
-
/**
|
|
26210
|
-
* Check if this pipeline contains a single task (skip pipeline overhead)
|
|
26211
|
-
*/
|
|
26212
|
-
isSingleTask() {
|
|
26213
|
-
return this.tasks.size === 1;
|
|
26214
|
-
}
|
|
26215
|
-
/**
|
|
26216
|
-
* Get the single task (for fallback when pipeline has only one task)
|
|
26217
|
-
*/
|
|
26218
|
-
getSingleTask() {
|
|
26219
|
-
if (!this.isSingleTask()) throw new Error("Pipeline has more than one task");
|
|
26220
|
-
return [...this.tasks.values()][0];
|
|
26221
|
-
}
|
|
26222
|
-
/**
|
|
26223
|
-
* Execute all tasks in dependency order.
|
|
26224
|
-
*
|
|
26225
|
-
* Tasks within the same level are executed in parallel.
|
|
26226
|
-
* Each level must complete before the next level starts.
|
|
26227
|
-
* If a task fails, all transitive dependents are cascade-failed.
|
|
26228
|
-
*/
|
|
26229
|
-
async execute(executor) {
|
|
26230
|
-
const results = /* @__PURE__ */ new Map();
|
|
26231
|
-
const failedTaskIds = /* @__PURE__ */ new Set();
|
|
26232
|
-
for (const level of this.executionOrder) {
|
|
26233
|
-
const levelPromises = level.map(async (taskId) => {
|
|
26234
|
-
const task = this.tasks.get(taskId);
|
|
26235
|
-
const failedDep = task.dependsOn.find((depId) => failedTaskIds.has(depId));
|
|
26236
|
-
if (failedDep) {
|
|
26237
|
-
task.status = "cascade_failed";
|
|
26238
|
-
task.error = `Blocked by failed dependency "${failedDep}"`;
|
|
26239
|
-
failedTaskIds.add(taskId);
|
|
26240
|
-
return;
|
|
26241
|
-
}
|
|
26242
|
-
task.status = "running";
|
|
26243
|
-
const depResults = /* @__PURE__ */ new Map();
|
|
26244
|
-
for (const depId of task.dependsOn) {
|
|
26245
|
-
const depResult = results.get(depId);
|
|
26246
|
-
if (depResult) depResults.set(depId, depResult);
|
|
26247
|
-
}
|
|
26248
|
-
try {
|
|
26249
|
-
const result = await executor(task, depResults);
|
|
26250
|
-
task.status = "completed";
|
|
26251
|
-
task.result = result;
|
|
26252
|
-
results.set(taskId, result);
|
|
26253
|
-
} catch (error) {
|
|
26254
|
-
task.status = "failed";
|
|
26255
|
-
task.error = error instanceof Error ? error.message : String(error);
|
|
26256
|
-
failedTaskIds.add(taskId);
|
|
26257
|
-
}
|
|
26258
|
-
});
|
|
26259
|
-
await Promise.all(levelPromises);
|
|
26260
|
-
}
|
|
26261
|
-
return this.buildResult();
|
|
26262
|
-
}
|
|
26263
|
-
/**
|
|
26264
|
-
* Validate the task graph:
|
|
26265
|
-
* - All dependency references point to existing tasks
|
|
26266
|
-
* - No circular dependencies
|
|
26267
|
-
*/
|
|
26268
|
-
validate() {
|
|
26269
|
-
for (const [taskId, task] of this.tasks) for (const depId of task.dependsOn) {
|
|
26270
|
-
if (!this.tasks.has(depId)) throw new Error(`Task "${taskId}" depends on unknown task "${depId}"`);
|
|
26271
|
-
if (depId === taskId) throw new Error(`Task "${taskId}" cannot depend on itself`);
|
|
26272
|
-
}
|
|
26273
|
-
this.detectCycles();
|
|
26274
|
-
}
|
|
26275
|
-
/**
|
|
26276
|
-
* Detect cycles in the dependency graph using iterative DFS
|
|
26277
|
-
*/
|
|
26278
|
-
detectCycles() {
|
|
26279
|
-
const visited = /* @__PURE__ */ new Set();
|
|
26280
|
-
const inStack = /* @__PURE__ */ new Set();
|
|
26281
|
-
for (const taskId of this.tasks.keys()) {
|
|
26282
|
-
if (visited.has(taskId)) continue;
|
|
26283
|
-
const stack = [{
|
|
26284
|
-
id: taskId,
|
|
26285
|
-
phase: "enter"
|
|
26286
|
-
}];
|
|
26287
|
-
while (stack.length > 0) {
|
|
26288
|
-
const { id, phase } = stack.pop();
|
|
26289
|
-
if (phase === "exit") {
|
|
26290
|
-
inStack.delete(id);
|
|
26291
|
-
continue;
|
|
26292
|
-
}
|
|
26293
|
-
if (inStack.has(id)) throw new Error(`Circular dependency detected involving task "${id}"`);
|
|
26294
|
-
if (visited.has(id)) continue;
|
|
26295
|
-
visited.add(id);
|
|
26296
|
-
inStack.add(id);
|
|
26297
|
-
stack.push({
|
|
26298
|
-
id,
|
|
26299
|
-
phase: "exit"
|
|
26300
|
-
});
|
|
26301
|
-
const task = this.tasks.get(id);
|
|
26302
|
-
for (const depId of task.dependsOn) {
|
|
26303
|
-
if (inStack.has(depId)) throw new Error(`Circular dependency detected: "${id}" → "${depId}"`);
|
|
26304
|
-
if (!visited.has(depId)) stack.push({
|
|
26305
|
-
id: depId,
|
|
26306
|
-
phase: "enter"
|
|
26307
|
-
});
|
|
26308
|
-
}
|
|
26309
|
-
}
|
|
26310
|
-
}
|
|
26311
|
-
}
|
|
26312
|
-
/**
|
|
26313
|
-
* Topological sort that groups tasks into execution levels.
|
|
26314
|
-
*
|
|
26315
|
-
* Each level contains tasks whose dependencies are all in earlier levels.
|
|
26316
|
-
* Tasks within a level can be executed in parallel.
|
|
26317
|
-
*
|
|
26318
|
-
* Uses Kahn's algorithm (BFS-based) for level detection.
|
|
26319
|
-
*/
|
|
26320
|
-
topologicalSort() {
|
|
26321
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
26322
|
-
const dependents = /* @__PURE__ */ new Map();
|
|
26323
|
-
for (const [taskId, task] of this.tasks) {
|
|
26324
|
-
inDegree.set(taskId, task.dependsOn.length);
|
|
26325
|
-
for (const depId of task.dependsOn) {
|
|
26326
|
-
const deps = dependents.get(depId) || [];
|
|
26327
|
-
deps.push(taskId);
|
|
26328
|
-
dependents.set(depId, deps);
|
|
26329
|
-
}
|
|
26330
|
-
}
|
|
26331
|
-
const levels = [];
|
|
26332
|
-
let currentLevel = [...this.tasks.keys()].filter((id) => inDegree.get(id) === 0);
|
|
26333
|
-
while (currentLevel.length > 0) {
|
|
26334
|
-
levels.push(currentLevel);
|
|
26335
|
-
const nextLevel = [];
|
|
26336
|
-
for (const taskId of currentLevel) for (const dependent of dependents.get(taskId) || []) {
|
|
26337
|
-
const newDegree = inDegree.get(dependent) - 1;
|
|
26338
|
-
inDegree.set(dependent, newDegree);
|
|
26339
|
-
if (newDegree === 0) nextLevel.push(dependent);
|
|
26340
|
-
}
|
|
26341
|
-
currentLevel = nextLevel;
|
|
26342
|
-
}
|
|
26343
|
-
return levels;
|
|
26344
|
-
}
|
|
26345
|
-
/**
|
|
26346
|
-
* Build the final execution result
|
|
26347
|
-
*/
|
|
26348
|
-
buildResult() {
|
|
26349
|
-
const taskResults = [...this.tasks.values()].map((task) => ({
|
|
26350
|
-
id: task.id,
|
|
26351
|
-
description: task.description,
|
|
26352
|
-
agentType: task.agentType,
|
|
26353
|
-
status: task.status,
|
|
26354
|
-
result: task.result,
|
|
26355
|
-
error: task.error
|
|
26356
|
-
}));
|
|
26357
|
-
const completed = taskResults.filter((t) => t.status === "completed");
|
|
26358
|
-
const failed = taskResults.filter((t) => t.status === "failed");
|
|
26359
|
-
const cascadeFailed = taskResults.filter((t) => t.status === "cascade_failed");
|
|
26360
|
-
const pending = taskResults.filter((t) => t.status === "pending");
|
|
26361
|
-
const success = failed.length === 0 && cascadeFailed.length === 0 && pending.length === 0;
|
|
26362
|
-
const summaryParts = [];
|
|
26363
|
-
if (completed.length > 0) {
|
|
26364
|
-
summaryParts.push(`## Completed Tasks (${completed.length}/${taskResults.length})\n`);
|
|
26365
|
-
for (const task of completed) {
|
|
26366
|
-
summaryParts.push(`### ${task.id}: ${task.description}\n`);
|
|
26367
|
-
summaryParts.push(`*Agent: ${task.agentType}*\n`);
|
|
26368
|
-
if (task.result) {
|
|
26369
|
-
const maxLen = 800;
|
|
26370
|
-
const truncated = task.result.length > maxLen ? task.result.slice(0, maxLen) + "\n...(truncated)" : task.result;
|
|
26371
|
-
summaryParts.push(truncated);
|
|
26372
|
-
}
|
|
26373
|
-
summaryParts.push("");
|
|
26374
|
-
}
|
|
26375
|
-
}
|
|
26376
|
-
if (failed.length > 0) {
|
|
26377
|
-
summaryParts.push(`## Failed Tasks (${failed.length})\n`);
|
|
26378
|
-
for (const task of failed) {
|
|
26379
|
-
summaryParts.push(`### ${task.id}: ${task.description}\n`);
|
|
26380
|
-
summaryParts.push(`*Agent: ${task.agentType}*\n`);
|
|
26381
|
-
summaryParts.push(`**Error:** ${task.error}\n`);
|
|
26382
|
-
}
|
|
26383
|
-
}
|
|
26384
|
-
if (cascadeFailed.length > 0) {
|
|
26385
|
-
summaryParts.push(`## Cascade-Failed Tasks (${cascadeFailed.length})\n`);
|
|
26386
|
-
for (const task of cascadeFailed) summaryParts.push(`- ${task.id}: ${task.description} — ${task.error}\n`);
|
|
26387
|
-
}
|
|
26388
|
-
if (pending.length > 0) {
|
|
26389
|
-
summaryParts.push(`## Skipped Tasks (${pending.length})\n`);
|
|
26390
|
-
for (const task of pending) summaryParts.push(`- ${task.id}: ${task.description}\n`);
|
|
26391
|
-
}
|
|
26392
|
-
return {
|
|
26393
|
-
success,
|
|
26394
|
-
taskResults,
|
|
26395
|
-
summary: summaryParts.join("\n")
|
|
26396
|
-
};
|
|
26397
|
-
}
|
|
26398
|
-
};
|
|
26399
|
-
//#endregion
|
|
26400
26319
|
//#region src/agents/decomposeTaskTool.ts
|
|
26401
26320
|
/**
|
|
26402
26321
|
* Create the decompose_task tool for the coordinator agent.
|
|
@@ -26499,6 +26418,87 @@ Tasks at the same dependency level run in parallel.
|
|
|
26499
26418
|
};
|
|
26500
26419
|
}
|
|
26501
26420
|
//#endregion
|
|
26421
|
+
//#region src/agents/TaskPipeline.ts
|
|
26422
|
+
/**
|
|
26423
|
+
* In-process DAG executor for the CLI.
|
|
26424
|
+
*
|
|
26425
|
+
* Validates the DAG via the shared validator, then runs each level
|
|
26426
|
+
* concurrently with `Promise.all`. The web's equivalent dispatches
|
|
26427
|
+
* each node to its own Lambda — see `coordinateTask.ts` for that path.
|
|
26428
|
+
*
|
|
26429
|
+
* Note: this executor honors `cascade` only; an `isolate` task that fails
|
|
26430
|
+
* still cascades in the CLI today. The web executor implements both.
|
|
26431
|
+
*/
|
|
26432
|
+
var TaskPipeline = class {
|
|
26433
|
+
constructor(input) {
|
|
26434
|
+
this.tasks = /* @__PURE__ */ new Map();
|
|
26435
|
+
for (const task of input.tasks) this.tasks.set(task.id, {
|
|
26436
|
+
...task,
|
|
26437
|
+
status: "pending"
|
|
26438
|
+
});
|
|
26439
|
+
this.executionOrder = validateAndSort(input);
|
|
26440
|
+
}
|
|
26441
|
+
get size() {
|
|
26442
|
+
return this.tasks.size;
|
|
26443
|
+
}
|
|
26444
|
+
getExecutionLevels() {
|
|
26445
|
+
return this.executionOrder;
|
|
26446
|
+
}
|
|
26447
|
+
isSingleTask() {
|
|
26448
|
+
return this.tasks.size === 1;
|
|
26449
|
+
}
|
|
26450
|
+
getSingleTask() {
|
|
26451
|
+
if (!this.isSingleTask()) throw new Error("Pipeline has more than one task");
|
|
26452
|
+
return [...this.tasks.values()][0];
|
|
26453
|
+
}
|
|
26454
|
+
/**
|
|
26455
|
+
* Execute all tasks in dependency order.
|
|
26456
|
+
* Tasks within the same level run in parallel; failed dependencies
|
|
26457
|
+
* cascade to dependents.
|
|
26458
|
+
*/
|
|
26459
|
+
async execute(executor) {
|
|
26460
|
+
const results = /* @__PURE__ */ new Map();
|
|
26461
|
+
const failedTaskIds = /* @__PURE__ */ new Set();
|
|
26462
|
+
for (const level of this.executionOrder) {
|
|
26463
|
+
const levelPromises = level.map(async (taskId) => {
|
|
26464
|
+
const task = this.tasks.get(taskId);
|
|
26465
|
+
const failedDep = task.dependsOn.find((depId) => failedTaskIds.has(depId));
|
|
26466
|
+
if (failedDep) {
|
|
26467
|
+
task.status = "cascade_failed";
|
|
26468
|
+
task.error = `Blocked by failed dependency "${failedDep}"`;
|
|
26469
|
+
failedTaskIds.add(taskId);
|
|
26470
|
+
return;
|
|
26471
|
+
}
|
|
26472
|
+
task.status = "running";
|
|
26473
|
+
const depResults = /* @__PURE__ */ new Map();
|
|
26474
|
+
for (const depId of task.dependsOn) {
|
|
26475
|
+
const depResult = results.get(depId);
|
|
26476
|
+
if (depResult) depResults.set(depId, depResult);
|
|
26477
|
+
}
|
|
26478
|
+
try {
|
|
26479
|
+
const result = await executor(task, depResults);
|
|
26480
|
+
task.status = "completed";
|
|
26481
|
+
task.result = result;
|
|
26482
|
+
results.set(taskId, result);
|
|
26483
|
+
} catch (error) {
|
|
26484
|
+
task.status = "failed";
|
|
26485
|
+
task.error = error instanceof Error ? error.message : String(error);
|
|
26486
|
+
failedTaskIds.add(taskId);
|
|
26487
|
+
}
|
|
26488
|
+
});
|
|
26489
|
+
await Promise.all(levelPromises);
|
|
26490
|
+
}
|
|
26491
|
+
return buildPipelineResult([...this.tasks.values()].map((t) => ({
|
|
26492
|
+
id: t.id,
|
|
26493
|
+
description: t.description,
|
|
26494
|
+
agentType: t.agentType,
|
|
26495
|
+
status: t.status,
|
|
26496
|
+
result: t.result,
|
|
26497
|
+
error: t.error
|
|
26498
|
+
})));
|
|
26499
|
+
}
|
|
26500
|
+
};
|
|
26501
|
+
//#endregion
|
|
26502
26502
|
//#region src/agents/SharedAgentContext.ts
|
|
26503
26503
|
/**
|
|
26504
26504
|
* SharedAgentContext — a namespaced key-value store for inter-agent communication.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -124,11 +124,11 @@
|
|
|
124
124
|
"tsx": "^4.22.3",
|
|
125
125
|
"typescript": "^5.9.3",
|
|
126
126
|
"vitest": "^4.1.7",
|
|
127
|
-
"@bike4mind/agents": "0.
|
|
127
|
+
"@bike4mind/agents": "0.12.0",
|
|
128
128
|
"@bike4mind/common": "2.107.0",
|
|
129
129
|
"@bike4mind/mcp": "1.37.22",
|
|
130
|
-
"@bike4mind/
|
|
131
|
-
"@bike4mind/
|
|
130
|
+
"@bike4mind/utils": "2.23.10",
|
|
131
|
+
"@bike4mind/services": "2.93.0"
|
|
132
132
|
},
|
|
133
133
|
"optionalDependencies": {
|
|
134
134
|
"@vscode/ripgrep": "^1.18.0"
|