@looplia/looplia-cli 0.7.4 → 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.
@@ -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-DRG2TRPF.js
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/provider/dist/chunk-KZZIM7FY.js
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
298
 
314
- // ../../node_modules/zod-to-json-schema/dist/esm/index.js
299
+ // ../../node_modules/zod/index.js
315
300
  init_esm_shims();
316
301
 
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
-
402
- // ../../node_modules/zod-to-json-schema/dist/esm/parseDef.js
403
- init_esm_shims();
404
-
405
- // ../../node_modules/zod-to-json-schema/dist/esm/selectParser.js
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
@@ -4347,7 +4354,799 @@ var coerce = {
4347
4354
  bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })),
4348
4355
  date: ((arg) => ZodDate.create({ ...arg, coerce: true }))
4349
4356
  };
4350
- var NEVER = INVALID;
4357
+ var NEVER = INVALID;
4358
+
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`);
4364
+ }
4365
+ commands.set(definition.name, definition);
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}
4374
+
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()
4491
+ };
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());
4497
+ }
4498
+ return null;
4499
+ }
4500
+ function stripQuotes(value) {
4501
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
4502
+ return value.slice(1, -1);
4503
+ }
4504
+ return value;
4505
+ }
4506
+ function parseYamlValue(value) {
4507
+ const array2 = parseArray(value);
4508
+ if (array2) {
4509
+ return array2;
4510
+ }
4511
+ if (value === "true") {
4512
+ return true;
4513
+ }
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);
4521
+ }
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);
4581
+ }
4582
+ }
4583
+ }
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
+ }
4603
+ }
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);
4613
+ }
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();
4351
5150
 
4352
5151
  // ../../node_modules/zod-to-json-schema/dist/esm/parsers/any.js
4353
5152
  init_esm_shims();
@@ -5592,7 +6391,7 @@ var zodToJsonSchema = (schema, options) => {
5592
6391
  return combined;
5593
6392
  };
5594
6393
 
5595
- // ../../packages/provider/dist/chunk-KZZIM7FY.js
6394
+ // ../../packages/provider/dist/chunk-W4MDOBYT.js
5596
6395
  import { join as join6 } from "path";
5597
6396
 
5598
6397
  // ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
@@ -5631,7 +6430,7 @@ var __toESM = (mod, isNodeMode, target) => {
5631
6430
  return to;
5632
6431
  };
5633
6432
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
5634
- var __export = (target, all) => {
6433
+ var __export2 = (target, all) => {
5635
6434
  for (var name in all)
5636
6435
  __defProp(target, name, {
5637
6436
  get: all[name],
@@ -17603,7 +18402,7 @@ function config(newConfig) {
17603
18402
  return globalConfig;
17604
18403
  }
17605
18404
  var exports_util = {};
17606
- __export(exports_util, {
18405
+ __export2(exports_util, {
17607
18406
  unwrapMessage: () => unwrapMessage,
17608
18407
  stringifyPrimitive: () => stringifyPrimitive,
17609
18408
  required: () => required,
@@ -20531,7 +21330,7 @@ function _refine(Class2, fn, _params) {
20531
21330
  return schema;
20532
21331
  }
20533
21332
  var exports_iso2 = {};
20534
- __export(exports_iso2, {
21333
+ __export2(exports_iso2, {
20535
21334
  time: () => time2,
20536
21335
  duration: () => duration2,
20537
21336
  datetime: () => datetime2,
@@ -22130,7 +22929,7 @@ function query({
22130
22929
  return queryInstance;
22131
22930
  }
22132
22931
 
22133
- // ../../packages/provider/dist/chunk-KZZIM7FY.js
22932
+ // ../../packages/provider/dist/chunk-W4MDOBYT.js
22134
22933
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync3, writeFileSync } from "fs";
22135
22934
  import { join as join33 } from "path";
22136
22935
  import { access, readdir as readdir3, readFile as readFile22, stat } from "fs/promises";
@@ -22138,17 +22937,19 @@ import { join as join42 } from "path";
22138
22937
  import { cp as cp2, mkdir as mkdir22, readFile as readFile3, rm as rm22, writeFile as writeFile22 } from "fs/promises";
22139
22938
  import { homedir as homedir32 } from "os";
22140
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";
22141
22942
  import {
22142
22943
  open as open2,
22143
- readdir as readdir22,
22144
- readFile as readFile4,
22145
- rename as rename2,
22146
- stat as stat2,
22944
+ readdir as readdir32,
22945
+ readFile as readFile5,
22946
+ rename as rename3,
22947
+ stat as stat3,
22147
22948
  unlink,
22148
- writeFile as writeFile3
22949
+ writeFile as writeFile4
22149
22950
  } from "fs/promises";
22150
- import { join as join7 } from "path";
22151
22951
  import { join as join8 } from "path";
22952
+ import { join as join9 } from "path";
22152
22953
  var LINE_SPLIT_REGEX = /\r?\n/;
22153
22954
  function findSdkBundledCliPath() {
22154
22955
  try {
@@ -22816,13 +23617,23 @@ function extractSandboxIdFromPrompt(prompt) {
22816
23617
  var extractContentIdFromPrompt = extractSandboxIdFromPrompt;
22817
23618
  var LOCK_MAX_RETRIES = 5;
22818
23619
  var LOCK_RETRY_DELAY_MS = 200;
22819
- function isValidationManifest(value) {
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) {
22820
23628
  if (!value || typeof value !== "object") {
22821
23629
  return false;
22822
23630
  }
22823
23631
  const obj = value;
22824
23632
  return typeof obj.workflow === "string" && typeof obj.steps === "object" && obj.steps !== null;
22825
23633
  }
23634
+ function isValidationManifest(value) {
23635
+ return isBuildManifest(value) || isRunValidationManifest(value);
23636
+ }
22826
23637
  async function sleep(ms) {
22827
23638
  await new Promise((resolve2) => setTimeout(resolve2, ms));
22828
23639
  }
@@ -22946,19 +23757,21 @@ async function readFinalArtifact(sandboxDir, outputPath) {
22946
23757
  return { error: validationError("artifact", errorMessage) };
22947
23758
  }
22948
23759
  }
22949
- async function extractSandboxResult(options) {
22950
- const loopliaHome = getLoopliaPluginPath();
22951
- const sandboxRoot = options?.sandboxRoot ?? join42(loopliaHome, "sandbox");
22952
- const sandboxId = options?.sandboxId;
22953
- const sandboxDir = await resolveSandboxDir(sandboxRoot, sandboxId);
22954
- if (!sandboxDir) {
22955
- const message = sandboxId ? `Sandbox not found: ${sandboxId}` : "No sandbox directories found";
22956
- return validationError("sandbox", message);
22957
- }
22958
- const { manifest, error: readError } = await readValidationManifest(sandboxDir);
22959
- if (!manifest) {
22960
- return validationError("validation.json", readError ?? "Unknown error");
23760
+ function extractBuildResult(manifest, sandboxDir) {
23761
+ if (!manifest.workflowValidated) {
23762
+ return validationError("build", manifest.error ?? "Workflow not validated");
22961
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
23771
+ }
23772
+ };
23773
+ }
23774
+ async function extractRunResult(manifest, sandboxDir) {
22962
23775
  const { allValidated, pendingSteps } = areAllStepsValidated(manifest.steps);
22963
23776
  if (!allValidated) {
22964
23777
  return validationError(
@@ -22987,6 +23800,24 @@ async function extractSandboxResult(options) {
22987
23800
  }
22988
23801
  };
22989
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);
23811
+ }
23812
+ const { manifest, error: readError } = await readValidationManifest(sandboxDir);
23813
+ if (!manifest) {
23814
+ return validationError("validation.json", readError ?? "Unknown error");
23815
+ }
23816
+ if (isBuildManifest(manifest)) {
23817
+ return extractBuildResult(manifest, sandboxDir);
23818
+ }
23819
+ return extractRunResult(manifest, sandboxDir);
23820
+ }
22990
23821
  function expandPath(path) {
22991
23822
  if (path.startsWith("~/") || path === "~") {
22992
23823
  const home = homedir32();
@@ -23771,7 +24602,10 @@ When processing --file arguments or user file paths, resolve them against the Us
23771
24602
  // v0.6.9: No custom agents - using built-in general-purpose for workflow steps
23772
24603
  // v0.7.4: Pass runHooks from config if provided (workflow protection)
23773
24604
  // Only the run command passes hooks - other SDK usage doesn't need them
23774
- ...config2?.runHooks && { hooks: config2.runHooks }
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 }
23775
24609
  }
23776
24610
  });
23777
24611
  let finalResult;
@@ -23945,12 +24779,194 @@ function createClaudeAgentExecutor(config2) {
23945
24779
  }
23946
24780
  };
23947
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
+ }
23948
24964
  var JSON_EXTENSION_REGEX = /\.json$/;
23949
24965
  var LOCK_TIMEOUT_MS = 3e4;
23950
24966
  var LOCK_RETRY_DELAY_MS2 = 200;
23951
24967
  async function findMostRecentSandbox2(sandboxRoot) {
23952
24968
  try {
23953
- const entries = await readdir22(sandboxRoot, { withFileTypes: true });
24969
+ const entries = await readdir32(sandboxRoot, { withFileTypes: true });
23954
24970
  const dirs = entries.filter(
23955
24971
  (e) => e.isDirectory() && !e.name.startsWith(".")
23956
24972
  );
@@ -23959,8 +24975,8 @@ async function findMostRecentSandbox2(sandboxRoot) {
23959
24975
  }
23960
24976
  const dirStats = await Promise.all(
23961
24977
  dirs.map(async (dir) => {
23962
- const dirPath = join7(sandboxRoot, dir.name);
23963
- const dirStat = await stat2(dirPath);
24978
+ const dirPath = join8(sandboxRoot, dir.name);
24979
+ const dirStat = await stat3(dirPath);
23964
24980
  return { path: dirPath, mtime: dirStat.mtime.getTime() };
23965
24981
  })
23966
24982
  );
@@ -23971,21 +24987,21 @@ async function findMostRecentSandbox2(sandboxRoot) {
23971
24987
  }
23972
24988
  }
23973
24989
  async function readValidationManifest2(sandboxDir) {
23974
- const validationPath = join7(sandboxDir, "validation.json");
24990
+ const validationPath = join8(sandboxDir, "validation.json");
23975
24991
  try {
23976
- const content = await readFile4(validationPath, "utf-8");
24992
+ const content = await readFile5(validationPath, "utf-8");
23977
24993
  return JSON.parse(content);
23978
24994
  } catch {
23979
24995
  return;
23980
24996
  }
23981
24997
  }
23982
- function resolveSandboxRoot(context) {
23983
- return context?.sandboxRoot ?? join7(getLoopliaPluginPath(), "sandbox");
24998
+ function resolveSandboxRoot2(context) {
24999
+ return context?.sandboxRoot ?? join8(getLoopliaPluginPath(), "sandbox");
23984
25000
  }
23985
- async function resolveSandboxDir2(context) {
23986
- const sandboxRoot = resolveSandboxRoot(context);
25001
+ async function resolveSandboxDir3(context) {
25002
+ const sandboxRoot = resolveSandboxRoot2(context);
23987
25003
  if (context?.sandboxId) {
23988
- return join7(sandboxRoot, context.sandboxId);
25004
+ return join8(sandboxRoot, context.sandboxId);
23989
25005
  }
23990
25006
  return await findMostRecentSandbox2(sandboxRoot);
23991
25007
  }
@@ -24010,7 +25026,7 @@ function getSandboxArtifactInfo(filePath) {
24010
25026
  }
24011
25027
  async function readArtifactData(filePath, artifact) {
24012
25028
  try {
24013
- const content = await readFile4(filePath, "utf-8");
25029
+ const content = await readFile5(filePath, "utf-8");
24014
25030
  return JSON.parse(content);
24015
25031
  } catch {
24016
25032
  console.error(`Validation failed for ${artifact}: Invalid JSON`);
@@ -24157,8 +25173,8 @@ async function acquireLock(lockPath, timeoutMs) {
24157
25173
  }
24158
25174
  async function writeValidationManifest(validationPath, manifest) {
24159
25175
  const tempPath = `${validationPath}.tmp`;
24160
- await writeFile3(tempPath, JSON.stringify(manifest, null, 2), "utf-8");
24161
- await rename2(tempPath, validationPath);
25176
+ await writeFile4(tempPath, JSON.stringify(manifest, null, 2), "utf-8");
25177
+ await rename3(tempPath, validationPath);
24162
25178
  }
24163
25179
  async function findMissingOutputs(sandboxDir, steps) {
24164
25180
  const missing = [];
@@ -24167,9 +25183,9 @@ async function findMissingOutputs(sandboxDir, steps) {
24167
25183
  if (!outputPath) {
24168
25184
  continue;
24169
25185
  }
24170
- const fullPath = join7(sandboxDir, outputPath);
25186
+ const fullPath = join8(sandboxDir, outputPath);
24171
25187
  try {
24172
- await stat2(fullPath);
25188
+ await stat3(fullPath);
24173
25189
  } catch {
24174
25190
  missing.push(stepId);
24175
25191
  }
@@ -24185,7 +25201,7 @@ function createStopGuardHook(context) {
24185
25201
  if (hookInput.stop_hook_active === true) {
24186
25202
  return {};
24187
25203
  }
24188
- const sandboxDir = await resolveSandboxDir2(context);
25204
+ const sandboxDir = await resolveSandboxDir3(context);
24189
25205
  if (!sandboxDir) {
24190
25206
  return {};
24191
25207
  }
@@ -24228,7 +25244,7 @@ function createPostWriteValidateHook() {
24228
25244
  if (!artifactData) {
24229
25245
  return {};
24230
25246
  }
24231
- const validationPath = join7(artifactInfo.sandboxDir, "validation.json");
25247
+ const validationPath = join8(artifactInfo.sandboxDir, "validation.json");
24232
25248
  const lock = await acquireLock(`${validationPath}.lock`, LOCK_TIMEOUT_MS);
24233
25249
  if (!lock) {
24234
25250
  console.error("Failed to acquire lock on validation.json");
@@ -24404,7 +25420,10 @@ When processing --file arguments or user file paths, resolve them against the Us
24404
25420
  "WebFetch",
24405
25421
  "AskUserQuestion"
24406
25422
  // Only in interactive mode
24407
- ]
25423
+ ],
25424
+ // v0.7.5: Pass hooks from config if provided (build validation)
25425
+ ...resolvedConfig?.runHooks && { hooks: resolvedConfig.runHooks },
25426
+ ...resolvedConfig?.buildHooks && { hooks: resolvedConfig.buildHooks }
24408
25427
  // v0.7.2: Removed outputFormat to support non-Anthropic models
24409
25428
  // Final results are now extracted from sandbox output files via extractSandboxResult()
24410
25429
  }
@@ -24433,7 +25452,7 @@ When processing --file arguments or user file paths, resolve them against the Us
24433
25452
  if (!finalResult) {
24434
25453
  finalResult = await extractSandboxResult({
24435
25454
  sandboxId: process.env.LOOPLIA_SANDBOX_ID,
24436
- sandboxRoot: process.env.LOOPLIA_SANDBOX_ROOT ?? join8(workspace, "sandbox")
25455
+ sandboxRoot: process.env.LOOPLIA_SANDBOX_ROOT ?? join9(workspace, "sandbox")
24437
25456
  });
24438
25457
  }
24439
25458
  return finalResult ?? {
@@ -24668,109 +25687,12 @@ export {
24668
25687
  copyPlugins,
24669
25688
  downloadRemotePlugins,
24670
25689
  isLoopliaInitialized,
24671
- util,
24672
- objectUtil,
24673
- ZodParsedType,
24674
- getParsedType,
24675
- ZodIssueCode,
24676
- quotelessJson,
24677
- ZodError,
24678
- en_default,
24679
- setErrorMap,
24680
- getErrorMap,
24681
- makeIssue,
24682
- EMPTY_PATH,
24683
- addIssueToContext,
24684
- ParseStatus,
24685
- INVALID,
24686
- DIRTY,
24687
- OK,
24688
- isAborted,
24689
- isDirty,
24690
- isValid,
24691
- isAsync,
24692
- ZodType,
24693
- datetimeRegex,
24694
- ZodString,
24695
- ZodNumber,
24696
- ZodBigInt,
24697
- ZodBoolean,
24698
- ZodDate,
24699
- ZodSymbol,
24700
- ZodUndefined,
24701
- ZodNull,
24702
- ZodAny,
24703
- ZodUnknown,
24704
- ZodNever,
24705
- ZodVoid,
24706
- ZodArray,
24707
- ZodObject,
24708
- ZodUnion,
24709
- ZodDiscriminatedUnion,
24710
- ZodIntersection,
24711
- ZodTuple,
24712
- ZodRecord,
24713
- ZodMap,
24714
- ZodSet,
24715
- ZodFunction,
24716
- ZodLazy,
24717
- ZodLiteral,
24718
- ZodEnum,
24719
- ZodNativeEnum,
24720
- ZodPromise,
24721
- ZodEffects,
24722
- ZodOptional,
24723
- ZodNullable,
24724
- ZodDefault,
24725
- ZodCatch,
24726
- ZodNaN,
24727
- BRAND,
24728
- ZodBranded,
24729
- ZodPipeline,
24730
- ZodReadonly,
24731
- custom,
24732
- late,
24733
- ZodFirstPartyTypeKind,
24734
- instanceOfType,
24735
- stringType,
24736
- numberType,
24737
- nanType,
24738
- bigIntType,
24739
- booleanType,
24740
- dateType,
24741
- symbolType,
24742
- undefinedType,
24743
- nullType,
24744
- anyType,
24745
- unknownType,
24746
- neverType,
24747
- voidType,
24748
- arrayType,
24749
- objectType,
24750
- strictObjectType,
24751
- unionType,
24752
- discriminatedUnionType,
24753
- intersectionType,
24754
- tupleType,
24755
- recordType,
24756
- mapType,
24757
- setType,
24758
- functionType,
24759
- lazyType,
24760
- literalType,
24761
- enumType,
24762
- nativeEnumType,
24763
- promiseType,
24764
- effectsType,
24765
- optionalType,
24766
- nullableType,
24767
- preprocessType,
24768
- pipelineType,
24769
- ostring,
24770
- onumber,
24771
- oboolean,
24772
- coerce,
24773
- NEVER,
25690
+ parseWorkflow,
25691
+ generateValidationManifest,
25692
+ getFinalStep,
25693
+ isInputlessWorkflow,
25694
+ extractWorkflowSkills,
25695
+ validateUserProfile,
24774
25696
  findClaudeCodePath,
24775
25697
  isClaudeCodeInstalled,
24776
25698
  clearClaudeCodePathCache,
@@ -24797,6 +25719,7 @@ export {
24797
25719
  writeUserProfile,
24798
25720
  executeAgenticQueryStreaming,
24799
25721
  createClaudeAgentExecutor,
25722
+ createBuildHooks,
24800
25723
  createWorkflowHooks,
24801
25724
  SUMMARIZE_SYSTEM_PROMPT,
24802
25725
  buildSummarizePrompt,