@looplia/looplia-cli 0.6.7 → 0.6.9
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
|
@@ -13,7 +13,7 @@ var getDirname = () => path.dirname(getFilename());
|
|
|
13
13
|
var __dirname = /* @__PURE__ */ getDirname();
|
|
14
14
|
|
|
15
15
|
// src/commands/build.ts
|
|
16
|
-
import { existsSync as
|
|
16
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
17
17
|
import { homedir as homedir5 } from "os";
|
|
18
18
|
import { resolve as resolve2 } from "path";
|
|
19
19
|
|
|
@@ -243,6 +243,13 @@ async function getPluginPaths() {
|
|
|
243
243
|
return await getProdPluginPaths();
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
// ../../packages/provider/dist/chunk-5W3I2MT7.js
|
|
247
|
+
import { execSync } from "child_process";
|
|
248
|
+
import { existsSync as existsSync3 } from "fs";
|
|
249
|
+
import { createRequire } from "module";
|
|
250
|
+
import { homedir as homedir3 } from "os";
|
|
251
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
252
|
+
|
|
246
253
|
// ../../node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
247
254
|
var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
248
255
|
var defaultOptions = {
|
|
@@ -5568,7 +5575,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
5568
5575
|
return combined;
|
|
5569
5576
|
};
|
|
5570
5577
|
|
|
5571
|
-
// ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
5578
|
+
// ../../packages/provider/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
5572
5579
|
import { join as join5 } from "path";
|
|
5573
5580
|
import { fileURLToPath as fileURLToPath23 } from "url";
|
|
5574
5581
|
import { setMaxListeners } from "events";
|
|
@@ -27363,9 +27370,9 @@ function query({
|
|
|
27363
27370
|
return queryInstance;
|
|
27364
27371
|
}
|
|
27365
27372
|
|
|
27366
|
-
// ../../packages/provider/dist/chunk-
|
|
27373
|
+
// ../../packages/provider/dist/chunk-5W3I2MT7.js
|
|
27367
27374
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
27368
|
-
import { join as
|
|
27375
|
+
import { join as join23 } from "path";
|
|
27369
27376
|
import {
|
|
27370
27377
|
chmod,
|
|
27371
27378
|
mkdir as mkdir2,
|
|
@@ -27374,11 +27381,74 @@ import {
|
|
|
27374
27381
|
rm as rm2,
|
|
27375
27382
|
writeFile as writeFile2
|
|
27376
27383
|
} from "fs/promises";
|
|
27377
|
-
import { homedir as homedir3 } from "os";
|
|
27378
|
-
import { join as join23 } from "path";
|
|
27379
|
-
import { cp as cp2, mkdir as mkdir22, readFile as readFile22, rm as rm22, stat as stat2, writeFile as writeFile22 } from "fs/promises";
|
|
27380
27384
|
import { homedir as homedir22 } from "os";
|
|
27381
|
-
import {
|
|
27385
|
+
import { join as join32 } from "path";
|
|
27386
|
+
import { cp as cp2, mkdir as mkdir22, readFile as readFile22, rm as rm22, stat as stat2, writeFile as writeFile22 } from "fs/promises";
|
|
27387
|
+
import { homedir as homedir32 } from "os";
|
|
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
|
+
}
|
|
27405
|
+
var CLAUDE_CODE_PATHS = [
|
|
27406
|
+
// User's local bin (npm global install location)
|
|
27407
|
+
join4(homedir3(), ".local", "bin", "claude"),
|
|
27408
|
+
// System-wide installations
|
|
27409
|
+
"/usr/local/bin/claude",
|
|
27410
|
+
// macOS Homebrew
|
|
27411
|
+
"/opt/homebrew/bin/claude",
|
|
27412
|
+
// Windows (if applicable)
|
|
27413
|
+
join4(homedir3(), "AppData", "Local", "Programs", "claude", "claude.exe")
|
|
27414
|
+
];
|
|
27415
|
+
var cachedClaudeCodePath;
|
|
27416
|
+
function findClaudeCodePath() {
|
|
27417
|
+
if (cachedClaudeCodePath !== void 0) {
|
|
27418
|
+
return cachedClaudeCodePath ?? void 0;
|
|
27419
|
+
}
|
|
27420
|
+
const envPath = process.env.CLAUDE_CODE_PATH;
|
|
27421
|
+
if (envPath && existsSync3(envPath)) {
|
|
27422
|
+
cachedClaudeCodePath = envPath;
|
|
27423
|
+
return cachedClaudeCodePath;
|
|
27424
|
+
}
|
|
27425
|
+
for (const path3 of CLAUDE_CODE_PATHS) {
|
|
27426
|
+
if (existsSync3(path3)) {
|
|
27427
|
+
cachedClaudeCodePath = path3;
|
|
27428
|
+
return cachedClaudeCodePath;
|
|
27429
|
+
}
|
|
27430
|
+
}
|
|
27431
|
+
try {
|
|
27432
|
+
const pathLookupCommand = process.platform === "win32" ? "where claude" : "which claude";
|
|
27433
|
+
const rawResult = execSync(pathLookupCommand, {
|
|
27434
|
+
encoding: "utf-8",
|
|
27435
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
27436
|
+
}).trim();
|
|
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;
|
|
27441
|
+
}
|
|
27442
|
+
} catch {
|
|
27443
|
+
}
|
|
27444
|
+
const sdkCliPath = findSdkBundledCliPath();
|
|
27445
|
+
if (sdkCliPath) {
|
|
27446
|
+
cachedClaudeCodePath = sdkCliPath;
|
|
27447
|
+
return cachedClaudeCodePath;
|
|
27448
|
+
}
|
|
27449
|
+
cachedClaudeCodePath = null;
|
|
27450
|
+
return;
|
|
27451
|
+
}
|
|
27382
27452
|
var DEFAULT_CONFIG = {
|
|
27383
27453
|
model: "claude-haiku-4-5-20251001",
|
|
27384
27454
|
workspace: "~/.looplia",
|
|
@@ -27404,10 +27474,10 @@ function createQueryLogger(workspace) {
|
|
|
27404
27474
|
let logPath = null;
|
|
27405
27475
|
return {
|
|
27406
27476
|
init(sandboxId) {
|
|
27407
|
-
const logsDir =
|
|
27477
|
+
const logsDir = join23(workspace, "sandbox", sandboxId, "logs");
|
|
27408
27478
|
mkdirSync3(logsDir, { recursive: true });
|
|
27409
27479
|
const filename = generateLogFilename();
|
|
27410
|
-
logPath =
|
|
27480
|
+
logPath = join23(logsDir, filename);
|
|
27411
27481
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
27412
27482
|
writeFileSync2(
|
|
27413
27483
|
logPath,
|
|
@@ -27442,7 +27512,7 @@ var DEFAULT_SETTINGS = {
|
|
|
27442
27512
|
},
|
|
27443
27513
|
agents: {
|
|
27444
27514
|
main: "claude-haiku-4-5-20251001",
|
|
27445
|
-
executor: "haiku"
|
|
27515
|
+
executor: "claude-haiku-4-5-20251001"
|
|
27446
27516
|
}
|
|
27447
27517
|
};
|
|
27448
27518
|
var PRESETS = {
|
|
@@ -27451,13 +27521,19 @@ var PRESETS = {
|
|
|
27451
27521
|
name: "Anthropic Claude Haiku",
|
|
27452
27522
|
apiProvider: "anthropic",
|
|
27453
27523
|
mainModel: "claude-haiku-4-5-20251001",
|
|
27454
|
-
executorModel: "haiku"
|
|
27524
|
+
executorModel: "claude-haiku-4-5-20251001",
|
|
27525
|
+
haikuModel: "claude-haiku-4-5-20251001",
|
|
27526
|
+
sonnetModel: "claude-haiku-4-5-20251001",
|
|
27527
|
+
opusModel: "claude-haiku-4-5-20251001"
|
|
27455
27528
|
},
|
|
27456
27529
|
ANTHROPIC_CLAUDE_SONNET: {
|
|
27457
27530
|
name: "Anthropic Claude Sonnet",
|
|
27458
27531
|
apiProvider: "anthropic",
|
|
27459
27532
|
mainModel: "claude-sonnet-4-5-20250514",
|
|
27460
|
-
executorModel: "
|
|
27533
|
+
executorModel: "claude-sonnet-4-5-20250514",
|
|
27534
|
+
haikuModel: "claude-sonnet-4-5-20250514",
|
|
27535
|
+
sonnetModel: "claude-sonnet-4-5-20250514",
|
|
27536
|
+
opusModel: "claude-sonnet-4-5-20250514"
|
|
27461
27537
|
},
|
|
27462
27538
|
// ZenMux Presets
|
|
27463
27539
|
ZENMUX_ANTHROPIC_HAIKU45: {
|
|
@@ -27465,106 +27541,148 @@ var PRESETS = {
|
|
|
27465
27541
|
apiProvider: "zenmux",
|
|
27466
27542
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27467
27543
|
mainModel: "anthropic/claude-haiku-4.5",
|
|
27468
|
-
executorModel: "anthropic/claude-haiku-4.5"
|
|
27544
|
+
executorModel: "anthropic/claude-haiku-4.5",
|
|
27545
|
+
haikuModel: "anthropic/claude-haiku-4.5",
|
|
27546
|
+
sonnetModel: "anthropic/claude-haiku-4.5",
|
|
27547
|
+
opusModel: "anthropic/claude-haiku-4.5"
|
|
27469
27548
|
},
|
|
27470
27549
|
ZENMUX_ZAI_GLM47: {
|
|
27471
27550
|
name: "ZenMux GLM-4.7",
|
|
27472
27551
|
apiProvider: "zenmux",
|
|
27473
27552
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27474
27553
|
mainModel: "z-ai/glm-4.7",
|
|
27475
|
-
executorModel: "z-ai/glm-4.7"
|
|
27554
|
+
executorModel: "z-ai/glm-4.7",
|
|
27555
|
+
haikuModel: "z-ai/glm-4.7",
|
|
27556
|
+
sonnetModel: "z-ai/glm-4.7",
|
|
27557
|
+
opusModel: "z-ai/glm-4.7"
|
|
27476
27558
|
},
|
|
27477
27559
|
ZENMUX_MINIMAX_M21: {
|
|
27478
27560
|
name: "ZenMux MiniMax-M2.1",
|
|
27479
27561
|
apiProvider: "zenmux",
|
|
27480
27562
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27481
27563
|
mainModel: "minimax/minimax-m2.1",
|
|
27482
|
-
executorModel: "minimax/minimax-m2.1"
|
|
27564
|
+
executorModel: "minimax/minimax-m2.1",
|
|
27565
|
+
haikuModel: "minimax/minimax-m2.1",
|
|
27566
|
+
sonnetModel: "minimax/minimax-m2.1",
|
|
27567
|
+
opusModel: "minimax/minimax-m2.1"
|
|
27483
27568
|
},
|
|
27484
27569
|
ZENMUX_GOOGLE_GEMINI3FLASH: {
|
|
27485
27570
|
name: "ZenMux Gemini-3-Flash",
|
|
27486
27571
|
apiProvider: "zenmux",
|
|
27487
27572
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27488
27573
|
mainModel: "google/gemini-3-flash-preview",
|
|
27489
|
-
executorModel: "google/gemini-3-flash-preview"
|
|
27574
|
+
executorModel: "google/gemini-3-flash-preview",
|
|
27575
|
+
haikuModel: "google/gemini-3-flash-preview",
|
|
27576
|
+
sonnetModel: "google/gemini-3-flash-preview",
|
|
27577
|
+
opusModel: "google/gemini-3-flash-preview"
|
|
27490
27578
|
},
|
|
27491
27579
|
ZENMUX_GOOGLE_GEMINI3FLASH_FREE: {
|
|
27492
27580
|
name: "ZenMux Gemini-3-Flash (Free)",
|
|
27493
27581
|
apiProvider: "zenmux",
|
|
27494
27582
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27495
27583
|
mainModel: "google/gemini-3-flash-preview-free",
|
|
27496
|
-
executorModel: "google/gemini-3-flash-preview-free"
|
|
27584
|
+
executorModel: "google/gemini-3-flash-preview-free",
|
|
27585
|
+
haikuModel: "google/gemini-3-flash-preview-free",
|
|
27586
|
+
sonnetModel: "google/gemini-3-flash-preview-free",
|
|
27587
|
+
opusModel: "google/gemini-3-flash-preview-free"
|
|
27497
27588
|
},
|
|
27498
27589
|
ZENMUX_XIAOMI_MIMOV2FLASH: {
|
|
27499
27590
|
name: "ZenMux MiMo-v2-Flash",
|
|
27500
27591
|
apiProvider: "zenmux",
|
|
27501
27592
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27502
27593
|
mainModel: "xiaomi/mimo-v2-flash",
|
|
27503
|
-
executorModel: "xiaomi/mimo-v2-flash"
|
|
27594
|
+
executorModel: "xiaomi/mimo-v2-flash",
|
|
27595
|
+
haikuModel: "xiaomi/mimo-v2-flash",
|
|
27596
|
+
sonnetModel: "xiaomi/mimo-v2-flash",
|
|
27597
|
+
opusModel: "xiaomi/mimo-v2-flash"
|
|
27504
27598
|
},
|
|
27505
27599
|
ZENMUX_XAI_GROK41FAST: {
|
|
27506
27600
|
name: "ZenMux Grok-4.1-Fast",
|
|
27507
27601
|
apiProvider: "zenmux",
|
|
27508
27602
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27509
27603
|
mainModel: "x-ai/grok-4.1-fast",
|
|
27510
|
-
executorModel: "x-ai/grok-4.1-fast"
|
|
27604
|
+
executorModel: "x-ai/grok-4.1-fast",
|
|
27605
|
+
haikuModel: "x-ai/grok-4.1-fast",
|
|
27606
|
+
sonnetModel: "x-ai/grok-4.1-fast",
|
|
27607
|
+
opusModel: "x-ai/grok-4.1-fast"
|
|
27511
27608
|
},
|
|
27512
27609
|
ZENMUX_DEEPSEEK_V32: {
|
|
27513
27610
|
name: "ZenMux DeepSeek-v3.2",
|
|
27514
27611
|
apiProvider: "zenmux",
|
|
27515
27612
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27516
27613
|
mainModel: "deepseek/deepseek-v3.2",
|
|
27517
|
-
executorModel: "deepseek/deepseek-v3.2"
|
|
27614
|
+
executorModel: "deepseek/deepseek-v3.2",
|
|
27615
|
+
haikuModel: "deepseek/deepseek-v3.2",
|
|
27616
|
+
sonnetModel: "deepseek/deepseek-v3.2",
|
|
27617
|
+
opusModel: "deepseek/deepseek-v3.2"
|
|
27518
27618
|
},
|
|
27519
27619
|
ZENMUX_DEEPSEEK_REASONER: {
|
|
27520
27620
|
name: "ZenMux DeepSeek-Reasoner",
|
|
27521
27621
|
apiProvider: "zenmux",
|
|
27522
27622
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27523
27623
|
mainModel: "deepseek/deepseek-reasoner",
|
|
27524
|
-
executorModel: "deepseek/deepseek-reasoner"
|
|
27624
|
+
executorModel: "deepseek/deepseek-reasoner",
|
|
27625
|
+
haikuModel: "deepseek/deepseek-reasoner",
|
|
27626
|
+
sonnetModel: "deepseek/deepseek-reasoner",
|
|
27627
|
+
opusModel: "deepseek/deepseek-reasoner"
|
|
27525
27628
|
},
|
|
27526
27629
|
ZENMUX_VOLCENGINE_DOUBAO_SEED: {
|
|
27527
27630
|
name: "ZenMux Doubao-Seed-1.8",
|
|
27528
27631
|
apiProvider: "zenmux",
|
|
27529
27632
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27530
27633
|
mainModel: "volcengine/doubao-seed-1.8",
|
|
27531
|
-
executorModel: "volcengine/doubao-seed-1.8"
|
|
27634
|
+
executorModel: "volcengine/doubao-seed-1.8",
|
|
27635
|
+
haikuModel: "volcengine/doubao-seed-1.8",
|
|
27636
|
+
sonnetModel: "volcengine/doubao-seed-1.8",
|
|
27637
|
+
opusModel: "volcengine/doubao-seed-1.8"
|
|
27532
27638
|
},
|
|
27533
27639
|
ZENMUX_MISTRAL_LARGE2512: {
|
|
27534
27640
|
name: "ZenMux Mistral-Large-2512",
|
|
27535
27641
|
apiProvider: "zenmux",
|
|
27536
27642
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27537
27643
|
mainModel: "mistralai/mistral-large-2512",
|
|
27538
|
-
executorModel: "mistralai/mistral-large-2512"
|
|
27644
|
+
executorModel: "mistralai/mistral-large-2512",
|
|
27645
|
+
haikuModel: "mistralai/mistral-large-2512",
|
|
27646
|
+
sonnetModel: "mistralai/mistral-large-2512",
|
|
27647
|
+
opusModel: "mistralai/mistral-large-2512"
|
|
27539
27648
|
},
|
|
27540
27649
|
ZENMUX_ZAI_GLM46VFLASH: {
|
|
27541
27650
|
name: "ZenMux GLM-4.6v-Flash",
|
|
27542
27651
|
apiProvider: "zenmux",
|
|
27543
27652
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27544
27653
|
mainModel: "z-ai/glm-4.6v-flash",
|
|
27545
|
-
executorModel: "z-ai/glm-4.6v-flash"
|
|
27654
|
+
executorModel: "z-ai/glm-4.6v-flash",
|
|
27655
|
+
haikuModel: "z-ai/glm-4.6v-flash",
|
|
27656
|
+
sonnetModel: "z-ai/glm-4.6v-flash",
|
|
27657
|
+
opusModel: "z-ai/glm-4.6v-flash"
|
|
27546
27658
|
},
|
|
27547
27659
|
ZENMUX_ZAI_GLM46V: {
|
|
27548
27660
|
name: "ZenMux GLM-4.6v",
|
|
27549
27661
|
apiProvider: "zenmux",
|
|
27550
27662
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27551
27663
|
mainModel: "z-ai/glm-4.6v",
|
|
27552
|
-
executorModel: "z-ai/glm-4.6v"
|
|
27664
|
+
executorModel: "z-ai/glm-4.6v",
|
|
27665
|
+
haikuModel: "z-ai/glm-4.6v",
|
|
27666
|
+
sonnetModel: "z-ai/glm-4.6v",
|
|
27667
|
+
opusModel: "z-ai/glm-4.6v"
|
|
27553
27668
|
},
|
|
27554
27669
|
ZENMUX_OPENAI_GPT51CODEXMINI: {
|
|
27555
27670
|
name: "ZenMux GPT-5.1 Codex Mini",
|
|
27556
27671
|
apiProvider: "zenmux",
|
|
27557
27672
|
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
27558
27673
|
mainModel: "openai/gpt-5.1-codex-mini",
|
|
27559
|
-
executorModel: "openai/gpt-5.1-codex-mini"
|
|
27674
|
+
executorModel: "openai/gpt-5.1-codex-mini",
|
|
27675
|
+
haikuModel: "openai/gpt-5.1-codex-mini",
|
|
27676
|
+
sonnetModel: "openai/gpt-5.1-codex-mini",
|
|
27677
|
+
opusModel: "openai/gpt-5.1-codex-mini"
|
|
27560
27678
|
}
|
|
27561
27679
|
};
|
|
27562
27680
|
var CONFIG_FILE = "looplia.setting.json";
|
|
27563
27681
|
function getLoopliaHome() {
|
|
27564
|
-
return
|
|
27682
|
+
return join32(homedir22(), ".looplia");
|
|
27565
27683
|
}
|
|
27566
27684
|
function getConfigPath() {
|
|
27567
|
-
return
|
|
27685
|
+
return join32(getLoopliaHome(), CONFIG_FILE);
|
|
27568
27686
|
}
|
|
27569
27687
|
async function readLoopliaSettings() {
|
|
27570
27688
|
const configPath = getConfigPath();
|
|
@@ -27596,23 +27714,33 @@ async function writeLoopliaSettings(settings) {
|
|
|
27596
27714
|
async function removeLoopliaSettings() {
|
|
27597
27715
|
await rm2(getConfigPath(), { force: true });
|
|
27598
27716
|
}
|
|
27717
|
+
function setEnvIfNotSet(key, value) {
|
|
27718
|
+
if (!process.env[key]) {
|
|
27719
|
+
process.env[key] = value;
|
|
27720
|
+
}
|
|
27721
|
+
}
|
|
27722
|
+
function injectModelTierEnv(mainModel, executorModel) {
|
|
27723
|
+
setEnvIfNotSet("ANTHROPIC_DEFAULT_HAIKU_MODEL", mainModel);
|
|
27724
|
+
setEnvIfNotSet("ANTHROPIC_DEFAULT_SONNET_MODEL", mainModel);
|
|
27725
|
+
setEnvIfNotSet("ANTHROPIC_DEFAULT_OPUS_MODEL", mainModel);
|
|
27726
|
+
setEnvIfNotSet("LOOPLIA_AGENT_MODEL_MAIN", mainModel);
|
|
27727
|
+
setEnvIfNotSet("LOOPLIA_AGENT_MODEL_EXECUTOR", executorModel);
|
|
27728
|
+
}
|
|
27599
27729
|
function injectLoopliaSettingsEnv(settings) {
|
|
27600
27730
|
if (settings.apiProvider.type !== "anthropic") {
|
|
27601
27731
|
if (settings.apiProvider.baseUrl && !process.env.ANTHROPIC_BASE_URL) {
|
|
27602
27732
|
process.env.ANTHROPIC_BASE_URL = settings.apiProvider.baseUrl;
|
|
27603
27733
|
}
|
|
27604
|
-
if (settings.apiProvider.
|
|
27605
|
-
process.env.ANTHROPIC_API_KEY = process.env.ZENMUX_API_KEY;
|
|
27606
|
-
} else if (!process.env.ANTHROPIC_API_KEY && settings.apiProvider.authToken) {
|
|
27734
|
+
if (settings.apiProvider.authToken) {
|
|
27607
27735
|
process.env.ANTHROPIC_API_KEY = settings.apiProvider.authToken;
|
|
27736
|
+
} else {
|
|
27737
|
+
const isZenmuxEndpoint = settings.apiProvider.type === "zenmux" || settings.apiProvider.baseUrl?.includes("zenmux.ai");
|
|
27738
|
+
if (isZenmuxEndpoint && process.env.ZENMUX_API_KEY) {
|
|
27739
|
+
process.env.ANTHROPIC_API_KEY = process.env.ZENMUX_API_KEY;
|
|
27740
|
+
}
|
|
27608
27741
|
}
|
|
27609
27742
|
}
|
|
27610
|
-
|
|
27611
|
-
process.env.LOOPLIA_AGENT_MODEL_MAIN = settings.agents.main;
|
|
27612
|
-
}
|
|
27613
|
-
if (!process.env.LOOPLIA_AGENT_MODEL_EXECUTOR) {
|
|
27614
|
-
process.env.LOOPLIA_AGENT_MODEL_EXECUTOR = settings.agents.executor;
|
|
27615
|
-
}
|
|
27743
|
+
injectModelTierEnv(settings.agents.main, settings.agents.executor);
|
|
27616
27744
|
}
|
|
27617
27745
|
function getSettingsDisplayInfo(settings) {
|
|
27618
27746
|
if (!settings) {
|
|
@@ -27762,11 +27890,11 @@ function extractSandboxIdFromPrompt(prompt) {
|
|
|
27762
27890
|
var extractContentIdFromPrompt = extractSandboxIdFromPrompt;
|
|
27763
27891
|
function expandPath(path3) {
|
|
27764
27892
|
if (path3.startsWith("~/") || path3 === "~") {
|
|
27765
|
-
const home =
|
|
27893
|
+
const home = homedir32();
|
|
27766
27894
|
if (!home) {
|
|
27767
27895
|
throw new Error("Unable to determine home directory");
|
|
27768
27896
|
}
|
|
27769
|
-
const expanded = path3 === "~" ? home :
|
|
27897
|
+
const expanded = path3 === "~" ? home : join42(home, path3.slice(2));
|
|
27770
27898
|
return normalize(expanded);
|
|
27771
27899
|
}
|
|
27772
27900
|
if (isAbsolute(path3)) {
|
|
@@ -27783,23 +27911,23 @@ async function pathExists2(path3) {
|
|
|
27783
27911
|
}
|
|
27784
27912
|
}
|
|
27785
27913
|
function getPluginPaths2() {
|
|
27786
|
-
const base =
|
|
27914
|
+
const base = join42(process.cwd(), "plugins");
|
|
27787
27915
|
return {
|
|
27788
|
-
core:
|
|
27789
|
-
writer:
|
|
27916
|
+
core: join42(base, "looplia-core"),
|
|
27917
|
+
writer: join42(base, "looplia-writer")
|
|
27790
27918
|
};
|
|
27791
27919
|
}
|
|
27792
27920
|
async function checkRequiredFiles(workspaceDir) {
|
|
27793
27921
|
const requiredPaths = [
|
|
27794
27922
|
// Core structure
|
|
27795
|
-
|
|
27796
|
-
|
|
27797
|
-
|
|
27798
|
-
|
|
27923
|
+
join42(workspaceDir, "CLAUDE.md"),
|
|
27924
|
+
join42(workspaceDir, ".claude", "agents"),
|
|
27925
|
+
join42(workspaceDir, ".claude", "skills"),
|
|
27926
|
+
join42(workspaceDir, "workflows"),
|
|
27799
27927
|
// From looplia-core plugin
|
|
27800
|
-
|
|
27801
|
-
|
|
27802
|
-
|
|
27928
|
+
join42(workspaceDir, ".claude", "commands"),
|
|
27929
|
+
join42(workspaceDir, ".claude", "skills", "workflow-executor"),
|
|
27930
|
+
join42(workspaceDir, ".claude", "skills", "workflow-validator")
|
|
27803
27931
|
];
|
|
27804
27932
|
for (const path3 of requiredPaths) {
|
|
27805
27933
|
if (!await pathExists2(path3)) {
|
|
@@ -27828,33 +27956,33 @@ async function createTestWorkspace(workspaceDir, force) {
|
|
|
27828
27956
|
await rm22(workspaceDir, { recursive: true, force: true });
|
|
27829
27957
|
}
|
|
27830
27958
|
await mkdir22(workspaceDir, { recursive: true });
|
|
27831
|
-
await mkdir22(
|
|
27832
|
-
await mkdir22(
|
|
27833
|
-
await mkdir22(
|
|
27959
|
+
await mkdir22(join42(workspaceDir, ".claude", "agents"), { recursive: true });
|
|
27960
|
+
await mkdir22(join42(workspaceDir, ".claude", "skills"), { recursive: true });
|
|
27961
|
+
await mkdir22(join42(workspaceDir, "sandbox"), { recursive: true });
|
|
27834
27962
|
const plugins = getPluginPaths2();
|
|
27835
|
-
const writerWorkflowsDir =
|
|
27963
|
+
const writerWorkflowsDir = join42(plugins.writer, "workflows");
|
|
27836
27964
|
if (await pathExists2(writerWorkflowsDir)) {
|
|
27837
|
-
await cp2(writerWorkflowsDir,
|
|
27965
|
+
await cp2(writerWorkflowsDir, join42(workspaceDir, "workflows"), {
|
|
27838
27966
|
recursive: true
|
|
27839
27967
|
});
|
|
27840
27968
|
} else {
|
|
27841
|
-
await mkdir22(
|
|
27969
|
+
await mkdir22(join42(workspaceDir, "workflows"), { recursive: true });
|
|
27842
27970
|
}
|
|
27843
|
-
const coreValidatorDir =
|
|
27971
|
+
const coreValidatorDir = join42(plugins.core, "skills", "workflow-validator");
|
|
27844
27972
|
if (await pathExists2(coreValidatorDir)) {
|
|
27845
27973
|
await cp2(
|
|
27846
27974
|
coreValidatorDir,
|
|
27847
|
-
|
|
27975
|
+
join42(workspaceDir, ".claude", "skills", "workflow-validator"),
|
|
27848
27976
|
{ recursive: true }
|
|
27849
27977
|
);
|
|
27850
27978
|
}
|
|
27851
27979
|
await writeFile22(
|
|
27852
|
-
|
|
27980
|
+
join42(workspaceDir, "CLAUDE.md"),
|
|
27853
27981
|
"# Test Workspace\n",
|
|
27854
27982
|
"utf-8"
|
|
27855
27983
|
);
|
|
27856
27984
|
await writeFile22(
|
|
27857
|
-
|
|
27985
|
+
join42(workspaceDir, "user-profile.json"),
|
|
27858
27986
|
JSON.stringify(createDefaultProfile2(), null, 2),
|
|
27859
27987
|
"utf-8"
|
|
27860
27988
|
);
|
|
@@ -27865,63 +27993,63 @@ async function bootstrapFromPlugins(workspaceDir, plugins) {
|
|
|
27865
27993
|
await rm22(workspaceDir, { recursive: true, force: true });
|
|
27866
27994
|
}
|
|
27867
27995
|
await mkdir22(workspaceDir, { recursive: true });
|
|
27868
|
-
await mkdir22(
|
|
27869
|
-
await mkdir22(
|
|
27870
|
-
const coreCommandsDir =
|
|
27996
|
+
await mkdir22(join42(workspaceDir, ".claude"), { recursive: true });
|
|
27997
|
+
await mkdir22(join42(workspaceDir, "sandbox"), { recursive: true });
|
|
27998
|
+
const coreCommandsDir = join42(plugins.core, "commands");
|
|
27871
27999
|
if (await pathExists2(coreCommandsDir)) {
|
|
27872
|
-
await cp2(coreCommandsDir,
|
|
28000
|
+
await cp2(coreCommandsDir, join42(workspaceDir, ".claude", "commands"), {
|
|
27873
28001
|
recursive: true
|
|
27874
28002
|
});
|
|
27875
28003
|
}
|
|
27876
|
-
const coreSkillsDir =
|
|
28004
|
+
const coreSkillsDir = join42(plugins.core, "skills");
|
|
27877
28005
|
if (await pathExists2(coreSkillsDir)) {
|
|
27878
|
-
await cp2(coreSkillsDir,
|
|
28006
|
+
await cp2(coreSkillsDir, join42(workspaceDir, ".claude", "skills"), {
|
|
27879
28007
|
recursive: true
|
|
27880
28008
|
});
|
|
27881
28009
|
}
|
|
27882
|
-
const coreHooksDir =
|
|
28010
|
+
const coreHooksDir = join42(plugins.core, "hooks");
|
|
27883
28011
|
if (await pathExists2(coreHooksDir)) {
|
|
27884
|
-
await cp2(coreHooksDir,
|
|
28012
|
+
await cp2(coreHooksDir, join42(workspaceDir, ".claude", "hooks"), {
|
|
27885
28013
|
recursive: true
|
|
27886
28014
|
});
|
|
27887
28015
|
}
|
|
27888
|
-
const coreAgentsDir =
|
|
28016
|
+
const coreAgentsDir = join42(plugins.core, "agents");
|
|
27889
28017
|
if (await pathExists2(coreAgentsDir)) {
|
|
27890
|
-
await mkdir22(
|
|
27891
|
-
await cp2(coreAgentsDir,
|
|
28018
|
+
await mkdir22(join42(workspaceDir, ".claude", "agents"), { recursive: true });
|
|
28019
|
+
await cp2(coreAgentsDir, join42(workspaceDir, ".claude", "agents"), {
|
|
27892
28020
|
recursive: true
|
|
27893
28021
|
});
|
|
27894
28022
|
}
|
|
27895
|
-
const coreScriptsDir =
|
|
28023
|
+
const coreScriptsDir = join42(plugins.core, "scripts");
|
|
27896
28024
|
if (await pathExists2(coreScriptsDir)) {
|
|
27897
|
-
await cp2(coreScriptsDir,
|
|
28025
|
+
await cp2(coreScriptsDir, join42(workspaceDir, "scripts"), {
|
|
27898
28026
|
recursive: true
|
|
27899
28027
|
});
|
|
27900
28028
|
}
|
|
27901
|
-
const coreClaudeMd =
|
|
28029
|
+
const coreClaudeMd = join42(plugins.core, "CLAUDE.md");
|
|
27902
28030
|
if (await pathExists2(coreClaudeMd)) {
|
|
27903
|
-
await cp2(coreClaudeMd,
|
|
28031
|
+
await cp2(coreClaudeMd, join42(workspaceDir, "CLAUDE.md"));
|
|
27904
28032
|
}
|
|
27905
|
-
const writerAgentsDir =
|
|
28033
|
+
const writerAgentsDir = join42(plugins.writer, "agents");
|
|
27906
28034
|
if (await pathExists2(writerAgentsDir)) {
|
|
27907
|
-
await cp2(writerAgentsDir,
|
|
28035
|
+
await cp2(writerAgentsDir, join42(workspaceDir, ".claude", "agents"), {
|
|
27908
28036
|
recursive: true
|
|
27909
28037
|
});
|
|
27910
28038
|
}
|
|
27911
|
-
const writerSkillsDir =
|
|
28039
|
+
const writerSkillsDir = join42(plugins.writer, "skills");
|
|
27912
28040
|
if (await pathExists2(writerSkillsDir)) {
|
|
27913
|
-
await cp2(writerSkillsDir,
|
|
28041
|
+
await cp2(writerSkillsDir, join42(workspaceDir, ".claude", "skills"), {
|
|
27914
28042
|
recursive: true
|
|
27915
28043
|
});
|
|
27916
28044
|
}
|
|
27917
|
-
const writerWorkflowsDir =
|
|
28045
|
+
const writerWorkflowsDir = join42(plugins.writer, "workflows");
|
|
27918
28046
|
if (await pathExists2(writerWorkflowsDir)) {
|
|
27919
|
-
await cp2(writerWorkflowsDir,
|
|
28047
|
+
await cp2(writerWorkflowsDir, join42(workspaceDir, "workflows"), {
|
|
27920
28048
|
recursive: true
|
|
27921
28049
|
});
|
|
27922
28050
|
}
|
|
27923
28051
|
await writeFile22(
|
|
27924
|
-
|
|
28052
|
+
join42(workspaceDir, "user-profile.json"),
|
|
27925
28053
|
JSON.stringify(createDefaultProfile2(), null, 2),
|
|
27926
28054
|
"utf-8"
|
|
27927
28055
|
);
|
|
@@ -27956,12 +28084,12 @@ async function ensureWorkspace(options) {
|
|
|
27956
28084
|
return workspaceDir;
|
|
27957
28085
|
}
|
|
27958
28086
|
async function readUserProfile(workspaceDir) {
|
|
27959
|
-
const profilePath =
|
|
28087
|
+
const profilePath = join42(workspaceDir, "user-profile.json");
|
|
27960
28088
|
const content = await readFile22(profilePath, "utf-8");
|
|
27961
28089
|
return JSON.parse(content);
|
|
27962
28090
|
}
|
|
27963
28091
|
async function writeUserProfile(workspaceDir, profile) {
|
|
27964
|
-
const profilePath =
|
|
28092
|
+
const profilePath = join42(workspaceDir, "user-profile.json");
|
|
27965
28093
|
await writeFile22(profilePath, JSON.stringify(profile, null, 2), "utf-8");
|
|
27966
28094
|
}
|
|
27967
28095
|
var workspaceCache = /* @__PURE__ */ new Map();
|
|
@@ -28448,14 +28576,10 @@ async function initializeAndValidateApiKey(config2) {
|
|
|
28448
28576
|
"API key is required. Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN environment variable"
|
|
28449
28577
|
);
|
|
28450
28578
|
}
|
|
28451
|
-
|
|
28452
|
-
return { apiKey, isProxyProvider };
|
|
28579
|
+
return apiKey;
|
|
28453
28580
|
}
|
|
28454
|
-
function
|
|
28455
|
-
return
|
|
28456
|
-
mainModel: process.env.LOOPLIA_AGENT_MODEL_MAIN ?? DEFAULT_SETTINGS.agents.main,
|
|
28457
|
-
executorModel: process.env.LOOPLIA_AGENT_MODEL_EXECUTOR ?? DEFAULT_SETTINGS.agents.executor
|
|
28458
|
-
};
|
|
28581
|
+
function getMainModel() {
|
|
28582
|
+
return process.env.LOOPLIA_AGENT_MODEL_MAIN ?? DEFAULT_SETTINGS.agents.main;
|
|
28459
28583
|
}
|
|
28460
28584
|
function* processEvent(event, progressTracker, context) {
|
|
28461
28585
|
if (event.type === "tool_start" && event.tool === "Skill") {
|
|
@@ -28471,8 +28595,8 @@ function* processEvent(event, progressTracker, context) {
|
|
|
28471
28595
|
}
|
|
28472
28596
|
async function* executeAgenticQueryStreaming(prompt, jsonSchema, config2) {
|
|
28473
28597
|
const resolvedConfig = resolveConfig(config2);
|
|
28474
|
-
|
|
28475
|
-
const
|
|
28598
|
+
await initializeAndValidateApiKey(config2);
|
|
28599
|
+
const mainModel = getMainModel();
|
|
28476
28600
|
try {
|
|
28477
28601
|
const workspace = config2?.workspace ?? await getOrInitWorkspace(
|
|
28478
28602
|
resolvedConfig.workspace,
|
|
@@ -28500,51 +28624,24 @@ async function* executeAgenticQueryStreaming(prompt, jsonSchema, config2) {
|
|
|
28500
28624
|
const context = createTransformContext(
|
|
28501
28625
|
resolvedConfig.model
|
|
28502
28626
|
);
|
|
28503
|
-
const pluginPaths = await getPluginPaths();
|
|
28627
|
+
const pluginPaths = process.env.LOOPLIA_NO_PLUGINS === "true" ? [] : await getPluginPaths();
|
|
28628
|
+
if (process.env.LOOPLIA_DEBUG === "true") {
|
|
28629
|
+
console.error(
|
|
28630
|
+
"[LOOPLIA_DEBUG] Plugin paths:",
|
|
28631
|
+
JSON.stringify(pluginPaths)
|
|
28632
|
+
);
|
|
28633
|
+
}
|
|
28504
28634
|
const userCwd = process.cwd();
|
|
28505
|
-
const loopliaHome = getLoopliaPluginPath();
|
|
28506
|
-
|
|
28507
|
-
|
|
28508
|
-
|
|
28509
|
-
|
|
28510
|
-
When executing looplia workflows (/run commands), use the "workflow-executor-inline" skill.
|
|
28511
|
-
Execute all workflow steps INLINE without spawning Task subagents.
|
|
28512
|
-
This ensures compatibility with your current API provider.` : "";
|
|
28513
|
-
const agents = isProxyProvider ? void 0 : {
|
|
28514
|
-
"skill-executor": {
|
|
28515
|
-
description: "Universal skill orchestrator for looplia workflow steps. Executes a single workflow step by invoking skills.",
|
|
28516
|
-
prompt: `You are the looplia skill-executor. Execute ONE workflow step by invoking the specified skill.
|
|
28517
|
-
|
|
28518
|
-
## Execution Protocol
|
|
28519
|
-
1. Read input files (if provided)
|
|
28520
|
-
2. Invoke the skill using the Skill tool
|
|
28521
|
-
3. Execute the mission with skill context
|
|
28522
|
-
4. Write JSON output to the specified path using Write tool
|
|
28523
|
-
|
|
28524
|
-
## CRITICAL: Output Writing is MANDATORY
|
|
28525
|
-
YOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the workflow fails.
|
|
28526
|
-
|
|
28527
|
-
## Rules
|
|
28528
|
-
- ALWAYS invoke the specified skill using Skill tool
|
|
28529
|
-
- ALWAYS write output to the exact path using Write tool
|
|
28530
|
-
- NEVER return results as text - always write JSON to output file
|
|
28531
|
-
- NEVER spawn Task subagents - execute skills directly
|
|
28532
|
-
- ALWAYS include contentId in JSON outputs`,
|
|
28533
|
-
tools: [
|
|
28534
|
-
"Read",
|
|
28535
|
-
"Write",
|
|
28536
|
-
"Skill",
|
|
28537
|
-
"Glob",
|
|
28538
|
-
"Grep",
|
|
28539
|
-
"WebSearch",
|
|
28540
|
-
"WebFetch"
|
|
28541
|
-
],
|
|
28542
|
-
model: executorModel
|
|
28543
|
-
}
|
|
28544
|
-
};
|
|
28635
|
+
const loopliaHome = process.env.LOOPLIA_WORKSPACE_PATH ?? getLoopliaPluginPath();
|
|
28636
|
+
if (process.env.LOOPLIA_DEBUG === "true") {
|
|
28637
|
+
console.error("[LOOPLIA_DEBUG] loopliaHome:", loopliaHome);
|
|
28638
|
+
}
|
|
28639
|
+
const claudeCodePath = findClaudeCodePath();
|
|
28545
28640
|
const result = query({
|
|
28546
28641
|
prompt,
|
|
28547
28642
|
options: {
|
|
28643
|
+
// v0.6.8: Use system-installed Claude Code if available, otherwise SDK uses built-in
|
|
28644
|
+
...claudeCodePath && { pathToClaudeCodeExecutable: claudeCodePath },
|
|
28548
28645
|
// v0.6.6: Use configured main model
|
|
28549
28646
|
model: mainModel,
|
|
28550
28647
|
// v0.6.5: SDK works relative to ~/.looplia (sandbox, workflows, etc.)
|
|
@@ -28554,7 +28651,7 @@ YOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the
|
|
|
28554
28651
|
// v0.6.5: Load plugins from local paths instead of project settings
|
|
28555
28652
|
plugins: pluginPaths,
|
|
28556
28653
|
// v0.6.5: Append looplia system prompt + user context to claude_code preset
|
|
28557
|
-
// v0.6.
|
|
28654
|
+
// v0.6.9: Removed provider-aware hint - unified subagent strategy for all providers
|
|
28558
28655
|
systemPrompt: {
|
|
28559
28656
|
type: "preset",
|
|
28560
28657
|
preset: "claude_code",
|
|
@@ -28564,7 +28661,7 @@ YOU MUST CALL THE WRITE TOOL before completing. If you don't write the file, the
|
|
|
28564
28661
|
|
|
28565
28662
|
User Working Directory: ${userCwd}
|
|
28566
28663
|
|
|
28567
|
-
When processing --file arguments or user file paths, resolve them against the User Working Directory above
|
|
28664
|
+
When processing --file arguments or user file paths, resolve them against the User Working Directory above.`
|
|
28568
28665
|
},
|
|
28569
28666
|
// v0.6.0: Enable Task for subagent spawning, Write/Glob for file operations
|
|
28570
28667
|
// v0.6.3: Added WebSearch/WebFetch for input-less search skill
|
|
@@ -28577,9 +28674,8 @@ When processing --file arguments or user file paths, resolve them against the Us
|
|
|
28577
28674
|
"WebSearch",
|
|
28578
28675
|
"WebFetch"
|
|
28579
28676
|
],
|
|
28580
|
-
outputFormat: { type: "json_schema", schema: jsonSchema }
|
|
28581
|
-
// v0.6.
|
|
28582
|
-
agents
|
|
28677
|
+
outputFormat: { type: "json_schema", schema: jsonSchema }
|
|
28678
|
+
// v0.6.9: No custom agents - using built-in general-purpose for workflow steps
|
|
28583
28679
|
}
|
|
28584
28680
|
});
|
|
28585
28681
|
let finalResult;
|
|
@@ -28608,6 +28704,25 @@ When processing --file arguments or user file paths, resolve them against the Us
|
|
|
28608
28704
|
error: { type: "unknown", message: "No result received" }
|
|
28609
28705
|
};
|
|
28610
28706
|
} catch (error2) {
|
|
28707
|
+
if (process.env.LOOPLIA_DEBUG === "true") {
|
|
28708
|
+
const debugInfo = {
|
|
28709
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28710
|
+
errorType: error2 instanceof Error ? error2.constructor.name : typeof error2,
|
|
28711
|
+
errorMessage: error2 instanceof Error ? error2.message : String(error2),
|
|
28712
|
+
errorStack: error2 instanceof Error ? error2.stack : void 0,
|
|
28713
|
+
cwd: process.cwd(),
|
|
28714
|
+
loopliaHome: getLoopliaPluginPath(),
|
|
28715
|
+
env: {
|
|
28716
|
+
LOOPLIA_DEBUG: process.env.LOOPLIA_DEBUG,
|
|
28717
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
28718
|
+
HOME: process.env.HOME
|
|
28719
|
+
}
|
|
28720
|
+
};
|
|
28721
|
+
console.error(
|
|
28722
|
+
"[LOOPLIA_DEBUG] SDK Error:",
|
|
28723
|
+
JSON.stringify(debugInfo, null, 2)
|
|
28724
|
+
);
|
|
28725
|
+
}
|
|
28611
28726
|
return mapException(error2);
|
|
28612
28727
|
}
|
|
28613
28728
|
}
|
|
@@ -29833,14 +29948,14 @@ import { Box as Box20, Text as Text21, useApp, useInput as useInput6 } from "ink
|
|
|
29833
29948
|
import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo2, useState as useState6 } from "react";
|
|
29834
29949
|
|
|
29835
29950
|
// src/utils/agent-logger.ts
|
|
29836
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
29951
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
29837
29952
|
import { homedir as homedir4 } from "os";
|
|
29838
29953
|
import { join as join6 } from "path";
|
|
29839
29954
|
var isDebugEnabled = () => process.env.LOOPLIA_DEBUG === "1";
|
|
29840
29955
|
var getLogsDir = (context) => join6(homedir4(), ".looplia", "logs", context);
|
|
29841
29956
|
function ensureLogsDir(context) {
|
|
29842
29957
|
const logsDir = getLogsDir(context);
|
|
29843
|
-
if (!
|
|
29958
|
+
if (!existsSync4(logsDir)) {
|
|
29844
29959
|
mkdirSync4(logsDir, { recursive: true });
|
|
29845
29960
|
}
|
|
29846
29961
|
return logsDir;
|
|
@@ -31338,14 +31453,14 @@ function getWorkspacePath2() {
|
|
|
31338
31453
|
function ensureWorkspace2(mock) {
|
|
31339
31454
|
const workspace = getWorkspacePath2();
|
|
31340
31455
|
const workflowsDir = resolve2(workspace, "workflows");
|
|
31341
|
-
if (!
|
|
31456
|
+
if (!existsSync5(workspace)) {
|
|
31342
31457
|
if (mock) {
|
|
31343
31458
|
mkdirSync5(workflowsDir, { recursive: true });
|
|
31344
31459
|
} else {
|
|
31345
31460
|
console.error("Workspace not initialized. Run: looplia init");
|
|
31346
31461
|
process.exit(1);
|
|
31347
31462
|
}
|
|
31348
|
-
} else if (!
|
|
31463
|
+
} else if (!existsSync5(workflowsDir)) {
|
|
31349
31464
|
mkdirSync5(workflowsDir, { recursive: true });
|
|
31350
31465
|
}
|
|
31351
31466
|
return workspace;
|
|
@@ -32564,11 +32679,11 @@ async function runConfigCommand(args) {
|
|
|
32564
32679
|
}
|
|
32565
32680
|
|
|
32566
32681
|
// src/commands/init.ts
|
|
32567
|
-
import { dirname as
|
|
32682
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
32568
32683
|
import { createInterface as createInterface2 } from "readline";
|
|
32569
32684
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
32570
32685
|
function getCliBundledPluginsPath() {
|
|
32571
|
-
const currentFile = typeof __dirname !== "undefined" ? __dirname :
|
|
32686
|
+
const currentFile = typeof __dirname !== "undefined" ? __dirname : dirname4(fileURLToPath3(import.meta.url));
|
|
32572
32687
|
return join7(currentFile, "..", "plugins");
|
|
32573
32688
|
}
|
|
32574
32689
|
function printInitHelp() {
|
|
@@ -32711,7 +32826,7 @@ async function runInitCommand(args) {
|
|
|
32711
32826
|
import { randomBytes } from "crypto";
|
|
32712
32827
|
import {
|
|
32713
32828
|
copyFileSync as copyFileSync2,
|
|
32714
|
-
existsSync as
|
|
32829
|
+
existsSync as existsSync6,
|
|
32715
32830
|
mkdirSync as mkdirSync6,
|
|
32716
32831
|
readFileSync as readFileSync2,
|
|
32717
32832
|
writeFileSync as writeFileSync4
|
|
@@ -32790,7 +32905,7 @@ function createSandboxWithInputs(workspace, workflowId, inputs) {
|
|
|
32790
32905
|
);
|
|
32791
32906
|
} else {
|
|
32792
32907
|
const absolutePath = resolve3(parsedInput.value);
|
|
32793
|
-
if (!
|
|
32908
|
+
if (!existsSync6(absolutePath)) {
|
|
32794
32909
|
throw new Error(`Input file not found: ${parsedInput.value}`);
|
|
32795
32910
|
}
|
|
32796
32911
|
copyFileSync2(absolutePath, join8(sandboxDir, "inputs", `${name}.md`));
|
|
@@ -32958,7 +33073,7 @@ function getWorkspacePath3() {
|
|
|
32958
33073
|
}
|
|
32959
33074
|
function ensureWorkspace3(mock) {
|
|
32960
33075
|
const workspace = getWorkspacePath3();
|
|
32961
|
-
if (!
|
|
33076
|
+
if (!existsSync6(workspace)) {
|
|
32962
33077
|
if (mock) {
|
|
32963
33078
|
mkdirSync6(join8(workspace, "sandbox"), { recursive: true });
|
|
32964
33079
|
} else {
|
|
@@ -32986,7 +33101,7 @@ function buildRunPrompt(workflowId, sandboxId) {
|
|
|
32986
33101
|
}
|
|
32987
33102
|
function checkWorkflowInputless(workspace, workflowId) {
|
|
32988
33103
|
const workflowPath = join8(workspace, "workflows", `${workflowId}.md`);
|
|
32989
|
-
if (!
|
|
33104
|
+
if (!existsSync6(workflowPath)) {
|
|
32990
33105
|
return false;
|
|
32991
33106
|
}
|
|
32992
33107
|
try {
|
|
@@ -33055,7 +33170,7 @@ async function executeBatch2(prompt, workspace, workflowId) {
|
|
|
33055
33170
|
function resolveSandboxId(workspace, parsed, allowInputless) {
|
|
33056
33171
|
if (parsed.sandboxId) {
|
|
33057
33172
|
const sandboxDir = join8(workspace, "sandbox", parsed.sandboxId);
|
|
33058
|
-
if (!
|
|
33173
|
+
if (!existsSync6(sandboxDir)) {
|
|
33059
33174
|
console.error(`Error: Sandbox not found: ${parsed.sandboxId}`);
|
|
33060
33175
|
console.error(`Path: ${sandboxDir}`);
|
|
33061
33176
|
process.exit(1);
|
|
@@ -33072,7 +33187,7 @@ function resolveSandboxId(workspace, parsed, allowInputless) {
|
|
|
33072
33187
|
return sandboxId;
|
|
33073
33188
|
}
|
|
33074
33189
|
if (parsed.file) {
|
|
33075
|
-
if (!
|
|
33190
|
+
if (!existsSync6(parsed.file)) {
|
|
33076
33191
|
console.error(`Error: File not found: ${parsed.file}`);
|
|
33077
33192
|
process.exit(1);
|
|
33078
33193
|
}
|
|
@@ -33152,7 +33267,7 @@ async function runRunCommand(args) {
|
|
|
33152
33267
|
}
|
|
33153
33268
|
|
|
33154
33269
|
// src/index.ts
|
|
33155
|
-
var VERSION = "0.6.
|
|
33270
|
+
var VERSION = "0.6.8";
|
|
33156
33271
|
function printHelp3() {
|
|
33157
33272
|
console.log(`
|
|
33158
33273
|
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.
|
|
3
|
+
"version": "0.6.9",
|
|
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/
|
|
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/",
|
|
@@ -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
|
|
10
|
-
invokes
|
|
11
|
-
per-step
|
|
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.
|
|
13
|
+
v0.6.9: Unified general-purpose subagent strategy for all providers (context offload).
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
# Workflow Executor Skill (v0.6.
|
|
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:
|
|
29
|
+
## CRITICAL: Task Invocation with general-purpose Subagent
|
|
30
30
|
|
|
31
|
-
**v0.6.
|
|
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": "
|
|
37
|
+
"subagent_type": "general-purpose",
|
|
38
38
|
"description": "Execute step: {step.id}",
|
|
39
|
-
"prompt": "Execute skill '{step.skill}' for step '{step.id}'.\n\
|
|
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": "
|
|
57
|
+
"subagent_type": "general-purpose",
|
|
58
58
|
"description": "Execute step: analyze-content",
|
|
59
|
-
"prompt": "Execute skill 'media-reviewer' for step 'analyze-content'.\n\
|
|
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: "
|
|
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(
|
|
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(
|
|
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
|
-
└─────────┘ │ "
|
|
273
|
+
└─────────┘ │ "general-purpose" │
|
|
275
274
|
│ │
|
|
276
|
-
│ 2.
|
|
277
|
-
│
|
|
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": "
|
|
304
|
+
"subagent_type": "general-purpose",
|
|
306
305
|
"description": "Execute step: analyze-content",
|
|
307
|
-
"prompt": "Execute skill 'media-reviewer' for step 'analyze-content'.\n\
|
|
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.
|
|
352
|
+
## Variable Substitution (v0.6.9)
|
|
354
353
|
|
|
355
|
-
Resolve variables before passing to
|
|
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="
|
|
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="
|
|
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="
|
|
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
|
-
-
|
|
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`
|