@looplia/looplia-cli 0.6.8 → 0.6.10

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/cli.js CHANGED
@@ -243,11 +243,22 @@ async function getPluginPaths() {
243
243
  return await getProdPluginPaths();
244
244
  }
245
245
 
246
- // ../../packages/provider/dist/chunk-4PGJBKLH.js
246
+ // ../../packages/provider/dist/chunk-L5AQO6ZO.js
247
247
  import { execSync } from "child_process";
248
248
  import { existsSync as existsSync3 } from "fs";
249
+ import { createRequire } from "module";
249
250
  import { homedir as homedir3 } from "os";
250
- import { join as join4 } from "path";
251
+ import { dirname as dirname3, join as join4 } from "path";
252
+ import {
253
+ chmod,
254
+ mkdir as mkdir2,
255
+ readFile as readFile2,
256
+ rename,
257
+ rm as rm2,
258
+ writeFile as writeFile2
259
+ } from "fs/promises";
260
+ import { homedir as homedir22 } from "os";
261
+ import { join as join23 } from "path";
251
262
 
252
263
  // ../../node_modules/zod-to-json-schema/dist/esm/Options.js
253
264
  var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
@@ -5574,7 +5585,7 @@ var zodToJsonSchema = (schema, options) => {
5574
5585
  return combined;
5575
5586
  };
5576
5587
 
5577
- // ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
5588
+ // ../../packages/provider/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
5578
5589
  import { join as join5 } from "path";
5579
5590
  import { fileURLToPath as fileURLToPath23 } from "url";
5580
5591
  import { setMaxListeners } from "events";
