indusagi-coding-agent 0.2.2 → 0.2.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/entry.js +12434 -9445
  3. package/dist/guardrails.js +897 -37
  4. package/dist/index.js +14081 -11111
  5. package/dist/types/boot/heap.d.ts +31 -0
  6. package/dist/types/boot/runners/delegate-runner.d.ts +27 -1
  7. package/dist/types/boot/runners/server-mode.d.ts +71 -0
  8. package/dist/types/boot/runners/session.d.ts +26 -18
  9. package/dist/types/boot/runners/session.test.d.ts +6 -1
  10. package/dist/types/boot/server-token.d.ts +97 -0
  11. package/dist/types/capability-deck/cards/index.d.ts +1 -0
  12. package/dist/types/capability-deck/cards/task-card.d.ts +26 -2
  13. package/dist/types/capability-deck/cards/workflow-card.d.ts +55 -0
  14. package/dist/types/capability-deck/cards/workflow-card.test.d.ts +12 -0
  15. package/dist/types/capability-deck/contract.d.ts +7 -6
  16. package/dist/types/capability-deck/index.d.ts +1 -1
  17. package/dist/types/conductor/conductor.d.ts +24 -0
  18. package/dist/types/conductor/contract.d.ts +79 -7
  19. package/dist/types/conductor/index.d.ts +3 -3
  20. package/dist/types/conductor/permissions.d.ts +74 -4
  21. package/dist/types/conductor/post-edit-diagnostics.test.d.ts +8 -3
  22. package/dist/types/conductor/quota-error.d.ts +35 -0
  23. package/dist/types/conductor/signal-hub/translate.d.ts +4 -1
  24. package/dist/types/console/auth-status.d.ts +28 -0
  25. package/dist/types/console/components/AgentsView.d.ts +41 -0
  26. package/dist/types/console/components/BackgroundAgents.d.ts +63 -0
  27. package/dist/types/console/components/BackgroundAgents.test.d.ts +8 -0
  28. package/dist/types/console/components/Banner.d.ts +67 -33
  29. package/dist/types/console/components/TerminalConsole.d.ts +0 -5
  30. package/dist/types/console/components/welcome.d.ts +115 -0
  31. package/dist/types/console/components/welcome.test.d.ts +9 -0
  32. package/dist/types/console/contract.d.ts +16 -1
  33. package/dist/types/console/index.d.ts +3 -0
  34. package/dist/types/console/input/index.d.ts +1 -1
  35. package/dist/types/console/input/keymap.d.ts +2 -2
  36. package/dist/types/console/input/paste.d.ts +58 -6
  37. package/dist/types/console/overlays/approval-queue.d.ts +18 -1
  38. package/dist/types/console/overlays/boards.d.ts +55 -0
  39. package/dist/types/console/overlays/index.d.ts +1 -1
  40. package/dist/types/console/theme/adapter.d.ts +1 -1
  41. package/dist/types/console/theme/index.d.ts +1 -1
  42. package/dist/types/console/theme/palette.d.ts +10 -0
  43. package/dist/types/launch/login.d.ts +68 -0
  44. package/dist/types/launch/oauth.test.d.ts +20 -0
  45. package/dist/types/window-budget/summarize/condense.d.ts +6 -0
  46. package/dist/types/workflow-engine/agent-runner.d.ts +124 -0
  47. package/dist/types/workflow-engine/agent-runner.test.d.ts +8 -0
  48. package/dist/types/workflow-engine/display.d.ts +148 -0
  49. package/dist/types/workflow-engine/display.test.d.ts +1 -0
  50. package/dist/types/workflow-engine/engine.d.ts +183 -0
  51. package/dist/types/workflow-engine/engine.test.d.ts +1 -0
  52. package/dist/types/workflow-engine/index.d.ts +21 -0
  53. package/dist/types/workflow-engine/parse.d.ts +64 -0
  54. package/dist/types/workflow-engine/parse.test.d.ts +1 -0
  55. package/dist/types/workflow-engine/structured-output.d.ts +51 -0
  56. package/dist/types/workflow-engine/structured-output.test.d.ts +1 -0
  57. package/dist/types/workspace/brand.d.ts +1 -1
  58. package/package.json +2 -2
  59. package/dist/types/console/components/Emblem.d.ts +0 -49
