@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.
- package/dist/chunk-4TKNQ5RW.js +305 -0
- package/dist/{chunk-PXCY2LDE.js → chunk-GIZRTNY3.js} +1179 -256
- package/dist/{claude-agent-sdk-IC25DTKL.js → claude-agent-sdk-W5MXMV4Q.js} +3 -1
- package/dist/cli.js +100 -34
- package/dist/{dist-LKL7WJ7K.js → dist-3XSIQAV3.js} +2 -2
- package/package.json +1 -1
- package/plugins/looplia-core/skills/workflow-executor/SKILL.md +73 -18
- package/dist/chunk-XKLZXCWO.js +0 -1211
- 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
298
|
|
|
314
|
-
// ../../node_modules/zod
|
|
299
|
+
// ../../node_modules/zod/index.js
|
|
315
300
|
init_esm_shims();
|
|
316
301
|
|
|
317
|
-
// ../../node_modules/zod
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
22144
|
-
readFile as
|
|
22145
|
-
rename as
|
|
22146
|
-
stat as
|
|
22944
|
+
readdir as readdir32,
|
|
22945
|
+
readFile as readFile5,
|
|
22946
|
+
rename as rename3,
|
|
22947
|
+
stat as stat3,
|
|
22147
22948
|
unlink,
|
|
22148
|
-
writeFile as
|
|
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
|
|
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
|
-
|
|
22950
|
-
|
|
22951
|
-
|
|
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
|
|
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 =
|
|
23963
|
-
const dirStat = await
|
|
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 =
|
|
24990
|
+
const validationPath = join8(sandboxDir, "validation.json");
|
|
23975
24991
|
try {
|
|
23976
|
-
const content = await
|
|
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
|
|
23983
|
-
return context?.sandboxRoot ??
|
|
24998
|
+
function resolveSandboxRoot2(context) {
|
|
24999
|
+
return context?.sandboxRoot ?? join8(getLoopliaPluginPath(), "sandbox");
|
|
23984
25000
|
}
|
|
23985
|
-
async function
|
|
23986
|
-
const sandboxRoot =
|
|
25001
|
+
async function resolveSandboxDir3(context) {
|
|
25002
|
+
const sandboxRoot = resolveSandboxRoot2(context);
|
|
23987
25003
|
if (context?.sandboxId) {
|
|
23988
|
-
return
|
|
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
|
|
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
|
|
24161
|
-
await
|
|
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 =
|
|
25186
|
+
const fullPath = join8(sandboxDir, outputPath);
|
|
24171
25187
|
try {
|
|
24172
|
-
await
|
|
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
|
|
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 =
|
|
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 ??
|
|
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
|
-
|
|
24672
|
-
|
|
24673
|
-
|
|
24674
|
-
|
|
24675
|
-
|
|
24676
|
-
|
|
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,
|