@@ -27369,22 +27380,28 @@ function query({
27369
27380
  return queryInstance;
27370
27381
  }
27371
27382
 
27372
- // ../../packages/provider/dist/chunk-4PGJBKLH.js
27383
+ // ../../packages/provider/dist/chunk-L5AQO6ZO.js
27373
27384
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
27374
- import { join as join23 } from "path";
27375
- import {
27376
- chmod,
27377
- mkdir as mkdir2,
27378
- readFile as readFile2,
27379
- rename,
27380
- rm as rm2,
27381
- writeFile as writeFile2
27382
- } from "fs/promises";
27383
- import { homedir as homedir22 } from "os";
27384
27385
  import { join as join32 } from "path";
27385
27386
  import { cp as cp2, mkdir as mkdir22, readFile as readFile22, rm as rm22, stat as stat2, writeFile as writeFile22 } from "fs/promises";
27386
27387
  import { homedir as homedir32 } from "os";
27387
27388
  import { isAbsolute, join as join42, normalize, resolve } from "path";
27389
+ var LINE_SPLIT_REGEX = /\r?\n/;
27390
+ function findSdkBundledCliPath() {
27391
+ try {
27392
+ const require2 = createRequire(import.meta.url);
27393
+ const sdkPackagePath = require2.resolve(
27394
+ "@anthropic-ai/claude-agent-sdk/package.json"
27395
+ );
27396
+ const sdkDir = dirname3(sdkPackagePath);
27397
+ const cliPath = join4(sdkDir, "cli.js");
27398
+ if (existsSync3(cliPath)) {
27399
+ return cliPath;
27400
+ }
27401
+ } catch {
27402
+ }
27403
+ return;
27404
+ }
27388
27405
  var CLAUDE_CODE_PATHS = [
27389
27406
  // User's local bin (npm global install location)
27390
27407
  join4(homedir3(), ".local", "bin", "claude"),
@@ -27395,92 +27412,42 @@ var CLAUDE_CODE_PATHS = [
27395
27412
  // Windows (if applicable)
27396
27413
  join4(homedir3(), "AppData", "Local", "Programs", "claude", "claude.exe")
27397
27414
  ];
27415
+ var cachedClaudeCodePath;
27398
27416
  function findClaudeCodePath() {
27417
+ if (cachedClaudeCodePath !== void 0) {
27418
+ return cachedClaudeCodePath ?? void 0;
27419
+ }
27399
27420
  const envPath = process.env.CLAUDE_CODE_PATH;
27400
27421
  if (envPath && existsSync3(envPath)) {
27401
- return envPath;
27422
+ cachedClaudeCodePath = envPath;
27423
+ return cachedClaudeCodePath;
27402
27424
  }
27403
27425
  for (const path3 of CLAUDE_CODE_PATHS) {
27404
27426
  if (existsSync3(path3)) {
27405
- return path3;
27427
+ cachedClaudeCodePath = path3;
27428
+ return cachedClaudeCodePath;
27406
27429
  }
27407
27430
  }
27408
27431
  try {
27409
- const whichResult = execSync("which claude", {
27432
+ const pathLookupCommand = process.platform === "win32" ? "where claude" : "which claude";
27433
+ const rawResult = execSync(pathLookupCommand, {
27410
27434
  encoding: "utf-8",
27411
27435
  stdio: ["pipe", "pipe", "pipe"]
27412
27436
  }).trim();
27413
- if (whichResult && existsSync3(whichResult)) {
27414
- return whichResult;
27437
+ const firstResult = rawResult.split(LINE_SPLIT_REGEX).find((line) => line.trim().length > 0) ?? "";
27438
+ if (firstResult && existsSync3(firstResult)) {
27439
+ cachedClaudeCodePath = firstResult;
27440
+ return cachedClaudeCodePath;
27415
27441
  }
27416
27442
  } catch {
27417
27443
  }
27418
- throw new Error(
27419
- `Claude Code not found. Looplia requires Claude Code to be installed.
27420
-
27421
- Install Claude Code:
27422
- npm install -g @anthropic-ai/claude-code
27423
-
27424
- Or set CLAUDE_CODE_PATH environment variable to your Claude installation.
27425
-
27426
- More info: https://docs.anthropic.com/claude-code`
27427
- );
27428
- }
27429
- var DEFAULT_CONFIG = {
27430
- model: "claude-haiku-4-5-20251001",
27431
- workspace: "~/.looplia",
27432
- useFilesystemExtensions: true,
27433
- maxRetries: 3,
27434
- timeout: 6e4
27435
- };
27436
- function resolveConfig(config2) {
27437
- return {
27438
- ...config2,
27439
- model: config2?.model ?? DEFAULT_CONFIG.model,
27440
- workspace: config2?.workspace ?? DEFAULT_CONFIG.workspace,
27441
- useFilesystemExtensions: config2?.useFilesystemExtensions ?? DEFAULT_CONFIG.useFilesystemExtensions,
27442
- maxRetries: config2?.maxRetries ?? DEFAULT_CONFIG.maxRetries,
27443
- timeout: config2?.timeout ?? DEFAULT_CONFIG.timeout
27444
- };
27445
- }
27446
- function generateLogFilename() {
27447
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
27448
- return `query-${timestamp}.log`;
27449
- }
27450
- function createQueryLogger(workspace) {
27451
- let logPath = null;
27452
- return {
27453
- init(sandboxId) {
27454
- const logsDir = join23(workspace, "sandbox", sandboxId, "logs");
27455
- mkdirSync3(logsDir, { recursive: true });
27456
- const filename = generateLogFilename();
27457
- logPath = join23(logsDir, filename);
27458
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
27459
- writeFileSync2(
27460
- logPath,
27461
- `Agent SDK Execution Log - ${timestamp}
27462
- ${"=".repeat(60)}
27463
-
27464
- `
27465
- );
27466
- return logPath;
27467
- },
27468
- log(message) {
27469
- if (!logPath) {
27470
- return;
27471
- }
27472
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
27473
- const logEntry = `[${timestamp}] ${JSON.stringify(message, null, 2)}
27474
-
27475
- `;
27476
- appendFileSync3(logPath, logEntry);
27477
- },
27478
- close() {
27479
- },
27480
- getLogPath() {
27481
- return logPath;
27482
- }
27483
- };
27444
+ const sdkCliPath = findSdkBundledCliPath();
27445
+ if (sdkCliPath) {
27446
+ cachedClaudeCodePath = sdkCliPath;
27447
+ return cachedClaudeCodePath;
27448
+ }
27449
+ cachedClaudeCodePath = null;
27450
+ return;
27484
27451
  }
27485
27452
  var DEFAULT_SETTINGS = {
27486
27453
  version: "1.0",
@@ -27489,7 +27456,7 @@ var DEFAULT_SETTINGS = {
27489
27456
  },
27490
27457
  agents: {
27491
27458
  main: "claude-haiku-4-5-20251001",
27492
- executor: "haiku"
27459
+ executor: "claude-haiku-4-5-20251001"
27493
27460
  }
27494
27461
  };
27495
27462
  var PRESETS = {
@@ -27498,13 +27465,19 @@ var PRESETS = {
27498
27465
  name: "Anthropic Claude Haiku",
27499
27466
  apiProvider: "anthropic",
27500
27467
  mainModel: "claude-haiku-4-5-20251001",
27501
- executorModel: "haiku"
27468
+ executorModel: "claude-haiku-4-5-20251001",
27469
+ haikuModel: "claude-haiku-4-5-20251001",
27470
+ sonnetModel: "claude-haiku-4-5-20251001",
27471
+ opusModel: "claude-haiku-4-5-20251001"
27502
27472
  },
27503
27473
  ANTHROPIC_CLAUDE_SONNET: {
27504
27474
  name: "Anthropic Claude Sonnet",
27505
27475
  apiProvider: "anthropic",
27506
27476
  mainModel: "claude-sonnet-4-5-20250514",
27507
- executorModel: "haiku"
27477
+ executorModel: "claude-sonnet-4-5-20250514",
27478
+ haikuModel: "claude-sonnet-4-5-20250514",
27479
+ sonnetModel: "claude-sonnet-4-5-20250514",
27480
+ opusModel: "claude-sonnet-4-5-20250514"
27508
27481
  },
27509
27482
  // ZenMux Presets
27510
27483
  ZENMUX_ANTHROPIC_HAIKU45: {
@@ -27512,106 +27485,148 @@ var PRESETS = {
27512
27485
  apiProvider: "zenmux",
27513
27486
  baseUrl: "https://zenmux.ai/api/anthropic",
27514
27487
  mainModel: "anthropic/claude-haiku-4.5",
27515
- executorModel: "anthropic/claude-haiku-4.5"
27488
+ executorModel: "anthropic/claude-haiku-4.5",
27489
+ haikuModel: "anthropic/claude-haiku-4.5",
27490
+ sonnetModel: "anthropic/claude-haiku-4.5",
27491
+ opusModel: "anthropic/claude-haiku-4.5"
27516
27492
  },
27517
27493
  ZENMUX_ZAI_GLM47: {
27518
27494
  name: "ZenMux GLM-4.7",
27519
27495
  apiProvider: "zenmux",
27520
27496
  baseUrl: "https://zenmux.ai/api/anthropic",
27521
27497
  mainModel: "z-ai/glm-4.7",
27522
- executorModel: "z-ai/glm-4.7"
27498
+ executorModel: "z-ai/glm-4.7",
27499
+ haikuModel: "z-ai/glm-4.7",
27500
+ sonnetModel: "z-ai/glm-4.7",
27501
+ opusModel: "z-ai/glm-4.7"
27523
27502
  },
27524
27503
  ZENMUX_MINIMAX_M21: {
27525
27504
  name: "ZenMux MiniMax-M2.1",
27526
27505
  apiProvider: "zenmux",
27527
27506
  baseUrl: "https://zenmux.ai/api/anthropic",
27528
27507
  mainModel: "minimax/minimax-m2.1",
27529
- executorModel: "minimax/minimax-m2.1"
27508
+ executorModel: "minimax/minimax-m2.1",
27509
+ haikuModel: "minimax/minimax-m2.1",
27510
+ sonnetModel: "minimax/minimax-m2.1",
27511
+ opusModel: "minimax/minimax-m2.1"
27530
27512
  },
27531
27513
  ZENMUX_GOOGLE_GEMINI3FLASH: {
27532
27514
  name: "ZenMux Gemini-3-Flash",
27533
27515
  apiProvider: "zenmux",
27534
27516
  baseUrl: "https://zenmux.ai/api/anthropic",
27535
27517
  mainModel: "google/gemini-3-flash-preview",
27536
- executorModel: "google/gemini-3-flash-preview"
27518
+ executorModel: "google/gemini-3-flash-preview",
27519
+ haikuModel: "google/gemini-3-flash-preview",
27520
+ sonnetModel: "google/gemini-3-flash-preview",
27521
+ opusModel: "google/gemini-3-flash-preview"
27537
27522
  },
27538
27523
  ZENMUX_GOOGLE_GEMINI3FLASH_FREE: {
27539
27524
  name: "ZenMux Gemini-3-Flash (Free)",
27540
27525
  apiProvider: "zenmux",
27541
27526
  baseUrl: "https://zenmux.ai/api/anthropic",
27542
27527
  mainModel: "google/gemini-3-flash-preview-free",
27543
- executorModel: "google/gemini-3-flash-preview-free"
27528
+ executorModel: "google/gemini-3-flash-preview-free",
27529
+ haikuModel: "google/gemini-3-flash-preview-free",
27530
+ sonnetModel: "google/gemini-3-flash-preview-free",
27531
+ opusModel: "google/gemini-3-flash-preview-free"
27544
27532
  },
27545
27533
  ZENMUX_XIAOMI_MIMOV2FLASH: {
27546
27534
  name: "ZenMux MiMo-v2-Flash",
27547
27535
  apiProvider: "zenmux",
27548
27536
  baseUrl: "https://zenmux.ai/api/anthropic",
27549
27537
  mainModel: "xiaomi/mimo-v2-flash",
27550
- executorModel: "xiaomi/mimo-v2-flash"
27538
+ executorModel: "xiaomi/mimo-v2-flash",
27539
+ haikuModel: "xiaomi/mimo-v2-flash",
27540
+ sonnetModel: "xiaomi/mimo-v2-flash",
27541
+ opusModel: "xiaomi/mimo-v2-flash"
27551
27542
  },
27552
27543
  ZENMUX_XAI_GROK41FAST: {
27553
27544
  name: "ZenMux Grok-4.1-Fast",
27554
27545
  apiProvider: "zenmux",
27555
27546
  baseUrl: "https://zenmux.ai/api/anthropic",
27556
27547
  mainModel: "x-ai/grok-4.1-fast",
27557
- executorModel: "x-ai/grok-4.1-fast"
27548
+ executorModel: "x-ai/grok-4.1-fast",
27549
+ haikuModel: "x-ai/grok-4.1-fast",
27550
+ sonnetModel: "x-ai/grok-4.1-fast",
27551
+ opusModel: "x-ai/grok-4.1-fast"
27558
27552
  },
27559
27553
  ZENMUX_DEEPSEEK_V32: {
27560
27554
  name: "ZenMux DeepSeek-v3.2",
27561
27555
  apiProvider: "zenmux",
27562
27556
  baseUrl: "https://zenmux.ai/api/anthropic",
27563
27557
  mainModel: "deepseek/deepseek-v3.2",
27564
- executorModel: "deepseek/deepseek-v3.2"
27558
+ executorModel: "deepseek/deepseek-v3.2",
27559
+ haikuModel: "deepseek/deepseek-v3.2",
27560
+ sonnetModel: "deepseek/deepseek-v3.2",
27561
+ opusModel: "deepseek/deepseek-v3.2"
27565
27562
  },
27566
27563
  ZENMUX_DEEPSEEK_REASONER: {
27567
27564
  name: "ZenMux DeepSeek-Reasoner",
27568
27565
  apiProvider: "zenmux",
27569
27566
  baseUrl: "https://zenmux.ai/api/anthropic",
27570
27567
  mainModel: "deepseek/deepseek-reasoner",
27571
- executorModel: "deepseek/deepseek-reasoner"
27568
+ executorModel: "deepseek/deepseek-reasoner",
27569
+ haikuModel: "deepseek/deepseek-reasoner",
27570
+ sonnetModel: "deepseek/deepseek-reasoner",
27571
+ opusModel: "deepseek/deepseek-reasoner"
27572
27572
  },
27573
27573
  ZENMUX_VOLCENGINE_DOUBAO_SEED: {
27574
27574
  name: "ZenMux Doubao-Seed-1.8",
27575
27575
  apiProvider: "zenmux",
27576
27576
  baseUrl: "https://zenmux.ai/api/anthropic",
27577
27577
  mainModel: "volcengine/doubao-seed-1.8",
27578
- executorModel: "volcengine/doubao-seed-1.8"
27578
+ executorModel: "volcengine/doubao-seed-1.8",
27579
+ haikuModel: "volcengine/doubao-seed-1.8",
27580
+ sonnetModel: "volcengine/doubao-seed-1.8",
27581
+ opusModel: "volcengine/doubao-seed-1.8"
27579
27582
  },
27580
27583
  ZENMUX_MISTRAL_LARGE2512: {
27581
27584
  name: "ZenMux Mistral-Large-2512",
27582
27585
  apiProvider: "zenmux",
27583
27586
  baseUrl: "https://zenmux.ai/api/anthropic",
27584
27587
  mainModel: "mistralai/mistral-large-2512",
27585
- executorModel: "mistralai/mistral-large-2512"
27588
+ executorModel: "mistralai/mistral-large-2512",
27589
+ haikuModel: "mistralai/mistral-large-2512",
27590
+ sonnetModel: "mistralai/mistral-large-2512",
27591
+ opusModel: "mistralai/mistral-large-2512"
27586
27592
  },
27587
27593
  ZENMUX_ZAI_GLM46VFLASH: {
27588
27594
  name: "ZenMux GLM-4.6v-Flash",
27589
27595
  apiProvider: "zenmux",
27590
27596
  baseUrl: "https://zenmux.ai/api/anthropic",
27591
27597
  mainModel: "z-ai/glm-4.6v-flash",
27592
- executorModel: "z-ai/glm-4.6v-flash"
27598
+ executorModel: "z-ai/glm-4.6v-flash",
27599
+ haikuModel: "z-ai/glm-4.6v-flash",
27600
+ sonnetModel: "z-ai/glm-4.6v-flash",
27601
+ opusModel: "z-ai/glm-4.6v-flash"
27593
27602
  },
27594
27603
  ZENMUX_ZAI_GLM46V: {
27595
27604
  name: "ZenMux GLM-4.6v",
27596
27605
  apiProvider: "zenmux",
27597
27606
  baseUrl: "https://zenmux.ai/api/anthropic",
27598
27607
  mainModel: "z-ai/glm-4.6v",
27599
- executorModel: "z-ai/glm-4.6v"
27608
+ executorModel: "z-ai/glm-4.6v",
27609
+ haikuModel: "z-ai/glm-4.6v",
27610
+ sonnetModel: "z-ai/glm-4.6v",
27611
+ opusModel: "z-ai/glm-4.6v"
27600
27612
  },
27601
27613
  ZENMUX_OPENAI_GPT51CODEXMINI: {
27602
27614
  name: "ZenMux GPT-5.1 Codex Mini",
27603
27615
  apiProvider: "zenmux",
27604
27616
  baseUrl: "https://zenmux.ai/api/anthropic",
27605
27617
  mainModel: "openai/gpt-5.1-codex-mini",
27606
- executorModel: "openai/gpt-5.1-codex-mini"
27618
+ executorModel: "openai/gpt-5.1-codex-mini",
27619
+ haikuModel: "openai/gpt-5.1-codex-mini",
27620
+ sonnetModel: "openai/gpt-5.1-codex-mini",
27621
+ opusModel: "openai/gpt-5.1-codex-mini"
27607
27622
  }
27608
27623
  };
27609
27624
  var CONFIG_FILE = "looplia.setting.json";
27610
27625
  function getLoopliaHome() {
27611
- return join32(homedir22(), ".looplia");
27626
+ return join23(homedir22(), ".looplia");
27612
27627
  }
27613
27628
  function getConfigPath() {
27614
- return join32(getLoopliaHome(), CONFIG_FILE);
27629
+ return join23(getLoopliaHome(), CONFIG_FILE);
27615
27630
  }
27616
27631
  async function readLoopliaSettings() {
27617
27632
  const configPath = getConfigPath();
@@ -27643,23 +27658,33 @@ async function writeLoopliaSettings(settings) {
27643
27658
  async function removeLoopliaSettings() {
27644
27659
  await rm2(getConfigPath(), { force: true });
27645
27660
  }
27661
+ function setEnvIfNotSet(key, value) {
27662
+ if (!process.env[key]) {
27663
+ process.env[key] = value;
27664
+ }
27665
+ }
27666
+ function injectModelTierEnv(mainModel, executorModel) {
27667
+ setEnvIfNotSet("ANTHROPIC_DEFAULT_HAIKU_MODEL", mainModel);
27668
+ setEnvIfNotSet("ANTHROPIC_DEFAULT_SONNET_MODEL", mainModel);
27669
+ setEnvIfNotSet("ANTHROPIC_DEFAULT_OPUS_MODEL", mainModel);
27670
+ setEnvIfNotSet("LOOPLIA_AGENT_MODEL_MAIN", mainModel);
27671
+ setEnvIfNotSet("LOOPLIA_AGENT_MODEL_EXECUTOR", executorModel);
27672
+ }
27646
27673
  function injectLoopliaSettingsEnv(settings) {
27647
27674
  if (settings.apiProvider.type !== "anthropic") {
27648
27675
  if (settings.apiProvider.baseUrl && !process.env.ANTHROPIC_BASE_URL) {
27649
27676
  process.env.ANTHROPIC_BASE_URL = settings.apiProvider.baseUrl;
27650
27677
  }
27651
- if (settings.apiProvider.type === "zenmux" && process.env.ZENMUX_API_KEY) {
27652
- process.env.ANTHROPIC_API_KEY = process.env.ZENMUX_API_KEY;
27653
- } else if (!process.env.ANTHROPIC_API_KEY && settings.apiProvider.authToken) {
27678
+ if (settings.apiProvider.authToken) {
27654
27679
  process.env.ANTHROPIC_API_KEY = settings.apiProvider.authToken;
27680
+ } else {
27681
+ const isZenmuxEndpoint = settings.apiProvider.type === "zenmux" || settings.apiProvider.baseUrl?.includes("zenmux.ai");
27682
+ if (isZenmuxEndpoint && process.env.ZENMUX_API_KEY) {
27683
+ process.env.ANTHROPIC_API_KEY = process.env.ZENMUX_API_KEY;
27684
+ }
27655
27685
  }
27656
27686
  }
27657
- if (!process.env.LOOPLIA_AGENT_MODEL_MAIN) {
27658
- process.env.LOOPLIA_AGENT_MODEL_MAIN = settings.agents.main;
27659
- }
27660
- if (!process.env.LOOPLIA_AGENT_MODEL_EXECUTOR) {
27661
- process.env.LOOPLIA_AGENT_MODEL_EXECUTOR = settings.agents.executor;
27662
- }
27687
+ injectModelTierEnv(settings.agents.main, settings.agents.executor);
27663
27688
  }
27664
27689
  function getSettingsDisplayInfo(settings) {
27665
27690
  if (!settings) {
@@ -27709,6 +27734,87 @@ function applyPreset(presetName, existingSettings) {
27709
27734
  }
27710
27735
  };
27711
27736
  }
27737
+ async function initializeCommandEnvironment(options = {}) {
27738
+ const settings = await readLoopliaSettings();
27739
+ if (settings) {
27740
+ injectLoopliaSettingsEnv(settings);
27741
+ }
27742
+ if (!options.mock) {
27743
+ validateApiKeyPresence();
27744
+ }
27745
+ return { settings };
27746
+ }
27747
+ function validateApiKeyPresence() {
27748
+ if (!(process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_OAUTH_TOKEN)) {
27749
+ console.error("Error: API key required");
27750
+ console.error("");
27751
+ console.error("Options:");
27752
+ console.error(" 1. Set ANTHROPIC_API_KEY environment variable");
27753
+ console.error(" 2. Set ZENMUX_API_KEY with a ZenMux preset");
27754
+ console.error(" 3. Configure via: looplia config provider preset <name>");
27755
+ console.error(" 4. Use --mock flag for testing without API");
27756
+ console.error("");
27757
+ console.error("Get your API key from: https://console.anthropic.com");
27758
+ console.error("Or use ZenMux at: https://zenmux.ai");
27759
+ process.exit(1);
27760
+ }
27761
+ }
27762
+ var DEFAULT_CONFIG = {
27763
+ model: "claude-haiku-4-5-20251001",
27764
+ workspace: "~/.looplia",
27765
+ useFilesystemExtensions: true,
27766
+ maxRetries: 3,
27767
+ timeout: 6e4
27768
+ };
27769
+ function resolveConfig(config2) {
27770
+ return {
27771
+ ...config2,
27772
+ model: config2?.model ?? DEFAULT_CONFIG.model,
27773
+ workspace: config2?.workspace ?? DEFAULT_CONFIG.workspace,
27774
+ useFilesystemExtensions: config2?.useFilesystemExtensions ?? DEFAULT_CONFIG.useFilesystemExtensions,
27775
+ maxRetries: config2?.maxRetries ?? DEFAULT_CONFIG.maxRetries,
27776
+ timeout: config2?.timeout ?? DEFAULT_CONFIG.timeout
27777
+ };
27778
+ }
27779
+ function generateLogFilename() {
27780
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
27781
+ return `query-${timestamp}.log`;
27782
+ }
27783
+ function createQueryLogger(workspace) {
27784
+ let logPath = null;
27785
+ return {
27786
+ init(sandboxId) {
27787
+ const logsDir = join32(workspace, "sandbox", sandboxId, "logs");
27788
+ mkdirSync3(logsDir, { recursive: true });
27789
+ const filename = generateLogFilename();
27790
+ logPath = join32(logsDir, filename);
27791
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
27792
+ writeFileSync2(
27793
+ logPath,
27794
+ `Agent SDK Execution Log - ${timestamp}
27795
+ ${"=".repeat(60)}
27796
+
27797
+ `
27798
+ );
27799
+ return logPath;
27800
+ },
27801
+ log(message) {
27802
+ if (!logPath) {
27803
+ return;
27804
+ }
27805
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
27806
+ const logEntry = `[${timestamp}] ${JSON.stringify(message, null, 2)}
27807
+
27808
+ `;
27809
+ appendFileSync3(logPath, logEntry);
27810
+ },
27811
+ close() {
27812
+ },
27813
+ getLogPath() {
27814
+ return logPath;
27815
+ }
27816
+ };
27817
+ }
27712
27818
  var DEFAULT_RATE_LIMIT_RETRY_MS = 6e4;
27713
27819
  function mapException(error2) {
27714
27820
  if (error2 instanceof Error) {
@@ -28495,14 +28601,10 @@ async function initializeAndValidateApiKey(config2) {
28495
28601
  "API key is required. Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN environment variable"
28496
28602
  );
28497
28603
  }
28498
- const isProxyProvider = settings !== null && settings.apiProvider.type !== "anthropic";
28499
- return { apiKey, isProxyProvider };
28604
+ return apiKey;
28500
28605
  }
28501
- function getAgentModels() {
28502
- return {
28503
- mainModel: process.env.LOOPLIA_AGENT_MODEL_MAIN ?? DEFAULT_SETTINGS.agents.main,
28504
- executorModel: process.env.LOOPLIA_AGENT_MODEL_EXECUTOR ?? DEFAULT_SETTINGS.agents.executor
28505
- };
28606
+ function getMainModel() {
28607
+ return process.env.LOOPLIA_AGENT_MODEL_MAIN ?? DEFAULT_SETTINGS.agents.main;
28506
28608
  }
28507
28609
  function* processEvent(event, progressTracker, context) {
28508
28610
  if (event.type === "tool_start" && event.tool === "Skill") {
@@ -28518,8 +28620,8 @@ function* processEvent(event, progressTracker, context) {
28518
28620
  }
28519
28621
  async function* executeAgenticQueryStreaming(prompt, jsonSchema, config2) {
28520
28622
  const resolvedConfig = resolveConfig(config2);
28521
- const { isProxyProvider } = await initializeAndValidateApiKey(config2);
28522
- const { mainModel, executorModel } = getAgentModels();
28623
+ await initializeAndValidateApiKey(config2);
28624
+ const mainModel = getMainModel();
28523
28625
  try {
28524
28626
  const workspace = config2?.workspace ?? await getOrInitWorkspace(
28525
28627
  resolvedConfig.workspace,
@@ -28550,51 +28652,12 @@ async function* executeAgenticQueryStreaming(prompt, jsonSchema, config2) {
28550
28652
  const pluginPaths = await getPluginPaths();
28551
28653
  const userCwd = process.cwd();
28552
28654
  const loopliaHome = getLoopliaPluginPath();
28553
- const workflowExecutionHint = isProxyProvider ? `
28554
-
28555
- ## Workflow Execution Mode: Inline (Proxy Provider)
28556
-
28557
- When executing looplia workflows (/run commands), use the "workflow-executor-inline" skill.
28558
- Execute all workflow steps INLINE without spawning Task subagents.
28559
- This ensures compatibility with your current API provider.` : "";
28560
- const agents = isProxyProvider ? void 0 : {
28561
- "skill-executor": {
28562
- description: "Universal skill orchestrator for looplia workflow steps. Executes a single workflow step by invoking skills.",
28563
- prompt: `You are the looplia skill-executor. Execute ONE workflow step by invoking the specified skill.
28564
-
28565
- ## Execution Protocol
28566
- 1. Read input files (if provided)
28567
- 2. Invoke the skill using the Skill tool
28568
- 3. Execute the mission with skill context
28569
- 4. Write JSON output to the specified path using Write tool
28570
-
28571
- ## CRITICAL: Output Writing is MANDATORY
28572
- YOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the workflow fails.
28573
-
28574
- ## Rules
28575
- - ALWAYS invoke the specified skill using Skill tool
28576
- - ALWAYS write output to the exact path using Write tool
28577
- - NEVER return results as text - always write JSON to output file
28578
- - NEVER spawn Task subagents - execute skills directly
28579
- - ALWAYS include contentId in JSON outputs`,
28580
- tools: [
28581
- "Read",
28582
- "Write",
28583
- "Skill",
28584
- "Glob",
28585
- "Grep",
28586
- "WebSearch",
28587
- "WebFetch"
28588
- ],
28589
- model: executorModel
28590
- }
28591
- };
28592
28655
  const claudeCodePath = findClaudeCodePath();
28593
28656
  const result = query({
28594
28657
  prompt,
28595
28658
  options: {
28596
- // v0.6.8: Use system-installed Claude Code
28597
- pathToClaudeCodeExecutable: claudeCodePath,
28659
+ // v0.6.8: Use system-installed Claude Code if available, otherwise SDK uses built-in
28660
+ ...claudeCodePath && { pathToClaudeCodeExecutable: claudeCodePath },
28598
28661
  // v0.6.6: Use configured main model
28599
28662
  model: mainModel,
28600
28663
  // v0.6.5: SDK works relative to ~/.looplia (sandbox, workflows, etc.)
@@ -28604,7 +28667,7 @@ YOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the
28604
28667
  // v0.6.5: Load plugins from local paths instead of project settings
28605
28668
  plugins: pluginPaths,
28606
28669
  // v0.6.5: Append looplia system prompt + user context to claude_code preset
28607
- // v0.6.6: Add provider-aware workflow hint for proxy providers
28670
+ // v0.6.9: Removed provider-aware hint - unified subagent strategy for all providers
28608
28671
  systemPrompt: {
28609
28672
  type: "preset",
28610
28673
  preset: "claude_code",
@@ -28614,7 +28677,7 @@ YOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the
28614
28677
 
28615
28678
  User Working Directory: ${userCwd}
28616
28679
 
28617
- When processing --file arguments or user file paths, resolve them against the User Working Directory above.${workflowExecutionHint}`
28680
+ When processing --file arguments or user file paths, resolve them against the User Working Directory above.`
28618
28681
  },
28619
28682
  // v0.6.0: Enable Task for subagent spawning, Write/Glob for file operations
28620
28683
  // v0.6.3: Added WebSearch/WebFetch for input-less search skill
@@ -28627,9 +28690,8 @@ When processing --file arguments or user file paths, resolve them against the Us
28627
28690
  "WebSearch",
28628
28691
  "WebFetch"
28629
28692
  ],
28630
- outputFormat: { type: "json_schema", schema: jsonSchema },
28631
- // v0.6.6: Conditional agents - only for Anthropic Direct API
28632
- agents
28693
+ outputFormat: { type: "json_schema", schema: jsonSchema }
28694
+ // v0.6.9: No custom agents - using built-in general-purpose for workflow steps
28633
28695
  }
28634
28696
  });
28635
28697
  let finalResult;
@@ -31400,19 +31462,6 @@ function ensureWorkspace2(mock) {
31400
31462
  }
31401
31463
  return workspace;
31402
31464
  }
31403
- function validateEnvironment(mock) {
31404
- if (mock) {
31405
- return;
31406
- }
31407
- if (!(process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_OAUTH_TOKEN)) {
31408
- console.error(
31409
- "Error: ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN required"
31410
- );
31411
- console.error("Get your API key from: https://console.anthropic.com");
31412
- console.error("Or use --mock flag to run without API key");
31413
- process.exit(1);
31414
- }
31415
- }
31416
31465
  function buildPrompt(args) {
31417
31466
  let prompt = BUILD_COMMAND;
31418
31467
  if (args.name) {
@@ -31603,8 +31652,8 @@ async function runBuildCommand(args) {
31603
31652
  return;
31604
31653
  }
31605
31654
  try {
31606
- validateEnvironment(parsed.mock);
31607
31655
  const workspace = ensureWorkspace2(parsed.mock);
31656
+ await initializeCommandEnvironment({ mock: parsed.mock });
31608
31657
  const prompt = buildPrompt(parsed);
31609
31658
  const result = await executeBuild(prompt, workspace, parsed);
31610
31659
  renderResult(result);
@@ -32614,11 +32663,11 @@ async function runConfigCommand(args) {
32614
32663
  }
32615
32664
 
32616
32665
  // src/commands/init.ts
32617
- import { dirname as dirname3, join as join7 } from "path";
32666
+ import { dirname as dirname4, join as join7 } from "path";
32618
32667
  import { createInterface as createInterface2 } from "readline";
32619
32668
  import { fileURLToPath as fileURLToPath3 } from "url";
32620
32669
  function getCliBundledPluginsPath() {
32621
- const currentFile = typeof __dirname !== "undefined" ? __dirname : dirname3(fileURLToPath3(import.meta.url));
32670
+ const currentFile = typeof __dirname !== "undefined" ? __dirname : dirname4(fileURLToPath3(import.meta.url));
32622
32671
  return join7(currentFile, "..", "plugins");
32623
32672
  }
32624
32673
  function printInitHelp() {
@@ -33018,19 +33067,6 @@ function ensureWorkspace3(mock) {
33018
33067
  }
33019
33068
  return workspace;
33020
33069
  }
33021
- function validateEnvironment2(mock) {
33022
- if (mock) {
33023
- return;
33024
- }
33025
- if (!(process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_OAUTH_TOKEN)) {
33026
- console.error(
33027
- "Error: ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN required"
33028
- );
33029
- console.error("Get your API key from: https://console.anthropic.com");
33030
- console.error("Or use --mock flag to run without API key");
33031
- process.exit(1);
33032
- }
33033
- }
33034
33070
  function buildRunPrompt(workflowId, sandboxId) {
33035
33071
  return `${RUN_COMMAND} ${workflowId} --sandbox-id ${sandboxId}`;
33036
33072
  }
@@ -33178,11 +33214,7 @@ async function runRunCommand(args) {
33178
33214
  const workspace = ensureWorkspace3(parsed.mock);
33179
33215
  const allowInputless = checkWorkflowInputless(workspace, parsed.workflowId);
33180
33216
  const sandboxId = resolveSandboxId(workspace, parsed, allowInputless);
33181
- const settings = await readLoopliaSettings();
33182
- if (settings) {
33183
- injectLoopliaSettingsEnv(settings);
33184
- }
33185
- validateEnvironment2(parsed.mock);
33217
+ await initializeCommandEnvironment({ mock: parsed.mock });
33186
33218
  const prompt = buildRunPrompt(parsed.workflowId, sandboxId);
33187
33219
  const result = await executeWorkflow(
33188
33220
  prompt,
@@ -33202,7 +33234,7 @@ async function runRunCommand(args) {
33202
33234
  }
33203
33235
 
33204
33236
  // src/index.ts
33205
- var VERSION = "0.6.8";
33237
+ var VERSION = "0.6.10";
33206
33238
  function printHelp3() {
33207
33239
  console.log(`
33208
33240
  looplia - Content intelligence CLI (v${VERSION})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@looplia/looplia-cli",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "description": "Looplia CLI - AI-powered workflow automation tool",
5
5
  "type": "module",
6
6
  "license": "Elastic-2.0",
@@ -30,7 +30,7 @@
30
30
  "scripts": {
31
31
  "build": "tsup",
32
32
  "dev": "tsup --watch",
33
- "start": "node dist/index.js",
33
+ "start": "node dist/cli.js",
34
34
  "test": "bun run build && bun test",
35
35
  "test:watch": "bun test --watch",
36
36
  "test:unit": "bun test commands/",
@@ -1,11 +1,6 @@
1
1
  {
2
2
  "$schema": "https://code.claude.com/schemas/hooks.json",
3
3
  "hooks": [
4
- {
5
- "event": "SessionStart",
6
- "command": "echo '🚀 Looplia session started'",
7
- "description": "Log session start"
8
- },
9
4
  {
10
5
  "event": "PostToolUse",
11
6
  "matcher": "Write",
@@ -76,6 +76,6 @@ LOCK_FILE="${VALIDATION_JSON}.lock"
76
76
  # Update validation.json to mark step as validated (v0.6.0 uses "steps")
77
77
  jq --arg art "$ARTIFACT" '.steps[$art].validated = true' "$VALIDATION_JSON" > "${VALIDATION_JSON}.tmp"
78
78
  mv "${VALIDATION_JSON}.tmp" "$VALIDATION_JSON"
79
- echo "✓ Validated: $ARTIFACT.json"
79
+ echo "✓ Validated: $ARTIFACT.json" >&2
80
80
 
81
81
  ) 200>"$LOCK_FILE"
@@ -6,14 +6,14 @@ description: |
6
6
  "execute this looplia pipeline", "/run writing-kit", "start the looplia automation", or
7
7
  "process these workflow steps".
8
8
 
9
- Architecture: One workflow step triggers one skill-executor subagent call, which then
10
- invokes multiple skills to accomplish the step's mission. Handles sandbox management,
11
- per-step skill-executor orchestration, and validation state tracking per v0.6.3.
9
+ Architecture: One workflow step triggers one general-purpose subagent call, which then
10
+ invokes skills to accomplish the step's mission. Each step = separate context window.
11
+ Handles sandbox management, per-step orchestration, and validation state tracking.
12
12
 
13
- v0.6.3: Named inputs (${{ inputs.name }}), input-less workflow support.
13
+ v0.6.9: Unified general-purpose subagent strategy for all providers (context offload).
14
14
  ---
15
15
 
16
- # Workflow Executor Skill (v0.6.3)
16
+ # Workflow Executor Skill (v0.6.9)
17
17
 
18
18
  Execute looplia workflows defined in `workflows/*.md` files using the skills-first architecture.
19
19
 
@@ -26,17 +26,17 @@ Use this skill when:
26
26
 
27
27
  ---
28
28
 
29
- ## CRITICAL: Universal Skill-Executor Invocation
29
+ ## CRITICAL: Task Invocation with general-purpose Subagent
30
30
 
31
- **v0.6.1 BREAKING CHANGE:** ALL workflow steps use `skill-executor` subagent.
31
+ **v0.6.9:** Using built-in `general-purpose` subagent for ALL workflow steps (all providers).
32
32
 
33
33
  When executing a step with `skill: {name}` and `mission:`:
34
34
 
35
35
  ```json
36
36
  {
37
- "subagent_type": "skill-executor",
37
+ "subagent_type": "general-purpose",
38
38
  "description": "Execute step: {step.id}",
39
- "prompt": "Execute skill '{step.skill}' for step '{step.id}'.\n\nMission: {step.mission}\n\nInput: {resolved input}\nOutput: {step.output}\nValidation: {step.validate}"
39
+ "prompt": "Execute skill '{step.skill}' for step '{step.id}'.\n\n## Mission\n{step.mission}\n\n## Execution Protocol\n1. Read input files (if provided)\n2. Invoke the skill using Skill tool\n3. Execute the mission with skill context\n4. Write JSON output to the specified path using Write tool\n\n## CRITICAL: Output Writing is MANDATORY\nYOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the workflow fails.\n\n## Rules\n- ALWAYS invoke the specified skill using Skill tool\n- ALWAYS write output to the exact path using Write tool\n- NEVER return results as text - always write JSON to output file\n- NEVER spawn Task subagents - execute skills directly\n- ALWAYS include contentId in JSON outputs\n\nInput: {resolved input path}\nOutput: {step.output}\nValidation: {step.validate JSON}"
40
40
  }
41
41
  ```
42
42
 
@@ -54,23 +54,22 @@ When executing a step with `skill: {name}` and `mission:`:
54
54
  **Task tool call:**
55
55
  ```json
56
56
  {
57
- "subagent_type": "skill-executor",
57
+ "subagent_type": "general-purpose",
58
58
  "description": "Execute step: analyze-content",
59
- "prompt": "Execute skill 'media-reviewer' for step 'analyze-content'.\n\nMission: Deep analysis of video transcript. Extract key themes, important quotes, and narrative structure.\n\nInput: sandbox/video-2025-01-15-abc123/inputs/content.md\nOutput: sandbox/video-2025-01-15-abc123/outputs/analysis.json\nValidation: {\"required_fields\":[\"contentId\",\"headline\",\"keyThemes\"]}"
59
+ "prompt": "Execute skill 'media-reviewer' for step 'analyze-content'.\n\n## Mission\nDeep analysis of video transcript. Extract key themes, important quotes, and narrative structure.\n\n## Execution Protocol\n1. Read input files (if provided)\n2. Invoke the skill using Skill tool\n3. Execute the mission with skill context\n4. Write JSON output to the specified path using Write tool\n\n## CRITICAL: Output Writing is MANDATORY\nYOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the workflow fails.\n\n## Rules\n- ALWAYS invoke the specified skill using Skill tool\n- ALWAYS write output to the exact path using Write tool\n- NEVER return results as text - always write JSON to output file\n- NEVER spawn Task subagents - execute skills directly\n- ALWAYS include contentId in JSON outputs\n\nInput: sandbox/video-2025-01-15-abc123/inputs/content.md\nOutput: sandbox/video-2025-01-15-abc123/outputs/analysis.json\nValidation: {\"required_fields\":[\"contentId\",\"headline\",\"keyThemes\"]}"
60
60
  }
61
61
  ```
62
62
 
63
63
  ### Rules
64
64
 
65
- - **ALWAYS** use `subagent_type: "skill-executor"` for ALL workflow steps
65
+ - **ALWAYS** use `subagent_type: "general-purpose"` for ALL workflow steps
66
66
  - **NEVER** use custom subagent_type per step (removed in v0.6.1)
67
- - **NEVER** use `subagent_type: "general-purpose"` for workflow steps
68
67
  - **VALIDATE** that step has both `skill:` and `mission:` fields
69
68
  - **REJECT** steps using deprecated `run:` syntax
70
69
 
71
70
  ### Why Per-Step Task Calls (Context Isolation)
72
71
 
73
- Each `Task(skill-executor)` creates a **separate context window**:
72
+ Each `Task(general-purpose)` creates a **separate context window**:
74
73
  - Isolates step processing from main agent context
75
74
  - Prevents context pollution across steps
76
75
  - Enables focused execution with only relevant inputs
@@ -249,7 +248,7 @@ Computed order: [analyze-content, generate-ideas, build-writing-kit]
249
248
  **Execute steps ONE AT A TIME (context isolation):**
250
249
 
251
250
  1. Get first unvalidated step from dependency order
252
- 2. Make ONE `Task(skill-executor)` call for THIS step only
251
+ 2. Make ONE `Task(general-purpose)` call for THIS step only
253
252
  3. WAIT for Task completion before proceeding
254
253
  4. Validate output, update validation.json
255
254
  5. REPEAT for next unvalidated step
@@ -271,10 +270,10 @@ FOR EACH step in dependency order:
271
270
  ┌─────────┐ ┌─────────────────────────────┐
272
271
  │ SKIP │ │ 1. INVOKE Task tool: │
273
272
  │ (done) │ │ subagent_type: │
274
- └─────────┘ │ "skill-executor"
273
+ └─────────┘ │ "general-purpose"
275
274
  │ │
276
- │ 2. skill-executor invokes
277
- the specified skill
275
+ │ 2. Subagent invokes the
276
+ │ specified skill
278
277
  │ │
279
278
  │ 3. VALIDATE output │
280
279
  │ │
@@ -302,9 +301,9 @@ For step:
302
301
  Invoke Task tool:
303
302
  ```json
304
303
  {
305
- "subagent_type": "skill-executor",
304
+ "subagent_type": "general-purpose",
306
305
  "description": "Execute step: analyze-content",
307
- "prompt": "Execute skill 'media-reviewer' for step 'analyze-content'.\n\nMission: Deep analysis of video transcript. Extract key themes, important quotes with timestamps, and narrative structure.\n\nInput: sandbox/article-2025-12-18-xk7m/inputs/content.md\nOutput: sandbox/article-2025-12-18-xk7m/outputs/analysis.json\nValidation: {\"required_fields\":[\"contentId\",\"headline\",\"keyThemes\"]}"
306
+ "prompt": "Execute skill 'media-reviewer' for step 'analyze-content'.\n\n## Mission\nDeep analysis of video transcript. Extract key themes, important quotes with timestamps, and narrative structure.\n\n## Execution Protocol\n1. Read input files (if provided)\n2. Invoke the skill using Skill tool\n3. Execute the mission with skill context\n4. Write JSON output to the specified path using Write tool\n\n## CRITICAL: Output Writing is MANDATORY\nYOU MUST CALL THE WRITE TOOL before completing.\n\n## Rules\n- ALWAYS invoke the specified skill using Skill tool\n- ALWAYS write output to the exact path using Write tool\n- NEVER return results as text - always write JSON to output file\n- ALWAYS include contentId in JSON outputs\n\nInput: sandbox/article-2025-12-18-xk7m/inputs/content.md\nOutput: sandbox/article-2025-12-18-xk7m/outputs/analysis.json\nValidation: {\"required_fields\":[\"contentId\",\"headline\",\"keyThemes\"]}"
308
307
  }
309
308
  ```
310
309
 
@@ -350,9 +349,9 @@ When step with `final: true` passes validation:
350
349
 
351
350
  ---
352
351
 
353
- ## Variable Substitution (v0.6.3)
352
+ ## Variable Substitution (v0.6.9)
354
353
 
355
- Resolve variables before passing to skill-executor:
354
+ Resolve variables before passing to general-purpose subagent:
356
355
 
357
356
  | Variable | Resolution | Example |
358
357
  |----------|------------|---------|
@@ -435,21 +434,21 @@ input: ${{ steps.analyze-content.output }}
435
434
  4. [ORDER] Computed: [analyze-content, generate-ideas, build-writing-kit]
436
435
 
437
436
  5. [STEP] analyze-content
438
- - Task tool: subagent_type="skill-executor"
437
+ - Task tool: subagent_type="general-purpose"
439
438
  - Skill: media-reviewer
440
439
  - Output: outputs/analysis.json
441
440
  - Validate: PASSED
442
441
  - Update: validation.json (analyze-content.validated = true)
443
442
 
444
443
  6. [STEP] generate-ideas
445
- - Task tool: subagent_type="skill-executor"
444
+ - Task tool: subagent_type="general-purpose"
446
445
  - Skill: idea-synthesis
447
446
  - Output: outputs/ideas.json
448
447
  - Validate: PASSED
449
448
  - Update: validation.json (generate-ideas.validated = true)
450
449
 
451
450
  7. [STEP] build-writing-kit
452
- - Task tool: subagent_type="skill-executor"
451
+ - Task tool: subagent_type="general-purpose"
453
452
  - Skill: writing-kit-assembler
454
453
  - Output: outputs/writing-kit.json
455
454
  - Validate: PASSED
@@ -463,7 +462,7 @@ input: ${{ steps.analyze-content.output }}
463
462
  ## File References
464
463
 
465
464
  - Workflow definitions: `workflows/*.md`
466
- - Skill-executor: Inline subagent defined in CLI (see query-executor.ts)
465
+ - Subagent: Built-in `general-purpose` agent (v0.6.9)
467
466
  - Skill definitions: `plugins/*/skills/*/SKILL.md`
468
467
  - Sandbox storage: `sandbox/{sandbox-id}/`
469
468
  - Validator script: `.claude/skills/workflow-validator/scripts/validate.ts`