@@ -2262,10 +2262,10 @@ var require_boolean = __commonJS({
2262
2262
  "../indus-rebuild/node_modules/@sinclair/typebox/build/cjs/type/boolean/boolean.js"(exports) {
2263
2263
  "use strict";
2264
2264
  Object.defineProperty(exports, "__esModule", { value: true });
2265
- exports.Boolean = Boolean;
2265
+ exports.Boolean = Boolean2;
2266
2266
  var index_1 = require_symbols2();
2267
2267
  var index_2 = require_create();
2268
- function Boolean(options) {
2268
+ function Boolean2(options) {
2269
2269
  return (0, index_2.CreateType)({ [index_1.Kind]: "Boolean", type: "boolean" }, options);
2270
2270
  }
2271
2271
  }
@@ -5387,8 +5387,8 @@ var require_pick = __commonJS({
5387
5387
  result[K2] = properties[K2];
5388
5388
  return result;
5389
5389
  }
5390
- function FromObject(Type7, keys, properties) {
5391
- const options = (0, discard_1.Discard)(Type7, [symbols_1.TransformKind, "$id", "required", "properties"]);
5390
+ function FromObject(Type8, keys, properties) {
5391
+ const options = (0, discard_1.Discard)(Type8, [symbols_1.TransformKind, "$id", "required", "properties"]);
5392
5392
  const mappedProperties = FromProperties(properties, keys);
5393
5393
  return (0, index_4.Object)(mappedProperties, options);
5394
5394
  }
@@ -7171,8 +7171,8 @@ var require_type6 = __commonJS({
7171
7171
  Object.defineProperty(exports, "JavaScriptTypeBuilder", { enumerable: true, get: function() {
7172
7172
  return javascript_1.JavaScriptTypeBuilder;
7173
7173
  } });
7174
- var Type7 = TypeBuilder;
7175
- exports.Type = Type7;
7174
+ var Type8 = TypeBuilder;
7175
+ exports.Type = Type8;
7176
7176
  }
7177
7177
  });
7178
7178
 
@@ -7849,8 +7849,18 @@ function resolveRuleDecision(toolName, input, rules, mode, readOnlyExtra) {
7849
7849
  }
7850
7850
  return "ask";
7851
7851
  }
7852
+ function allowAlwaysRuleStrings(toolName, input) {
7853
+ if (isBashTool(toolName)) {
7854
+ const bag = input;
7855
+ const command = typeof input === "string" ? input : bag !== null && typeof bag === "object" && typeof bag.command === "string" ? bag.command : "";
7856
+ if (command.length > 0) {
7857
+ return bashSubcommandSubjects(command).map((subject) => `${toolName}(${subject})`);
7858
+ }
7859
+ }
7860
+ return [toolName];
7861
+ }
7852
7862
  function noResolverMessage(toolName) {
7853
- return `Tool "${toolName}" requires approval, but this session is non-interactive (no approval prompt is available). Denying. Add an allow rule under permissions.allow in settings, or run with --permission-mode acceptEdits/bypass, to permit it.`;
7863
+ return `Tool "${toolName}" requires approval, but no interactive approval prompt is available here (a non-interactive run, or a sub-agent). Denying. Add an allow rule under permissions.allow in settings, or run with --permission-mode acceptEdits/bypass, to permit it.`;
7854
7864
  }
7855
7865
  function declinedMessage(toolName) {
7856
7866
  return `Tool "${toolName}" was denied by the user.`;
@@ -7892,13 +7902,18 @@ function createPermissionGate(config) {
7892
7902
  } catch {
7893
7903
  choice = "deny";
7894
7904
  }
7895
- if (choice === "deny") {
7896
- return { behavior: "deny", message: declinedMessage(toolName) };
7905
+ if (choice === "allow-once" || choice === "allow-always") {
7906
+ if (choice === "allow-always" && config.appendAllowRule) {
7907
+ for (const raw of allowAlwaysRuleStrings(toolName, input)) {
7908
+ config.appendAllowRule(makeRule("allow", raw));
7909
+ }
7910
+ }
7911
+ return { behavior: "allow" };
7897
7912
  }
7898
- if (choice === "allow-always" && config.appendAllowRule) {
7899
- config.appendAllowRule(makeRule("allow", toolName));
7913
+ if (choice === "unavailable") {
7914
+ return { behavior: "deny", message: noResolverMessage(toolName) };
7900
7915
  }
7901
- return { behavior: "allow" };
7916
+ return { behavior: "deny", message: declinedMessage(toolName) };
7902
7917
  };
7903
7918
  }
7904
7919
 
@@ -8813,7 +8828,7 @@ function buildTaskCapability(ctx) {
8813
8828
  label: "Delegate task",
8814
8829
  description: baseDescription(agents),
8815
8830
  parameters: TaskParams,
8816
- async execute(_toolCallId, params, signal) {
8831
+ async execute(_toolCallId, params, signal, onUpdate) {
8817
8832
  if (!runner) {
8818
8833
  return {
8819
8834
  content: [{ type: "text", text: STUB_NOTE }],
@@ -8823,7 +8838,22 @@ function buildTaskCapability(ctx) {
8823
8838
  }
8824
8839
  const result = await runner.run(
8825
8840
  { objective: params.objective, agent: params.agent, context: params.context },
8826
- signal
8841
+ signal,
8842
+ // Stream live token spend as a tool_update so the background-agents panel
8843
+ // can show a running token count next to the elapsed clock. The `details`
8844
+ // carries the structured `tokens`; the console reads it off the signal.
8845
+ (progress) => {
8846
+ onUpdate?.({
8847
+ content: [{ type: "text", text: `${progress.tokens} tokens` }],
8848
+ details: {
8849
+ delegated: true,
8850
+ ok: false,
8851
+ agent: params.agent,
8852
+ tokens: progress.tokens,
8853
+ activity: progress.activity
8854
+ }
8855
+ });
8856
+ }
8827
8857
  );
8828
8858
  return {
8829
8859
  content: [{ type: "text", text: result.report }],
@@ -8842,8 +8872,837 @@ var taskCard = {
8842
8872
  build: (ctx) => buildTaskCapability(ctx)
8843
8873
  };
8844
8874
 
8845
- // src/capability-deck/cards/saas-card.ts
8875
+ // src/capability-deck/cards/workflow-card.ts
8846
8876
  var import_typebox4 = __toESM(require_cjs(), 1);
8877
+
8878
+ // src/workflow-engine/parse.ts
8879
+ import vm from "node:vm";
8880
+ var NONDETERMINISM_ERROR = "Workflow scripts must be deterministic: Date.now()/Math.random()/new Date() are unavailable";
8881
+ var NONDETERMINISTIC_PATTERNS = [
8882
+ /\bDate\s*\.\s*now\s*\(/,
8883
+ /\bMath\s*\.\s*random\s*\(/,
8884
+ /\bnew\s+Date\b/
8885
+ ];
8886
+ function parseWorkflowScript(script) {
8887
+ if (typeof script !== "string") {
8888
+ throw new TypeError("workflow script must be a string");
8889
+ }
8890
+ assertDeterministicSource(script);
8891
+ const located = locateMetaExport(script);
8892
+ const meta = evaluateMetaLiteral(located.literal);
8893
+ validateMeta(meta);
8894
+ return {
8895
+ meta,
8896
+ body: script.slice(0, located.start) + script.slice(located.end)
8897
+ };
8898
+ }
8899
+ function assertDeterministicSource(script) {
8900
+ for (const pattern of NONDETERMINISTIC_PATTERNS) {
8901
+ if (pattern.test(script)) throw new Error(NONDETERMINISM_ERROR);
8902
+ }
8903
+ }
8904
+ function locateMetaExport(script) {
8905
+ const firstToken = skipTrivia(script, 0);
8906
+ const header = /export\s+const\s+meta\s*=\s*/y;
8907
+ header.lastIndex = firstToken;
8908
+ const match = header.exec(script);
8909
+ if (!match || match.index !== firstToken) {
8910
+ throw new Error(
8911
+ "`export const meta = { name, description }` must be the first statement in the script"
8912
+ );
8913
+ }
8914
+ const braceStart = header.lastIndex;
8915
+ if (script[braceStart] !== "{") {
8916
+ throw new Error("meta export must be assigned a plain object literal: `export const meta = { \u2026 }`");
8917
+ }
8918
+ const braceEnd = matchBraces(script, braceStart);
8919
+ const literal = script.slice(braceStart, braceEnd);
8920
+ let end = braceEnd;
8921
+ const afterBrace = skipTrivia(script, braceEnd);
8922
+ if (script[afterBrace] === ";") end = afterBrace + 1;
8923
+ return { start: firstToken, end, literal };
8924
+ }
8925
+ function skipTrivia(source, from) {
8926
+ let i = from;
8927
+ while (i < source.length) {
8928
+ const ch = source[i];
8929
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v") {
8930
+ i++;
8931
+ continue;
8932
+ }
8933
+ if (ch === "/" && source[i + 1] === "/") {
8934
+ i += 2;
8935
+ while (i < source.length && source[i] !== "\n") i++;
8936
+ continue;
8937
+ }
8938
+ if (ch === "/" && source[i + 1] === "*") {
8939
+ i += 2;
8940
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) i++;
8941
+ i += 2;
8942
+ continue;
8943
+ }
8944
+ break;
8945
+ }
8946
+ return i;
8947
+ }
8948
+ function matchBraces(source, open) {
8949
+ let depth = 0;
8950
+ let i = open;
8951
+ while (i < source.length) {
8952
+ const ch = source[i];
8953
+ if (ch === "/" && source[i + 1] === "/") {
8954
+ i += 2;
8955
+ while (i < source.length && source[i] !== "\n") i++;
8956
+ continue;
8957
+ }
8958
+ if (ch === "/" && source[i + 1] === "*") {
8959
+ i += 2;
8960
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) i++;
8961
+ i += 2;
8962
+ continue;
8963
+ }
8964
+ if (ch === '"' || ch === "'" || ch === "`") {
8965
+ i = skipStringLike(source, i, ch);
8966
+ continue;
8967
+ }
8968
+ if (ch === "{") depth++;
8969
+ else if (ch === "}") {
8970
+ depth--;
8971
+ if (depth === 0) return i + 1;
8972
+ }
8973
+ i++;
8974
+ }
8975
+ throw new Error("meta object literal is not closed: missing `}`");
8976
+ }
8977
+ function skipStringLike(source, start, quote) {
8978
+ let i = start + 1;
8979
+ while (i < source.length) {
8980
+ const ch = source[i];
8981
+ if (ch === "\\") {
8982
+ i += 2;
8983
+ continue;
8984
+ }
8985
+ if (quote === "`" && ch === "$" && source[i + 1] === "{") {
8986
+ let depth = 1;
8987
+ i += 2;
8988
+ while (i < source.length && depth > 0) {
8989
+ if (source[i] === "{") depth++;
8990
+ else if (source[i] === "}") depth--;
8991
+ i++;
8992
+ }
8993
+ continue;
8994
+ }
8995
+ if (ch === quote) return i + 1;
8996
+ i++;
8997
+ }
8998
+ throw new Error("unterminated string in meta object literal");
8999
+ }
9000
+ function evaluateMetaLiteral(literal) {
9001
+ const context = vm.createContext(/* @__PURE__ */ Object.create(null));
9002
+ let value;
9003
+ try {
9004
+ value = new vm.Script(`(${literal})`, { filename: "workflow.meta.js" }).runInContext(context, {
9005
+ timeout: 1e3
9006
+ });
9007
+ } catch (error) {
9008
+ const detail = error instanceof Error ? `: ${error.message}` : "";
9009
+ throw new Error(`meta export must be a plain object literal${detail}`);
9010
+ }
9011
+ return value;
9012
+ }
9013
+ function validateMeta(meta) {
9014
+ if (!meta || typeof meta !== "object") throw new Error("meta must be an object");
9015
+ const value = meta;
9016
+ if (typeof value.name !== "string" || !value.name.trim()) {
9017
+ throw new Error("meta.name must be a non-empty string");
9018
+ }
9019
+ if (typeof value.description !== "string" || !value.description.trim()) {
9020
+ throw new Error("meta.description must be a non-empty string");
9021
+ }
9022
+ if (value.whenToUse !== void 0 && typeof value.whenToUse !== "string") {
9023
+ throw new Error("meta.whenToUse must be a string");
9024
+ }
9025
+ if (value.phases !== void 0) {
9026
+ if (!Array.isArray(value.phases)) throw new Error("meta.phases must be an array");
9027
+ for (const phase of value.phases) {
9028
+ if (!phase || typeof phase !== "object" || typeof phase.title !== "string") {
9029
+ throw new Error("each meta phase must have a title string");
9030
+ }
9031
+ const detail = phase.detail;
9032
+ if (detail !== void 0 && typeof detail !== "string") {
9033
+ throw new Error("meta phase detail must be a string");
9034
+ }
9035
+ }
9036
+ }
9037
+ }
9038
+
9039
+ // src/workflow-engine/display.ts
9040
+ function createWorkflowSnapshot(meta) {
9041
+ return {
9042
+ name: meta.name,
9043
+ description: meta.description,
9044
+ phases: [],
9045
+ logs: [],
9046
+ agents: [],
9047
+ agentCount: 0,
9048
+ runningCount: 0,
9049
+ doneCount: 0,
9050
+ errorCount: 0
9051
+ };
9052
+ }
9053
+ function recomputeWorkflowSnapshot(snapshot) {
9054
+ const runningCount = snapshot.agents.filter((agent) => agent.status === "running").length;
9055
+ const doneCount = snapshot.agents.filter((agent) => agent.status === "done").length;
9056
+ const errorCount = snapshot.agents.filter((agent) => agent.status === "error").length;
9057
+ return { ...snapshot, agentCount: snapshot.agents.length, runningCount, doneCount, errorCount };
9058
+ }
9059
+ function renderWorkflowLines(snapshot, options = {}, now = Date.now()) {
9060
+ const maxAgents = options.maxAgents ?? 8;
9061
+ const maxLogs = options.maxLogs ?? 2;
9062
+ const maxLines = options.maxLines ?? 9;
9063
+ const showResultPreviews = options.showResultPreviews ?? false;
9064
+ const state = snapshot.errorCount > 0 ? `, ${snapshot.errorCount} errors` : snapshot.runningCount > 0 ? `, ${snapshot.runningCount} running` : "";
9065
+ const header = `\u25C6 Workflow: ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`;
9066
+ const agentPhaseNames = snapshot.agents.map((agent) => agent.phase).filter((phase) => Boolean(phase));
9067
+ const phaseNames = unique([
9068
+ ...snapshot.phases,
9069
+ ...snapshot.currentPhase ? [snapshot.currentPhase] : [],
9070
+ ...agentPhaseNames
9071
+ ]);
9072
+ const rendered = /* @__PURE__ */ new Set();
9073
+ const blocks = [];
9074
+ for (const phase of phaseNames) {
9075
+ const agents = snapshot.agents.filter((agent) => agent.phase === phase);
9076
+ if (agents.length === 0 && snapshot.currentPhase !== phase) continue;
9077
+ for (const agent of agents) rendered.add(agent);
9078
+ const done = agents.filter((agent) => agent.status === "done").length;
9079
+ const running = agents.filter((agent) => agent.status === "running").length;
9080
+ const errors = agents.filter((agent) => agent.status === "error").length;
9081
+ const skipped = agents.filter((agent) => agent.status === "skipped").length;
9082
+ const complete = agents.length > 0 && done + errors + skipped === agents.length;
9083
+ const active = running > 0 || errors > 0 || snapshot.currentPhase === phase || !complete;
9084
+ const marker = running > 0 || !complete && snapshot.currentPhase === phase ? "\u25B6" : complete ? "\u2713" : " ";
9085
+ const counts = `${done}/${agents.length}${running ? ` \xB7 ${running} running` : ""}${errors ? ` \xB7 ${errors} errors` : ""}${skipped ? ` \xB7 ${skipped} skipped` : ""}`;
9086
+ const full = [` ${marker} ${phase} ${counts}`];
9087
+ const visibleAgents = agents.slice(-maxAgents);
9088
+ for (const agent of visibleAgents) {
9089
+ const order = `#${agent.id}`;
9090
+ const result = showResultPreviews && agent.resultPreview ? ` \u2014 ${agent.resultPreview}` : "";
9091
+ const metrics = renderAgentMetrics(agent, now);
9092
+ full.push(` ${order} ${statusIcon(agent.status)} ${shorten(agent.label, 48)}${metrics}${result}`);
9093
+ }
9094
+ if (agents.length > visibleAgents.length)
9095
+ full.push(` \u2026 ${agents.length - visibleAgents.length} earlier agents`);
9096
+ blocks.push({ full, active, compact: compactPhaseLine(marker, phase, done, agents, now) });
9097
+ }
9098
+ const unphased = snapshot.agents.filter((agent) => !rendered.has(agent));
9099
+ if (unphased.length) {
9100
+ const full = [" Unphased"];
9101
+ for (const agent of unphased.slice(-maxAgents)) {
9102
+ const result = showResultPreviews && agent.resultPreview ? ` \u2014 ${agent.resultPreview}` : "";
9103
+ const metrics = renderAgentMetrics(agent, now);
9104
+ full.push(` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 48)}${metrics}${result}`);
9105
+ }
9106
+ blocks.push({ full, active: true, compact: full[0] });
9107
+ }
9108
+ const visibleLogs = snapshot.logs.slice(-maxLogs);
9109
+ const logLines = visibleLogs.length ? ["", ...visibleLogs.map((log) => ` log: ${log}`)] : [];
9110
+ return assembleTree(header, blocks, logLines, maxLines);
9111
+ }
9112
+ function assembleTree(header, blocks, logLines, maxLines) {
9113
+ if (!Number.isFinite(maxLines)) {
9114
+ return [header, ...blocks.flatMap((b) => b.full), ...logLines];
9115
+ }
9116
+ const baseRow = (b) => b.active ? b.full : [b.compact];
9117
+ const baseLen = 1 + blocks.reduce((n, b) => n + baseRow(b).length, 0) + logLines.length;
9118
+ if (baseLen <= maxLines) {
9119
+ return [header, ...blocks.flatMap(baseRow), ...logLines];
9120
+ }
9121
+ const folded = /* @__PURE__ */ new Set();
9122
+ for (let i = 0; i < blocks.length; i++) {
9123
+ if (blocks[i].active) continue;
9124
+ const keptLen = blocks.reduce((n, b, j) => folded.has(j) ? n : n + baseRow(b).length, 0);
9125
+ const summaryCost = folded.size ? 1 : 0;
9126
+ if (1 + keptLen + summaryCost + logLines.length <= maxLines) break;
9127
+ folded.add(i);
9128
+ }
9129
+ const out = [header];
9130
+ if (folded.size) out.push(` \u2026 ${folded.size} earlier phases done`);
9131
+ blocks.forEach((b, i) => {
9132
+ if (!folded.has(i)) out.push(...baseRow(b));
9133
+ });
9134
+ out.push(...logLines);
9135
+ return out;
9136
+ }
9137
+ function compactPhaseLine(marker, phase, done, agents, now) {
9138
+ const prefix = ` ${marker} ${phase} ${done}/${agents.length}`;
9139
+ const totalTools = agents.reduce((n, a) => n + (a.toolCount ?? 0), 0);
9140
+ const toolSeg = totalTools > 0 ? ` \xB7 ${totalTools} ${totalTools === 1 ? "tool" : "tools"}` : "";
9141
+ if (agents.length === 1) {
9142
+ const agent = agents[0];
9143
+ const elapsedMs = Math.max(0, (agent.endedAt ?? now) - (agent.startedAt ?? agent.endedAt ?? now));
9144
+ const secs = agent.startedAt !== void 0 ? ` \xB7 #${agent.id} ${Math.floor(elapsedMs / 1e3)}s` : "";
9145
+ return `${prefix}${secs}${toolSeg}`;
9146
+ }
9147
+ const totalIn = agents.reduce((n, a) => n + (a.tokensIn ?? 0), 0);
9148
+ const totalOut = agents.reduce((n, a) => n + (a.tokensOut ?? 0), 0);
9149
+ const totalTokens = totalIn + totalOut;
9150
+ const tokSeg = totalTokens > 0 ? ` \xB7 ${formatTokens(totalTokens)} tok` : "";
9151
+ return `${prefix}${tokSeg}${toolSeg}`;
9152
+ }
9153
+ function renderWorkflowText(snapshot, completed = false, options = {}, now = Date.now()) {
9154
+ const effective = completed && options.maxLines === void 0 ? { ...options, maxLines: Infinity } : options;
9155
+ const tree = renderWorkflowLines(snapshot, effective, now);
9156
+ return completed ? ["Workflow completed", ...tree].join("\n") : tree.join("\n");
9157
+ }
9158
+ function statusIcon(status) {
9159
+ switch (status) {
9160
+ case "queued":
9161
+ return "\u25CB";
9162
+ case "running":
9163
+ return "\u25CF";
9164
+ case "done":
9165
+ return "\u2713";
9166
+ case "error":
9167
+ return "\u2717";
9168
+ case "skipped":
9169
+ return "-";
9170
+ }
9171
+ }
9172
+ function renderAgentMetrics(agent, now) {
9173
+ if (agent.startedAt === void 0) return "";
9174
+ const running = agent.status === "running";
9175
+ const elapsedMs = Math.max(0, (agent.endedAt ?? now) - agent.startedAt);
9176
+ const segments = [`${Math.floor(elapsedMs / 1e3)}s`];
9177
+ const tokensIn = agent.tokensIn ?? 0;
9178
+ const tokensOut = agent.tokensOut ?? 0;
9179
+ if (tokensIn > 0 || tokensOut > 0) {
9180
+ segments.push(`\u2191${formatTokens(tokensIn)} \u2193${formatTokens(tokensOut)}`);
9181
+ }
9182
+ const toolCount = agent.toolCount ?? 0;
9183
+ if (running) {
9184
+ if (toolCount > 0 || agent.currentTool) {
9185
+ const tail = agent.currentTool ? ` (running ${agent.currentTool})` : "";
9186
+ const last = agent.lastTool ?? agent.currentTool;
9187
+ segments.push(last ? `${last} \xD7${toolCount}${tail}` : `0 tools${tail}`);
9188
+ }
9189
+ } else if (toolCount > 0) {
9190
+ segments.push(`${toolCount} ${toolCount === 1 ? "tool" : "tools"}`);
9191
+ }
9192
+ return ` ${segments.join(" \xB7 ")}`;
9193
+ }
9194
+ function formatTokens(value) {
9195
+ if (value < 1e3) return String(value);
9196
+ const thousands = value / 1e3;
9197
+ return `${thousands.toFixed(1)}k`;
9198
+ }
9199
+ function unique(values) {
9200
+ return [...new Set(values)];
9201
+ }
9202
+ function shorten(value, max) {
9203
+ const text = value.replace(/\s+/g, " ").trim();
9204
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
9205
+ }
9206
+ function preview(value, max = 80) {
9207
+ const text = typeof value === "string" ? value : JSON.stringify(value);
9208
+ if (!text) return "";
9209
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
9210
+ }
9211
+
9212
+ // src/workflow-engine/engine.ts
9213
+ import vm2 from "node:vm";
9214
+ import os from "node:os";
9215
+ async function runWorkflow(script, options) {
9216
+ const started = Date.now();
9217
+ const { meta, body } = parseWorkflowScript(script);
9218
+ const state = { logs: [], phases: [], agentCount: 0, spent: 0 };
9219
+ const agentRunner = options.agentRunner;
9220
+ if (!agentRunner || typeof agentRunner.run !== "function") {
9221
+ throw new TypeError("runWorkflow requires an agentRunner with a run() method");
9222
+ }
9223
+ const concurrency = Math.max(
9224
+ 1,
9225
+ Math.min(options.concurrency ?? Math.max(1, defaultConcurrency() - 2), 16)
9226
+ );
9227
+ const limiter = createLimiter(concurrency);
9228
+ const pendingAgentRuns = /* @__PURE__ */ new Set();
9229
+ const log = (message) => {
9230
+ const text = String(message);
9231
+ state.logs.push(text);
9232
+ options.onLog?.(text);
9233
+ };
9234
+ const phase = (title) => {
9235
+ const text = requireString(title, "phase title");
9236
+ state.currentPhase = text;
9237
+ if (!state.phases.includes(text)) state.phases.push(text);
9238
+ options.onPhase?.(text);
9239
+ };
9240
+ const budget = Object.freeze({
9241
+ total: options.tokenBudget ?? null,
9242
+ spent: () => state.spent,
9243
+ remaining: () => options.tokenBudget == null ? Infinity : Math.max(0, options.tokenBudget - state.spent)
9244
+ });
9245
+ const throwIfAborted = () => {
9246
+ if (options.signal?.aborted) throw new Error("workflow aborted");
9247
+ };
9248
+ const agent = async (prompt, agentOptions = {}) => {
9249
+ throwIfAborted();
9250
+ if (budget.total !== null && budget.remaining() <= 0) {
9251
+ throw new Error("workflow token budget exhausted");
9252
+ }
9253
+ const taskPrompt = requireString(prompt, "agent prompt");
9254
+ const normalizedOptions = normalizeAgentOptions(agentOptions);
9255
+ const assignedPhase = normalizedOptions.phase ?? state.currentPhase;
9256
+ const requestedLabel = normalizedOptions.label?.trim();
9257
+ const run = limiter(async () => {
9258
+ const id = ++state.agentCount;
9259
+ const label = requestedLabel || defaultAgentLabel(assignedPhase, id);
9260
+ options.onAgentStart?.({ id, label, phase: assignedPhase, prompt: taskPrompt });
9261
+ try {
9262
+ throwIfAborted();
9263
+ const result2 = await agentRunner.run(taskPrompt, {
9264
+ label,
9265
+ phase: assignedPhase,
9266
+ schema: normalizedOptions.schema,
9267
+ model: normalizedOptions.model,
9268
+ agentType: normalizedOptions.agentType,
9269
+ isolation: normalizedOptions.isolation,
9270
+ signal: options.signal,
9271
+ instructions: buildAgentInstructions(assignedPhase, normalizedOptions),
9272
+ onActivity: options.onAgentActivity ? (metrics) => options.onAgentActivity?.(id, metrics) : void 0
9273
+ });
9274
+ throwIfAborted();
9275
+ state.spent += estimateTokens(result2);
9276
+ options.onAgentEnd?.({ id, label, phase: assignedPhase, result: result2 });
9277
+ return result2;
9278
+ } catch (error) {
9279
+ if (options.signal?.aborted) throw error;
9280
+ log(`agent ${label} failed: ${error instanceof Error ? error.message : String(error)}`);
9281
+ options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null });
9282
+ return null;
9283
+ }
9284
+ });
9285
+ pendingAgentRuns.add(run);
9286
+ run.then(
9287
+ () => pendingAgentRuns.delete(run),
9288
+ () => pendingAgentRuns.delete(run)
9289
+ );
9290
+ return run;
9291
+ };
9292
+ const parallel = async (thunks) => {
9293
+ throwIfAborted();
9294
+ if (!Array.isArray(thunks)) throw new TypeError("parallel() expects an array of functions");
9295
+ if (thunks.some((thunk) => typeof thunk !== "function")) {
9296
+ throw new TypeError(
9297
+ "parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
9298
+ );
9299
+ }
9300
+ return Promise.all(
9301
+ thunks.map(async (thunk, index) => {
9302
+ try {
9303
+ return await thunk();
9304
+ } catch (error) {
9305
+ if (options.signal?.aborted) throw error;
9306
+ log(`parallel[${index}] failed: ${error instanceof Error ? error.message : String(error)}`);
9307
+ return null;
9308
+ }
9309
+ })
9310
+ );
9311
+ };
9312
+ const pipeline = async (items, ...stages) => {
9313
+ throwIfAborted();
9314
+ if (!Array.isArray(items)) throw new TypeError("pipeline() expects an array as the first argument");
9315
+ if (stages.some((stage) => typeof stage !== "function")) {
9316
+ throw new TypeError(
9317
+ "pipeline() stages must be functions: pipeline(items, item => ..., result => ...)"
9318
+ );
9319
+ }
9320
+ return Promise.all(
9321
+ items.map(async (item, index) => {
9322
+ let value = item;
9323
+ for (const stage of stages) {
9324
+ try {
9325
+ throwIfAborted();
9326
+ value = await stage(value, item, index);
9327
+ throwIfAborted();
9328
+ } catch (error) {
9329
+ if (options.signal?.aborted) throw error;
9330
+ log(`pipeline[${index}] failed: ${error instanceof Error ? error.message : String(error)}`);
9331
+ return null;
9332
+ }
9333
+ }
9334
+ return value;
9335
+ })
9336
+ );
9337
+ };
9338
+ const resolvedCwd = options.cwd ?? process.cwd();
9339
+ const context = vm2.createContext({
9340
+ agent,
9341
+ parallel,
9342
+ pipeline,
9343
+ log,
9344
+ phase,
9345
+ args: options.args,
9346
+ cwd: resolvedCwd,
9347
+ process: Object.freeze({ cwd: () => resolvedCwd }),
9348
+ budget,
9349
+ console: Object.freeze({
9350
+ log,
9351
+ info: log,
9352
+ warn: (m) => log(`[warn] ${String(m)}`),
9353
+ error: (m) => log(`[error] ${String(m)}`)
9354
+ }),
9355
+ JSON,
9356
+ Math,
9357
+ Array,
9358
+ Object,
9359
+ String,
9360
+ Number,
9361
+ Boolean,
9362
+ Set,
9363
+ Map,
9364
+ Promise
9365
+ });
9366
+ const wrapped = `(async () => {
9367
+ ${body}
9368
+ })()`;
9369
+ const result = await new vm2.Script(wrapped, {
9370
+ filename: `${meta.name || "workflow"}.js`
9371
+ }).runInContext(context);
9372
+ await Promise.allSettled([...pendingAgentRuns]);
9373
+ assertStructuredCloneable(result, "workflow result");
9374
+ return {
9375
+ meta,
9376
+ result,
9377
+ logs: state.logs,
9378
+ phases: state.phases,
9379
+ agentCount: state.agentCount,
9380
+ durationMs: Date.now() - started
9381
+ };
9382
+ }
9383
+ function defaultConcurrency() {
9384
+ const count = os.cpus()?.length;
9385
+ return typeof count === "number" && count > 0 ? count : 8;
9386
+ }
9387
+ function createLimiter(limit) {
9388
+ let active = 0;
9389
+ const queue = [];
9390
+ const next = () => {
9391
+ active--;
9392
+ queue.shift()?.();
9393
+ };
9394
+ return async (fn) => {
9395
+ if (active >= limit) await new Promise((resolve2) => queue.push(resolve2));
9396
+ active++;
9397
+ try {
9398
+ return await fn();
9399
+ } finally {
9400
+ next();
9401
+ }
9402
+ };
9403
+ }
9404
+ function requireString(value, name) {
9405
+ if (typeof value !== "string") throw new TypeError(`${name} must be a string`);
9406
+ return value;
9407
+ }
9408
+ function optionalString(value, name) {
9409
+ if (value === void 0) return void 0;
9410
+ return requireString(value, name);
9411
+ }
9412
+ function normalizeAgentOptions(value) {
9413
+ if (!value || typeof value !== "object") throw new TypeError("agent options must be an object");
9414
+ const options = value;
9415
+ return {
9416
+ ...options,
9417
+ label: optionalString(options.label, "agent label"),
9418
+ phase: optionalString(options.phase, "agent phase"),
9419
+ model: optionalString(options.model, "agent model"),
9420
+ isolation: options.isolation,
9421
+ agentType: optionalString(options.agentType, "agent type")
9422
+ };
9423
+ }
9424
+ function assertStructuredCloneable(value, name) {
9425
+ try {
9426
+ structuredClone(value);
9427
+ } catch (error) {
9428
+ const detail = error instanceof Error ? ` ${error.message}` : "";
9429
+ throw new Error(
9430
+ `${name} must be structured-cloneable; did you forget to await agent(), parallel(), or pipeline()?${detail}`
9431
+ );
9432
+ }
9433
+ }
9434
+ function defaultAgentLabel(phase, index) {
9435
+ return phase ? `${phase} agent ${index}` : `agent ${index}`;
9436
+ }
9437
+ function buildAgentInstructions(phase, options) {
9438
+ const lines = [];
9439
+ if (phase) lines.push(`Workflow phase: ${phase}`);
9440
+ if (options.agentType) lines.push(`Act as workflow subagent type: ${options.agentType}`);
9441
+ if (options.isolation) lines.push(`Requested isolation: ${options.isolation}`);
9442
+ if (options.model) lines.push(`Requested model: ${options.model}`);
9443
+ return lines.length ? lines.join("\n") : void 0;
9444
+ }
9445
+ function estimateTokens(value) {
9446
+ return Math.ceil(JSON.stringify(value ?? "").length / 4);
9447
+ }
9448
+
9449
+ // src/conductor/conductor.ts
9450
+ import { Agent } from "indusagi/agent";
9451
+ import { createZeroUsage as createZeroUsage2 } from "indusagi/ai";
9452
+
9453
+ // src/conductor/catalog/catalog.ts
9454
+ import { z } from "zod";
9455
+ import { getModels, getProviders } from "indusagi/ai";
9456
+ var rawModelGate = z.object({
9457
+ id: z.string().min(1),
9458
+ name: z.string().min(1),
9459
+ provider: z.string().min(1),
9460
+ reasoning: z.boolean().optional(),
9461
+ input: z.array(z.string()).optional(),
9462
+ contextWindow: z.number().optional()
9463
+ });
9464
+
9465
+ // src/conductor/signal-hub/translate.ts
9466
+ import { createZeroUsage } from "indusagi/ai";
9467
+
9468
+ // src/conductor/transcript-store/store.ts
9469
+ import { ulid } from "ulid";
9470
+
9471
+ // src/conductor/transcript-store/serialize.ts
9472
+ import {
9473
+ buildSessionContext,
9474
+ convertToLlm,
9475
+ loadEntriesFromFile,
9476
+ parseSessionEntries
9477
+ } from "indusagi/agent";
9478
+
9479
+ // src/window-budget/summarize/prompt.ts
9480
+ var CONDENSER_BRIEF = [
9481
+ "You are a transcript recorder for a long-running coding session.",
9482
+ "The text you receive is archival data, not a live chat \u2014 do NOT reply to it,",
9483
+ "continue it, run tools, or ask questions. Your sole job is to distill it into",
9484
+ "a compact, faithful digest under the exact headings requested below.",
9485
+ "",
9486
+ "Rules:",
9487
+ "- Preserve concrete facts: file paths, identifiers, commands, error text,",
9488
+ " decisions, and anything the session would need to resume without the",
9489
+ " original turns.",
9490
+ "- Prefer specifics over paraphrase; never invent details that are not present.",
9491
+ "- Keep each heading even if a section is empty (write `none` under it).",
9492
+ "- Emit only the digest \u2014 no preamble, no sign-off, no commentary."
9493
+ ].join("\n");
9494
+ var SECTION_TEMPLATE = [
9495
+ "# Objective",
9496
+ "# Guardrails",
9497
+ "# Status (Shipped / Active / Stuck)",
9498
+ "# Rationale",
9499
+ "# Plan",
9500
+ "# Carryover"
9501
+ ].join("\n");
9502
+
9503
+ // src/window-budget/summarize/condense.ts
9504
+ import { completeSimple } from "indusagi/ai";
9505
+
9506
+ // src/capability-deck/bridge-ledger/key.ts
9507
+ import { ulid as ulid2, monotonicFactory } from "ulid";
9508
+ import { QUALIFIER } from "indusagi/interop";
9509
+ var nextUlid = monotonicFactory();
9510
+
9511
+ // src/capability-deck/bridge-ledger/network.ts
9512
+ import {
9513
+ mountProtocolBridge,
9514
+ isProtocolFault
9515
+ } from "indusagi/interop";
9516
+
9517
+ // src/workflow-engine/agent-runner.ts
9518
+ import { Agent as Agent2 } from "indusagi/agent";
9519
+ var STRUCTURED_CONTRACT = [
9520
+ "Final output contract:",
9521
+ "- Your final action MUST be a structured_output tool call.",
9522
+ "- The structured_output arguments are the return value of this subagent.",
9523
+ "- Do not emit a prose final answer instead of structured_output.",
9524
+ "- If you need to inspect files or run commands first, do so, then call structured_output exactly once."
9525
+ ].join("\n");
9526
+
9527
+ // src/capability-deck/cards/workflow-card.ts
9528
+ var WORKFLOW_HANDLE_KEY = "workflow";
9529
+ function readWorkflowRunner(ctx) {
9530
+ const handle = ctx.framework?.[WORKFLOW_HANDLE_KEY];
9531
+ if (handle && typeof handle.run === "function") {
9532
+ return handle;
9533
+ }
9534
+ return void 0;
9535
+ }
9536
+ var WorkflowParams = import_typebox4.Type.Object(
9537
+ {
9538
+ script: import_typebox4.Type.String({
9539
+ description: [
9540
+ "Required raw JavaScript workflow script, with no Markdown fences.",
9541
+ "First statement: export const meta = { name: 'short_snake_case', description: 'non-empty description' }.",
9542
+ "Use phase(title), agent(prompt, opts), parallel(arrayOfFunctions), pipeline(items, ...stages), log(message), args, and budget. The workflow must call agent() at least once.",
9543
+ "parallel() requires functions, not promises: await parallel(items.map(item => () => agent(...))).",
9544
+ "Plain JavaScript only \u2014 no imports, require(), fs, Date.now(), Math.random(), or new Date()."
9545
+ ].join(" ")
9546
+ }),
9547
+ args: import_typebox4.Type.Optional(
9548
+ import_typebox4.Type.Any({ description: "Optional JSON value exposed to the workflow script as global `args`." })
9549
+ )
9550
+ },
9551
+ { additionalProperties: false }
9552
+ );
9553
+ var DESCRIPTION = [
9554
+ "Execute a deterministic JavaScript workflow that orchestrates multiple subagents with agent(), parallel(), and pipeline().",
9555
+ "Use it for decomposable work \u2014 repository inspection, independent research/checks, multi-perspective review, or fan-out/fan-in synthesis.",
9556
+ "script is required raw JavaScript; it must start with `export const meta = { name, description }` and must call agent() at least once."
9557
+ ].join(" ");
9558
+ var STUB_NOTE2 = "Workflow orchestration is not wired in this environment, so the script was not run. Wire a WorkflowAgentRunner into the deck context to enable it, or perform the work inline with the other tools.";
9559
+ function isAbortError(error) {
9560
+ if (!(error instanceof Error)) return false;
9561
+ return /\babort(?:ed)?\b/i.test(error.message);
9562
+ }
9563
+ function buildWorkflowCapability(ctx) {
9564
+ const runner = readWorkflowRunner(ctx);
9565
+ return {
9566
+ name: "workflow",
9567
+ label: "Workflow",
9568
+ description: DESCRIPTION,
9569
+ parameters: WorkflowParams,
9570
+ async execute(_toolCallId, params, signal, onUpdate) {
9571
+ if (!runner) {
9572
+ const stub = createWorkflowSnapshot({ name: "workflow", description: STUB_NOTE2 });
9573
+ return {
9574
+ content: [{ type: "text", text: STUB_NOTE2 }],
9575
+ details: stub,
9576
+ isError: true
9577
+ };
9578
+ }
9579
+ let snapshot = createWorkflowSnapshot({
9580
+ name: "workflow",
9581
+ description: ""
9582
+ });
9583
+ const emit = (completed = false) => {
9584
+ snapshot = recomputeWorkflowSnapshot(snapshot);
9585
+ onUpdate?.({
9586
+ content: [{ type: "text", text: renderWorkflowText(snapshot, completed) }],
9587
+ details: snapshot
9588
+ });
9589
+ };
9590
+ const recordPhase = (title) => {
9591
+ if (!title) return;
9592
+ if (!snapshot.phases.includes(title)) snapshot.phases.push(title);
9593
+ };
9594
+ const agentById = (id) => snapshot.agents.find((item) => item.id === id);
9595
+ const ticker = setInterval(() => {
9596
+ if (snapshot.agents.some((item) => item.status === "running")) emit();
9597
+ }, 1e3);
9598
+ if (typeof ticker.unref === "function") ticker.unref();
9599
+ try {
9600
+ let result;
9601
+ try {
9602
+ result = await runWorkflow(params.script, {
9603
+ agentRunner: runner,
9604
+ cwd: ctx.cwd,
9605
+ args: params.args,
9606
+ signal,
9607
+ onLog(message) {
9608
+ snapshot.logs.push(message);
9609
+ },
9610
+ onPhase(title) {
9611
+ snapshot.currentPhase = title;
9612
+ recordPhase(title);
9613
+ emit();
9614
+ },
9615
+ onAgentStart(event) {
9616
+ recordPhase(event.phase);
9617
+ snapshot.agents.push({
9618
+ id: event.id,
9619
+ label: event.label,
9620
+ phase: event.phase,
9621
+ prompt: event.prompt,
9622
+ status: "running",
9623
+ startedAt: Date.now()
9624
+ });
9625
+ emit();
9626
+ },
9627
+ onAgentActivity(id, metrics) {
9628
+ const agent = agentById(id);
9629
+ if (!agent) return;
9630
+ agent.tokensIn = metrics.tokensIn;
9631
+ agent.tokensOut = metrics.tokensOut;
9632
+ agent.toolCount = metrics.toolCount;
9633
+ agent.currentTool = metrics.currentTool;
9634
+ agent.lastTool = metrics.lastTool;
9635
+ },
9636
+ onAgentEnd(event) {
9637
+ const agent = agentById(event.id) ?? [...snapshot.agents].reverse().find((item) => item.label === event.label && item.status === "running");
9638
+ if (agent) {
9639
+ agent.status = event.result === null ? "error" : "done";
9640
+ agent.resultPreview = preview(event.result);
9641
+ agent.endedAt = Date.now();
9642
+ agent.currentTool = void 0;
9643
+ }
9644
+ emit();
9645
+ }
9646
+ });
9647
+ } catch (error) {
9648
+ if (signal?.aborted || isAbortError(error)) {
9649
+ for (const agent of snapshot.agents) {
9650
+ if (agent.status === "running") {
9651
+ agent.status = "skipped";
9652
+ agent.error = "aborted";
9653
+ }
9654
+ }
9655
+ snapshot = recomputeWorkflowSnapshot(snapshot);
9656
+ emit(true);
9657
+ return {
9658
+ content: [{ type: "text", text: renderWorkflowText(snapshot, true) }],
9659
+ details: snapshot,
9660
+ isError: true
9661
+ };
9662
+ }
9663
+ const message = error instanceof Error ? error.message : String(error);
9664
+ snapshot = recomputeWorkflowSnapshot(snapshot);
9665
+ return {
9666
+ content: [{ type: "text", text: `Workflow failed: ${message}` }],
9667
+ details: snapshot,
9668
+ isError: true
9669
+ };
9670
+ }
9671
+ snapshot.name = result.meta.name;
9672
+ snapshot.description = result.meta.description;
9673
+ snapshot.result = result.result;
9674
+ snapshot.durationMs = result.durationMs;
9675
+ snapshot = recomputeWorkflowSnapshot(snapshot);
9676
+ emit(true);
9677
+ const noAgents = result.agentCount === 0;
9678
+ const body = noAgents ? "workflow scripts must call agent() at least once; this workflow declared phases but did not run any subagents" : `Workflow ${result.meta.name} completed with ${result.agentCount} agent(s).
9679
+
9680
+ ${renderWorkflowText(snapshot, true)}
9681
+
9682
+ Result:
9683
+ ${JSON.stringify(result.result, null, 2)}`;
9684
+ return {
9685
+ content: [{ type: "text", text: body }],
9686
+ details: snapshot,
9687
+ isError: noAgents ? true : void 0
9688
+ };
9689
+ } finally {
9690
+ clearInterval(ticker);
9691
+ }
9692
+ }
9693
+ };
9694
+ }
9695
+ var workflowCard = {
9696
+ id: capabilityId("workflow"),
9697
+ title: "Workflow",
9698
+ summary: "Run a deterministic JavaScript workflow that fans work out across many subagents.",
9699
+ // Erase the precisely-typed builder to the `Capability` card surface (through
9700
+ // `unknown`, as TypeBox tools are invariant in their parameter schema).
9701
+ build: (ctx) => buildWorkflowCapability(ctx)
9702
+ };
9703
+
9704
+ // src/capability-deck/cards/saas-card.ts
9705
+ var import_typebox5 = __toESM(require_cjs(), 1);
8847
9706
  var SAAS_GATEWAY_KEY = "saasGateway";
8848
9707
  function readGateway(ctx) {
8849
9708
  const handle = ctx.framework?.[SAAS_GATEWAY_KEY];
@@ -8852,28 +9711,28 @@ function readGateway(ctx) {
8852
9711
  }
8853
9712
  return void 0;
8854
9713
  }
8855
- var SaasParams = import_typebox4.Type.Object(
9714
+ var SaasParams = import_typebox5.Type.Object(
8856
9715
  {
8857
- action: import_typebox4.Type.Union([import_typebox4.Type.Literal("discover"), import_typebox4.Type.Literal("execute")], {
9716
+ action: import_typebox5.Type.Union([import_typebox5.Type.Literal("discover"), import_typebox5.Type.Literal("execute")], {
8858
9717
  description: "`discover` lists available remote tool slugs; `execute` runs one slug with arguments."
8859
9718
  }),
8860
- slug: import_typebox4.Type.Optional(
8861
- import_typebox4.Type.String({
9719
+ slug: import_typebox5.Type.Optional(
9720
+ import_typebox5.Type.String({
8862
9721
  description: "Vendor tool slug to run (e.g. GITHUB_CREATE_ISSUE). Required for `execute`."
8863
9722
  })
8864
9723
  ),
8865
- arguments: import_typebox4.Type.Optional(
8866
- import_typebox4.Type.Record(import_typebox4.Type.String(), import_typebox4.Type.Unknown(), {
9724
+ arguments: import_typebox5.Type.Optional(
9725
+ import_typebox5.Type.Record(import_typebox5.Type.String(), import_typebox5.Type.Unknown(), {
8867
9726
  description: "Arguments object for the remote tool, as the connector expects."
8868
9727
  })
8869
9728
  ),
8870
- toolkits: import_typebox4.Type.Optional(
8871
- import_typebox4.Type.Array(import_typebox4.Type.String(), {
9729
+ toolkits: import_typebox5.Type.Optional(
9730
+ import_typebox5.Type.Array(import_typebox5.Type.String(), {
8872
9731
  description: "On `discover`, restrict results to these toolkit names."
8873
9732
  })
8874
9733
  ),
8875
- query: import_typebox4.Type.Optional(
8876
- import_typebox4.Type.String({
9734
+ query: import_typebox5.Type.Optional(
9735
+ import_typebox5.Type.String({
8877
9736
  description: "On `discover`, free-text filter over available tools."
8878
9737
  })
8879
9738
  )
@@ -8881,7 +9740,7 @@ var SaasParams = import_typebox4.Type.Object(
8881
9740
  { additionalProperties: false }
8882
9741
  );
8883
9742
  var SAAS_DESCRIPTION = 'Discover and run third-party SaaS actions (GitHub, Slack, Gmail, etc.) through the connector gateway. Use `action:"discover"` to find the right tool slug, then `action:"execute"` with that `slug` and an `arguments` object to perform the action. Tool slugs are vendor-defined and case-sensitive; pass them exactly as listed.';
8884
- var STUB_NOTE2 = "The SaaS connector gateway is not configured in this environment, so no remote action was performed. Configure a connector (and authenticate the relevant toolkit) to enable these actions.";
9743
+ var STUB_NOTE3 = "The SaaS connector gateway is not configured in this environment, so no remote action was performed. Configure a connector (and authenticate the relevant toolkit) to enable these actions.";
8885
9744
  function buildSaasCapability(ctx) {
8886
9745
  const gateway = readGateway(ctx);
8887
9746
  return {
@@ -8892,7 +9751,7 @@ function buildSaasCapability(ctx) {
8892
9751
  async execute(_toolCallId, params) {
8893
9752
  if (!gateway) {
8894
9753
  return {
8895
- content: [{ type: "text", text: STUB_NOTE2 }],
9754
+ content: [{ type: "text", text: STUB_NOTE3 }],
8896
9755
  details: { action: params.action, ok: false },
8897
9756
  isError: true
8898
9757
  };
@@ -8931,7 +9790,7 @@ var saasCard = {
8931
9790
  };
8932
9791
 
8933
9792
  // src/capability-deck/cards/memory-card.ts
8934
- var import_typebox5 = __toESM(require_cjs(), 1);
9793
+ var import_typebox6 = __toESM(require_cjs(), 1);
8935
9794
  var MEMORY_HANDLE_KEY = "memoryStore";
8936
9795
  var InMemoryStore = class {
8937
9796
  buffer = "";
@@ -8953,16 +9812,16 @@ function readStore(ctx) {
8953
9812
  }
8954
9813
  return new InMemoryStore();
8955
9814
  }
8956
- var MemoryParams = import_typebox5.Type.Object(
9815
+ var MemoryParams = import_typebox6.Type.Object(
8957
9816
  {
8958
- action: import_typebox5.Type.Union(
8959
- [import_typebox5.Type.Literal("read"), import_typebox5.Type.Literal("replace"), import_typebox5.Type.Literal("append")],
9817
+ action: import_typebox6.Type.Union(
9818
+ [import_typebox6.Type.Literal("read"), import_typebox6.Type.Literal("replace"), import_typebox6.Type.Literal("append")],
8960
9819
  {
8961
9820
  description: "`read` returns the note; `replace` overwrites it; `append` adds a line to the end."
8962
9821
  }
8963
9822
  ),
8964
- content: import_typebox5.Type.Optional(
8965
- import_typebox5.Type.String({
9823
+ content: import_typebox6.Type.Optional(
9824
+ import_typebox6.Type.String({
8966
9825
  description: "New note body (for `replace`) or the line to add (for `append`). Ignored for `read`."
8967
9826
  })
8968
9827
  )
@@ -9001,7 +9860,7 @@ var memoryCard = {
9001
9860
  };
9002
9861
 
9003
9862
  // src/capability-deck/cards/plan-tools.ts
9004
- var import_typebox6 = __toESM(require_cjs(), 1);
9863
+ var import_typebox7 = __toESM(require_cjs(), 1);
9005
9864
  var PLAN_HANDLE_KEY = "planController";
9006
9865
  function readPlanController(ctx) {
9007
9866
  const handle = ctx.framework?.[PLAN_HANDLE_KEY];
@@ -9010,7 +9869,7 @@ function readPlanController(ctx) {
9010
9869
  }
9011
9870
  return void 0;
9012
9871
  }
9013
- var EnterPlanParams = import_typebox6.Type.Object({}, { additionalProperties: false });
9872
+ var EnterPlanParams = import_typebox7.Type.Object({}, { additionalProperties: false });
9014
9873
  var ENTER_PLAN_DESCRIPTION = "Enter plan mode: a read-only research phase in which you may only read, search, and inspect \u2014 every file-mutating and shell tool is blocked until you leave. Use this when a task needs investigation and a plan before any change is made. While in plan mode, gather all the context you need, then call `exit_plan_mode` with the plan you intend to carry out; the user reviews and approves it before you act.";
9015
9874
  var ENTER_PLAN_PROSE = "You are now in plan mode (read-only). Investigate freely with the read, search, and listing tools, but do not attempt to edit files or run shell commands \u2014 they are blocked here. When you have a concrete plan, call `exit_plan_mode` with the full plan text so the user can approve it before you make any changes.";
9016
9875
  function buildEnterPlanModeCapability(ctx) {
@@ -9031,9 +9890,9 @@ function buildEnterPlanModeCapability(ctx) {
9031
9890
  }
9032
9891
  };
9033
9892
  }
9034
- var ExitPlanParams = import_typebox6.Type.Object(
9893
+ var ExitPlanParams = import_typebox7.Type.Object(
9035
9894
  {
9036
- plan: import_typebox6.Type.String({
9895
+ plan: import_typebox7.Type.String({
9037
9896
  description: "The plan you intend to carry out, in markdown. The user reviews this before approving the exit from plan mode; on approval you leave plan mode and begin."
9038
9897
  })
9039
9898
  },
@@ -9083,6 +9942,7 @@ var APP_NOVEL_CARDS = [
9083
9942
  todoCard,
9084
9943
  daemonCard,
9085
9944
  taskCard,
9945
+ workflowCard,
9086
9946
  saasCard,
9087
9947
  memoryCard,
9088
9948
  enterPlanModeCard,