@looplia/looplia-cli 0.7.3 → 0.7.5
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/chunk-4TKNQ5RW.js +305 -0
- package/dist/{chunk-MHR5TPHE.js → chunk-GIZRTNY3.js} +1991 -417
- package/dist/{claude-agent-sdk-SQ6YU4VE.js → claude-agent-sdk-W5MXMV4Q.js} +5 -1
- package/dist/cli.js +157 -35
- package/dist/{dist-PMEIK6PJ.js → dist-3XSIQAV3.js} +2 -2
- package/package.json +1 -1
- package/plugins/looplia-core/skills/workflow-executor/SKILL.md +73 -18
- package/plugins/looplia-writer/workflows/writing-kit.md +1 -3
- package/dist/chunk-VYGRYFSY.js +0 -1148
- package/plugins/looplia-core/hooks/hooks.json +0 -22
- package/plugins/looplia-core/scripts/hooks/compact-inject-state.sh +0 -36
- package/plugins/looplia-core/scripts/hooks/post-write-validate.sh +0 -81
- package/plugins/looplia-core/scripts/hooks/stop-guard.sh +0 -56
- package/plugins/looplia-core/skills/workflow-executor-inline/SKILL.md +0 -217
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
pathExists
|
|
5
5
|
} from "./chunk-VRBGWKZ6.js";
|
|
6
6
|
import {
|
|
7
|
+
__export,
|
|
7
8
|
init_esm_shims
|
|
8
9
|
} from "./chunk-Y55L47HC.js";
|
|
9
10
|
|
|
10
|
-
// ../../packages/provider/dist/chunk-
|
|
11
|
+
// ../../packages/provider/dist/chunk-5BLYIGE4.js
|
|
11
12
|
init_esm_shims();
|
|
12
13
|
import { createHash } from "crypto";
|
|
13
14
|
import {
|
|
@@ -29,7 +30,6 @@ import { promisify } from "util";
|
|
|
29
30
|
var execAsync = promisify(exec);
|
|
30
31
|
var CORE_SKILLS = [
|
|
31
32
|
"workflow-executor",
|
|
32
|
-
"workflow-executor-inline",
|
|
33
33
|
"workflow-validator",
|
|
34
34
|
"registry-loader"
|
|
35
35
|
];
|
|
@@ -293,116 +293,123 @@ async function getPluginPaths() {
|
|
|
293
293
|
return await getProdPluginPaths();
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
// ../../packages/
|
|
296
|
+
// ../../packages/core/dist/index.js
|
|
297
297
|
init_esm_shims();
|
|
298
|
-
import { execSync } from "child_process";
|
|
299
|
-
import { existsSync as existsSync3 } from "fs";
|
|
300
|
-
import { createRequire } from "module";
|
|
301
|
-
import { homedir as homedir3 } from "os";
|
|
302
|
-
import { dirname as dirname3, join as join4 } from "path";
|
|
303
|
-
import {
|
|
304
|
-
chmod,
|
|
305
|
-
mkdir as mkdir3,
|
|
306
|
-
readFile as readFile2,
|
|
307
|
-
rename,
|
|
308
|
-
rm as rm2,
|
|
309
|
-
writeFile as writeFile2
|
|
310
|
-
} from "fs/promises";
|
|
311
|
-
import { homedir as homedir22 } from "os";
|
|
312
|
-
import { join as join23 } from "path";
|
|
313
|
-
|
|
314
|
-
// ../../node_modules/zod-to-json-schema/dist/esm/index.js
|
|
315
|
-
init_esm_shims();
|
|
316
|
-
|
|
317
|
-
// ../../node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
318
|
-
init_esm_shims();
|
|
319
|
-
var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
320
|
-
var defaultOptions = {
|
|
321
|
-
name: void 0,
|
|
322
|
-
$refStrategy: "root",
|
|
323
|
-
basePath: ["#"],
|
|
324
|
-
effectStrategy: "input",
|
|
325
|
-
pipeStrategy: "all",
|
|
326
|
-
dateStrategy: "format:date-time",
|
|
327
|
-
mapStrategy: "entries",
|
|
328
|
-
removeAdditionalStrategy: "passthrough",
|
|
329
|
-
allowedAdditionalProperties: true,
|
|
330
|
-
rejectedAdditionalProperties: false,
|
|
331
|
-
definitionPath: "definitions",
|
|
332
|
-
target: "jsonSchema7",
|
|
333
|
-
strictUnions: false,
|
|
334
|
-
definitions: {},
|
|
335
|
-
errorMessages: false,
|
|
336
|
-
markdownDescription: false,
|
|
337
|
-
patternStrategy: "escape",
|
|
338
|
-
applyRegexFlags: false,
|
|
339
|
-
emailStrategy: "format:email",
|
|
340
|
-
base64Strategy: "contentEncoding:base64",
|
|
341
|
-
nameStrategy: "ref",
|
|
342
|
-
openAiAnyTypeName: "OpenAiAnyType"
|
|
343
|
-
};
|
|
344
|
-
var getDefaultOptions = (options) => typeof options === "string" ? {
|
|
345
|
-
...defaultOptions,
|
|
346
|
-
name: options
|
|
347
|
-
} : {
|
|
348
|
-
...defaultOptions,
|
|
349
|
-
...options
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
// ../../node_modules/zod-to-json-schema/dist/esm/Refs.js
|
|
353
|
-
init_esm_shims();
|
|
354
|
-
var getRefs = (options) => {
|
|
355
|
-
const _options = getDefaultOptions(options);
|
|
356
|
-
const currentPath = _options.name !== void 0 ? [..._options.basePath, _options.definitionPath, _options.name] : _options.basePath;
|
|
357
|
-
return {
|
|
358
|
-
..._options,
|
|
359
|
-
flags: { hasReferencedOpenAiAnyType: false },
|
|
360
|
-
currentPath,
|
|
361
|
-
propertyPath: void 0,
|
|
362
|
-
seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
|
|
363
|
-
def._def,
|
|
364
|
-
{
|
|
365
|
-
def: def._def,
|
|
366
|
-
path: [..._options.basePath, _options.definitionPath, name],
|
|
367
|
-
// Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
|
|
368
|
-
jsonSchema: void 0
|
|
369
|
-
}
|
|
370
|
-
]))
|
|
371
|
-
};
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
// ../../node_modules/zod-to-json-schema/dist/esm/errorMessages.js
|
|
375
|
-
init_esm_shims();
|
|
376
|
-
function addErrorMessage(res, key, errorMessage, refs) {
|
|
377
|
-
if (!refs?.errorMessages)
|
|
378
|
-
return;
|
|
379
|
-
if (errorMessage) {
|
|
380
|
-
res.errorMessage = {
|
|
381
|
-
...res.errorMessage,
|
|
382
|
-
[key]: errorMessage
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
|
|
387
|
-
res[key] = value;
|
|
388
|
-
addErrorMessage(res, key, errorMessage, refs);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// ../../node_modules/zod-to-json-schema/dist/esm/getRelativePath.js
|
|
392
|
-
init_esm_shims();
|
|
393
|
-
var getRelativePath = (pathA, pathB) => {
|
|
394
|
-
let i = 0;
|
|
395
|
-
for (; i < pathA.length && i < pathB.length; i++) {
|
|
396
|
-
if (pathA[i] !== pathB[i])
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/");
|
|
400
|
-
};
|
|
401
298
|
|
|
402
|
-
// ../../node_modules/zod
|
|
299
|
+
// ../../node_modules/zod/index.js
|
|
403
300
|
init_esm_shims();
|
|
404
301
|
|
|
405
|
-
// ../../node_modules/zod
|
|
302
|
+
// ../../node_modules/zod/v3/external.js
|
|
303
|
+
var external_exports = {};
|
|
304
|
+
__export(external_exports, {
|
|
305
|
+
BRAND: () => BRAND,
|
|
306
|
+
DIRTY: () => DIRTY,
|
|
307
|
+
EMPTY_PATH: () => EMPTY_PATH,
|
|
308
|
+
INVALID: () => INVALID,
|
|
309
|
+
NEVER: () => NEVER,
|
|
310
|
+
OK: () => OK,
|
|
311
|
+
ParseStatus: () => ParseStatus,
|
|
312
|
+
Schema: () => ZodType,
|
|
313
|
+
ZodAny: () => ZodAny,
|
|
314
|
+
ZodArray: () => ZodArray,
|
|
315
|
+
ZodBigInt: () => ZodBigInt,
|
|
316
|
+
ZodBoolean: () => ZodBoolean,
|
|
317
|
+
ZodBranded: () => ZodBranded,
|
|
318
|
+
ZodCatch: () => ZodCatch,
|
|
319
|
+
ZodDate: () => ZodDate,
|
|
320
|
+
ZodDefault: () => ZodDefault,
|
|
321
|
+
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
322
|
+
ZodEffects: () => ZodEffects,
|
|
323
|
+
ZodEnum: () => ZodEnum,
|
|
324
|
+
ZodError: () => ZodError,
|
|
325
|
+
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
326
|
+
ZodFunction: () => ZodFunction,
|
|
327
|
+
ZodIntersection: () => ZodIntersection,
|
|
328
|
+
ZodIssueCode: () => ZodIssueCode,
|
|
329
|
+
ZodLazy: () => ZodLazy,
|
|
330
|
+
ZodLiteral: () => ZodLiteral,
|
|
331
|
+
ZodMap: () => ZodMap,
|
|
332
|
+
ZodNaN: () => ZodNaN,
|
|
333
|
+
ZodNativeEnum: () => ZodNativeEnum,
|
|
334
|
+
ZodNever: () => ZodNever,
|
|
335
|
+
ZodNull: () => ZodNull,
|
|
336
|
+
ZodNullable: () => ZodNullable,
|
|
337
|
+
ZodNumber: () => ZodNumber,
|
|
338
|
+
ZodObject: () => ZodObject,
|
|
339
|
+
ZodOptional: () => ZodOptional,
|
|
340
|
+
ZodParsedType: () => ZodParsedType,
|
|
341
|
+
ZodPipeline: () => ZodPipeline,
|
|
342
|
+
ZodPromise: () => ZodPromise,
|
|
343
|
+
ZodReadonly: () => ZodReadonly,
|
|
344
|
+
ZodRecord: () => ZodRecord,
|
|
345
|
+
ZodSchema: () => ZodType,
|
|
346
|
+
ZodSet: () => ZodSet,
|
|
347
|
+
ZodString: () => ZodString,
|
|
348
|
+
ZodSymbol: () => ZodSymbol,
|
|
349
|
+
ZodTransformer: () => ZodEffects,
|
|
350
|
+
ZodTuple: () => ZodTuple,
|
|
351
|
+
ZodType: () => ZodType,
|
|
352
|
+
ZodUndefined: () => ZodUndefined,
|
|
353
|
+
ZodUnion: () => ZodUnion,
|
|
354
|
+
ZodUnknown: () => ZodUnknown,
|
|
355
|
+
ZodVoid: () => ZodVoid,
|
|
356
|
+
addIssueToContext: () => addIssueToContext,
|
|
357
|
+
any: () => anyType,
|
|
358
|
+
array: () => arrayType,
|
|
359
|
+
bigint: () => bigIntType,
|
|
360
|
+
boolean: () => booleanType,
|
|
361
|
+
coerce: () => coerce,
|
|
362
|
+
custom: () => custom,
|
|
363
|
+
date: () => dateType,
|
|
364
|
+
datetimeRegex: () => datetimeRegex,
|
|
365
|
+
defaultErrorMap: () => en_default,
|
|
366
|
+
discriminatedUnion: () => discriminatedUnionType,
|
|
367
|
+
effect: () => effectsType,
|
|
368
|
+
enum: () => enumType,
|
|
369
|
+
function: () => functionType,
|
|
370
|
+
getErrorMap: () => getErrorMap,
|
|
371
|
+
getParsedType: () => getParsedType,
|
|
372
|
+
instanceof: () => instanceOfType,
|
|
373
|
+
intersection: () => intersectionType,
|
|
374
|
+
isAborted: () => isAborted,
|
|
375
|
+
isAsync: () => isAsync,
|
|
376
|
+
isDirty: () => isDirty,
|
|
377
|
+
isValid: () => isValid,
|
|
378
|
+
late: () => late,
|
|
379
|
+
lazy: () => lazyType,
|
|
380
|
+
literal: () => literalType,
|
|
381
|
+
makeIssue: () => makeIssue,
|
|
382
|
+
map: () => mapType,
|
|
383
|
+
nan: () => nanType,
|
|
384
|
+
nativeEnum: () => nativeEnumType,
|
|
385
|
+
never: () => neverType,
|
|
386
|
+
null: () => nullType,
|
|
387
|
+
nullable: () => nullableType,
|
|
388
|
+
number: () => numberType,
|
|
389
|
+
object: () => objectType,
|
|
390
|
+
objectUtil: () => objectUtil,
|
|
391
|
+
oboolean: () => oboolean,
|
|
392
|
+
onumber: () => onumber,
|
|
393
|
+
optional: () => optionalType,
|
|
394
|
+
ostring: () => ostring,
|
|
395
|
+
pipeline: () => pipelineType,
|
|
396
|
+
preprocess: () => preprocessType,
|
|
397
|
+
promise: () => promiseType,
|
|
398
|
+
quotelessJson: () => quotelessJson,
|
|
399
|
+
record: () => recordType,
|
|
400
|
+
set: () => setType,
|
|
401
|
+
setErrorMap: () => setErrorMap,
|
|
402
|
+
strictObject: () => strictObjectType,
|
|
403
|
+
string: () => stringType,
|
|
404
|
+
symbol: () => symbolType,
|
|
405
|
+
transformer: () => effectsType,
|
|
406
|
+
tuple: () => tupleType,
|
|
407
|
+
undefined: () => undefinedType,
|
|
408
|
+
union: () => unionType,
|
|
409
|
+
unknown: () => unknownType,
|
|
410
|
+
util: () => util,
|
|
411
|
+
void: () => voidType
|
|
412
|
+
});
|
|
406
413
|
init_esm_shims();
|
|
407
414
|
|
|
408
415
|
// ../../node_modules/zod/v3/errors.js
|
|
@@ -4349,112 +4356,904 @@ var coerce = {
|
|
|
4349
4356
|
};
|
|
4350
4357
|
var NEVER = INVALID;
|
|
4351
4358
|
|
|
4352
|
-
// ../../
|
|
4353
|
-
|
|
4354
|
-
function
|
|
4355
|
-
if (
|
|
4356
|
-
|
|
4359
|
+
// ../../packages/core/dist/index.js
|
|
4360
|
+
var commands = /* @__PURE__ */ new Map();
|
|
4361
|
+
function registerCommand(definition) {
|
|
4362
|
+
if (commands.has(definition.name)) {
|
|
4363
|
+
throw new Error(`Command "${definition.name}" is already registered`);
|
|
4357
4364
|
}
|
|
4358
|
-
|
|
4359
|
-
...refs.basePath,
|
|
4360
|
-
refs.definitionPath,
|
|
4361
|
-
refs.openAiAnyTypeName
|
|
4362
|
-
];
|
|
4363
|
-
refs.flags.hasReferencedOpenAiAnyType = true;
|
|
4364
|
-
return {
|
|
4365
|
-
$ref: refs.$refStrategy === "relative" ? getRelativePath(anyDefinitionPath, refs.currentPath) : anyDefinitionPath.join("/")
|
|
4366
|
-
};
|
|
4365
|
+
commands.set(definition.name, definition);
|
|
4367
4366
|
}
|
|
4367
|
+
function buildWorkflowPrompt(ctx) {
|
|
4368
|
+
if (!(ctx.workflowName && ctx.workflowDefinition)) {
|
|
4369
|
+
throw new Error(
|
|
4370
|
+
"Workflow context is required (workflowName, workflowDefinition)"
|
|
4371
|
+
);
|
|
4372
|
+
}
|
|
4373
|
+
return `Task: Execute workflow "${ctx.workflowName}" for session: contentItem/${ctx.contentId}
|
|
4368
4374
|
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4375
|
+
## Workflow Definition
|
|
4376
|
+
|
|
4377
|
+
\`\`\`yaml
|
|
4378
|
+
${ctx.workflowDefinition}
|
|
4379
|
+
\`\`\`
|
|
4380
|
+
|
|
4381
|
+
${ctx.workflowInstructions ? `## Custom Instructions
|
|
4382
|
+
|
|
4383
|
+
${ctx.workflowInstructions}
|
|
4384
|
+
` : ""}
|
|
4385
|
+
## Execution Protocol
|
|
4386
|
+
|
|
4387
|
+
### Step 1: Read Validation State
|
|
4388
|
+
Read \`contentItem/${ctx.contentId}/validation.json\` to understand:
|
|
4389
|
+
- What outputs are required
|
|
4390
|
+
- Validation criteria for each output
|
|
4391
|
+
- Which outputs have already passed validation
|
|
4392
|
+
|
|
4393
|
+
If validation.json is missing, the workflow hasn't started properly.
|
|
4394
|
+
|
|
4395
|
+
### Step 2: Execute Outputs (Dependency Order)
|
|
4396
|
+
|
|
4397
|
+
For each output in the workflow (following dependency order):
|
|
4398
|
+
|
|
4399
|
+
1. **Check completion**:
|
|
4400
|
+
- If artifact exists AND validated=true in validation.json \u2192 skip
|
|
4401
|
+
|
|
4402
|
+
2. **If incomplete - use Task tool with custom subagent_type**:
|
|
4403
|
+
|
|
4404
|
+
Use the **Task** tool to invoke the agent specified in the workflow definition.
|
|
4405
|
+
The subagent_type MUST match the \`agent\` field exactly from the workflow YAML.
|
|
4406
|
+
|
|
4407
|
+
Example for an output with \`agent: content-analyzer\`:
|
|
4408
|
+
\`\`\`json
|
|
4409
|
+
{
|
|
4410
|
+
"name": "Task",
|
|
4411
|
+
"input": {
|
|
4412
|
+
"subagent_type": "content-analyzer",
|
|
4413
|
+
"description": "Generate summary artifact",
|
|
4414
|
+
"prompt": "Analyze content at contentItem/${ctx.contentId}/content.md and write summary.json"
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
4417
|
+
\`\`\`
|
|
4418
|
+
|
|
4419
|
+
The subagent will:
|
|
4420
|
+
- Auto-load its configured skills (from .claude/agents/*.md)
|
|
4421
|
+
- Write artifact to \`contentItem/${ctx.contentId}/{artifact}\`
|
|
4422
|
+
|
|
4423
|
+
3. **After artifact written - use Skill tool for validation**:
|
|
4424
|
+
|
|
4425
|
+
Use the **Skill** tool to invoke workflow-validator:
|
|
4426
|
+
\`\`\`json
|
|
4427
|
+
{
|
|
4428
|
+
"name": "Skill",
|
|
4429
|
+
"input": { "skill": "workflow-validator" }
|
|
4430
|
+
}
|
|
4431
|
+
\`\`\`
|
|
4432
|
+
|
|
4433
|
+
Then follow the skill's instructions to validate the artifact against criteria.
|
|
4434
|
+
|
|
4435
|
+
4. **Handle validation result**:
|
|
4436
|
+
- If passed: Update validation.json \u2192 set \`outputs.{name}.validated = true\`
|
|
4437
|
+
- If failed: Review failed checks, retry subagent with specific feedback
|
|
4438
|
+
|
|
4439
|
+
### Step 3: Return Final Output
|
|
4440
|
+
|
|
4441
|
+
When the output marked \`final: true\` passes validation:
|
|
4442
|
+
1. Read the final artifact JSON
|
|
4443
|
+
2. Return it as structured output
|
|
4444
|
+
|
|
4445
|
+
## Workspace Structure
|
|
4446
|
+
|
|
4447
|
+
- **Content**: \`contentItem/${ctx.contentId}/content.md\`
|
|
4448
|
+
- **Validation**: \`contentItem/${ctx.contentId}/validation.json\`
|
|
4449
|
+
- **Artifacts**: \`contentItem/${ctx.contentId}/*.json\`
|
|
4450
|
+
- **Workflow**: \`workflows/${ctx.workflowName}.md\`
|
|
4451
|
+
- **Agents**: \`.claude/agents/*.md\`
|
|
4452
|
+
- **Skills**: \`.claude/skills/*/SKILL.md\`
|
|
4453
|
+
|
|
4454
|
+
## Important Rules
|
|
4455
|
+
|
|
4456
|
+
- **Validate after each step** - Never skip validation
|
|
4457
|
+
- **Update validation.json** - Mark outputs validated when passed
|
|
4458
|
+
- **Follow dependencies** - Complete required outputs before dependent ones
|
|
4459
|
+
- **Retry on failure** - Give subagent specific feedback on validation failures
|
|
4460
|
+
- **Return structured JSON** - Final output must match expected schema`;
|
|
4461
|
+
}
|
|
4462
|
+
var workflowCommand = {
|
|
4463
|
+
name: "workflow",
|
|
4464
|
+
promptTemplate: buildWorkflowPrompt,
|
|
4465
|
+
// Generic object schema - allows any JSON object structure
|
|
4466
|
+
// Must be an object schema (not z.unknown()) to produce valid JSON schema with "type" field
|
|
4467
|
+
outputSchema: external_exports.record(external_exports.string(), external_exports.unknown())
|
|
4468
|
+
};
|
|
4469
|
+
registerCommand(workflowCommand);
|
|
4470
|
+
var RUN_PATTERN = /^agents\/([a-z][a-z0-9-]*)$/;
|
|
4471
|
+
function isValidRunFormat(run) {
|
|
4472
|
+
return RUN_PATTERN.test(run);
|
|
4473
|
+
}
|
|
4474
|
+
var INPUTLESS_CAPABLE_SKILLS = ["browser-research"];
|
|
4475
|
+
var ARRAY_PATTERN = /^\[(.*)\]$/;
|
|
4476
|
+
var INTEGER_PATTERN = /^\d+$/;
|
|
4477
|
+
var NON_SPACE_PATTERN = /\S/;
|
|
4478
|
+
var FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
4479
|
+
function isSkippableLine(line) {
|
|
4480
|
+
const trimmed = line.trim();
|
|
4481
|
+
return !trimmed || trimmed.startsWith("#");
|
|
4482
|
+
}
|
|
4483
|
+
function parseKeyValue(trimmed) {
|
|
4484
|
+
const colonIndex = trimmed.indexOf(":");
|
|
4485
|
+
if (colonIndex === -1) {
|
|
4486
|
+
return null;
|
|
4487
|
+
}
|
|
4488
|
+
return {
|
|
4489
|
+
key: trimmed.slice(0, colonIndex),
|
|
4490
|
+
value: trimmed.slice(colonIndex + 1).trim()
|
|
4374
4491
|
};
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4492
|
+
}
|
|
4493
|
+
function parseArray(value) {
|
|
4494
|
+
const match = value.match(ARRAY_PATTERN);
|
|
4495
|
+
if (match?.[1] !== void 0) {
|
|
4496
|
+
return match[1].split(",").map((s) => s.trim());
|
|
4380
4497
|
}
|
|
4381
|
-
|
|
4382
|
-
|
|
4498
|
+
return null;
|
|
4499
|
+
}
|
|
4500
|
+
function stripQuotes(value) {
|
|
4501
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
4502
|
+
return value.slice(1, -1);
|
|
4383
4503
|
}
|
|
4384
|
-
|
|
4385
|
-
|
|
4504
|
+
return value;
|
|
4505
|
+
}
|
|
4506
|
+
function parseYamlValue(value) {
|
|
4507
|
+
const array2 = parseArray(value);
|
|
4508
|
+
if (array2) {
|
|
4509
|
+
return array2;
|
|
4386
4510
|
}
|
|
4387
|
-
if (
|
|
4388
|
-
|
|
4389
|
-
setResponseValueAndErrors(res, "maxItems", def.exactLength.value, def.exactLength.message, refs);
|
|
4511
|
+
if (value === "true") {
|
|
4512
|
+
return true;
|
|
4390
4513
|
}
|
|
4391
|
-
|
|
4514
|
+
if (value === "false") {
|
|
4515
|
+
return false;
|
|
4516
|
+
}
|
|
4517
|
+
if (INTEGER_PATTERN.test(value)) {
|
|
4518
|
+
return Number.parseInt(value, 10);
|
|
4519
|
+
}
|
|
4520
|
+
return stripQuotes(value);
|
|
4392
4521
|
}
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
const
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
if (
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4522
|
+
function processYamlLine(state, line) {
|
|
4523
|
+
if (isSkippableLine(line)) {
|
|
4524
|
+
return;
|
|
4525
|
+
}
|
|
4526
|
+
const indent = line.search(NON_SPACE_PATTERN);
|
|
4527
|
+
const trimmed = line.trim();
|
|
4528
|
+
if (indent === 0) {
|
|
4529
|
+
processTopLevel(state, trimmed);
|
|
4530
|
+
} else if (indent === 2 && state.currentKey === "skills") {
|
|
4531
|
+
processSkillItem(state, trimmed);
|
|
4532
|
+
} else if (indent === 2 && state.currentKey === "inputs") {
|
|
4533
|
+
processInputItem(state, trimmed);
|
|
4534
|
+
} else if (indent === 2 && state.currentKey === "steps") {
|
|
4535
|
+
processStepItem(state, trimmed);
|
|
4536
|
+
} else if (indent === 4 && state.currentInput) {
|
|
4537
|
+
processInputProperty(state, trimmed);
|
|
4538
|
+
} else if (indent === 4 && state.currentStep) {
|
|
4539
|
+
processStepProperty(state, trimmed);
|
|
4540
|
+
} else if (indent === 6 && state.currentValidate) {
|
|
4541
|
+
processValidateProperty(state, trimmed);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
function processSkillItem(state, trimmed) {
|
|
4545
|
+
if (trimmed.startsWith("- ")) {
|
|
4546
|
+
const skillName = trimmed.slice(2).trim();
|
|
4547
|
+
if (skillName) {
|
|
4548
|
+
state.skills.push(skillName);
|
|
4549
|
+
}
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
function processTopLevel(state, trimmed) {
|
|
4553
|
+
if (state.currentStep?.id) {
|
|
4554
|
+
state.steps.push(state.currentStep);
|
|
4555
|
+
state.currentStep = null;
|
|
4556
|
+
}
|
|
4557
|
+
if (state.currentInput?.name) {
|
|
4558
|
+
state.inputs.push(state.currentInput);
|
|
4559
|
+
state.currentInput = null;
|
|
4560
|
+
}
|
|
4561
|
+
const kv = parseKeyValue(trimmed);
|
|
4562
|
+
if (!kv) {
|
|
4563
|
+
return;
|
|
4564
|
+
}
|
|
4565
|
+
state.currentKey = kv.key;
|
|
4566
|
+
if (kv.key !== "steps" && kv.key !== "inputs" && kv.key !== "skills" && kv.value) {
|
|
4567
|
+
state.result[kv.key] = kv.value;
|
|
4568
|
+
}
|
|
4569
|
+
state.currentValidate = null;
|
|
4570
|
+
}
|
|
4571
|
+
function processInputItem(state, trimmed) {
|
|
4572
|
+
if (trimmed.startsWith("- ")) {
|
|
4573
|
+
if (state.currentInput?.name) {
|
|
4574
|
+
state.inputs.push(state.currentInput);
|
|
4575
|
+
}
|
|
4576
|
+
state.currentInput = {};
|
|
4577
|
+
const firstProp = trimmed.slice(2).trim();
|
|
4578
|
+
const kv = parseKeyValue(firstProp);
|
|
4579
|
+
if (kv) {
|
|
4580
|
+
handleInputProperty(state.currentInput, kv.key, kv.value);
|
|
4436
4581
|
}
|
|
4437
4582
|
}
|
|
4438
|
-
return res;
|
|
4439
4583
|
}
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4584
|
+
function handleInputProperty(input, key, value) {
|
|
4585
|
+
switch (key) {
|
|
4586
|
+
case "name":
|
|
4587
|
+
input.name = value;
|
|
4588
|
+
break;
|
|
4589
|
+
case "required":
|
|
4590
|
+
input.required = value === "true";
|
|
4591
|
+
break;
|
|
4592
|
+
case "description":
|
|
4593
|
+
input.description = value;
|
|
4594
|
+
break;
|
|
4595
|
+
case "type":
|
|
4596
|
+
if (value === "file" || value === "json") {
|
|
4597
|
+
input.type = value;
|
|
4598
|
+
}
|
|
4599
|
+
break;
|
|
4600
|
+
default:
|
|
4601
|
+
break;
|
|
4602
|
+
}
|
|
4447
4603
|
}
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4604
|
+
function processInputProperty(state, trimmed) {
|
|
4605
|
+
if (!state.currentInput) {
|
|
4606
|
+
return;
|
|
4607
|
+
}
|
|
4608
|
+
const kv = parseKeyValue(trimmed);
|
|
4609
|
+
if (!kv) {
|
|
4610
|
+
return;
|
|
4611
|
+
}
|
|
4612
|
+
handleInputProperty(state.currentInput, kv.key, kv.value);
|
|
4453
4613
|
}
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4614
|
+
function processStepItem(state, trimmed) {
|
|
4615
|
+
if (trimmed.startsWith("- ")) {
|
|
4616
|
+
if (state.currentStep?.id) {
|
|
4617
|
+
state.steps.push(state.currentStep);
|
|
4618
|
+
}
|
|
4619
|
+
state.currentStep = {};
|
|
4620
|
+
state.currentValidate = null;
|
|
4621
|
+
const firstProp = trimmed.slice(2).trim();
|
|
4622
|
+
const kv = parseKeyValue(firstProp);
|
|
4623
|
+
if (kv) {
|
|
4624
|
+
handleStepProperty(state.currentStep, kv.key, kv.value);
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
function handleStepProperty(step, key, value) {
|
|
4629
|
+
switch (key) {
|
|
4630
|
+
case "id":
|
|
4631
|
+
step.id = value;
|
|
4632
|
+
break;
|
|
4633
|
+
case "skill":
|
|
4634
|
+
step.skill = value;
|
|
4635
|
+
break;
|
|
4636
|
+
case "mission":
|
|
4637
|
+
step.mission = value;
|
|
4638
|
+
break;
|
|
4639
|
+
case "run":
|
|
4640
|
+
step.run = value;
|
|
4641
|
+
break;
|
|
4642
|
+
case "input": {
|
|
4643
|
+
const arr = parseArray(value);
|
|
4644
|
+
step.input = arr ?? value;
|
|
4645
|
+
break;
|
|
4646
|
+
}
|
|
4647
|
+
case "output":
|
|
4648
|
+
step.output = value;
|
|
4649
|
+
break;
|
|
4650
|
+
case "needs": {
|
|
4651
|
+
const arr = parseArray(value);
|
|
4652
|
+
if (arr) {
|
|
4653
|
+
step.needs = arr;
|
|
4654
|
+
}
|
|
4655
|
+
break;
|
|
4656
|
+
}
|
|
4657
|
+
case "final":
|
|
4658
|
+
step.final = value === "true";
|
|
4659
|
+
break;
|
|
4660
|
+
case "validate": {
|
|
4661
|
+
const validate = {};
|
|
4662
|
+
step.validate = validate;
|
|
4663
|
+
return validate;
|
|
4664
|
+
}
|
|
4665
|
+
default:
|
|
4666
|
+
break;
|
|
4667
|
+
}
|
|
4668
|
+
return null;
|
|
4669
|
+
}
|
|
4670
|
+
function processStepProperty(state, trimmed) {
|
|
4671
|
+
if (!state.currentStep) {
|
|
4672
|
+
return;
|
|
4673
|
+
}
|
|
4674
|
+
const kv = parseKeyValue(trimmed);
|
|
4675
|
+
if (!kv) {
|
|
4676
|
+
return;
|
|
4677
|
+
}
|
|
4678
|
+
const validate = handleStepProperty(state.currentStep, kv.key, kv.value);
|
|
4679
|
+
if (validate) {
|
|
4680
|
+
state.currentValidate = validate;
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
function processValidateProperty(state, trimmed) {
|
|
4684
|
+
if (!state.currentValidate) {
|
|
4685
|
+
return;
|
|
4686
|
+
}
|
|
4687
|
+
const kv = parseKeyValue(trimmed);
|
|
4688
|
+
if (!kv) {
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
state.currentValidate[kv.key] = parseYamlValue(kv.value);
|
|
4692
|
+
}
|
|
4693
|
+
function parseFrontmatter(content) {
|
|
4694
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
4695
|
+
if (!match) {
|
|
4696
|
+
throw new Error(
|
|
4697
|
+
"Invalid workflow file: missing YAML frontmatter (must start with ---)"
|
|
4698
|
+
);
|
|
4699
|
+
}
|
|
4700
|
+
const yamlContent = match[1] ?? "";
|
|
4701
|
+
const body = match[2] ?? "";
|
|
4702
|
+
const frontmatter = parseSimpleYaml(yamlContent);
|
|
4703
|
+
return { frontmatter, body: body.trim() };
|
|
4704
|
+
}
|
|
4705
|
+
function parseSimpleYaml(yaml) {
|
|
4706
|
+
const state = {
|
|
4707
|
+
result: {},
|
|
4708
|
+
steps: [],
|
|
4709
|
+
inputs: [],
|
|
4710
|
+
skills: [],
|
|
4711
|
+
currentKey: "",
|
|
4712
|
+
currentStep: null,
|
|
4713
|
+
currentInput: null,
|
|
4714
|
+
currentValidate: null
|
|
4715
|
+
};
|
|
4716
|
+
for (const line of yaml.split("\n")) {
|
|
4717
|
+
processYamlLine(state, line);
|
|
4718
|
+
}
|
|
4719
|
+
if (state.currentInput?.name) {
|
|
4720
|
+
state.inputs.push(state.currentInput);
|
|
4721
|
+
}
|
|
4722
|
+
if (state.currentStep?.id) {
|
|
4723
|
+
state.steps.push(state.currentStep);
|
|
4724
|
+
}
|
|
4725
|
+
if (state.skills.length > 0) {
|
|
4726
|
+
state.result.skills = state.skills;
|
|
4727
|
+
}
|
|
4728
|
+
if (state.inputs.length > 0) {
|
|
4729
|
+
state.result.inputs = state.inputs;
|
|
4730
|
+
}
|
|
4731
|
+
if (state.steps.length > 0) {
|
|
4732
|
+
state.result.steps = state.steps;
|
|
4733
|
+
}
|
|
4734
|
+
return state.result;
|
|
4735
|
+
}
|
|
4736
|
+
var INPUT_REFERENCE_PATTERN = /\$\{\{\s*inputs\.(\w[\w-]*)\s*\}\}/g;
|
|
4737
|
+
function validateInputReferences(input, workflowInputs) {
|
|
4738
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
4739
|
+
const declaredNames = new Set(
|
|
4740
|
+
workflowInputs.filter((i) => i.name).map((i) => i.name)
|
|
4741
|
+
);
|
|
4742
|
+
for (const inp of inputs) {
|
|
4743
|
+
const matches = inp.matchAll(INPUT_REFERENCE_PATTERN);
|
|
4744
|
+
for (const match of matches) {
|
|
4745
|
+
const referencedName = match[1];
|
|
4746
|
+
if (referencedName && !declaredNames.has(referencedName)) {
|
|
4747
|
+
throw new Error(
|
|
4748
|
+
`Unknown input reference: inputs.${referencedName}. Declared inputs: ${[...declaredNames].join(", ") || "(none)"}`
|
|
4749
|
+
);
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
function validateStepExecutionMode(step) {
|
|
4755
|
+
const hasSkill = Boolean(step.skill && step.mission);
|
|
4756
|
+
const hasRun = Boolean(step.run);
|
|
4757
|
+
if (!(hasSkill || hasRun)) {
|
|
4758
|
+
throw new Error(
|
|
4759
|
+
`Step '${step.id}' must have either 'skill' + 'mission' (v0.6.1) or 'run' (v0.6.0 deprecated)`
|
|
4760
|
+
);
|
|
4761
|
+
}
|
|
4762
|
+
if (hasSkill && hasRun) {
|
|
4763
|
+
throw new Error(
|
|
4764
|
+
`Step '${step.id}' cannot have both 'skill' and 'run' - use one or the other`
|
|
4765
|
+
);
|
|
4766
|
+
}
|
|
4767
|
+
if (hasRun && step.run && !isValidRunFormat(step.run)) {
|
|
4768
|
+
throw new Error(
|
|
4769
|
+
`Step '${step.id}' has invalid run format '${step.run}'. Expected 'agents/{name}' where name is lowercase alphanumeric with hyphens.`
|
|
4770
|
+
);
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
function validateStep(step, workflowInputs = []) {
|
|
4774
|
+
if (!step.id) {
|
|
4775
|
+
throw new Error("Each step must have an 'id' field");
|
|
4776
|
+
}
|
|
4777
|
+
validateStepExecutionMode(step);
|
|
4778
|
+
const isInputlessCapable = step.skill && INPUTLESS_CAPABLE_SKILLS.includes(step.skill);
|
|
4779
|
+
if (!(step.input || isInputlessCapable)) {
|
|
4780
|
+
throw new Error(
|
|
4781
|
+
`Step '${step.id}' must have an 'input' field (or use an input-less capable skill like: ${INPUTLESS_CAPABLE_SKILLS.join(", ")})`
|
|
4782
|
+
);
|
|
4783
|
+
}
|
|
4784
|
+
if (Array.isArray(step.input) && step.input.length === 0) {
|
|
4785
|
+
throw new Error(`Step '${step.id}' input array cannot be empty`);
|
|
4786
|
+
}
|
|
4787
|
+
if (step.input && workflowInputs.length > 0) {
|
|
4788
|
+
validateInputReferences(step.input, workflowInputs);
|
|
4789
|
+
}
|
|
4790
|
+
if (!step.output) {
|
|
4791
|
+
throw new Error(`Step '${step.id}' must have an 'output' field`);
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
function parseWorkflow(content) {
|
|
4795
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
4796
|
+
if (!frontmatter.name || typeof frontmatter.name !== "string") {
|
|
4797
|
+
throw new Error("Workflow must have a 'name' field");
|
|
4798
|
+
}
|
|
4799
|
+
if (!frontmatter.description || typeof frontmatter.description !== "string") {
|
|
4800
|
+
throw new Error("Workflow must have a 'description' field");
|
|
4801
|
+
}
|
|
4802
|
+
if (!(frontmatter.steps && Array.isArray(frontmatter.steps)) || frontmatter.steps.length === 0) {
|
|
4803
|
+
throw new Error("Workflow must have at least one step defined");
|
|
4804
|
+
}
|
|
4805
|
+
const workflowInputs = Array.isArray(frontmatter.inputs) ? frontmatter.inputs : [];
|
|
4806
|
+
const workflowSkills = Array.isArray(frontmatter.skills) ? frontmatter.skills : [];
|
|
4807
|
+
for (const step of frontmatter.steps) {
|
|
4808
|
+
validateStep(step, workflowInputs);
|
|
4809
|
+
}
|
|
4810
|
+
const inputs = workflowInputs.filter((inp) => inp.name).map((inp) => ({
|
|
4811
|
+
name: inp.name,
|
|
4812
|
+
required: inp.required ?? true,
|
|
4813
|
+
description: inp.description,
|
|
4814
|
+
type: inp.type
|
|
4815
|
+
}));
|
|
4816
|
+
return {
|
|
4817
|
+
definition: {
|
|
4818
|
+
name: frontmatter.name,
|
|
4819
|
+
version: frontmatter.version,
|
|
4820
|
+
description: frontmatter.description,
|
|
4821
|
+
skills: workflowSkills.length > 0 ? workflowSkills : void 0,
|
|
4822
|
+
inputs: inputs.length > 0 ? inputs : void 0,
|
|
4823
|
+
steps: frontmatter.steps
|
|
4824
|
+
},
|
|
4825
|
+
instructions: body
|
|
4826
|
+
};
|
|
4827
|
+
}
|
|
4828
|
+
function generateValidationManifest(definition) {
|
|
4829
|
+
const steps = {};
|
|
4830
|
+
for (const step of definition.steps) {
|
|
4831
|
+
steps[step.id] = {
|
|
4832
|
+
output: step.output,
|
|
4833
|
+
validate: step.validate,
|
|
4834
|
+
validated: false
|
|
4835
|
+
};
|
|
4836
|
+
}
|
|
4837
|
+
return {
|
|
4838
|
+
workflow: definition.name,
|
|
4839
|
+
version: definition.version,
|
|
4840
|
+
finalStepId: getFinalStep(definition),
|
|
4841
|
+
steps
|
|
4842
|
+
};
|
|
4843
|
+
}
|
|
4844
|
+
function getExecutionOrder(definition) {
|
|
4845
|
+
const stepsMap = new Map(definition.steps.map((s) => [s.id, s]));
|
|
4846
|
+
const order = [];
|
|
4847
|
+
const visited = /* @__PURE__ */ new Set();
|
|
4848
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
4849
|
+
function visit(id) {
|
|
4850
|
+
if (visited.has(id)) {
|
|
4851
|
+
return;
|
|
4852
|
+
}
|
|
4853
|
+
if (visiting.has(id)) {
|
|
4854
|
+
throw new Error(`Circular dependency detected: ${id}`);
|
|
4855
|
+
}
|
|
4856
|
+
visiting.add(id);
|
|
4857
|
+
const step = stepsMap.get(id);
|
|
4858
|
+
if (step?.needs) {
|
|
4859
|
+
for (const dep of step.needs) {
|
|
4860
|
+
if (!stepsMap.has(dep)) {
|
|
4861
|
+
throw new Error(`Unknown dependency '${dep}' in step '${id}'`);
|
|
4862
|
+
}
|
|
4863
|
+
visit(dep);
|
|
4864
|
+
}
|
|
4865
|
+
}
|
|
4866
|
+
visiting.delete(id);
|
|
4867
|
+
visited.add(id);
|
|
4868
|
+
order.push(id);
|
|
4869
|
+
}
|
|
4870
|
+
for (const step of definition.steps) {
|
|
4871
|
+
visit(step.id);
|
|
4872
|
+
}
|
|
4873
|
+
return order;
|
|
4874
|
+
}
|
|
4875
|
+
function getFinalStep(definition) {
|
|
4876
|
+
for (const step of definition.steps) {
|
|
4877
|
+
if (step.final) {
|
|
4878
|
+
return step.id;
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
const order = getExecutionOrder(definition);
|
|
4882
|
+
const lastStep = order.at(-1);
|
|
4883
|
+
if (!lastStep) {
|
|
4884
|
+
throw new Error("Workflow has no steps");
|
|
4885
|
+
}
|
|
4886
|
+
return lastStep;
|
|
4887
|
+
}
|
|
4888
|
+
function isInputlessWorkflow(definition) {
|
|
4889
|
+
if (definition.inputs?.some((input) => input.required)) {
|
|
4890
|
+
return false;
|
|
4891
|
+
}
|
|
4892
|
+
const firstSteps = definition.steps.filter(
|
|
4893
|
+
(step) => !step.needs || step.needs.length === 0
|
|
4894
|
+
);
|
|
4895
|
+
if (firstSteps.length === 0) {
|
|
4896
|
+
return false;
|
|
4897
|
+
}
|
|
4898
|
+
return firstSteps.every(
|
|
4899
|
+
(step) => step.skill && INPUTLESS_CAPABLE_SKILLS.includes(step.skill)
|
|
4900
|
+
);
|
|
4901
|
+
}
|
|
4902
|
+
function extractWorkflowSkills(workflow) {
|
|
4903
|
+
if (workflow.definition.skills && workflow.definition.skills.length > 0) {
|
|
4904
|
+
return workflow.definition.skills;
|
|
4905
|
+
}
|
|
4906
|
+
const skills = /* @__PURE__ */ new Set();
|
|
4907
|
+
for (const step of workflow.definition.steps) {
|
|
4908
|
+
if (step.skill) {
|
|
4909
|
+
skills.add(step.skill);
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
return [...skills];
|
|
4913
|
+
}
|
|
4914
|
+
var SourceTypeSchema = external_exports.enum([
|
|
4915
|
+
"rss",
|
|
4916
|
+
"youtube",
|
|
4917
|
+
"podcast",
|
|
4918
|
+
"twitter",
|
|
4919
|
+
"custom"
|
|
4920
|
+
]);
|
|
4921
|
+
var SourceSchema = external_exports.object({
|
|
4922
|
+
id: external_exports.string().min(1),
|
|
4923
|
+
type: SourceTypeSchema,
|
|
4924
|
+
label: external_exports.string().optional(),
|
|
4925
|
+
url: external_exports.string(),
|
|
4926
|
+
metadata: external_exports.record(external_exports.unknown()).optional()
|
|
4927
|
+
});
|
|
4928
|
+
var ContentMetadataSchema = external_exports.object({
|
|
4929
|
+
language: external_exports.string().length(2).optional(),
|
|
4930
|
+
durationSeconds: external_exports.number().positive().optional(),
|
|
4931
|
+
author: external_exports.string().optional(),
|
|
4932
|
+
wordCount: external_exports.number().positive().optional()
|
|
4933
|
+
}).passthrough();
|
|
4934
|
+
var ContentItemSchema = external_exports.object({
|
|
4935
|
+
id: external_exports.string().min(1),
|
|
4936
|
+
source: SourceSchema,
|
|
4937
|
+
title: external_exports.string().min(1),
|
|
4938
|
+
url: external_exports.string(),
|
|
4939
|
+
publishedAt: external_exports.string().optional(),
|
|
4940
|
+
rawText: external_exports.string().min(1),
|
|
4941
|
+
metadata: ContentMetadataSchema
|
|
4942
|
+
});
|
|
4943
|
+
var ValidationCriteriaSchema = external_exports.object({
|
|
4944
|
+
required_fields: external_exports.array(external_exports.string()).optional(),
|
|
4945
|
+
min_quotes: external_exports.number().int().positive().optional(),
|
|
4946
|
+
min_key_points: external_exports.number().int().positive().optional(),
|
|
4947
|
+
min_outline_sections: external_exports.number().int().positive().optional(),
|
|
4948
|
+
has_hooks: external_exports.boolean().optional()
|
|
4949
|
+
}).passthrough();
|
|
4950
|
+
var WorkflowInputSchema = external_exports.object({
|
|
4951
|
+
name: external_exports.string().min(1).regex(/^[a-z][a-z0-9-]*$/, "Input name must be kebab-case"),
|
|
4952
|
+
required: external_exports.boolean(),
|
|
4953
|
+
description: external_exports.string().optional(),
|
|
4954
|
+
type: external_exports.enum(["file", "json"]).optional()
|
|
4955
|
+
});
|
|
4956
|
+
var WorkflowStepSchema = external_exports.object({
|
|
4957
|
+
id: external_exports.string().min(1),
|
|
4958
|
+
skill: external_exports.string().min(1).optional(),
|
|
4959
|
+
mission: external_exports.string().min(1).optional(),
|
|
4960
|
+
run: external_exports.string().min(1).optional(),
|
|
4961
|
+
input: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional(),
|
|
4962
|
+
output: external_exports.string().min(1),
|
|
4963
|
+
needs: external_exports.array(external_exports.string()).optional(),
|
|
4964
|
+
final: external_exports.boolean().optional(),
|
|
4965
|
+
validate: ValidationCriteriaSchema.optional()
|
|
4966
|
+
}).refine(
|
|
4967
|
+
(step) => step.skill && step.mission || step.run,
|
|
4968
|
+
"Step must have either 'skill' + 'mission' or 'run'"
|
|
4969
|
+
).refine(
|
|
4970
|
+
(step) => !(step.skill && step.run),
|
|
4971
|
+
"Step cannot have both 'skill' and 'run'"
|
|
4972
|
+
);
|
|
4973
|
+
var WorkflowDefinitionSchema = external_exports.object({
|
|
4974
|
+
name: external_exports.string().min(1),
|
|
4975
|
+
version: external_exports.string().optional(),
|
|
4976
|
+
description: external_exports.string().min(1),
|
|
4977
|
+
inputs: external_exports.array(WorkflowInputSchema).optional(),
|
|
4978
|
+
steps: external_exports.array(WorkflowStepSchema)
|
|
4979
|
+
});
|
|
4980
|
+
var StepValidationStateSchema = external_exports.object({
|
|
4981
|
+
output: external_exports.string().min(1),
|
|
4982
|
+
validate: ValidationCriteriaSchema.optional(),
|
|
4983
|
+
validated: external_exports.boolean()
|
|
4984
|
+
});
|
|
4985
|
+
var ValidationManifestSchema = external_exports.object({
|
|
4986
|
+
workflow: external_exports.string().min(1),
|
|
4987
|
+
version: external_exports.string().optional(),
|
|
4988
|
+
sandboxId: external_exports.string().optional(),
|
|
4989
|
+
createdAt: external_exports.string().optional(),
|
|
4990
|
+
finalStepId: external_exports.string().optional(),
|
|
4991
|
+
steps: external_exports.record(external_exports.string(), StepValidationStateSchema)
|
|
4992
|
+
});
|
|
4993
|
+
var ValidationCheckSchema = external_exports.object({
|
|
4994
|
+
name: external_exports.string().min(1),
|
|
4995
|
+
passed: external_exports.boolean(),
|
|
4996
|
+
message: external_exports.string()
|
|
4997
|
+
});
|
|
4998
|
+
var ValidationResultSchema = external_exports.object({
|
|
4999
|
+
passed: external_exports.boolean(),
|
|
5000
|
+
checks: external_exports.array(ValidationCheckSchema)
|
|
5001
|
+
});
|
|
5002
|
+
var SessionManifestSchema = external_exports.object({
|
|
5003
|
+
version: external_exports.literal(1),
|
|
5004
|
+
contentId: external_exports.string().min(1),
|
|
5005
|
+
pipeline: external_exports.string().min(1),
|
|
5006
|
+
desiredOutput: external_exports.string().min(1),
|
|
5007
|
+
updatedAt: external_exports.string(),
|
|
5008
|
+
steps: external_exports.record(external_exports.string(), external_exports.literal("done"))
|
|
5009
|
+
});
|
|
5010
|
+
var UserTopicSchema = external_exports.object({
|
|
5011
|
+
topic: external_exports.string().min(1),
|
|
5012
|
+
interestLevel: external_exports.union([
|
|
5013
|
+
external_exports.literal(1),
|
|
5014
|
+
external_exports.literal(2),
|
|
5015
|
+
external_exports.literal(3),
|
|
5016
|
+
external_exports.literal(4),
|
|
5017
|
+
external_exports.literal(5)
|
|
5018
|
+
])
|
|
5019
|
+
});
|
|
5020
|
+
var WritingStyleSchema = external_exports.object({
|
|
5021
|
+
tone: external_exports.enum(["beginner", "intermediate", "expert", "mixed"]),
|
|
5022
|
+
targetWordCount: external_exports.number().min(100).max(1e4),
|
|
5023
|
+
voice: external_exports.enum(["first-person", "third-person", "instructional"])
|
|
5024
|
+
});
|
|
5025
|
+
var UserProfileSchema = external_exports.object({
|
|
5026
|
+
userId: external_exports.string().min(1),
|
|
5027
|
+
topics: external_exports.array(UserTopicSchema),
|
|
5028
|
+
style: WritingStyleSchema,
|
|
5029
|
+
writingSamples: external_exports.array(external_exports.string()).optional()
|
|
5030
|
+
});
|
|
5031
|
+
function validateUserProfile(data) {
|
|
5032
|
+
const result = UserProfileSchema.safeParse(data);
|
|
5033
|
+
if (result.success) {
|
|
5034
|
+
return { success: true, data: result.data };
|
|
5035
|
+
}
|
|
5036
|
+
return { success: false, error: { message: result.error.message } };
|
|
5037
|
+
}
|
|
5038
|
+
|
|
5039
|
+
// ../../packages/provider/dist/chunk-W4MDOBYT.js
|
|
5040
|
+
init_esm_shims();
|
|
5041
|
+
import { execSync } from "child_process";
|
|
5042
|
+
import { existsSync as existsSync3 } from "fs";
|
|
5043
|
+
import { createRequire } from "module";
|
|
5044
|
+
import { homedir as homedir3 } from "os";
|
|
5045
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
5046
|
+
import {
|
|
5047
|
+
chmod,
|
|
5048
|
+
mkdir as mkdir3,
|
|
5049
|
+
readFile as readFile2,
|
|
5050
|
+
rename,
|
|
5051
|
+
rm as rm2,
|
|
5052
|
+
writeFile as writeFile2
|
|
5053
|
+
} from "fs/promises";
|
|
5054
|
+
import { homedir as homedir22 } from "os";
|
|
5055
|
+
import { join as join23 } from "path";
|
|
5056
|
+
|
|
5057
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/index.js
|
|
5058
|
+
init_esm_shims();
|
|
5059
|
+
|
|
5060
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
5061
|
+
init_esm_shims();
|
|
5062
|
+
var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
5063
|
+
var defaultOptions = {
|
|
5064
|
+
name: void 0,
|
|
5065
|
+
$refStrategy: "root",
|
|
5066
|
+
basePath: ["#"],
|
|
5067
|
+
effectStrategy: "input",
|
|
5068
|
+
pipeStrategy: "all",
|
|
5069
|
+
dateStrategy: "format:date-time",
|
|
5070
|
+
mapStrategy: "entries",
|
|
5071
|
+
removeAdditionalStrategy: "passthrough",
|
|
5072
|
+
allowedAdditionalProperties: true,
|
|
5073
|
+
rejectedAdditionalProperties: false,
|
|
5074
|
+
definitionPath: "definitions",
|
|
5075
|
+
target: "jsonSchema7",
|
|
5076
|
+
strictUnions: false,
|
|
5077
|
+
definitions: {},
|
|
5078
|
+
errorMessages: false,
|
|
5079
|
+
markdownDescription: false,
|
|
5080
|
+
patternStrategy: "escape",
|
|
5081
|
+
applyRegexFlags: false,
|
|
5082
|
+
emailStrategy: "format:email",
|
|
5083
|
+
base64Strategy: "contentEncoding:base64",
|
|
5084
|
+
nameStrategy: "ref",
|
|
5085
|
+
openAiAnyTypeName: "OpenAiAnyType"
|
|
5086
|
+
};
|
|
5087
|
+
var getDefaultOptions = (options) => typeof options === "string" ? {
|
|
5088
|
+
...defaultOptions,
|
|
5089
|
+
name: options
|
|
5090
|
+
} : {
|
|
5091
|
+
...defaultOptions,
|
|
5092
|
+
...options
|
|
5093
|
+
};
|
|
5094
|
+
|
|
5095
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/Refs.js
|
|
5096
|
+
init_esm_shims();
|
|
5097
|
+
var getRefs = (options) => {
|
|
5098
|
+
const _options = getDefaultOptions(options);
|
|
5099
|
+
const currentPath = _options.name !== void 0 ? [..._options.basePath, _options.definitionPath, _options.name] : _options.basePath;
|
|
5100
|
+
return {
|
|
5101
|
+
..._options,
|
|
5102
|
+
flags: { hasReferencedOpenAiAnyType: false },
|
|
5103
|
+
currentPath,
|
|
5104
|
+
propertyPath: void 0,
|
|
5105
|
+
seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
|
|
5106
|
+
def._def,
|
|
5107
|
+
{
|
|
5108
|
+
def: def._def,
|
|
5109
|
+
path: [..._options.basePath, _options.definitionPath, name],
|
|
5110
|
+
// Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
|
|
5111
|
+
jsonSchema: void 0
|
|
5112
|
+
}
|
|
5113
|
+
]))
|
|
5114
|
+
};
|
|
5115
|
+
};
|
|
5116
|
+
|
|
5117
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/errorMessages.js
|
|
5118
|
+
init_esm_shims();
|
|
5119
|
+
function addErrorMessage(res, key, errorMessage, refs) {
|
|
5120
|
+
if (!refs?.errorMessages)
|
|
5121
|
+
return;
|
|
5122
|
+
if (errorMessage) {
|
|
5123
|
+
res.errorMessage = {
|
|
5124
|
+
...res.errorMessage,
|
|
5125
|
+
[key]: errorMessage
|
|
5126
|
+
};
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
|
|
5130
|
+
res[key] = value;
|
|
5131
|
+
addErrorMessage(res, key, errorMessage, refs);
|
|
5132
|
+
}
|
|
5133
|
+
|
|
5134
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/getRelativePath.js
|
|
5135
|
+
init_esm_shims();
|
|
5136
|
+
var getRelativePath = (pathA, pathB) => {
|
|
5137
|
+
let i = 0;
|
|
5138
|
+
for (; i < pathA.length && i < pathB.length; i++) {
|
|
5139
|
+
if (pathA[i] !== pathB[i])
|
|
5140
|
+
break;
|
|
5141
|
+
}
|
|
5142
|
+
return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/");
|
|
5143
|
+
};
|
|
5144
|
+
|
|
5145
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parseDef.js
|
|
5146
|
+
init_esm_shims();
|
|
5147
|
+
|
|
5148
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/selectParser.js
|
|
5149
|
+
init_esm_shims();
|
|
5150
|
+
|
|
5151
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parsers/any.js
|
|
5152
|
+
init_esm_shims();
|
|
5153
|
+
function parseAnyDef(refs) {
|
|
5154
|
+
if (refs.target !== "openAi") {
|
|
5155
|
+
return {};
|
|
5156
|
+
}
|
|
5157
|
+
const anyDefinitionPath = [
|
|
5158
|
+
...refs.basePath,
|
|
5159
|
+
refs.definitionPath,
|
|
5160
|
+
refs.openAiAnyTypeName
|
|
5161
|
+
];
|
|
5162
|
+
refs.flags.hasReferencedOpenAiAnyType = true;
|
|
5163
|
+
return {
|
|
5164
|
+
$ref: refs.$refStrategy === "relative" ? getRelativePath(anyDefinitionPath, refs.currentPath) : anyDefinitionPath.join("/")
|
|
5165
|
+
};
|
|
5166
|
+
}
|
|
5167
|
+
|
|
5168
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parsers/array.js
|
|
5169
|
+
init_esm_shims();
|
|
5170
|
+
function parseArrayDef(def, refs) {
|
|
5171
|
+
const res = {
|
|
5172
|
+
type: "array"
|
|
5173
|
+
};
|
|
5174
|
+
if (def.type?._def && def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) {
|
|
5175
|
+
res.items = parseDef(def.type._def, {
|
|
5176
|
+
...refs,
|
|
5177
|
+
currentPath: [...refs.currentPath, "items"]
|
|
5178
|
+
});
|
|
5179
|
+
}
|
|
5180
|
+
if (def.minLength) {
|
|
5181
|
+
setResponseValueAndErrors(res, "minItems", def.minLength.value, def.minLength.message, refs);
|
|
5182
|
+
}
|
|
5183
|
+
if (def.maxLength) {
|
|
5184
|
+
setResponseValueAndErrors(res, "maxItems", def.maxLength.value, def.maxLength.message, refs);
|
|
5185
|
+
}
|
|
5186
|
+
if (def.exactLength) {
|
|
5187
|
+
setResponseValueAndErrors(res, "minItems", def.exactLength.value, def.exactLength.message, refs);
|
|
5188
|
+
setResponseValueAndErrors(res, "maxItems", def.exactLength.value, def.exactLength.message, refs);
|
|
5189
|
+
}
|
|
5190
|
+
return res;
|
|
5191
|
+
}
|
|
5192
|
+
|
|
5193
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js
|
|
5194
|
+
init_esm_shims();
|
|
5195
|
+
function parseBigintDef(def, refs) {
|
|
5196
|
+
const res = {
|
|
5197
|
+
type: "integer",
|
|
5198
|
+
format: "int64"
|
|
5199
|
+
};
|
|
5200
|
+
if (!def.checks)
|
|
5201
|
+
return res;
|
|
5202
|
+
for (const check2 of def.checks) {
|
|
5203
|
+
switch (check2.kind) {
|
|
5204
|
+
case "min":
|
|
5205
|
+
if (refs.target === "jsonSchema7") {
|
|
5206
|
+
if (check2.inclusive) {
|
|
5207
|
+
setResponseValueAndErrors(res, "minimum", check2.value, check2.message, refs);
|
|
5208
|
+
} else {
|
|
5209
|
+
setResponseValueAndErrors(res, "exclusiveMinimum", check2.value, check2.message, refs);
|
|
5210
|
+
}
|
|
5211
|
+
} else {
|
|
5212
|
+
if (!check2.inclusive) {
|
|
5213
|
+
res.exclusiveMinimum = true;
|
|
5214
|
+
}
|
|
5215
|
+
setResponseValueAndErrors(res, "minimum", check2.value, check2.message, refs);
|
|
5216
|
+
}
|
|
5217
|
+
break;
|
|
5218
|
+
case "max":
|
|
5219
|
+
if (refs.target === "jsonSchema7") {
|
|
5220
|
+
if (check2.inclusive) {
|
|
5221
|
+
setResponseValueAndErrors(res, "maximum", check2.value, check2.message, refs);
|
|
5222
|
+
} else {
|
|
5223
|
+
setResponseValueAndErrors(res, "exclusiveMaximum", check2.value, check2.message, refs);
|
|
5224
|
+
}
|
|
5225
|
+
} else {
|
|
5226
|
+
if (!check2.inclusive) {
|
|
5227
|
+
res.exclusiveMaximum = true;
|
|
5228
|
+
}
|
|
5229
|
+
setResponseValueAndErrors(res, "maximum", check2.value, check2.message, refs);
|
|
5230
|
+
}
|
|
5231
|
+
break;
|
|
5232
|
+
case "multipleOf":
|
|
5233
|
+
setResponseValueAndErrors(res, "multipleOf", check2.value, check2.message, refs);
|
|
5234
|
+
break;
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
return res;
|
|
5238
|
+
}
|
|
5239
|
+
|
|
5240
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js
|
|
5241
|
+
init_esm_shims();
|
|
5242
|
+
function parseBooleanDef() {
|
|
5243
|
+
return {
|
|
5244
|
+
type: "boolean"
|
|
5245
|
+
};
|
|
5246
|
+
}
|
|
5247
|
+
|
|
5248
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parsers/branded.js
|
|
5249
|
+
init_esm_shims();
|
|
5250
|
+
function parseBrandedDef(_def, refs) {
|
|
5251
|
+
return parseDef(_def.type._def, refs);
|
|
5252
|
+
}
|
|
5253
|
+
|
|
5254
|
+
// ../../node_modules/zod-to-json-schema/dist/esm/parsers/catch.js
|
|
5255
|
+
init_esm_shims();
|
|
5256
|
+
var parseCatchDef = (def, refs) => {
|
|
4458
5257
|
return parseDef(def.innerType._def, refs);
|
|
4459
5258
|
};
|
|
4460
5259
|
|
|
@@ -5592,6 +6391,9 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
5592
6391
|
return combined;
|
|
5593
6392
|
};
|
|
5594
6393
|
|
|
6394
|
+
// ../../packages/provider/dist/chunk-W4MDOBYT.js
|
|
6395
|
+
import { join as join6 } from "path";
|
|
6396
|
+
|
|
5595
6397
|
// ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
5596
6398
|
init_esm_shims();
|
|
5597
6399
|
import { join as join5 } from "path";
|
|
@@ -5628,7 +6430,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
5628
6430
|
return to;
|
|
5629
6431
|
};
|
|
5630
6432
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
5631
|
-
var
|
|
6433
|
+
var __export2 = (target, all) => {
|
|
5632
6434
|
for (var name in all)
|
|
5633
6435
|
__defProp(target, name, {
|
|
5634
6436
|
get: all[name],
|
|
@@ -17600,7 +18402,7 @@ function config(newConfig) {
|
|
|
17600
18402
|
return globalConfig;
|
|
17601
18403
|
}
|
|
17602
18404
|
var exports_util = {};
|
|
17603
|
-
|
|
18405
|
+
__export2(exports_util, {
|
|
17604
18406
|
unwrapMessage: () => unwrapMessage,
|
|
17605
18407
|
stringifyPrimitive: () => stringifyPrimitive,
|
|
17606
18408
|
required: () => required,
|
|
@@ -20528,7 +21330,7 @@ function _refine(Class2, fn, _params) {
|
|
|
20528
21330
|
return schema;
|
|
20529
21331
|
}
|
|
20530
21332
|
var exports_iso2 = {};
|
|
20531
|
-
|
|
21333
|
+
__export2(exports_iso2, {
|
|
20532
21334
|
time: () => time2,
|
|
20533
21335
|
duration: () => duration2,
|
|
20534
21336
|
datetime: () => datetime2,
|
|
@@ -22127,12 +22929,27 @@ function query({
|
|
|
22127
22929
|
return queryInstance;
|
|
22128
22930
|
}
|
|
22129
22931
|
|
|
22130
|
-
// ../../packages/provider/dist/chunk-
|
|
22932
|
+
// ../../packages/provider/dist/chunk-W4MDOBYT.js
|
|
22131
22933
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync3, writeFileSync } from "fs";
|
|
22132
22934
|
import { join as join33 } from "path";
|
|
22133
|
-
import {
|
|
22935
|
+
import { access, readdir as readdir3, readFile as readFile22, stat } from "fs/promises";
|
|
22936
|
+
import { join as join42 } from "path";
|
|
22937
|
+
import { cp as cp2, mkdir as mkdir22, readFile as readFile3, rm as rm22, writeFile as writeFile22 } from "fs/promises";
|
|
22134
22938
|
import { homedir as homedir32 } from "os";
|
|
22135
|
-
import { isAbsolute, join as
|
|
22939
|
+
import { isAbsolute, join as join52, normalize, resolve } from "path";
|
|
22940
|
+
import { readdir as readdir22, readFile as readFile4, rename as rename2, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
22941
|
+
import { join as join7 } from "path";
|
|
22942
|
+
import {
|
|
22943
|
+
open as open2,
|
|
22944
|
+
readdir as readdir32,
|
|
22945
|
+
readFile as readFile5,
|
|
22946
|
+
rename as rename3,
|
|
22947
|
+
stat as stat3,
|
|
22948
|
+
unlink,
|
|
22949
|
+
writeFile as writeFile4
|
|
22950
|
+
} from "fs/promises";
|
|
22951
|
+
import { join as join8 } from "path";
|
|
22952
|
+
import { join as join9 } from "path";
|
|
22136
22953
|
var LINE_SPLIT_REGEX = /\r?\n/;
|
|
22137
22954
|
function findSdkBundledCliPath() {
|
|
22138
22955
|
try {
|
|
@@ -22226,11 +23043,42 @@ var PRESETS = {
|
|
|
22226
23043
|
ANTHROPIC_CLAUDE_SONNET: {
|
|
22227
23044
|
name: "Anthropic Claude Sonnet",
|
|
22228
23045
|
apiProvider: "anthropic",
|
|
22229
|
-
mainModel: "claude-sonnet-4-5-
|
|
22230
|
-
executorModel: "claude-sonnet-4-5-
|
|
22231
|
-
haikuModel: "claude-sonnet-4-5-
|
|
22232
|
-
sonnetModel: "claude-sonnet-4-5-
|
|
22233
|
-
opusModel: "claude-sonnet-4-5-
|
|
23046
|
+
mainModel: "claude-sonnet-4-5-20250929",
|
|
23047
|
+
executorModel: "claude-sonnet-4-5-20250929",
|
|
23048
|
+
haikuModel: "claude-sonnet-4-5-20250929",
|
|
23049
|
+
sonnetModel: "claude-sonnet-4-5-20250929",
|
|
23050
|
+
opusModel: "claude-sonnet-4-5-20250929"
|
|
23051
|
+
},
|
|
23052
|
+
// Claude Code Subscription (macOS Keychain)
|
|
23053
|
+
CLAUDE_CODE_SUBSCRIPTION_HAIKU: {
|
|
23054
|
+
name: "Claude Code Subscription (Haiku)",
|
|
23055
|
+
apiProvider: "anthropic",
|
|
23056
|
+
authTokenSource: "subscription",
|
|
23057
|
+
mainModel: "claude-haiku-4-5-20251001",
|
|
23058
|
+
executorModel: "claude-haiku-4-5-20251001",
|
|
23059
|
+
haikuModel: "claude-haiku-4-5-20251001",
|
|
23060
|
+
sonnetModel: "claude-haiku-4-5-20251001",
|
|
23061
|
+
opusModel: "claude-haiku-4-5-20251001"
|
|
23062
|
+
},
|
|
23063
|
+
CLAUDE_CODE_SUBSCRIPTION_SONNET: {
|
|
23064
|
+
name: "Claude Code Subscription (Sonnet)",
|
|
23065
|
+
apiProvider: "anthropic",
|
|
23066
|
+
authTokenSource: "subscription",
|
|
23067
|
+
mainModel: "claude-sonnet-4-5-20250929",
|
|
23068
|
+
executorModel: "claude-sonnet-4-5-20250929",
|
|
23069
|
+
haikuModel: "claude-sonnet-4-5-20250929",
|
|
23070
|
+
sonnetModel: "claude-sonnet-4-5-20250929",
|
|
23071
|
+
opusModel: "claude-sonnet-4-5-20250929"
|
|
23072
|
+
},
|
|
23073
|
+
CLAUDE_CODE_SUBSCRIPTION_OPUS: {
|
|
23074
|
+
name: "Claude Code Subscription (Opus)",
|
|
23075
|
+
apiProvider: "anthropic",
|
|
23076
|
+
authTokenSource: "subscription",
|
|
23077
|
+
mainModel: "claude-opus-4-5-20251101",
|
|
23078
|
+
executorModel: "claude-opus-4-5-20251101",
|
|
23079
|
+
haikuModel: "claude-opus-4-5-20251101",
|
|
23080
|
+
sonnetModel: "claude-opus-4-5-20251101",
|
|
23081
|
+
opusModel: "claude-opus-4-5-20251101"
|
|
22234
23082
|
},
|
|
22235
23083
|
// ZenMux Presets
|
|
22236
23084
|
ZENMUX_ANTHROPIC_HAIKU45: {
|
|
@@ -22253,6 +23101,16 @@ var PRESETS = {
|
|
|
22253
23101
|
sonnetModel: "z-ai/glm-4.7",
|
|
22254
23102
|
opusModel: "z-ai/glm-4.7"
|
|
22255
23103
|
},
|
|
23104
|
+
ZENMUX_ZAI_GLM47FLASHX: {
|
|
23105
|
+
name: "ZenMux GLM-4.7-FlashX",
|
|
23106
|
+
apiProvider: "zenmux",
|
|
23107
|
+
baseUrl: "https://zenmux.ai/api/anthropic",
|
|
23108
|
+
mainModel: "z-ai/glm-4.7-flashx",
|
|
23109
|
+
executorModel: "z-ai/glm-4.7-flashx",
|
|
23110
|
+
haikuModel: "z-ai/glm-4.7-flashx",
|
|
23111
|
+
sonnetModel: "z-ai/glm-4.7-flashx",
|
|
23112
|
+
opusModel: "z-ai/glm-4.7-flashx"
|
|
23113
|
+
},
|
|
22256
23114
|
ZENMUX_MINIMAX_M21: {
|
|
22257
23115
|
name: "ZenMux MiniMax-M2.1",
|
|
22258
23116
|
apiProvider: "zenmux",
|
|
@@ -22372,6 +23230,48 @@ var PRESETS = {
|
|
|
22372
23230
|
haikuModel: "openai/gpt-5.1-codex-mini",
|
|
22373
23231
|
sonnetModel: "openai/gpt-5.1-codex-mini",
|
|
22374
23232
|
opusModel: "openai/gpt-5.1-codex-mini"
|
|
23233
|
+
},
|
|
23234
|
+
// OpenRouter Presets
|
|
23235
|
+
OPENROUTER_PRESET: {
|
|
23236
|
+
name: "OpenRouter (User-Configured Preset)",
|
|
23237
|
+
apiProvider: "openrouter",
|
|
23238
|
+
baseUrl: "https://openrouter.ai/api",
|
|
23239
|
+
mainModel: "@preset/looplia-default",
|
|
23240
|
+
executorModel: "@preset/looplia-default",
|
|
23241
|
+
haikuModel: "@preset/looplia-default",
|
|
23242
|
+
sonnetModel: "@preset/looplia-default",
|
|
23243
|
+
opusModel: "@preset/looplia-default"
|
|
23244
|
+
},
|
|
23245
|
+
OPENROUTER_ZAI_GLM47FLASH: {
|
|
23246
|
+
name: "OpenRouter GLM-4.7-Flash",
|
|
23247
|
+
apiProvider: "openrouter",
|
|
23248
|
+
baseUrl: "https://openrouter.ai/api",
|
|
23249
|
+
mainModel: "z-ai/glm-4.7-flash",
|
|
23250
|
+
executorModel: "z-ai/glm-4.7-flash",
|
|
23251
|
+
haikuModel: "z-ai/glm-4.7-flash",
|
|
23252
|
+
sonnetModel: "z-ai/glm-4.7-flash",
|
|
23253
|
+
opusModel: "z-ai/glm-4.7-flash"
|
|
23254
|
+
},
|
|
23255
|
+
// Ollama Cloud Presets
|
|
23256
|
+
OLLAMA_GLM47_CLOUD: {
|
|
23257
|
+
name: "Ollama GLM-4.7 Cloud",
|
|
23258
|
+
apiProvider: "ollama",
|
|
23259
|
+
baseUrl: "http://localhost:11434",
|
|
23260
|
+
mainModel: "glm-4.7:cloud",
|
|
23261
|
+
executorModel: "glm-4.7:cloud",
|
|
23262
|
+
haikuModel: "glm-4.7:cloud",
|
|
23263
|
+
sonnetModel: "glm-4.7:cloud",
|
|
23264
|
+
opusModel: "glm-4.7:cloud"
|
|
23265
|
+
},
|
|
23266
|
+
OLLAMA_MINIMAX_M21_CLOUD: {
|
|
23267
|
+
name: "Ollama MiniMax-M2.1 Cloud",
|
|
23268
|
+
apiProvider: "ollama",
|
|
23269
|
+
baseUrl: "http://localhost:11434",
|
|
23270
|
+
mainModel: "minimax-m2.1:cloud",
|
|
23271
|
+
executorModel: "minimax-m2.1:cloud",
|
|
23272
|
+
haikuModel: "minimax-m2.1:cloud",
|
|
23273
|
+
sonnetModel: "minimax-m2.1:cloud",
|
|
23274
|
+
opusModel: "minimax-m2.1:cloud"
|
|
22375
23275
|
}
|
|
22376
23276
|
};
|
|
22377
23277
|
var CONFIG_FILE = "looplia.setting.json";
|
|
@@ -22423,19 +23323,45 @@ function injectModelTierEnv(mainModel, executorModel) {
|
|
|
22423
23323
|
setEnvIfNotSet("LOOPLIA_AGENT_MODEL_MAIN", mainModel);
|
|
22424
23324
|
setEnvIfNotSet("LOOPLIA_AGENT_MODEL_EXECUTOR", executorModel);
|
|
22425
23325
|
}
|
|
22426
|
-
function
|
|
22427
|
-
if (
|
|
22428
|
-
|
|
22429
|
-
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
23326
|
+
function injectSubscriptionAuth() {
|
|
23327
|
+
if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
23328
|
+
console.warn(
|
|
23329
|
+
"Warning: CLAUDE_CODE_OAUTH_TOKEN not set. Set this environment variable to use Claude Code subscription auth."
|
|
23330
|
+
);
|
|
23331
|
+
}
|
|
23332
|
+
process.env.ANTHROPIC_API_KEY = void 0;
|
|
23333
|
+
}
|
|
23334
|
+
function injectNonAnthropicProviderEnv(apiProvider) {
|
|
23335
|
+
if (apiProvider.baseUrl && !process.env.ANTHROPIC_BASE_URL) {
|
|
23336
|
+
process.env.ANTHROPIC_BASE_URL = apiProvider.baseUrl;
|
|
23337
|
+
}
|
|
23338
|
+
const isOpenRouterEndpoint = apiProvider.type === "openrouter" || apiProvider.baseUrl?.includes("openrouter.ai");
|
|
23339
|
+
const isZenmuxEndpoint = apiProvider.type === "zenmux" || apiProvider.baseUrl?.includes("zenmux.ai");
|
|
23340
|
+
const isOllamaEndpoint = apiProvider.type === "ollama" || apiProvider.baseUrl?.includes("localhost:11434");
|
|
23341
|
+
if (apiProvider.authToken) {
|
|
23342
|
+
if (isOpenRouterEndpoint) {
|
|
23343
|
+
process.env.ANTHROPIC_AUTH_TOKEN = apiProvider.authToken;
|
|
23344
|
+
process.env.ANTHROPIC_API_KEY = void 0;
|
|
22433
23345
|
} else {
|
|
22434
|
-
|
|
22435
|
-
if (isZenmuxEndpoint && process.env.ZENMUX_API_KEY) {
|
|
22436
|
-
process.env.ANTHROPIC_API_KEY = process.env.ZENMUX_API_KEY;
|
|
22437
|
-
}
|
|
23346
|
+
process.env.ANTHROPIC_API_KEY = apiProvider.authToken;
|
|
22438
23347
|
}
|
|
23348
|
+
return;
|
|
23349
|
+
}
|
|
23350
|
+
if (isZenmuxEndpoint && process.env.ZENMUX_API_KEY) {
|
|
23351
|
+
process.env.ANTHROPIC_API_KEY = process.env.ZENMUX_API_KEY;
|
|
23352
|
+
} else if (isOpenRouterEndpoint && process.env.OPENROUTER_API_KEY) {
|
|
23353
|
+
process.env.ANTHROPIC_AUTH_TOKEN = process.env.OPENROUTER_API_KEY;
|
|
23354
|
+
process.env.ANTHROPIC_API_KEY = void 0;
|
|
23355
|
+
} else if (isOllamaEndpoint) {
|
|
23356
|
+
process.env.ANTHROPIC_API_KEY = process.env.OLLAMA_API_KEY || "ollama";
|
|
23357
|
+
}
|
|
23358
|
+
}
|
|
23359
|
+
function injectLoopliaSettingsEnv(settings) {
|
|
23360
|
+
if (settings.apiProvider.authTokenSource === "subscription") {
|
|
23361
|
+
injectSubscriptionAuth();
|
|
23362
|
+
}
|
|
23363
|
+
if (settings.apiProvider.type !== "anthropic") {
|
|
23364
|
+
injectNonAnthropicProviderEnv(settings.apiProvider);
|
|
22439
23365
|
}
|
|
22440
23366
|
injectModelTierEnv(settings.agents.main, settings.agents.executor);
|
|
22441
23367
|
}
|
|
@@ -22456,6 +23382,7 @@ function getSettingsDisplayInfo(settings) {
|
|
|
22456
23382
|
preset: settings.preset,
|
|
22457
23383
|
provider,
|
|
22458
23384
|
authToken: settings.apiProvider.authToken,
|
|
23385
|
+
authTokenSource: settings.apiProvider.authTokenSource,
|
|
22459
23386
|
agents: {
|
|
22460
23387
|
main: settings.agents.main,
|
|
22461
23388
|
executor: settings.agents.executor
|
|
@@ -22479,7 +23406,8 @@ function applyPreset(presetName, existingSettings) {
|
|
|
22479
23406
|
apiProvider: {
|
|
22480
23407
|
type: preset.apiProvider,
|
|
22481
23408
|
baseUrl: preset.baseUrl,
|
|
22482
|
-
authToken: existingSettings?.apiProvider.authToken
|
|
23409
|
+
authToken: existingSettings?.apiProvider.authToken,
|
|
23410
|
+
authTokenSource: preset.authTokenSource
|
|
22483
23411
|
},
|
|
22484
23412
|
agents: {
|
|
22485
23413
|
main: preset.mainModel,
|
|
@@ -22498,17 +23426,19 @@ async function initializeCommandEnvironment(options = {}) {
|
|
|
22498
23426
|
return { settings };
|
|
22499
23427
|
}
|
|
22500
23428
|
function validateApiKeyPresence() {
|
|
22501
|
-
if (!(process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_OAUTH_TOKEN)) {
|
|
23429
|
+
if (!(process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_CODE_OAUTH_TOKEN)) {
|
|
22502
23430
|
console.error("Error: API key required");
|
|
22503
23431
|
console.error("");
|
|
22504
23432
|
console.error("Options:");
|
|
22505
23433
|
console.error(" 1. Set ANTHROPIC_API_KEY environment variable");
|
|
22506
23434
|
console.error(" 2. Set ZENMUX_API_KEY with a ZenMux preset");
|
|
22507
|
-
console.error(" 3.
|
|
22508
|
-
console.error(" 4.
|
|
23435
|
+
console.error(" 3. Set OPENROUTER_API_KEY with an OpenRouter preset");
|
|
23436
|
+
console.error(" 4. Configure via: looplia config provider preset <name>");
|
|
23437
|
+
console.error(" 5. Use --mock flag for testing without API");
|
|
22509
23438
|
console.error("");
|
|
22510
23439
|
console.error("Get your API key from: https://console.anthropic.com");
|
|
22511
23440
|
console.error("Or use ZenMux at: https://zenmux.ai");
|
|
23441
|
+
console.error("Or use OpenRouter at: https://openrouter.ai");
|
|
22512
23442
|
process.exit(1);
|
|
22513
23443
|
}
|
|
22514
23444
|
}
|
|
@@ -22640,58 +23570,261 @@ function mapException(error2) {
|
|
|
22640
23570
|
};
|
|
22641
23571
|
}
|
|
22642
23572
|
return {
|
|
22643
|
-
success: false,
|
|
22644
|
-
error: {
|
|
22645
|
-
type: "unknown",
|
|
22646
|
-
message: String(error2)
|
|
23573
|
+
success: false,
|
|
23574
|
+
error: {
|
|
23575
|
+
type: "unknown",
|
|
23576
|
+
message: String(error2)
|
|
23577
|
+
}
|
|
23578
|
+
};
|
|
23579
|
+
}
|
|
23580
|
+
var SANDBOX_ID_REGEX = /sandbox\/([^\s/]+)/;
|
|
23581
|
+
var CONTENT_ID_REGEX = /contentItem\/([^\s/]+)/;
|
|
23582
|
+
var SANDBOX_ARG_REGEX = /--sandbox-id\s+([^\s]+)/;
|
|
23583
|
+
var SANDBOX_RESUME_REGEX = /--sandbox\s+([^\s]+)/;
|
|
23584
|
+
var VALID_SANDBOX_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
23585
|
+
function extractSandboxIdFromPrompt(prompt) {
|
|
23586
|
+
let match = prompt.match(SANDBOX_ID_REGEX);
|
|
23587
|
+
if (!match) {
|
|
23588
|
+
match = prompt.match(SANDBOX_ARG_REGEX);
|
|
23589
|
+
}
|
|
23590
|
+
if (!match) {
|
|
23591
|
+
match = prompt.match(SANDBOX_RESUME_REGEX);
|
|
23592
|
+
}
|
|
23593
|
+
if (!match) {
|
|
23594
|
+
match = prompt.match(CONTENT_ID_REGEX);
|
|
23595
|
+
}
|
|
23596
|
+
const rawId = match?.[1];
|
|
23597
|
+
if (!rawId) {
|
|
23598
|
+
return null;
|
|
23599
|
+
}
|
|
23600
|
+
let decodedId;
|
|
23601
|
+
try {
|
|
23602
|
+
decodedId = decodeURIComponent(rawId);
|
|
23603
|
+
} catch {
|
|
23604
|
+
return null;
|
|
23605
|
+
}
|
|
23606
|
+
if (decodedId.includes("\0")) {
|
|
23607
|
+
return null;
|
|
23608
|
+
}
|
|
23609
|
+
if (decodedId.includes("..") || decodedId.includes("/") || decodedId.includes("\\")) {
|
|
23610
|
+
return null;
|
|
23611
|
+
}
|
|
23612
|
+
if (!VALID_SANDBOX_ID_PATTERN.test(decodedId)) {
|
|
23613
|
+
return null;
|
|
23614
|
+
}
|
|
23615
|
+
return decodedId;
|
|
23616
|
+
}
|
|
23617
|
+
var extractContentIdFromPrompt = extractSandboxIdFromPrompt;
|
|
23618
|
+
var LOCK_MAX_RETRIES = 5;
|
|
23619
|
+
var LOCK_RETRY_DELAY_MS = 200;
|
|
23620
|
+
function isBuildManifest(value) {
|
|
23621
|
+
if (!value || typeof value !== "object") {
|
|
23622
|
+
return false;
|
|
23623
|
+
}
|
|
23624
|
+
const obj = value;
|
|
23625
|
+
return obj.type === "build";
|
|
23626
|
+
}
|
|
23627
|
+
function isRunValidationManifest(value) {
|
|
23628
|
+
if (!value || typeof value !== "object") {
|
|
23629
|
+
return false;
|
|
23630
|
+
}
|
|
23631
|
+
const obj = value;
|
|
23632
|
+
return typeof obj.workflow === "string" && typeof obj.steps === "object" && obj.steps !== null;
|
|
23633
|
+
}
|
|
23634
|
+
function isValidationManifest(value) {
|
|
23635
|
+
return isBuildManifest(value) || isRunValidationManifest(value);
|
|
23636
|
+
}
|
|
23637
|
+
async function sleep(ms) {
|
|
23638
|
+
await new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
23639
|
+
}
|
|
23640
|
+
async function lockExists(lockPath) {
|
|
23641
|
+
try {
|
|
23642
|
+
await access(lockPath);
|
|
23643
|
+
return true;
|
|
23644
|
+
} catch {
|
|
23645
|
+
return false;
|
|
23646
|
+
}
|
|
23647
|
+
}
|
|
23648
|
+
function validationError(field, message) {
|
|
23649
|
+
return {
|
|
23650
|
+
success: false,
|
|
23651
|
+
error: { type: "validation_error", field, message }
|
|
23652
|
+
};
|
|
23653
|
+
}
|
|
23654
|
+
async function findMostRecentSandbox(sandboxRoot) {
|
|
23655
|
+
try {
|
|
23656
|
+
const entries = await readdir3(sandboxRoot, { withFileTypes: true });
|
|
23657
|
+
const dirs = entries.filter(
|
|
23658
|
+
(e) => e.isDirectory() && !e.name.startsWith(".")
|
|
23659
|
+
);
|
|
23660
|
+
if (dirs.length === 0) {
|
|
23661
|
+
return;
|
|
23662
|
+
}
|
|
23663
|
+
const dirStats = await Promise.all(
|
|
23664
|
+
dirs.map(async (dir) => {
|
|
23665
|
+
const dirPath = join42(sandboxRoot, dir.name);
|
|
23666
|
+
const dirStat = await stat(dirPath);
|
|
23667
|
+
return { path: dirPath, mtime: dirStat.mtime.getTime() };
|
|
23668
|
+
})
|
|
23669
|
+
);
|
|
23670
|
+
dirStats.sort((a, b) => b.mtime - a.mtime);
|
|
23671
|
+
return dirStats[0]?.path;
|
|
23672
|
+
} catch {
|
|
23673
|
+
return;
|
|
23674
|
+
}
|
|
23675
|
+
}
|
|
23676
|
+
function findFinalStep(steps) {
|
|
23677
|
+
const stepEntries = Object.entries(steps);
|
|
23678
|
+
if (stepEntries.length === 0) {
|
|
23679
|
+
return;
|
|
23680
|
+
}
|
|
23681
|
+
const lastEntry = stepEntries.at(-1);
|
|
23682
|
+
if (!lastEntry) {
|
|
23683
|
+
return;
|
|
23684
|
+
}
|
|
23685
|
+
return { id: lastEntry[0], output: lastEntry[1].output };
|
|
23686
|
+
}
|
|
23687
|
+
function resolveFinalStep(steps, finalStepId) {
|
|
23688
|
+
if (finalStepId) {
|
|
23689
|
+
const step = steps[finalStepId];
|
|
23690
|
+
if (step?.output) {
|
|
23691
|
+
return { id: finalStepId, output: step.output };
|
|
23692
|
+
}
|
|
23693
|
+
}
|
|
23694
|
+
return findFinalStep(steps);
|
|
23695
|
+
}
|
|
23696
|
+
function areAllStepsValidated(steps) {
|
|
23697
|
+
const pendingSteps = [];
|
|
23698
|
+
for (const [stepId, stepState] of Object.entries(steps)) {
|
|
23699
|
+
if (!stepState.validated) {
|
|
23700
|
+
pendingSteps.push(stepId);
|
|
23701
|
+
}
|
|
23702
|
+
}
|
|
23703
|
+
return {
|
|
23704
|
+
allValidated: pendingSteps.length === 0,
|
|
23705
|
+
pendingSteps
|
|
23706
|
+
};
|
|
23707
|
+
}
|
|
23708
|
+
function resolveSandboxDir(sandboxRoot, sandboxId) {
|
|
23709
|
+
if (sandboxId) {
|
|
23710
|
+
return join42(sandboxRoot, sandboxId);
|
|
23711
|
+
}
|
|
23712
|
+
return findMostRecentSandbox(sandboxRoot);
|
|
23713
|
+
}
|
|
23714
|
+
async function readValidationManifest(sandboxDir) {
|
|
23715
|
+
const validationPath = join42(sandboxDir, "validation.json");
|
|
23716
|
+
const lockPath = `${validationPath}.lock`;
|
|
23717
|
+
for (let attempt = 0; attempt < LOCK_MAX_RETRIES; attempt++) {
|
|
23718
|
+
if (await lockExists(lockPath)) {
|
|
23719
|
+
await sleep(LOCK_RETRY_DELAY_MS);
|
|
23720
|
+
continue;
|
|
23721
|
+
}
|
|
23722
|
+
try {
|
|
23723
|
+
const content = await readFile22(validationPath, "utf-8");
|
|
23724
|
+
const parsed = JSON.parse(content);
|
|
23725
|
+
if (!isValidationManifest(parsed)) {
|
|
23726
|
+
return { error: "Invalid validation manifest structure" };
|
|
23727
|
+
}
|
|
23728
|
+
return { manifest: parsed };
|
|
23729
|
+
} catch (error2) {
|
|
23730
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
23731
|
+
return { error: `Failed to read validation.json: ${message}` };
|
|
23732
|
+
}
|
|
23733
|
+
}
|
|
23734
|
+
return { error: "Timeout waiting for validation.json lock to release" };
|
|
23735
|
+
}
|
|
23736
|
+
async function readFinalArtifact(sandboxDir, outputPath) {
|
|
23737
|
+
const artifactPath = join42(sandboxDir, outputPath);
|
|
23738
|
+
try {
|
|
23739
|
+
const content = await readFile22(artifactPath, "utf-8");
|
|
23740
|
+
return { artifact: JSON.parse(content) };
|
|
23741
|
+
} catch (error2) {
|
|
23742
|
+
const errorMessage = `Failed to read final artifact from ${outputPath}: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
23743
|
+
const isParseError = error2 instanceof Error && error2.message.includes("JSON");
|
|
23744
|
+
if (isParseError) {
|
|
23745
|
+
return {
|
|
23746
|
+
error: {
|
|
23747
|
+
success: false,
|
|
23748
|
+
error: {
|
|
23749
|
+
type: "malformed_output",
|
|
23750
|
+
expected: "valid JSON",
|
|
23751
|
+
got: "invalid JSON",
|
|
23752
|
+
message: errorMessage
|
|
23753
|
+
}
|
|
23754
|
+
}
|
|
23755
|
+
};
|
|
23756
|
+
}
|
|
23757
|
+
return { error: validationError("artifact", errorMessage) };
|
|
23758
|
+
}
|
|
23759
|
+
}
|
|
23760
|
+
function extractBuildResult(manifest, sandboxDir) {
|
|
23761
|
+
if (!manifest.workflowValidated) {
|
|
23762
|
+
return validationError("build", manifest.error ?? "Workflow not validated");
|
|
23763
|
+
}
|
|
23764
|
+
return {
|
|
23765
|
+
success: true,
|
|
23766
|
+
data: {
|
|
23767
|
+
status: "success",
|
|
23768
|
+
sandboxId: manifest.sandboxId ?? sandboxDir.split("/").pop(),
|
|
23769
|
+
workflowName: manifest.workflowName,
|
|
23770
|
+
workflowPath: manifest.workflowPath
|
|
22647
23771
|
}
|
|
22648
23772
|
};
|
|
22649
23773
|
}
|
|
22650
|
-
|
|
22651
|
-
|
|
22652
|
-
|
|
22653
|
-
|
|
22654
|
-
|
|
22655
|
-
|
|
22656
|
-
|
|
22657
|
-
if (!match) {
|
|
22658
|
-
match = prompt.match(SANDBOX_ARG_REGEX);
|
|
22659
|
-
}
|
|
22660
|
-
if (!match) {
|
|
22661
|
-
match = prompt.match(SANDBOX_RESUME_REGEX);
|
|
22662
|
-
}
|
|
22663
|
-
if (!match) {
|
|
22664
|
-
match = prompt.match(CONTENT_ID_REGEX);
|
|
23774
|
+
async function extractRunResult(manifest, sandboxDir) {
|
|
23775
|
+
const { allValidated, pendingSteps } = areAllStepsValidated(manifest.steps);
|
|
23776
|
+
if (!allValidated) {
|
|
23777
|
+
return validationError(
|
|
23778
|
+
"steps",
|
|
23779
|
+
`Workflow incomplete. Pending steps: ${pendingSteps.join(", ")}`
|
|
23780
|
+
);
|
|
22665
23781
|
}
|
|
22666
|
-
const
|
|
22667
|
-
if (!
|
|
22668
|
-
return
|
|
23782
|
+
const finalStep = resolveFinalStep(manifest.steps, manifest.finalStepId);
|
|
23783
|
+
if (!finalStep) {
|
|
23784
|
+
return validationError("steps", "No steps found in validation manifest");
|
|
22669
23785
|
}
|
|
22670
|
-
|
|
22671
|
-
|
|
22672
|
-
|
|
22673
|
-
|
|
22674
|
-
|
|
23786
|
+
const { artifact, error: artifactError } = await readFinalArtifact(
|
|
23787
|
+
sandboxDir,
|
|
23788
|
+
finalStep.output
|
|
23789
|
+
);
|
|
23790
|
+
if (artifactError) {
|
|
23791
|
+
return artifactError;
|
|
22675
23792
|
}
|
|
22676
|
-
|
|
22677
|
-
|
|
23793
|
+
return {
|
|
23794
|
+
success: true,
|
|
23795
|
+
data: {
|
|
23796
|
+
status: "success",
|
|
23797
|
+
sandboxId: manifest.sandboxId ?? sandboxDir.split("/").pop(),
|
|
23798
|
+
workflowId: manifest.workflow,
|
|
23799
|
+
artifact
|
|
23800
|
+
}
|
|
23801
|
+
};
|
|
23802
|
+
}
|
|
23803
|
+
async function extractSandboxResult(options) {
|
|
23804
|
+
const loopliaHome = getLoopliaPluginPath();
|
|
23805
|
+
const sandboxRoot = options?.sandboxRoot ?? join42(loopliaHome, "sandbox");
|
|
23806
|
+
const sandboxId = options?.sandboxId;
|
|
23807
|
+
const sandboxDir = await resolveSandboxDir(sandboxRoot, sandboxId);
|
|
23808
|
+
if (!sandboxDir) {
|
|
23809
|
+
const message = sandboxId ? `Sandbox not found: ${sandboxId}` : "No sandbox directories found";
|
|
23810
|
+
return validationError("sandbox", message);
|
|
22678
23811
|
}
|
|
22679
|
-
|
|
22680
|
-
|
|
23812
|
+
const { manifest, error: readError } = await readValidationManifest(sandboxDir);
|
|
23813
|
+
if (!manifest) {
|
|
23814
|
+
return validationError("validation.json", readError ?? "Unknown error");
|
|
22681
23815
|
}
|
|
22682
|
-
if (
|
|
22683
|
-
return
|
|
23816
|
+
if (isBuildManifest(manifest)) {
|
|
23817
|
+
return extractBuildResult(manifest, sandboxDir);
|
|
22684
23818
|
}
|
|
22685
|
-
return
|
|
23819
|
+
return extractRunResult(manifest, sandboxDir);
|
|
22686
23820
|
}
|
|
22687
|
-
var extractContentIdFromPrompt = extractSandboxIdFromPrompt;
|
|
22688
23821
|
function expandPath(path) {
|
|
22689
23822
|
if (path.startsWith("~/") || path === "~") {
|
|
22690
23823
|
const home = homedir32();
|
|
22691
23824
|
if (!home) {
|
|
22692
23825
|
throw new Error("Unable to determine home directory");
|
|
22693
23826
|
}
|
|
22694
|
-
const expanded = path === "~" ? home :
|
|
23827
|
+
const expanded = path === "~" ? home : join52(home, path.slice(2));
|
|
22695
23828
|
return normalize(expanded);
|
|
22696
23829
|
}
|
|
22697
23830
|
if (isAbsolute(path)) {
|
|
@@ -22700,26 +23833,26 @@ function expandPath(path) {
|
|
|
22700
23833
|
return normalize(resolve(path));
|
|
22701
23834
|
}
|
|
22702
23835
|
function getPluginPath() {
|
|
22703
|
-
return
|
|
23836
|
+
return join52(process.cwd(), "plugins", "looplia-writer");
|
|
22704
23837
|
}
|
|
22705
23838
|
function getPluginPaths2() {
|
|
22706
|
-
const base =
|
|
23839
|
+
const base = join52(process.cwd(), "plugins");
|
|
22707
23840
|
return {
|
|
22708
|
-
core:
|
|
22709
|
-
writer:
|
|
23841
|
+
core: join52(base, "looplia-core"),
|
|
23842
|
+
writer: join52(base, "looplia-writer")
|
|
22710
23843
|
};
|
|
22711
23844
|
}
|
|
22712
23845
|
async function checkRequiredFiles(workspaceDir) {
|
|
22713
23846
|
const requiredPaths = [
|
|
22714
23847
|
// Core structure
|
|
22715
|
-
|
|
22716
|
-
|
|
22717
|
-
|
|
22718
|
-
|
|
23848
|
+
join52(workspaceDir, "CLAUDE.md"),
|
|
23849
|
+
join52(workspaceDir, ".claude", "agents"),
|
|
23850
|
+
join52(workspaceDir, ".claude", "skills"),
|
|
23851
|
+
join52(workspaceDir, "workflows"),
|
|
22719
23852
|
// From looplia-core plugin
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
|
|
23853
|
+
join52(workspaceDir, ".claude", "commands"),
|
|
23854
|
+
join52(workspaceDir, ".claude", "skills", "workflow-executor"),
|
|
23855
|
+
join52(workspaceDir, ".claude", "skills", "workflow-validator")
|
|
22723
23856
|
];
|
|
22724
23857
|
for (const path of requiredPaths) {
|
|
22725
23858
|
if (!await pathExists(path)) {
|
|
@@ -22748,33 +23881,33 @@ async function createTestWorkspace(workspaceDir, force) {
|
|
|
22748
23881
|
await rm22(workspaceDir, { recursive: true, force: true });
|
|
22749
23882
|
}
|
|
22750
23883
|
await mkdir22(workspaceDir, { recursive: true });
|
|
22751
|
-
await mkdir22(
|
|
22752
|
-
await mkdir22(
|
|
22753
|
-
await mkdir22(
|
|
23884
|
+
await mkdir22(join52(workspaceDir, ".claude", "agents"), { recursive: true });
|
|
23885
|
+
await mkdir22(join52(workspaceDir, ".claude", "skills"), { recursive: true });
|
|
23886
|
+
await mkdir22(join52(workspaceDir, "sandbox"), { recursive: true });
|
|
22754
23887
|
const plugins = getPluginPaths2();
|
|
22755
|
-
const writerWorkflowsDir =
|
|
23888
|
+
const writerWorkflowsDir = join52(plugins.writer, "workflows");
|
|
22756
23889
|
if (await pathExists(writerWorkflowsDir)) {
|
|
22757
|
-
await cp2(writerWorkflowsDir,
|
|
23890
|
+
await cp2(writerWorkflowsDir, join52(workspaceDir, "workflows"), {
|
|
22758
23891
|
recursive: true
|
|
22759
23892
|
});
|
|
22760
23893
|
} else {
|
|
22761
|
-
await mkdir22(
|
|
23894
|
+
await mkdir22(join52(workspaceDir, "workflows"), { recursive: true });
|
|
22762
23895
|
}
|
|
22763
|
-
const coreValidatorDir =
|
|
23896
|
+
const coreValidatorDir = join52(plugins.core, "skills", "workflow-validator");
|
|
22764
23897
|
if (await pathExists(coreValidatorDir)) {
|
|
22765
23898
|
await cp2(
|
|
22766
23899
|
coreValidatorDir,
|
|
22767
|
-
|
|
23900
|
+
join52(workspaceDir, ".claude", "skills", "workflow-validator"),
|
|
22768
23901
|
{ recursive: true }
|
|
22769
23902
|
);
|
|
22770
23903
|
}
|
|
22771
23904
|
await writeFile22(
|
|
22772
|
-
|
|
23905
|
+
join52(workspaceDir, "CLAUDE.md"),
|
|
22773
23906
|
"# Test Workspace\n",
|
|
22774
23907
|
"utf-8"
|
|
22775
23908
|
);
|
|
22776
23909
|
await writeFile22(
|
|
22777
|
-
|
|
23910
|
+
join52(workspaceDir, "user-profile.json"),
|
|
22778
23911
|
JSON.stringify(createDefaultProfile2(), null, 2),
|
|
22779
23912
|
"utf-8"
|
|
22780
23913
|
);
|
|
@@ -22785,63 +23918,63 @@ async function bootstrapFromPlugins(workspaceDir, plugins) {
|
|
|
22785
23918
|
await rm22(workspaceDir, { recursive: true, force: true });
|
|
22786
23919
|
}
|
|
22787
23920
|
await mkdir22(workspaceDir, { recursive: true });
|
|
22788
|
-
await mkdir22(
|
|
22789
|
-
await mkdir22(
|
|
22790
|
-
const coreCommandsDir =
|
|
23921
|
+
await mkdir22(join52(workspaceDir, ".claude"), { recursive: true });
|
|
23922
|
+
await mkdir22(join52(workspaceDir, "sandbox"), { recursive: true });
|
|
23923
|
+
const coreCommandsDir = join52(plugins.core, "commands");
|
|
22791
23924
|
if (await pathExists(coreCommandsDir)) {
|
|
22792
|
-
await cp2(coreCommandsDir,
|
|
23925
|
+
await cp2(coreCommandsDir, join52(workspaceDir, ".claude", "commands"), {
|
|
22793
23926
|
recursive: true
|
|
22794
23927
|
});
|
|
22795
23928
|
}
|
|
22796
|
-
const coreSkillsDir =
|
|
23929
|
+
const coreSkillsDir = join52(plugins.core, "skills");
|
|
22797
23930
|
if (await pathExists(coreSkillsDir)) {
|
|
22798
|
-
await cp2(coreSkillsDir,
|
|
23931
|
+
await cp2(coreSkillsDir, join52(workspaceDir, ".claude", "skills"), {
|
|
22799
23932
|
recursive: true
|
|
22800
23933
|
});
|
|
22801
23934
|
}
|
|
22802
|
-
const coreHooksDir =
|
|
23935
|
+
const coreHooksDir = join52(plugins.core, "hooks");
|
|
22803
23936
|
if (await pathExists(coreHooksDir)) {
|
|
22804
|
-
await cp2(coreHooksDir,
|
|
23937
|
+
await cp2(coreHooksDir, join52(workspaceDir, ".claude", "hooks"), {
|
|
22805
23938
|
recursive: true
|
|
22806
23939
|
});
|
|
22807
23940
|
}
|
|
22808
|
-
const coreAgentsDir =
|
|
23941
|
+
const coreAgentsDir = join52(plugins.core, "agents");
|
|
22809
23942
|
if (await pathExists(coreAgentsDir)) {
|
|
22810
|
-
await mkdir22(
|
|
22811
|
-
await cp2(coreAgentsDir,
|
|
23943
|
+
await mkdir22(join52(workspaceDir, ".claude", "agents"), { recursive: true });
|
|
23944
|
+
await cp2(coreAgentsDir, join52(workspaceDir, ".claude", "agents"), {
|
|
22812
23945
|
recursive: true
|
|
22813
23946
|
});
|
|
22814
23947
|
}
|
|
22815
|
-
const coreScriptsDir =
|
|
23948
|
+
const coreScriptsDir = join52(plugins.core, "scripts");
|
|
22816
23949
|
if (await pathExists(coreScriptsDir)) {
|
|
22817
|
-
await cp2(coreScriptsDir,
|
|
23950
|
+
await cp2(coreScriptsDir, join52(workspaceDir, "scripts"), {
|
|
22818
23951
|
recursive: true
|
|
22819
23952
|
});
|
|
22820
23953
|
}
|
|
22821
|
-
const coreClaudeMd =
|
|
23954
|
+
const coreClaudeMd = join52(plugins.core, "CLAUDE.md");
|
|
22822
23955
|
if (await pathExists(coreClaudeMd)) {
|
|
22823
|
-
await cp2(coreClaudeMd,
|
|
23956
|
+
await cp2(coreClaudeMd, join52(workspaceDir, "CLAUDE.md"));
|
|
22824
23957
|
}
|
|
22825
|
-
const writerAgentsDir =
|
|
23958
|
+
const writerAgentsDir = join52(plugins.writer, "agents");
|
|
22826
23959
|
if (await pathExists(writerAgentsDir)) {
|
|
22827
|
-
await cp2(writerAgentsDir,
|
|
23960
|
+
await cp2(writerAgentsDir, join52(workspaceDir, ".claude", "agents"), {
|
|
22828
23961
|
recursive: true
|
|
22829
23962
|
});
|
|
22830
23963
|
}
|
|
22831
|
-
const writerSkillsDir =
|
|
23964
|
+
const writerSkillsDir = join52(plugins.writer, "skills");
|
|
22832
23965
|
if (await pathExists(writerSkillsDir)) {
|
|
22833
|
-
await cp2(writerSkillsDir,
|
|
23966
|
+
await cp2(writerSkillsDir, join52(workspaceDir, ".claude", "skills"), {
|
|
22834
23967
|
recursive: true
|
|
22835
23968
|
});
|
|
22836
23969
|
}
|
|
22837
|
-
const writerWorkflowsDir =
|
|
23970
|
+
const writerWorkflowsDir = join52(plugins.writer, "workflows");
|
|
22838
23971
|
if (await pathExists(writerWorkflowsDir)) {
|
|
22839
|
-
await cp2(writerWorkflowsDir,
|
|
23972
|
+
await cp2(writerWorkflowsDir, join52(workspaceDir, "workflows"), {
|
|
22840
23973
|
recursive: true
|
|
22841
23974
|
});
|
|
22842
23975
|
}
|
|
22843
23976
|
await writeFile22(
|
|
22844
|
-
|
|
23977
|
+
join52(workspaceDir, "user-profile.json"),
|
|
22845
23978
|
JSON.stringify(createDefaultProfile2(), null, 2),
|
|
22846
23979
|
"utf-8"
|
|
22847
23980
|
);
|
|
@@ -22879,12 +24012,12 @@ function getWorkspacePath(baseDir) {
|
|
|
22879
24012
|
return expandPath(baseDir ?? "~/.looplia");
|
|
22880
24013
|
}
|
|
22881
24014
|
async function readUserProfile(workspaceDir) {
|
|
22882
|
-
const profilePath =
|
|
22883
|
-
const content = await
|
|
24015
|
+
const profilePath = join52(workspaceDir, "user-profile.json");
|
|
24016
|
+
const content = await readFile3(profilePath, "utf-8");
|
|
22884
24017
|
return JSON.parse(content);
|
|
22885
24018
|
}
|
|
22886
24019
|
async function writeUserProfile(workspaceDir, profile) {
|
|
22887
|
-
const profilePath =
|
|
24020
|
+
const profilePath = join52(workspaceDir, "user-profile.json");
|
|
22888
24021
|
await writeFile22(profilePath, JSON.stringify(profile, null, 2), "utf-8");
|
|
22889
24022
|
}
|
|
22890
24023
|
var workspaceCache = /* @__PURE__ */ new Map();
|
|
@@ -22902,7 +24035,7 @@ async function getOrInitWorkspace(baseDir, useFilesystemExtensions) {
|
|
|
22902
24035
|
return workspace;
|
|
22903
24036
|
}
|
|
22904
24037
|
function getApiKey(config2) {
|
|
22905
|
-
return config2?.apiKey ?? process.env.ANTHROPIC_API_KEY ?? process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
24038
|
+
return config2?.apiKey ?? process.env.ANTHROPIC_API_KEY ?? process.env.ANTHROPIC_AUTH_TOKEN ?? process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
22906
24039
|
}
|
|
22907
24040
|
async function initializeAndValidateApiKey(config2) {
|
|
22908
24041
|
const settings = await readLoopliaSettings();
|
|
@@ -22912,7 +24045,7 @@ async function initializeAndValidateApiKey(config2) {
|
|
|
22912
24045
|
const apiKey = getApiKey(config2);
|
|
22913
24046
|
if (!apiKey) {
|
|
22914
24047
|
throw new Error(
|
|
22915
|
-
"API key is required. Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN environment variable"
|
|
24048
|
+
"API key is required. Set ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, or CLAUDE_CODE_OAUTH_TOKEN environment variable"
|
|
22916
24049
|
);
|
|
22917
24050
|
}
|
|
22918
24051
|
return apiKey;
|
|
@@ -23392,7 +24525,7 @@ function truncate(str, maxLen) {
|
|
|
23392
24525
|
}
|
|
23393
24526
|
return `${str.slice(0, maxLen - 3)}...`;
|
|
23394
24527
|
}
|
|
23395
|
-
async function* executeAgenticQueryStreaming(prompt,
|
|
24528
|
+
async function* executeAgenticQueryStreaming(prompt, _jsonSchema, config2) {
|
|
23396
24529
|
const resolvedConfig = resolveConfig(config2);
|
|
23397
24530
|
await initializeAndValidateApiKey(config2);
|
|
23398
24531
|
const mainModel = getMainModel();
|
|
@@ -23464,8 +24597,15 @@ When processing --file arguments or user file paths, resolve them against the Us
|
|
|
23464
24597
|
"WebSearch",
|
|
23465
24598
|
"WebFetch"
|
|
23466
24599
|
],
|
|
23467
|
-
|
|
24600
|
+
// v0.7.2: Removed outputFormat to support non-Anthropic models
|
|
24601
|
+
// Final results are now extracted from sandbox output files via extractSandboxResult()
|
|
23468
24602
|
// v0.6.9: No custom agents - using built-in general-purpose for workflow steps
|
|
24603
|
+
// v0.7.4: Pass runHooks from config if provided (workflow protection)
|
|
24604
|
+
// Only the run command passes hooks - other SDK usage doesn't need them
|
|
24605
|
+
...config2?.runHooks && { hooks: config2.runHooks },
|
|
24606
|
+
// v0.7.5: Pass buildHooks from config if provided (build validation)
|
|
24607
|
+
// Only the build command passes hooks - validates workflow file structure
|
|
24608
|
+
...config2?.buildHooks && { hooks: config2.buildHooks }
|
|
23469
24609
|
}
|
|
23470
24610
|
});
|
|
23471
24611
|
let finalResult;
|
|
@@ -23489,6 +24629,12 @@ When processing --file arguments or user file paths, resolve them against the Us
|
|
|
23489
24629
|
}
|
|
23490
24630
|
logger.close();
|
|
23491
24631
|
yield progressTracker.onComplete();
|
|
24632
|
+
if (!finalResult) {
|
|
24633
|
+
finalResult = await extractSandboxResult({
|
|
24634
|
+
sandboxId: process.env.LOOPLIA_SANDBOX_ID,
|
|
24635
|
+
sandboxRoot: process.env.LOOPLIA_SANDBOX_ROOT ?? join6(workspace, "sandbox")
|
|
24636
|
+
});
|
|
24637
|
+
}
|
|
23492
24638
|
return finalResult ?? {
|
|
23493
24639
|
success: false,
|
|
23494
24640
|
error: { type: "unknown", message: "No result received" }
|
|
@@ -23633,6 +24779,519 @@ function createClaudeAgentExecutor(config2) {
|
|
|
23633
24779
|
}
|
|
23634
24780
|
};
|
|
23635
24781
|
}
|
|
24782
|
+
var DEBUG = process.env.LOOPLIA_DEBUG === "1";
|
|
24783
|
+
function isWorkflowFile(filePath) {
|
|
24784
|
+
if (!filePath) {
|
|
24785
|
+
return false;
|
|
24786
|
+
}
|
|
24787
|
+
return filePath.includes("/workflows/") && filePath.endsWith(".md");
|
|
24788
|
+
}
|
|
24789
|
+
function resolveSandboxRoot(context) {
|
|
24790
|
+
return context?.sandboxRoot ?? join7(getLoopliaPluginPath(), "sandbox");
|
|
24791
|
+
}
|
|
24792
|
+
async function findMostRecentBuildSandbox(sandboxRoot) {
|
|
24793
|
+
try {
|
|
24794
|
+
const entries = await readdir22(sandboxRoot, { withFileTypes: true });
|
|
24795
|
+
const dirs = entries.filter(
|
|
24796
|
+
(e) => e.isDirectory() && e.name.startsWith("build-")
|
|
24797
|
+
);
|
|
24798
|
+
if (dirs.length === 0) {
|
|
24799
|
+
return;
|
|
24800
|
+
}
|
|
24801
|
+
const dirStats = await Promise.all(
|
|
24802
|
+
dirs.map(async (dir) => {
|
|
24803
|
+
const dirPath = join7(sandboxRoot, dir.name);
|
|
24804
|
+
const dirStat = await stat2(dirPath);
|
|
24805
|
+
return { path: dirPath, mtime: dirStat.mtime.getTime() };
|
|
24806
|
+
})
|
|
24807
|
+
);
|
|
24808
|
+
dirStats.sort((a, b) => b.mtime - a.mtime);
|
|
24809
|
+
return dirStats[0]?.path;
|
|
24810
|
+
} catch {
|
|
24811
|
+
return;
|
|
24812
|
+
}
|
|
24813
|
+
}
|
|
24814
|
+
async function resolveSandboxDir2(context) {
|
|
24815
|
+
const sandboxRoot = resolveSandboxRoot(context);
|
|
24816
|
+
if (context?.sandboxId) {
|
|
24817
|
+
return join7(sandboxRoot, context.sandboxId);
|
|
24818
|
+
}
|
|
24819
|
+
return await findMostRecentBuildSandbox(sandboxRoot);
|
|
24820
|
+
}
|
|
24821
|
+
async function readBuildValidation(context) {
|
|
24822
|
+
const sandboxDir = await resolveSandboxDir2(context);
|
|
24823
|
+
if (!sandboxDir) {
|
|
24824
|
+
if (DEBUG) {
|
|
24825
|
+
console.error("[build-hooks] readBuildValidation: no sandbox dir found");
|
|
24826
|
+
}
|
|
24827
|
+
return;
|
|
24828
|
+
}
|
|
24829
|
+
const validationPath = join7(sandboxDir, "validation.json");
|
|
24830
|
+
try {
|
|
24831
|
+
const content = await readFile4(validationPath, "utf-8");
|
|
24832
|
+
const manifest = JSON.parse(content);
|
|
24833
|
+
if (manifest.type === "build") {
|
|
24834
|
+
return manifest;
|
|
24835
|
+
}
|
|
24836
|
+
return;
|
|
24837
|
+
} catch {
|
|
24838
|
+
return;
|
|
24839
|
+
}
|
|
24840
|
+
}
|
|
24841
|
+
async function updateBuildValidation(context, updates) {
|
|
24842
|
+
const sandboxDir = await resolveSandboxDir2(context);
|
|
24843
|
+
if (!sandboxDir) {
|
|
24844
|
+
if (DEBUG) {
|
|
24845
|
+
console.error(
|
|
24846
|
+
"[build-hooks] updateBuildValidation: no sandbox dir found"
|
|
24847
|
+
);
|
|
24848
|
+
}
|
|
24849
|
+
return;
|
|
24850
|
+
}
|
|
24851
|
+
const validationPath = join7(sandboxDir, "validation.json");
|
|
24852
|
+
try {
|
|
24853
|
+
const content = await readFile4(validationPath, "utf-8");
|
|
24854
|
+
const manifest = JSON.parse(content);
|
|
24855
|
+
const updated = {
|
|
24856
|
+
...manifest,
|
|
24857
|
+
...updates
|
|
24858
|
+
};
|
|
24859
|
+
const tempPath = `${validationPath}.tmp`;
|
|
24860
|
+
await writeFile3(tempPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
24861
|
+
await rename2(tempPath, validationPath);
|
|
24862
|
+
if (DEBUG) {
|
|
24863
|
+
console.error(
|
|
24864
|
+
`[build-hooks] updateBuildValidation: updated ${validationPath}`
|
|
24865
|
+
);
|
|
24866
|
+
}
|
|
24867
|
+
} catch (error2) {
|
|
24868
|
+
if (DEBUG) {
|
|
24869
|
+
console.error("[build-hooks] updateBuildValidation error:", error2);
|
|
24870
|
+
}
|
|
24871
|
+
}
|
|
24872
|
+
}
|
|
24873
|
+
function createBuildValidateHook(context) {
|
|
24874
|
+
return async (input) => {
|
|
24875
|
+
if (DEBUG) {
|
|
24876
|
+
console.error(
|
|
24877
|
+
"[build-hooks] PostToolUse fired:",
|
|
24878
|
+
JSON.stringify(input).slice(0, 200)
|
|
24879
|
+
);
|
|
24880
|
+
}
|
|
24881
|
+
const hookInput = input;
|
|
24882
|
+
const filePath = hookInput.tool_input?.file_path;
|
|
24883
|
+
const content = hookInput.tool_input?.content;
|
|
24884
|
+
if (DEBUG) {
|
|
24885
|
+
console.error("[build-hooks] file_path:", filePath);
|
|
24886
|
+
console.error("[build-hooks] isWorkflowFile:", isWorkflowFile(filePath));
|
|
24887
|
+
}
|
|
24888
|
+
if (!isWorkflowFile(filePath)) {
|
|
24889
|
+
return {};
|
|
24890
|
+
}
|
|
24891
|
+
if (!content) {
|
|
24892
|
+
return {
|
|
24893
|
+
decision: "block",
|
|
24894
|
+
reason: "Workflow validation failed: No content provided. Please write the workflow content to the file."
|
|
24895
|
+
};
|
|
24896
|
+
}
|
|
24897
|
+
try {
|
|
24898
|
+
const parsed = parseWorkflow(content);
|
|
24899
|
+
await updateBuildValidation(context ?? {}, {
|
|
24900
|
+
workflowValidated: true,
|
|
24901
|
+
workflowPath: filePath,
|
|
24902
|
+
workflowName: parsed.definition.name,
|
|
24903
|
+
status: "validated"
|
|
24904
|
+
});
|
|
24905
|
+
console.error(`\u2713 Workflow validated: ${parsed.definition.name}`);
|
|
24906
|
+
return {};
|
|
24907
|
+
} catch (error2) {
|
|
24908
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
24909
|
+
await updateBuildValidation(context ?? {}, {
|
|
24910
|
+
workflowValidated: false,
|
|
24911
|
+
status: "failed",
|
|
24912
|
+
error: errorMessage
|
|
24913
|
+
});
|
|
24914
|
+
return {
|
|
24915
|
+
decision: "block",
|
|
24916
|
+
reason: `Workflow validation failed: ${errorMessage}
|
|
24917
|
+
|
|
24918
|
+
Please fix the workflow file and try writing it again. Ensure the workflow has valid YAML frontmatter with 'name', 'description', and 'steps' fields.`
|
|
24919
|
+
};
|
|
24920
|
+
}
|
|
24921
|
+
};
|
|
24922
|
+
}
|
|
24923
|
+
function createBuildStopGuardHook(context) {
|
|
24924
|
+
return async (input) => {
|
|
24925
|
+
if (DEBUG) {
|
|
24926
|
+
console.error(
|
|
24927
|
+
"[build-hooks] Stop/SubagentStop fired:",
|
|
24928
|
+
JSON.stringify(input).slice(0, 200)
|
|
24929
|
+
);
|
|
24930
|
+
}
|
|
24931
|
+
const hookInput = input;
|
|
24932
|
+
if (hookInput.stop_hook_active === true) {
|
|
24933
|
+
return {};
|
|
24934
|
+
}
|
|
24935
|
+
const validation = await readBuildValidation(context);
|
|
24936
|
+
if (DEBUG) {
|
|
24937
|
+
console.error("[build-hooks] validation:", JSON.stringify(validation));
|
|
24938
|
+
}
|
|
24939
|
+
if (!validation) {
|
|
24940
|
+
return {};
|
|
24941
|
+
}
|
|
24942
|
+
if (!validation.workflowValidated) {
|
|
24943
|
+
return {
|
|
24944
|
+
decision: "block",
|
|
24945
|
+
reason: "Build incomplete. The workflow file has not been validated yet. Please write the workflow to ~/.looplia/workflows/ with valid YAML frontmatter including 'name', 'description', and 'steps' fields. Do not stop until the workflow is successfully created."
|
|
24946
|
+
};
|
|
24947
|
+
}
|
|
24948
|
+
return {};
|
|
24949
|
+
};
|
|
24950
|
+
}
|
|
24951
|
+
function createBuildHooks() {
|
|
24952
|
+
const context = {
|
|
24953
|
+
sandboxId: process.env.LOOPLIA_SANDBOX_ID,
|
|
24954
|
+
sandboxRoot: process.env.LOOPLIA_SANDBOX_ROOT
|
|
24955
|
+
};
|
|
24956
|
+
return {
|
|
24957
|
+
Stop: [{ hooks: [createBuildStopGuardHook(context)] }],
|
|
24958
|
+
SubagentStop: [{ hooks: [createBuildStopGuardHook(context)] }],
|
|
24959
|
+
PostToolUse: [
|
|
24960
|
+
{ matcher: "Write", hooks: [createBuildValidateHook(context)] }
|
|
24961
|
+
]
|
|
24962
|
+
};
|
|
24963
|
+
}
|
|
24964
|
+
var JSON_EXTENSION_REGEX = /\.json$/;
|
|
24965
|
+
var LOCK_TIMEOUT_MS = 3e4;
|
|
24966
|
+
var LOCK_RETRY_DELAY_MS2 = 200;
|
|
24967
|
+
async function findMostRecentSandbox2(sandboxRoot) {
|
|
24968
|
+
try {
|
|
24969
|
+
const entries = await readdir32(sandboxRoot, { withFileTypes: true });
|
|
24970
|
+
const dirs = entries.filter(
|
|
24971
|
+
(e) => e.isDirectory() && !e.name.startsWith(".")
|
|
24972
|
+
);
|
|
24973
|
+
if (dirs.length === 0) {
|
|
24974
|
+
return;
|
|
24975
|
+
}
|
|
24976
|
+
const dirStats = await Promise.all(
|
|
24977
|
+
dirs.map(async (dir) => {
|
|
24978
|
+
const dirPath = join8(sandboxRoot, dir.name);
|
|
24979
|
+
const dirStat = await stat3(dirPath);
|
|
24980
|
+
return { path: dirPath, mtime: dirStat.mtime.getTime() };
|
|
24981
|
+
})
|
|
24982
|
+
);
|
|
24983
|
+
dirStats.sort((a, b) => b.mtime - a.mtime);
|
|
24984
|
+
return dirStats[0]?.path;
|
|
24985
|
+
} catch {
|
|
24986
|
+
return;
|
|
24987
|
+
}
|
|
24988
|
+
}
|
|
24989
|
+
async function readValidationManifest2(sandboxDir) {
|
|
24990
|
+
const validationPath = join8(sandboxDir, "validation.json");
|
|
24991
|
+
try {
|
|
24992
|
+
const content = await readFile5(validationPath, "utf-8");
|
|
24993
|
+
return JSON.parse(content);
|
|
24994
|
+
} catch {
|
|
24995
|
+
return;
|
|
24996
|
+
}
|
|
24997
|
+
}
|
|
24998
|
+
function resolveSandboxRoot2(context) {
|
|
24999
|
+
return context?.sandboxRoot ?? join8(getLoopliaPluginPath(), "sandbox");
|
|
25000
|
+
}
|
|
25001
|
+
async function resolveSandboxDir3(context) {
|
|
25002
|
+
const sandboxRoot = resolveSandboxRoot2(context);
|
|
25003
|
+
if (context?.sandboxId) {
|
|
25004
|
+
return join8(sandboxRoot, context.sandboxId);
|
|
25005
|
+
}
|
|
25006
|
+
return await findMostRecentSandbox2(sandboxRoot);
|
|
25007
|
+
}
|
|
25008
|
+
function isRecord(value) {
|
|
25009
|
+
return typeof value === "object" && value !== null;
|
|
25010
|
+
}
|
|
25011
|
+
function getSandboxArtifactInfo(filePath) {
|
|
25012
|
+
if (!filePath) {
|
|
25013
|
+
return;
|
|
25014
|
+
}
|
|
25015
|
+
if (!(filePath.includes("/sandbox/") && filePath.includes("/outputs/"))) {
|
|
25016
|
+
return;
|
|
25017
|
+
}
|
|
25018
|
+
const outputsIndex = filePath.lastIndexOf("/outputs/");
|
|
25019
|
+
if (outputsIndex < 0) {
|
|
25020
|
+
return;
|
|
25021
|
+
}
|
|
25022
|
+
const sandboxDir = filePath.slice(0, outputsIndex);
|
|
25023
|
+
const filename = filePath.slice(outputsIndex + "/outputs/".length);
|
|
25024
|
+
const artifact = filename.replace(JSON_EXTENSION_REGEX, "");
|
|
25025
|
+
return { sandboxDir, artifact };
|
|
25026
|
+
}
|
|
25027
|
+
async function readArtifactData(filePath, artifact) {
|
|
25028
|
+
try {
|
|
25029
|
+
const content = await readFile5(filePath, "utf-8");
|
|
25030
|
+
return JSON.parse(content);
|
|
25031
|
+
} catch {
|
|
25032
|
+
console.error(`Validation failed for ${artifact}: Invalid JSON`);
|
|
25033
|
+
return;
|
|
25034
|
+
}
|
|
25035
|
+
}
|
|
25036
|
+
function validateWorkflowArtifact(data, criteria) {
|
|
25037
|
+
const checks = [];
|
|
25038
|
+
if (criteria.required_fields) {
|
|
25039
|
+
checks.push(...checkRequiredFields(data, criteria.required_fields));
|
|
25040
|
+
}
|
|
25041
|
+
if (criteria.min_quotes !== void 0) {
|
|
25042
|
+
checks.push(checkMinQuotes(data, criteria.min_quotes));
|
|
25043
|
+
}
|
|
25044
|
+
if (criteria.min_key_points !== void 0) {
|
|
25045
|
+
checks.push(checkMinKeyPoints(data, criteria.min_key_points));
|
|
25046
|
+
}
|
|
25047
|
+
if (criteria.min_outline_sections !== void 0) {
|
|
25048
|
+
checks.push(checkMinOutlineSections(data, criteria.min_outline_sections));
|
|
25049
|
+
}
|
|
25050
|
+
if (criteria.has_hooks === true) {
|
|
25051
|
+
checks.push(checkHasHooks(data));
|
|
25052
|
+
}
|
|
25053
|
+
const passed = checks.every((check2) => check2.passed);
|
|
25054
|
+
return { passed, checks };
|
|
25055
|
+
}
|
|
25056
|
+
function checkRequiredFields(data, fields) {
|
|
25057
|
+
return fields.map((field) => {
|
|
25058
|
+
const exists = hasField(data, field);
|
|
25059
|
+
return {
|
|
25060
|
+
name: `has_${field}`,
|
|
25061
|
+
passed: exists,
|
|
25062
|
+
message: exists ? "OK" : `Missing required field: ${field}`
|
|
25063
|
+
};
|
|
25064
|
+
});
|
|
25065
|
+
}
|
|
25066
|
+
function checkMinQuotes(data, minQuotes) {
|
|
25067
|
+
const quotes = getArrayLength(data, "importantQuotes");
|
|
25068
|
+
const passed = quotes >= minQuotes;
|
|
25069
|
+
return {
|
|
25070
|
+
name: "min_quotes",
|
|
25071
|
+
passed,
|
|
25072
|
+
message: passed ? `Found ${quotes} quotes (min: ${minQuotes})` : `Found ${quotes} quotes, need at least ${minQuotes}`
|
|
25073
|
+
};
|
|
25074
|
+
}
|
|
25075
|
+
function checkMinKeyPoints(data, minPoints) {
|
|
25076
|
+
const bullets = getArrayLength(data, "bullets");
|
|
25077
|
+
const keyPoints = getArrayLength(data, "keyPoints");
|
|
25078
|
+
const count = Math.max(bullets, keyPoints);
|
|
25079
|
+
const passed = count >= minPoints;
|
|
25080
|
+
return {
|
|
25081
|
+
name: "min_key_points",
|
|
25082
|
+
passed,
|
|
25083
|
+
message: passed ? `Found ${count} key points (min: ${minPoints})` : `Found ${count} key points, need at least ${minPoints}`
|
|
25084
|
+
};
|
|
25085
|
+
}
|
|
25086
|
+
function checkMinOutlineSections(data, minSections) {
|
|
25087
|
+
const sections = getArrayLength(data, "suggestedOutline");
|
|
25088
|
+
const passed = sections >= minSections;
|
|
25089
|
+
return {
|
|
25090
|
+
name: "min_outline_sections",
|
|
25091
|
+
passed,
|
|
25092
|
+
message: passed ? `Found ${sections} outline sections (min: ${minSections})` : `Found ${sections} sections, need at least ${minSections}`
|
|
25093
|
+
};
|
|
25094
|
+
}
|
|
25095
|
+
function checkHasHooks(data) {
|
|
25096
|
+
const hooksCount = getHooksCount(data);
|
|
25097
|
+
const passed = hooksCount > 0;
|
|
25098
|
+
return {
|
|
25099
|
+
name: "has_hooks",
|
|
25100
|
+
passed,
|
|
25101
|
+
message: passed ? `Found ${hooksCount} hooks` : "No hooks found in artifact"
|
|
25102
|
+
};
|
|
25103
|
+
}
|
|
25104
|
+
function getHooksCount(data) {
|
|
25105
|
+
const ideas = data.ideas;
|
|
25106
|
+
if (ideas && Array.isArray(ideas.hooks)) {
|
|
25107
|
+
return ideas.hooks.length;
|
|
25108
|
+
}
|
|
25109
|
+
if (Array.isArray(data.hooks)) {
|
|
25110
|
+
return data.hooks.length;
|
|
25111
|
+
}
|
|
25112
|
+
return 0;
|
|
25113
|
+
}
|
|
25114
|
+
function hasField(data, field) {
|
|
25115
|
+
const parts = field.split(".");
|
|
25116
|
+
let current = data;
|
|
25117
|
+
for (const part of parts) {
|
|
25118
|
+
if (current === null || typeof current !== "object") {
|
|
25119
|
+
return false;
|
|
25120
|
+
}
|
|
25121
|
+
current = current[part];
|
|
25122
|
+
}
|
|
25123
|
+
return current !== void 0 && current !== null;
|
|
25124
|
+
}
|
|
25125
|
+
function getArrayLength(data, field) {
|
|
25126
|
+
const value = data[field];
|
|
25127
|
+
return Array.isArray(value) ? value.length : 0;
|
|
25128
|
+
}
|
|
25129
|
+
function validateArtifactData(artifact, artifactData, criteria) {
|
|
25130
|
+
if (criteria === void 0 || criteria === null) {
|
|
25131
|
+
return true;
|
|
25132
|
+
}
|
|
25133
|
+
if (!isRecord(criteria)) {
|
|
25134
|
+
console.error(`Validation failed for ${artifact}: Invalid criteria`);
|
|
25135
|
+
return false;
|
|
25136
|
+
}
|
|
25137
|
+
const result = validateWorkflowArtifact(
|
|
25138
|
+
artifactData,
|
|
25139
|
+
criteria
|
|
25140
|
+
);
|
|
25141
|
+
if (!result.passed) {
|
|
25142
|
+
console.error(`Semantic validation failed for ${artifact}:`);
|
|
25143
|
+
console.error(JSON.stringify(result, null, 2));
|
|
25144
|
+
}
|
|
25145
|
+
return result.passed;
|
|
25146
|
+
}
|
|
25147
|
+
async function sleep2(ms) {
|
|
25148
|
+
await new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
25149
|
+
}
|
|
25150
|
+
async function acquireLock(lockPath, timeoutMs) {
|
|
25151
|
+
const start = Date.now();
|
|
25152
|
+
while (Date.now() - start < timeoutMs) {
|
|
25153
|
+
try {
|
|
25154
|
+
const handle = await open2(lockPath, "wx");
|
|
25155
|
+
return {
|
|
25156
|
+
release: async () => {
|
|
25157
|
+
await handle.close();
|
|
25158
|
+
try {
|
|
25159
|
+
await unlink(lockPath);
|
|
25160
|
+
} catch {
|
|
25161
|
+
}
|
|
25162
|
+
}
|
|
25163
|
+
};
|
|
25164
|
+
} catch (error2) {
|
|
25165
|
+
if (error2 instanceof Error && "code" in error2 && error2.code === "EEXIST") {
|
|
25166
|
+
await sleep2(LOCK_RETRY_DELAY_MS2);
|
|
25167
|
+
continue;
|
|
25168
|
+
}
|
|
25169
|
+
throw error2;
|
|
25170
|
+
}
|
|
25171
|
+
}
|
|
25172
|
+
return;
|
|
25173
|
+
}
|
|
25174
|
+
async function writeValidationManifest(validationPath, manifest) {
|
|
25175
|
+
const tempPath = `${validationPath}.tmp`;
|
|
25176
|
+
await writeFile4(tempPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
25177
|
+
await rename3(tempPath, validationPath);
|
|
25178
|
+
}
|
|
25179
|
+
async function findMissingOutputs(sandboxDir, steps) {
|
|
25180
|
+
const missing = [];
|
|
25181
|
+
for (const [stepId, stepState] of Object.entries(steps)) {
|
|
25182
|
+
const outputPath = stepState.output;
|
|
25183
|
+
if (!outputPath) {
|
|
25184
|
+
continue;
|
|
25185
|
+
}
|
|
25186
|
+
const fullPath = join8(sandboxDir, outputPath);
|
|
25187
|
+
try {
|
|
25188
|
+
await stat3(fullPath);
|
|
25189
|
+
} catch {
|
|
25190
|
+
missing.push(stepId);
|
|
25191
|
+
}
|
|
25192
|
+
}
|
|
25193
|
+
return missing;
|
|
25194
|
+
}
|
|
25195
|
+
function findPendingSteps(steps) {
|
|
25196
|
+
return Object.entries(steps).filter(([, stepState]) => !stepState.validated).map(([stepId]) => stepId);
|
|
25197
|
+
}
|
|
25198
|
+
function createStopGuardHook(context) {
|
|
25199
|
+
return async (input) => {
|
|
25200
|
+
const hookInput = input;
|
|
25201
|
+
if (hookInput.stop_hook_active === true) {
|
|
25202
|
+
return {};
|
|
25203
|
+
}
|
|
25204
|
+
const sandboxDir = await resolveSandboxDir3(context);
|
|
25205
|
+
if (!sandboxDir) {
|
|
25206
|
+
return {};
|
|
25207
|
+
}
|
|
25208
|
+
const manifest = await readValidationManifest2(sandboxDir);
|
|
25209
|
+
if (!manifest) {
|
|
25210
|
+
return {};
|
|
25211
|
+
}
|
|
25212
|
+
const missingOutputs = await findMissingOutputs(sandboxDir, manifest.steps);
|
|
25213
|
+
if (missingOutputs.length > 0) {
|
|
25214
|
+
const stepsList = missingOutputs.join(", ");
|
|
25215
|
+
return {
|
|
25216
|
+
decision: "block",
|
|
25217
|
+
reason: `Your workflow is not complete. You still need to create output files for these steps: ${stepsList}. Please continue working on the workflow by using the Write tool to create the required JSON files at the paths specified in validation.json for each incomplete step. Do not stop until all workflow steps have their output files created.`
|
|
25218
|
+
};
|
|
25219
|
+
}
|
|
25220
|
+
const pendingSteps = findPendingSteps(manifest.steps);
|
|
25221
|
+
if (pendingSteps.length > 0) {
|
|
25222
|
+
const stepsList = pendingSteps.join(", ");
|
|
25223
|
+
return {
|
|
25224
|
+
decision: "block",
|
|
25225
|
+
reason: `Your workflow is not complete. The following steps need validation: ${stepsList}. The output files exist but have not been validated yet. Please re-write these output files using the Write tool to trigger validation. Do not stop until all workflow steps are validated.`
|
|
25226
|
+
};
|
|
25227
|
+
}
|
|
25228
|
+
return {};
|
|
25229
|
+
};
|
|
25230
|
+
}
|
|
25231
|
+
var stopGuardHook = createStopGuardHook();
|
|
25232
|
+
function createPostWriteValidateHook() {
|
|
25233
|
+
return async (input) => {
|
|
25234
|
+
const hookInput = input;
|
|
25235
|
+
const filePath = hookInput.tool_input?.file_path;
|
|
25236
|
+
const artifactInfo = getSandboxArtifactInfo(filePath);
|
|
25237
|
+
if (!(artifactInfo && filePath)) {
|
|
25238
|
+
return {};
|
|
25239
|
+
}
|
|
25240
|
+
const artifactData = await readArtifactData(
|
|
25241
|
+
filePath,
|
|
25242
|
+
artifactInfo.artifact
|
|
25243
|
+
);
|
|
25244
|
+
if (!artifactData) {
|
|
25245
|
+
return {};
|
|
25246
|
+
}
|
|
25247
|
+
const validationPath = join8(artifactInfo.sandboxDir, "validation.json");
|
|
25248
|
+
const lock = await acquireLock(`${validationPath}.lock`, LOCK_TIMEOUT_MS);
|
|
25249
|
+
if (!lock) {
|
|
25250
|
+
console.error("Failed to acquire lock on validation.json");
|
|
25251
|
+
return {};
|
|
25252
|
+
}
|
|
25253
|
+
try {
|
|
25254
|
+
const manifest = await readValidationManifest2(artifactInfo.sandboxDir);
|
|
25255
|
+
if (!manifest) {
|
|
25256
|
+
return {};
|
|
25257
|
+
}
|
|
25258
|
+
const stepState = manifest.steps[artifactInfo.artifact];
|
|
25259
|
+
if (!stepState) {
|
|
25260
|
+
return {};
|
|
25261
|
+
}
|
|
25262
|
+
const isValid3 = validateArtifactData(
|
|
25263
|
+
artifactInfo.artifact,
|
|
25264
|
+
artifactData,
|
|
25265
|
+
stepState.validate
|
|
25266
|
+
);
|
|
25267
|
+
if (!isValid3) {
|
|
25268
|
+
return {};
|
|
25269
|
+
}
|
|
25270
|
+
manifest.steps[artifactInfo.artifact] = {
|
|
25271
|
+
...stepState,
|
|
25272
|
+
validated: true,
|
|
25273
|
+
validatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25274
|
+
};
|
|
25275
|
+
await writeValidationManifest(validationPath, manifest);
|
|
25276
|
+
console.error(`\u2713 Validated: ${artifactInfo.artifact}.json`);
|
|
25277
|
+
} finally {
|
|
25278
|
+
await lock.release();
|
|
25279
|
+
}
|
|
25280
|
+
return {};
|
|
25281
|
+
};
|
|
25282
|
+
}
|
|
25283
|
+
var postWriteValidateHook = createPostWriteValidateHook();
|
|
25284
|
+
function createWorkflowHooks() {
|
|
25285
|
+
const context = {
|
|
25286
|
+
sandboxId: process.env.LOOPLIA_SANDBOX_ID,
|
|
25287
|
+
sandboxRoot: process.env.LOOPLIA_SANDBOX_ROOT
|
|
25288
|
+
};
|
|
25289
|
+
return {
|
|
25290
|
+
Stop: [{ hooks: [createStopGuardHook(context)] }],
|
|
25291
|
+
SubagentStop: [{ hooks: [createStopGuardHook(context)] }],
|
|
25292
|
+
PostToolUse: [{ matcher: "Write", hooks: [createPostWriteValidateHook()] }]
|
|
25293
|
+
};
|
|
25294
|
+
}
|
|
23636
25295
|
var SUMMARIZE_SYSTEM_PROMPT = `You are an expert content analyst specializing in summarization and content intelligence.
|
|
23637
25296
|
|
|
23638
25297
|
Your expertise includes:
|
|
@@ -23663,7 +25322,7 @@ The content-analyzer agent will:
|
|
|
23663
25322
|
3. Use content-documenter skill for structured documentation
|
|
23664
25323
|
4. Write results to sandbox/${content.id}/outputs/summary.json`;
|
|
23665
25324
|
}
|
|
23666
|
-
async function* executeInteractiveQueryStreaming(prompt,
|
|
25325
|
+
async function* executeInteractiveQueryStreaming(prompt, _jsonSchema, config2, questionCallback) {
|
|
23667
25326
|
const resolvedConfig = resolveConfig(config2);
|
|
23668
25327
|
await initializeAndValidateApiKey(config2);
|
|
23669
25328
|
const mainModel = getMainModel();
|
|
@@ -23762,7 +25421,11 @@ When processing --file arguments or user file paths, resolve them against the Us
|
|
|
23762
25421
|
"AskUserQuestion"
|
|
23763
25422
|
// Only in interactive mode
|
|
23764
25423
|
],
|
|
23765
|
-
|
|
25424
|
+
// v0.7.5: Pass hooks from config if provided (build validation)
|
|
25425
|
+
...resolvedConfig?.runHooks && { hooks: resolvedConfig.runHooks },
|
|
25426
|
+
...resolvedConfig?.buildHooks && { hooks: resolvedConfig.buildHooks }
|
|
25427
|
+
// v0.7.2: Removed outputFormat to support non-Anthropic models
|
|
25428
|
+
// Final results are now extracted from sandbox output files via extractSandboxResult()
|
|
23766
25429
|
}
|
|
23767
25430
|
});
|
|
23768
25431
|
let finalResult;
|
|
@@ -23786,6 +25449,12 @@ When processing --file arguments or user file paths, resolve them against the Us
|
|
|
23786
25449
|
}
|
|
23787
25450
|
logger.close();
|
|
23788
25451
|
yield progressTracker.onComplete();
|
|
25452
|
+
if (!finalResult) {
|
|
25453
|
+
finalResult = await extractSandboxResult({
|
|
25454
|
+
sandboxId: process.env.LOOPLIA_SANDBOX_ID,
|
|
25455
|
+
sandboxRoot: process.env.LOOPLIA_SANDBOX_ROOT ?? join9(workspace, "sandbox")
|
|
25456
|
+
});
|
|
25457
|
+
}
|
|
23789
25458
|
return finalResult ?? {
|
|
23790
25459
|
success: false,
|
|
23791
25460
|
error: { type: "unknown", message: "No result received" }
|
|
@@ -24018,109 +25687,12 @@ export {
|
|
|
24018
25687
|
copyPlugins,
|
|
24019
25688
|
downloadRemotePlugins,
|
|
24020
25689
|
isLoopliaInitialized,
|
|
24021
|
-
|
|
24022
|
-
|
|
24023
|
-
|
|
24024
|
-
|
|
24025
|
-
|
|
24026
|
-
|
|
24027
|
-
ZodError,
|
|
24028
|
-
en_default,
|
|
24029
|
-
setErrorMap,
|
|
24030
|
-
getErrorMap,
|
|
24031
|
-
makeIssue,
|
|
24032
|
-
EMPTY_PATH,
|
|
24033
|
-
addIssueToContext,
|
|
24034
|
-
ParseStatus,
|
|
24035
|
-
INVALID,
|
|
24036
|
-
DIRTY,
|
|
24037
|
-
OK,
|
|
24038
|
-
isAborted,
|
|
24039
|
-
isDirty,
|
|
24040
|
-
isValid,
|
|
24041
|
-
isAsync,
|
|
24042
|
-
ZodType,
|
|
24043
|
-
datetimeRegex,
|
|
24044
|
-
ZodString,
|
|
24045
|
-
ZodNumber,
|
|
24046
|
-
ZodBigInt,
|
|
24047
|
-
ZodBoolean,
|
|
24048
|
-
ZodDate,
|
|
24049
|
-
ZodSymbol,
|
|
24050
|
-
ZodUndefined,
|
|
24051
|
-
ZodNull,
|
|
24052
|
-
ZodAny,
|
|
24053
|
-
ZodUnknown,
|
|
24054
|
-
ZodNever,
|
|
24055
|
-
ZodVoid,
|
|
24056
|
-
ZodArray,
|
|
24057
|
-
ZodObject,
|
|
24058
|
-
ZodUnion,
|
|
24059
|
-
ZodDiscriminatedUnion,
|
|
24060
|
-
ZodIntersection,
|
|
24061
|
-
ZodTuple,
|
|
24062
|
-
ZodRecord,
|
|
24063
|
-
ZodMap,
|
|
24064
|
-
ZodSet,
|
|
24065
|
-
ZodFunction,
|
|
24066
|
-
ZodLazy,
|
|
24067
|
-
ZodLiteral,
|
|
24068
|
-
ZodEnum,
|
|
24069
|
-
ZodNativeEnum,
|
|
24070
|
-
ZodPromise,
|
|
24071
|
-
ZodEffects,
|
|
24072
|
-
ZodOptional,
|
|
24073
|
-
ZodNullable,
|
|
24074
|
-
ZodDefault,
|
|
24075
|
-
ZodCatch,
|
|
24076
|
-
ZodNaN,
|
|
24077
|
-
BRAND,
|
|
24078
|
-
ZodBranded,
|
|
24079
|
-
ZodPipeline,
|
|
24080
|
-
ZodReadonly,
|
|
24081
|
-
custom,
|
|
24082
|
-
late,
|
|
24083
|
-
ZodFirstPartyTypeKind,
|
|
24084
|
-
instanceOfType,
|
|
24085
|
-
stringType,
|
|
24086
|
-
numberType,
|
|
24087
|
-
nanType,
|
|
24088
|
-
bigIntType,
|
|
24089
|
-
booleanType,
|
|
24090
|
-
dateType,
|
|
24091
|
-
symbolType,
|
|
24092
|
-
undefinedType,
|
|
24093
|
-
nullType,
|
|
24094
|
-
anyType,
|
|
24095
|
-
unknownType,
|
|
24096
|
-
neverType,
|
|
24097
|
-
voidType,
|
|
24098
|
-
arrayType,
|
|
24099
|
-
objectType,
|
|
24100
|
-
strictObjectType,
|
|
24101
|
-
unionType,
|
|
24102
|
-
discriminatedUnionType,
|
|
24103
|
-
intersectionType,
|
|
24104
|
-
tupleType,
|
|
24105
|
-
recordType,
|
|
24106
|
-
mapType,
|
|
24107
|
-
setType,
|
|
24108
|
-
functionType,
|
|
24109
|
-
lazyType,
|
|
24110
|
-
literalType,
|
|
24111
|
-
enumType,
|
|
24112
|
-
nativeEnumType,
|
|
24113
|
-
promiseType,
|
|
24114
|
-
effectsType,
|
|
24115
|
-
optionalType,
|
|
24116
|
-
nullableType,
|
|
24117
|
-
preprocessType,
|
|
24118
|
-
pipelineType,
|
|
24119
|
-
ostring,
|
|
24120
|
-
onumber,
|
|
24121
|
-
oboolean,
|
|
24122
|
-
coerce,
|
|
24123
|
-
NEVER,
|
|
25690
|
+
parseWorkflow,
|
|
25691
|
+
generateValidationManifest,
|
|
25692
|
+
getFinalStep,
|
|
25693
|
+
isInputlessWorkflow,
|
|
25694
|
+
extractWorkflowSkills,
|
|
25695
|
+
validateUserProfile,
|
|
24124
25696
|
findClaudeCodePath,
|
|
24125
25697
|
isClaudeCodeInstalled,
|
|
24126
25698
|
clearClaudeCodePathCache,
|
|
@@ -24147,6 +25719,8 @@ export {
|
|
|
24147
25719
|
writeUserProfile,
|
|
24148
25720
|
executeAgenticQueryStreaming,
|
|
24149
25721
|
createClaudeAgentExecutor,
|
|
25722
|
+
createBuildHooks,
|
|
25723
|
+
createWorkflowHooks,
|
|
24150
25724
|
SUMMARIZE_SYSTEM_PROMPT,
|
|
24151
25725
|
buildSummarizePrompt,
|
|
24152
25726
|
executeInteractiveQueryStreaming,
|