pagegraph 0.14.1 → 0.15.1
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/README.md +169 -10
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +1 -1
- package/dist/{checks-BS-aDXB_.js → checks-BEhJPNzN.js} +12 -1
- package/dist/checks-BEhJPNzN.js.map +1 -0
- package/dist/{claims-Bch7Lxlo.d.ts → claims-CCf2_Jox.d.ts} +2 -2
- package/dist/{claims-Bv7voeEV.js → claims-CQlzze1K.js} +2 -2
- package/dist/{claims-Bv7voeEV.js.map → claims-CQlzze1K.js.map} +1 -1
- package/dist/claims.d.ts +2 -2
- package/dist/claims.js +1 -1
- package/dist/cli.js +1355 -616
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +7 -3
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/{content-CHd0X4s6.js → content-D5jZprMq.js} +2 -2
- package/dist/{content-CHd0X4s6.js.map → content-D5jZprMq.js.map} +1 -1
- package/dist/{content-DgNr7apS.d.ts → content-DerWgQy9.d.ts} +11 -3
- package/dist/{dist-cFoAzruL.js → dist-Br2oOB2Q.js} +2 -2
- package/dist/{dist-cFoAzruL.js.map → dist-Br2oOB2Q.js.map} +1 -1
- package/dist/{document-CztEu3Vd.d.ts → document-D9P8yY5g.d.ts} +4 -4
- package/dist/{graph-D1PIndsC.d.ts → graph-ChrvU-6X.d.ts} +27 -4
- package/dist/{graph-DMNOLXLu.js → graph-UONEaqIX.js} +43 -5
- package/dist/graph-UONEaqIX.js.map +1 -0
- package/dist/{index-C5w9ripz.d.ts → index-DzjUmbHY.d.ts} +5 -5
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/{page-heads-BfjWQvau.d.ts → page-heads-DDz_2_hq.d.ts} +3 -2
- package/dist/{page-heads-BgbaIjj9.js → page-heads-YL8nyYjF.js} +4 -3
- package/dist/page-heads-YL8nyYjF.js.map +1 -0
- package/dist/{pi-D3mMmYey.js → pi-Bz4BgZdC.js} +184 -154
- package/dist/pi-Bz4BgZdC.js.map +1 -0
- package/dist/{projections-Bk-qOOsR.d.ts → projections-Dqo_ih-J.d.ts} +2 -2
- package/dist/react.d.ts +5 -3
- package/dist/react.js +43 -19
- package/dist/react.js.map +1 -1
- package/dist/{state-BuJP_3Lr.js → state-2ikjo7uI.js} +638 -25
- package/dist/state-2ikjo7uI.js.map +1 -0
- package/dist/tanstack-start/index.d.ts +1 -1
- package/dist/tanstack-start/index.js +14 -5
- package/dist/tanstack-start/index.js.map +1 -1
- package/dist/tanstack-start/react.d.ts +1 -1
- package/dist/tanstack-start/server.d.ts +2 -2
- package/dist/tanstack-start/server.js +1 -1
- package/dist/tanstack-start/server.js.map +1 -1
- package/dist/{vite-graph-loader-DZCwejuJ.d.ts → vite-graph-loader-BtLgkN0V.d.ts} +7 -5
- package/package.json +1 -1
- package/dist/checks-BS-aDXB_.js.map +0 -1
- package/dist/declare-D5o7hwmv.js +0 -9
- package/dist/declare-D5o7hwmv.js.map +0 -1
- package/dist/graph-DMNOLXLu.js.map +0 -1
- package/dist/page-heads-BgbaIjj9.js.map +0 -1
- package/dist/pi-D3mMmYey.js.map +0 -1
- package/dist/state-BuJP_3Lr.js.map +0 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
|
+
import { lstat, mkdir, readFile, realpath, writeFile } from "node:fs/promises";
|
|
6
|
+
import { promisify } from "node:util";
|
|
1
7
|
//#region node_modules/effect/dist/Pipeable.js
|
|
2
8
|
/**
|
|
3
9
|
* The `Pipeable` module defines the shared interface and implementation helpers
|
|
@@ -17629,12 +17635,12 @@ const toReadableStreamEffect = /*#__PURE__*/ dual((args) => isStream(args[0]), (
|
|
|
17629
17635
|
//#endregion
|
|
17630
17636
|
//#region node_modules/effect/dist/internal/schema/annotations.js
|
|
17631
17637
|
/** @internal */
|
|
17632
|
-
function resolve$
|
|
17638
|
+
function resolve$2(ast) {
|
|
17633
17639
|
return ast.checks ? ast.checks[ast.checks.length - 1].annotations : ast.annotations;
|
|
17634
17640
|
}
|
|
17635
17641
|
/** @internal */
|
|
17636
17642
|
function resolveAt(key) {
|
|
17637
|
-
return (ast) => resolve$
|
|
17643
|
+
return (ast) => resolve$2(ast)?.[key];
|
|
17638
17644
|
}
|
|
17639
17645
|
/** @internal */
|
|
17640
17646
|
const STRUCTURAL_ANNOTATION_KEY = "~structural";
|
|
@@ -17663,7 +17669,7 @@ const resolveIdentifier = /*#__PURE__*/ resolveAt("identifier");
|
|
|
17663
17669
|
const resolveIdentifierFallback = /*#__PURE__*/ resolveAt(IDENTIFIER_FALLBACK_KEY);
|
|
17664
17670
|
/** @internal */
|
|
17665
17671
|
const getExpected = /*#__PURE__*/ memoize((ast) => {
|
|
17666
|
-
const identifier = resolve$
|
|
17672
|
+
const identifier = resolve$2(ast)?.identifier;
|
|
17667
17673
|
if (typeof identifier === "string") return identifier;
|
|
17668
17674
|
return ast.getExpected(getExpected);
|
|
17669
17675
|
});
|
|
@@ -20413,6 +20419,11 @@ function tuple(elements, checks = void 0) {
|
|
|
20413
20419
|
function union(members, options, checks) {
|
|
20414
20420
|
return new Union$1(members.map(getAST), options, void 0, checks);
|
|
20415
20421
|
}
|
|
20422
|
+
/** @internal */
|
|
20423
|
+
function mutable$1(ast) {
|
|
20424
|
+
if (ast.encoding) throw new Error("mutable does not support encodings");
|
|
20425
|
+
return new Arrays(true, ast.elements, ast.rest, ast.annotations, ast.checks, void 0, ast.context, ast.encodingChecks);
|
|
20426
|
+
}
|
|
20416
20427
|
const toCandidate = /*#__PURE__*/ memoizeIdempotent((ast) => {
|
|
20417
20428
|
while (true) {
|
|
20418
20429
|
if (isSuspend(ast)) return unknown;
|
|
@@ -22255,8 +22266,8 @@ function compile(ast, compile, compileField, base, specialize) {
|
|
|
22255
22266
|
/** @internal */
|
|
22256
22267
|
const invalid = /*#__PURE__*/ Symbol();
|
|
22257
22268
|
const cache = /*#__PURE__*/ new WeakMap();
|
|
22258
|
-
const decodeChild = (ast) => resolve(ast).parser;
|
|
22259
|
-
const makeChild = (ast) => resolve(ast).makeEffect;
|
|
22269
|
+
const decodeChild = (ast) => resolve$1(ast).parser;
|
|
22270
|
+
const makeChild = (ast) => resolve$1(ast).makeEffect;
|
|
22260
22271
|
const makeField = (ast) => compileField(ast, makeChild);
|
|
22261
22272
|
var InterpretedEntry = class {
|
|
22262
22273
|
ast;
|
|
@@ -22274,7 +22285,7 @@ var InterpretedEntry = class {
|
|
|
22274
22285
|
}
|
|
22275
22286
|
};
|
|
22276
22287
|
/** @internal */
|
|
22277
|
-
function resolve(ast) {
|
|
22288
|
+
function resolve$1(ast) {
|
|
22278
22289
|
const cached = cache.get(ast);
|
|
22279
22290
|
if (cached !== void 0) return cached;
|
|
22280
22291
|
const entry = new InterpretedEntry(ast);
|
|
@@ -22528,7 +22539,7 @@ function makeConstructorSync(ast) {
|
|
|
22528
22539
|
let entry;
|
|
22529
22540
|
let parser;
|
|
22530
22541
|
return (input, options) => {
|
|
22531
|
-
entry ??= resolve(ast);
|
|
22542
|
+
entry ??= resolve$1(ast);
|
|
22532
22543
|
const parseOptions = options?.disableChecks ? options.parseOptions ? {
|
|
22533
22544
|
...options.parseOptions,
|
|
22534
22545
|
disableChecks: true
|
|
@@ -22547,8 +22558,8 @@ function makeConstructorSync(ast) {
|
|
|
22547
22558
|
return runSync(parserResult((parser ??= entry.makeEffect)(input, parseOptions), input), "Constructor adapter can only throw schema issues");
|
|
22548
22559
|
};
|
|
22549
22560
|
}
|
|
22550
|
-
const normalCompiler = (ast) => resolve(ast).parser;
|
|
22551
|
-
const constructorCompiler = (ast) => resolve(ast).makeEffect;
|
|
22561
|
+
const normalCompiler = (ast) => resolve$1(ast).parser;
|
|
22562
|
+
const constructorCompiler = (ast) => resolve$1(ast).makeEffect;
|
|
22552
22563
|
//#endregion
|
|
22553
22564
|
//#region node_modules/effect/dist/internal/schema/make.js
|
|
22554
22565
|
/** @internal */
|
|
@@ -24600,6 +24611,33 @@ function Tuple(elements) {
|
|
|
24600
24611
|
* @since 4.0.0
|
|
24601
24612
|
*/
|
|
24602
24613
|
const ArraySchema = /*#__PURE__*/ lambda((schema) => make$5(new Arrays(false, [], [schema.ast]), { value: schema }));
|
|
24614
|
+
/**
|
|
24615
|
+
* Makes an array or tuple schema mutable, removing the `readonly` modifier.
|
|
24616
|
+
*
|
|
24617
|
+
* **Gotchas**
|
|
24618
|
+
*
|
|
24619
|
+
* This combinator does not support an encoding attached to the array or tuple
|
|
24620
|
+
* node and throws if one is present. Encodings on element schemas are
|
|
24621
|
+
* supported.
|
|
24622
|
+
*
|
|
24623
|
+
* **Example** (Defining mutable arrays)
|
|
24624
|
+
*
|
|
24625
|
+
* ```ts import.meta.vitest
|
|
24626
|
+
* import { Schema } from "effect"
|
|
24627
|
+
*
|
|
24628
|
+
* const schema = Schema.mutable(Schema.Array(Schema.Number))
|
|
24629
|
+
*
|
|
24630
|
+
* // number[] (mutable)
|
|
24631
|
+
* type T = typeof schema.Type
|
|
24632
|
+
* const value: T = [1, 2]
|
|
24633
|
+
* value.push(3)
|
|
24634
|
+
* value // => [1, 2, 3]
|
|
24635
|
+
* ```
|
|
24636
|
+
*
|
|
24637
|
+
* @category transforming
|
|
24638
|
+
* @since 3.10.0
|
|
24639
|
+
*/
|
|
24640
|
+
const mutable = /*#__PURE__*/ lambda((schema) => make$5(mutable$1(schema.ast), { schema }));
|
|
24603
24641
|
function makeUnion(ast, members) {
|
|
24604
24642
|
return make$5(ast, {
|
|
24605
24643
|
members,
|
|
@@ -25258,6 +25296,53 @@ const Int = /*#__PURE__*/ Number$1.check(/*#__PURE__*/ isInt());
|
|
|
25258
25296
|
* @since 4.0.0
|
|
25259
25297
|
*/
|
|
25260
25298
|
const Natural = /*#__PURE__*/ Int.check(/*#__PURE__*/ isGreaterThanOrEqualTo(0));
|
|
25299
|
+
function makeIsMinLength(minLength, minCodePoints, annotations) {
|
|
25300
|
+
return makeFilter((input) => input.length >= minLength, {
|
|
25301
|
+
expected: `a value with a length of at least ${minLength}`,
|
|
25302
|
+
representation: {
|
|
25303
|
+
id: "effect/schema/isMinLength",
|
|
25304
|
+
payload: { minLength }
|
|
25305
|
+
},
|
|
25306
|
+
toJsonSchema: ({ type }) => type === "string" ? minLength <= 1 ? { minLength: minCodePoints } : [{ minLength: minCodePoints }, true] : type === "array" ? { minItems: minLength } : type === void 0 ? [{
|
|
25307
|
+
minLength: minCodePoints,
|
|
25308
|
+
minItems: minLength
|
|
25309
|
+
}, true] : [{}, true],
|
|
25310
|
+
toCode: () => ({ runtime: `Schema.isMinLength(${minLength})` }),
|
|
25311
|
+
[STRUCTURAL_ANNOTATION_KEY]: true,
|
|
25312
|
+
arbitraryConstraint: { minLength },
|
|
25313
|
+
...annotations
|
|
25314
|
+
});
|
|
25315
|
+
}
|
|
25316
|
+
/**
|
|
25317
|
+
* Validates that a value has at least one element. Works with strings and arrays.
|
|
25318
|
+
* This is equivalent to `isMinLength(1)`.
|
|
25319
|
+
*
|
|
25320
|
+
* **Details**
|
|
25321
|
+
*
|
|
25322
|
+
* JSON Schema:
|
|
25323
|
+
*
|
|
25324
|
+
* This check corresponds to the `minLength: 1` constraint for strings or the
|
|
25325
|
+
* `minItems: 1` constraint for arrays in JSON Schema.
|
|
25326
|
+
*
|
|
25327
|
+
* Arbitrary:
|
|
25328
|
+
*
|
|
25329
|
+
* During arbitrary generation, this applies a `minLength: 1`
|
|
25330
|
+
* constraint to ensure generated strings or arrays are non-empty.
|
|
25331
|
+
*
|
|
25332
|
+
* @category validation
|
|
25333
|
+
* @since 4.0.0
|
|
25334
|
+
*/
|
|
25335
|
+
function isNonEmpty(annotations) {
|
|
25336
|
+
return makeIsMinLength(1, 1, annotations);
|
|
25337
|
+
}
|
|
25338
|
+
/**
|
|
25339
|
+
* Schema for non-empty strings. Validates that a string has at least one
|
|
25340
|
+
* character.
|
|
25341
|
+
*
|
|
25342
|
+
* @category schemas
|
|
25343
|
+
* @since 3.10.0
|
|
25344
|
+
*/
|
|
25345
|
+
const NonEmptyString = /*#__PURE__*/ String$2.check(/*#__PURE__*/ isNonEmpty());
|
|
25261
25346
|
const getErrorOptionsKey = (options) => (options?.includeStack === true ? 1 : 0) | (options?.excludeCause === true ? 2 : 0);
|
|
25262
25347
|
const getErrorOptions = (key) => {
|
|
25263
25348
|
switch (key) {
|
|
@@ -25934,6 +26019,27 @@ const Json = /*#__PURE__*/ make$5(/*#__PURE__*/ annotate(Json$1, { toCode: () =>
|
|
|
25934
26019
|
Type: "Schema.Json"
|
|
25935
26020
|
}) }));
|
|
25936
26021
|
/**
|
|
26022
|
+
* Schema for readonly string-keyed records whose values are JSON-compatible.
|
|
26023
|
+
*
|
|
26024
|
+
* **When to use**
|
|
26025
|
+
*
|
|
26026
|
+
* Use when you need to validate a JSON object rather than any JSON value.
|
|
26027
|
+
*
|
|
26028
|
+
* **Example** (Validating a JSON object)
|
|
26029
|
+
*
|
|
26030
|
+
* ```ts import.meta.vitest
|
|
26031
|
+
* import { Option, Schema } from "effect"
|
|
26032
|
+
*
|
|
26033
|
+
* Schema.decodeUnknownOption(Schema.JsonObject)({ key: [1, true, null] }) // => Option.some({ key: [1, true, null] })
|
|
26034
|
+
* Schema.decodeUnknownOption(Schema.JsonObject)([1, 2, 3]) // => Option.none()
|
|
26035
|
+
* ```
|
|
26036
|
+
*
|
|
26037
|
+
* @see {@link Json} for a schema that also accepts JSON arrays and primitive values
|
|
26038
|
+
* @category schemas
|
|
26039
|
+
* @since 4.0.0
|
|
26040
|
+
*/
|
|
26041
|
+
const JsonObject = /*#__PURE__*/ Record(String$2, Json);
|
|
26042
|
+
/**
|
|
25937
26043
|
* Schema that accepts any mutable JSON-compatible value. See {@link Json} for
|
|
25938
26044
|
* the immutable variant.
|
|
25939
26045
|
*
|
|
@@ -26736,6 +26842,488 @@ function Redacted(name) {
|
|
|
26736
26842
|
return schema(Redacted$1(String$2), name);
|
|
26737
26843
|
}
|
|
26738
26844
|
//#endregion
|
|
26845
|
+
//#region src/workflows/prompts/summary.md
|
|
26846
|
+
var summary_default = "# PageGraph {{workflow}}\n\n- Run: `{{runId}}`\n- Model: `{{model}}`\n- Pages: {{pages}}\n- Decisions: {{decisions}} ({{review}} review)\n- Executor searches: {{executorSearches}}\n- Executor calls: {{executorCalls}}\n- Changed files: {{changedFiles}}\n\n{{summary}}\n";
|
|
26847
|
+
//#endregion
|
|
26848
|
+
//#region src/workflows/template.ts
|
|
26849
|
+
const placeholder = /\{\{([A-Za-z][A-Za-z0-9]*)\}\}/g;
|
|
26850
|
+
/** A small immutable builder for checked text templates imported with `type: "text"`. */
|
|
26851
|
+
var TextTemplate = class TextTemplate {
|
|
26852
|
+
#source;
|
|
26853
|
+
#values;
|
|
26854
|
+
constructor(source, values) {
|
|
26855
|
+
this.#source = source;
|
|
26856
|
+
this.#values = values;
|
|
26857
|
+
}
|
|
26858
|
+
static from(source) {
|
|
26859
|
+
return new TextTemplate(source, {});
|
|
26860
|
+
}
|
|
26861
|
+
value(name, value) {
|
|
26862
|
+
return new TextTemplate(this.#source, {
|
|
26863
|
+
...this.#values,
|
|
26864
|
+
[name]: String(value)
|
|
26865
|
+
});
|
|
26866
|
+
}
|
|
26867
|
+
values(values) {
|
|
26868
|
+
let template = this;
|
|
26869
|
+
for (const [name, value] of Object.entries(values)) template = template.value(name, value);
|
|
26870
|
+
return template;
|
|
26871
|
+
}
|
|
26872
|
+
render() {
|
|
26873
|
+
const missing = /* @__PURE__ */ new Set();
|
|
26874
|
+
const rendered = this.#source.replace(placeholder, (_match, name) => {
|
|
26875
|
+
const value = this.#values[name];
|
|
26876
|
+
if (value === void 0) {
|
|
26877
|
+
missing.add(name);
|
|
26878
|
+
return "";
|
|
26879
|
+
}
|
|
26880
|
+
return value;
|
|
26881
|
+
});
|
|
26882
|
+
if (missing.size > 0) throw new Error(`Missing template values: ${[...missing].sort().join(", ")}`);
|
|
26883
|
+
return rendered;
|
|
26884
|
+
}
|
|
26885
|
+
};
|
|
26886
|
+
//#endregion
|
|
26887
|
+
//#region src/workflows/artifact.ts
|
|
26888
|
+
/** Write JSON through a temporary file and rename, so readers never see a partial artifact. */
|
|
26889
|
+
const writeJsonArtifact = (path, value) => {
|
|
26890
|
+
const temporary = resolve(dirname(path), `.${basename(path)}.${randomUUID()}.tmp`);
|
|
26891
|
+
try {
|
|
26892
|
+
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, {
|
|
26893
|
+
encoding: "utf8",
|
|
26894
|
+
flag: "wx"
|
|
26895
|
+
});
|
|
26896
|
+
renameSync(temporary, path);
|
|
26897
|
+
} catch (cause) {
|
|
26898
|
+
try {
|
|
26899
|
+
unlinkSync(temporary);
|
|
26900
|
+
} catch (cleanup) {
|
|
26901
|
+
if (!(cleanup instanceof Error && "code" in cleanup && cleanup.code === "ENOENT")) throw new AggregateError([cause, cleanup], `Could not write artifact or remove its temporary file: ${path}`);
|
|
26902
|
+
}
|
|
26903
|
+
throw cause;
|
|
26904
|
+
}
|
|
26905
|
+
};
|
|
26906
|
+
const createRunId = (date = /* @__PURE__ */ new Date(), workflow = "workflow", nonce = randomUUID()) => `${date.toISOString().replaceAll(":", "-").replace(".", "-")}-${nonce.slice(0, 8)}-${workflow.replaceAll(".", "-")}`;
|
|
26907
|
+
const resultSummary = (result) => {
|
|
26908
|
+
if (result !== null && typeof result === "object") {
|
|
26909
|
+
const summary = result["summary"];
|
|
26910
|
+
if (typeof summary === "string") return summary;
|
|
26911
|
+
}
|
|
26912
|
+
return "Workflow completed; inspect run.json for the structured result.";
|
|
26913
|
+
};
|
|
26914
|
+
const summary = (run) => {
|
|
26915
|
+
const counts = run.decisions[0]?.report.counts;
|
|
26916
|
+
return TextTemplate.from(summary_default).values({
|
|
26917
|
+
workflow: run.workflow,
|
|
26918
|
+
runId: run.id,
|
|
26919
|
+
model: `${run.model.provider}/${run.model.id}`,
|
|
26920
|
+
pages: run.targets.pages.length,
|
|
26921
|
+
decisions: counts?.inputs ?? 0,
|
|
26922
|
+
review: counts?.review ?? 0,
|
|
26923
|
+
executorSearches: run.evidence.executor.searches.length,
|
|
26924
|
+
executorCalls: run.evidence.executor.calls.length,
|
|
26925
|
+
changedFiles: run.changes.files.length,
|
|
26926
|
+
summary: resultSummary(run.result)
|
|
26927
|
+
}).render();
|
|
26928
|
+
};
|
|
26929
|
+
const writeRunBundle = (root, runsDirectory, run) => {
|
|
26930
|
+
const directory = resolve(root, runsDirectory, run.id);
|
|
26931
|
+
mkdirSync(directory, { recursive: true });
|
|
26932
|
+
writeJsonArtifact(resolve(directory, "run.json"), run);
|
|
26933
|
+
writeFileSync(resolve(directory, "summary.md"), summary(run), "utf8");
|
|
26934
|
+
return directory;
|
|
26935
|
+
};
|
|
26936
|
+
const writeResearchCheckpoint = (root, runsDirectory, checkpoint) => {
|
|
26937
|
+
const directory = resolve(root, runsDirectory, checkpoint.id);
|
|
26938
|
+
mkdirSync(directory, { recursive: true });
|
|
26939
|
+
const path = resolve(directory, "research.json");
|
|
26940
|
+
writeJsonArtifact(path, checkpoint);
|
|
26941
|
+
return path;
|
|
26942
|
+
};
|
|
26943
|
+
const writeWorkflowFailure = (root, runsDirectory, id, details) => {
|
|
26944
|
+
const directory = resolve(root, runsDirectory, id);
|
|
26945
|
+
mkdirSync(directory, { recursive: true });
|
|
26946
|
+
const path = resolve(directory, "failure.json");
|
|
26947
|
+
writeJsonArtifact(path, details);
|
|
26948
|
+
return path;
|
|
26949
|
+
};
|
|
26950
|
+
const serializeCause = (value, top = true, seen = /* @__PURE__ */ new Set()) => {
|
|
26951
|
+
if (seen.has(value)) return {
|
|
26952
|
+
name: "CircularCause",
|
|
26953
|
+
message: "Circular error cause"
|
|
26954
|
+
};
|
|
26955
|
+
if (value !== null && typeof value === "object") {
|
|
26956
|
+
seen.add(value);
|
|
26957
|
+
return {
|
|
26958
|
+
message: value instanceof Error ? value.message : "message" in value ? String(value.message) : JSON.stringify(value),
|
|
26959
|
+
name: value instanceof Error ? value.name : "name" in value ? String(value.name) : "Error",
|
|
26960
|
+
...top && value instanceof Error ? { stack: value.stack } : {},
|
|
26961
|
+
..."cause" in value ? { cause: serializeCause(value.cause, false, seen) } : {},
|
|
26962
|
+
...value instanceof AggregateError ? { errors: value.errors.map((error) => serializeCause(error, false, new Set(seen))) } : {}
|
|
26963
|
+
};
|
|
26964
|
+
}
|
|
26965
|
+
return {
|
|
26966
|
+
name: "Error",
|
|
26967
|
+
message: String(value)
|
|
26968
|
+
};
|
|
26969
|
+
};
|
|
26970
|
+
const writeWorkflowProgress = (root, runsDirectory, progress) => {
|
|
26971
|
+
const directory = resolve(root, runsDirectory, progress.id);
|
|
26972
|
+
mkdirSync(directory, { recursive: true });
|
|
26973
|
+
const path = resolve(directory, "progress.json");
|
|
26974
|
+
writeJsonArtifact(path, progress);
|
|
26975
|
+
return path;
|
|
26976
|
+
};
|
|
26977
|
+
//#endregion
|
|
26978
|
+
//#region src/workflows/repository-paths.ts
|
|
26979
|
+
const resolveWorkflowRepositoryRoot = async (appRoot, configuredRoot) => {
|
|
26980
|
+
const root = await realpath(appRoot);
|
|
26981
|
+
if (configuredRoot !== void 0) return realpath(resolve(root, configuredRoot));
|
|
26982
|
+
try {
|
|
26983
|
+
const { stdout } = await promisify(execFile)("git", ["rev-parse", "--show-toplevel"], { cwd: root });
|
|
26984
|
+
return await realpath(stdout.trim());
|
|
26985
|
+
} catch {
|
|
26986
|
+
return root;
|
|
26987
|
+
}
|
|
26988
|
+
};
|
|
26989
|
+
const missingPath = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
26990
|
+
const resolveWritablePath = async (path) => {
|
|
26991
|
+
let ancestor = path;
|
|
26992
|
+
const suffix = [];
|
|
26993
|
+
while (true) try {
|
|
26994
|
+
return resolve(await realpath(ancestor), ...suffix);
|
|
26995
|
+
} catch (cause) {
|
|
26996
|
+
if (!missingPath(cause)) throw cause;
|
|
26997
|
+
try {
|
|
26998
|
+
if ((await lstat(ancestor)).isSymbolicLink()) throw new Error(`Repository path has a dangling symlink: ${path}`);
|
|
26999
|
+
} catch (statCause) {
|
|
27000
|
+
if (!missingPath(statCause)) throw statCause;
|
|
27001
|
+
}
|
|
27002
|
+
const parent = dirname(ancestor);
|
|
27003
|
+
if (parent === ancestor) throw cause;
|
|
27004
|
+
suffix.unshift(relative(parent, ancestor));
|
|
27005
|
+
ancestor = parent;
|
|
27006
|
+
}
|
|
27007
|
+
};
|
|
27008
|
+
const insideRoot = (root, path) => {
|
|
27009
|
+
const pathFromRoot = relative(root, path);
|
|
27010
|
+
return pathFromRoot !== ".." && !pathFromRoot.startsWith(`..${sep}`) && !isAbsolute(pathFromRoot);
|
|
27011
|
+
};
|
|
27012
|
+
const resolveRepositoryReadPath = async (root, path, options = {}) => {
|
|
27013
|
+
const projectRoot = await realpath(root);
|
|
27014
|
+
const requested = resolve(projectRoot, path);
|
|
27015
|
+
const allowedRoots = [{
|
|
27016
|
+
requested: resolve(root),
|
|
27017
|
+
actual: projectRoot
|
|
27018
|
+
}];
|
|
27019
|
+
if (options.runsDirectory !== void 0) {
|
|
27020
|
+
const runsDirectory = resolve(options.runsDirectory);
|
|
27021
|
+
allowedRoots.push({
|
|
27022
|
+
requested: runsDirectory,
|
|
27023
|
+
actual: await resolveWritablePath(runsDirectory)
|
|
27024
|
+
});
|
|
27025
|
+
}
|
|
27026
|
+
const matchingRoots = allowedRoots.filter((allowed) => insideRoot(allowed.requested, requested) || insideRoot(allowed.actual, requested));
|
|
27027
|
+
if (matchingRoots.length === 0) throw new Error(`Repository path escapes project root: ${path}`);
|
|
27028
|
+
const resolved = await realpath(requested);
|
|
27029
|
+
if (!matchingRoots.some((allowed) => insideRoot(allowed.actual, resolved))) throw new Error(`Repository path escapes project root through a symlink: ${path}`);
|
|
27030
|
+
return resolved;
|
|
27031
|
+
};
|
|
27032
|
+
/** Resolve an edit target inside the app root, rejecting escapes, protected directories, and hard links. */
|
|
27033
|
+
const resolveWorkflowWritePath = async (root, path, options) => {
|
|
27034
|
+
const projectRoot = await realpath(root);
|
|
27035
|
+
const requested = resolve(projectRoot, path);
|
|
27036
|
+
if (!insideRoot(projectRoot, requested)) throw new Error(`Repository path escapes project root: ${path}`);
|
|
27037
|
+
const resolved = await resolveWritablePath(requested);
|
|
27038
|
+
if (!insideRoot(projectRoot, resolved)) throw new Error(`Repository path escapes project root through a symlink: ${path}`);
|
|
27039
|
+
if ([requested, resolved].some((target) => relative(projectRoot, target).split(sep).some((part) => part === ".git" || part === "node_modules"))) throw new Error(`Repository write targets a protected directory: ${path}`);
|
|
27040
|
+
const forbidden = [
|
|
27041
|
+
resolve(projectRoot, ".git"),
|
|
27042
|
+
resolve(projectRoot, "node_modules"),
|
|
27043
|
+
resolve(projectRoot, options.runsDirectory),
|
|
27044
|
+
resolve(projectRoot, options.presetDirectory)
|
|
27045
|
+
];
|
|
27046
|
+
for (const directory of forbidden) {
|
|
27047
|
+
const actual = await resolveWritablePath(directory);
|
|
27048
|
+
if (insideRoot(directory, requested) || insideRoot(actual, resolved)) throw new Error(`Repository write targets a protected directory: ${path}`);
|
|
27049
|
+
}
|
|
27050
|
+
const existing = await lstat(resolved).catch((error) => {
|
|
27051
|
+
if (missingPath(error)) return void 0;
|
|
27052
|
+
throw error;
|
|
27053
|
+
});
|
|
27054
|
+
if (existing !== void 0 && existing.nlink > 1) throw new Error(`Repository write targets a hard-linked file: ${path}`);
|
|
27055
|
+
return resolved;
|
|
27056
|
+
};
|
|
27057
|
+
//#endregion
|
|
27058
|
+
//#region src/workflows/review.ts
|
|
27059
|
+
/**
|
|
27060
|
+
* One source change. `oldText` is copied exactly from the current file and must match once;
|
|
27061
|
+
* omitting it creates `path`, which must not exist yet.
|
|
27062
|
+
*/
|
|
27063
|
+
const WorkflowEdit = Struct({
|
|
27064
|
+
path: String$2,
|
|
27065
|
+
oldText: optional(NonEmptyString),
|
|
27066
|
+
newText: String$2,
|
|
27067
|
+
reason: String$2,
|
|
27068
|
+
evidence: ArraySchema(String$2)
|
|
27069
|
+
});
|
|
27070
|
+
/** A recommendation a human must handle because the agent cannot or should not edit it. */
|
|
27071
|
+
const WorkflowReviewItem = Struct({
|
|
27072
|
+
path: String$2,
|
|
27073
|
+
reason: String$2,
|
|
27074
|
+
evidence: ArraySchema(String$2)
|
|
27075
|
+
});
|
|
27076
|
+
/** The structured result an improve workflow's action turn submits. */
|
|
27077
|
+
const ActionState = Struct({
|
|
27078
|
+
summary: String$2,
|
|
27079
|
+
edits: ArraySchema(WorkflowEdit),
|
|
27080
|
+
reviewItems: ArraySchema(WorkflowReviewItem)
|
|
27081
|
+
});
|
|
27082
|
+
const decodeActionState = decodeUnknownSync(ActionState, { errors: "all" });
|
|
27083
|
+
const actionDocument = toJsonSchemaDocument(ActionState);
|
|
27084
|
+
const actionStateJsonSchema = {
|
|
27085
|
+
...actionDocument.schema,
|
|
27086
|
+
$defs: actionDocument.definitions
|
|
27087
|
+
};
|
|
27088
|
+
const RecordedEdit = Struct({
|
|
27089
|
+
id: String$2,
|
|
27090
|
+
...WorkflowEdit.fields
|
|
27091
|
+
});
|
|
27092
|
+
const RecordedReviewItem = Struct({
|
|
27093
|
+
source: Literals(["agent", "decision"]),
|
|
27094
|
+
...WorkflowReviewItem.fields
|
|
27095
|
+
});
|
|
27096
|
+
const decodeWorkflowEdits = decodeUnknownSync(Struct({
|
|
27097
|
+
kind: Literal("pagegraph-workflow-edits"),
|
|
27098
|
+
schemaVersion: Literal(1),
|
|
27099
|
+
id: String$2,
|
|
27100
|
+
workflow: String$2,
|
|
27101
|
+
/** `write` runs applied these edits before recording them; `dry-run` runs left sources untouched. */
|
|
27102
|
+
mode: Literals(["write", "dry-run"]),
|
|
27103
|
+
/** The app root containing `pagegraph.config.ts`; edit paths are relative to it. */
|
|
27104
|
+
root: String$2,
|
|
27105
|
+
summary: String$2,
|
|
27106
|
+
edits: ArraySchema(RecordedEdit),
|
|
27107
|
+
reviewItems: ArraySchema(RecordedReviewItem)
|
|
27108
|
+
}), { errors: "all" });
|
|
27109
|
+
/**
|
|
27110
|
+
* Re-express agent edit paths relative to the app root. Agents read through the repository read
|
|
27111
|
+
* root, so they submit paths in that frame; edits.json and `pagegraph apply` use the app root.
|
|
27112
|
+
*/
|
|
27113
|
+
const normalizeEditPaths = (state, readRoot, root) => {
|
|
27114
|
+
const repositoryRoot = realpathSync(readRoot);
|
|
27115
|
+
const appRoot = realpathSync(root);
|
|
27116
|
+
return {
|
|
27117
|
+
...state,
|
|
27118
|
+
edits: state.edits.map((edit) => {
|
|
27119
|
+
const absolute = resolve(repositoryRoot, edit.path);
|
|
27120
|
+
if (!insideRoot(appRoot, absolute)) throw new Error(`Edit path is outside the app root ${relative(repositoryRoot, appRoot) || "."}: ${edit.path}`);
|
|
27121
|
+
return {
|
|
27122
|
+
...edit,
|
|
27123
|
+
path: relative(appRoot, absolute)
|
|
27124
|
+
};
|
|
27125
|
+
})
|
|
27126
|
+
};
|
|
27127
|
+
};
|
|
27128
|
+
const answerSummary = (answers) => {
|
|
27129
|
+
if (answers === null || typeof answers !== "object") return [];
|
|
27130
|
+
return Object.entries(answers).map(([name, answer]) => {
|
|
27131
|
+
if (answer !== null && typeof answer === "object") {
|
|
27132
|
+
const value = answer;
|
|
27133
|
+
if (typeof value.probability === "number") return `${name}: ${value.probability.toFixed(2)}`;
|
|
27134
|
+
if (typeof value.label === "string") {
|
|
27135
|
+
const probability = value.probabilities !== null && typeof value.probabilities === "object" ? value.probabilities[value.label] : void 0;
|
|
27136
|
+
return `${name}: ${value.label}${typeof probability === "number" ? ` (${probability.toFixed(2)})` : ""}`;
|
|
27137
|
+
}
|
|
27138
|
+
}
|
|
27139
|
+
return `${name}: ${JSON.stringify(answer)}`;
|
|
27140
|
+
});
|
|
27141
|
+
};
|
|
27142
|
+
/** The researched proposal a review decision judged, so a reviewer can act without opening research.json. */
|
|
27143
|
+
const decisionProposal = (decisionId, inputs) => {
|
|
27144
|
+
const match = /:(\d+)$/.exec(decisionId);
|
|
27145
|
+
const proposal = match === null ? void 0 : inputs[Number(match[1])];
|
|
27146
|
+
return proposal === void 0 ? [] : [`proposal: ${JSON.stringify(proposal)}`];
|
|
27147
|
+
};
|
|
27148
|
+
const workflowEditsArtifact = (input) => ({
|
|
27149
|
+
kind: "pagegraph-workflow-edits",
|
|
27150
|
+
schemaVersion: 1,
|
|
27151
|
+
id: input.id,
|
|
27152
|
+
workflow: input.workflow,
|
|
27153
|
+
mode: input.mode,
|
|
27154
|
+
root: input.root,
|
|
27155
|
+
summary: input.action.summary,
|
|
27156
|
+
edits: input.action.edits.map((edit, index) => ({
|
|
27157
|
+
id: `e${index + 1}`,
|
|
27158
|
+
...edit
|
|
27159
|
+
})),
|
|
27160
|
+
reviewItems: [...input.action.reviewItems.map((item) => ({
|
|
27161
|
+
source: "agent",
|
|
27162
|
+
...item
|
|
27163
|
+
})), ...input.decisions.review.map((record) => ({
|
|
27164
|
+
source: "decision",
|
|
27165
|
+
path: record.inputRef,
|
|
27166
|
+
reason: `Jev returned ${record.verdict} for ${record.decisionId} at threshold ${record.threshold}; a human decides whether to change it.`,
|
|
27167
|
+
evidence: [...decisionProposal(record.decisionId, input.decisionInputs), ...answerSummary(record.answers)]
|
|
27168
|
+
}))]
|
|
27169
|
+
});
|
|
27170
|
+
const fenceFor = (text) => {
|
|
27171
|
+
const longest = Math.max(2, ...[...text.matchAll(/`+/g)].map((match) => match[0].length));
|
|
27172
|
+
return "`".repeat(longest + 1);
|
|
27173
|
+
};
|
|
27174
|
+
const prefixed = (prefix, text) => text.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
27175
|
+
const evidenceList = (evidence) => evidence.length === 0 ? "Evidence: none recorded." : `Evidence:\n\n${evidence.map((item) => `- ${item}`).join("\n")}`;
|
|
27176
|
+
const renderReview = (edits, runDirectory) => {
|
|
27177
|
+
const body = edits.edits.map((edit) => {
|
|
27178
|
+
const diff = edit.oldText === void 0 ? prefixed("+ ", edit.newText) : `${prefixed("- ", edit.oldText)}\n${prefixed("+ ", edit.newText)}`;
|
|
27179
|
+
const fence = fenceFor(diff);
|
|
27180
|
+
return [
|
|
27181
|
+
`### ${edit.id} · \`${edit.path}\`${edit.oldText === void 0 ? " (new file)" : ""}`,
|
|
27182
|
+
edit.reason,
|
|
27183
|
+
evidenceList(edit.evidence),
|
|
27184
|
+
`${fence}diff\n${diff}\n${fence}`
|
|
27185
|
+
].join("\n\n");
|
|
27186
|
+
});
|
|
27187
|
+
const review = edits.reviewItems.map((item) => [
|
|
27188
|
+
`### \`${item.path}\` (${item.source})`,
|
|
27189
|
+
item.reason,
|
|
27190
|
+
evidenceList(item.evidence)
|
|
27191
|
+
].join("\n\n"));
|
|
27192
|
+
return [
|
|
27193
|
+
`# PageGraph ${edits.workflow} review`,
|
|
27194
|
+
[
|
|
27195
|
+
`- Run: \`${edits.id}\``,
|
|
27196
|
+
`- Mode: ${edits.mode === "write" ? "write (PageGraph applies these edits during the run)" : "dry-run (source files are unchanged)"}`,
|
|
27197
|
+
`- Edits: ${edits.edits.length}`,
|
|
27198
|
+
`- Review items: ${edits.reviewItems.length}`
|
|
27199
|
+
].join("\n"),
|
|
27200
|
+
edits.summary,
|
|
27201
|
+
`## Edits\n\n${body.length === 0 ? "No edits." : body.join("\n\n")}`,
|
|
27202
|
+
`## Review items\n\n${review.length === 0 ? "No review items." : review.join("\n\n")}`,
|
|
27203
|
+
...edits.mode === "dry-run" && edits.edits.length > 0 ? [[
|
|
27204
|
+
"## Apply",
|
|
27205
|
+
"Check and apply from the directory containing `pagegraph.config.ts`. Edits whose target text changed are refused as stale.",
|
|
27206
|
+
[
|
|
27207
|
+
"```sh",
|
|
27208
|
+
`pagegraph apply ${runDirectory} --check`,
|
|
27209
|
+
`pagegraph apply ${runDirectory}`,
|
|
27210
|
+
`pagegraph apply ${runDirectory} --only e1`,
|
|
27211
|
+
"```"
|
|
27212
|
+
].join("\n")
|
|
27213
|
+
].join("\n\n")] : []
|
|
27214
|
+
].join("\n\n") + "\n";
|
|
27215
|
+
};
|
|
27216
|
+
/** Write `edits.json` and `review.md` into the run directory. */
|
|
27217
|
+
const writeWorkflowEdits = (runDirectory, edits) => {
|
|
27218
|
+
mkdirSync(runDirectory, { recursive: true });
|
|
27219
|
+
const path = resolve(runDirectory, "edits.json");
|
|
27220
|
+
writeJsonArtifact(path, edits);
|
|
27221
|
+
writeFileSync(resolve(runDirectory, "review.md"), renderReview(edits, runDirectory), "utf8");
|
|
27222
|
+
return path;
|
|
27223
|
+
};
|
|
27224
|
+
/** Resolve `<run-dir|run-id>` the same way `--from` does and decode its `edits.json`. */
|
|
27225
|
+
const readWorkflowEdits = (root, runsDirectory, run) => {
|
|
27226
|
+
const directory = isAbsolute(run) || run.includes("/") || run.includes("\\") ? resolve(root, run) : resolve(root, runsDirectory, run);
|
|
27227
|
+
const path = resolve(directory, "edits.json");
|
|
27228
|
+
if (!existsSync(path)) throw new Error(`No edits.json in ${directory}; only completed improve workflow runs record edits.`);
|
|
27229
|
+
try {
|
|
27230
|
+
return {
|
|
27231
|
+
directory,
|
|
27232
|
+
edits: decodeWorkflowEdits(JSON.parse(readFileSync(path, "utf8")))
|
|
27233
|
+
};
|
|
27234
|
+
} catch (cause) {
|
|
27235
|
+
throw new Error(`Invalid edits artifact ${path}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
27236
|
+
}
|
|
27237
|
+
};
|
|
27238
|
+
const occurrences = (content, text) => {
|
|
27239
|
+
let count = 0;
|
|
27240
|
+
for (let index = content.indexOf(text); index >= 0; index = content.indexOf(text, index + 1)) count++;
|
|
27241
|
+
return count;
|
|
27242
|
+
};
|
|
27243
|
+
const readOptional = async (path) => {
|
|
27244
|
+
try {
|
|
27245
|
+
return await readFile(path, "utf8");
|
|
27246
|
+
} catch (cause) {
|
|
27247
|
+
if (cause instanceof Error && "code" in cause && cause.code === "ENOENT") return void 0;
|
|
27248
|
+
throw cause;
|
|
27249
|
+
}
|
|
27250
|
+
};
|
|
27251
|
+
/**
|
|
27252
|
+
* Apply edits in order against current files. Each edit is checked independently: a target that
|
|
27253
|
+
* no longer matches exactly once (or a new file that now exists) is `stale` and skipped; a path the
|
|
27254
|
+
* write policy refuses or an I/O error is `failed`. `check` reports `applicable` without writing.
|
|
27255
|
+
*/
|
|
27256
|
+
const applyWorkflowEdits = async (root, edits, options) => {
|
|
27257
|
+
const outcomes = /* @__PURE__ */ new Map();
|
|
27258
|
+
const fail = (edit, cause) => outcomes.set(edit.id, {
|
|
27259
|
+
id: edit.id,
|
|
27260
|
+
path: edit.path,
|
|
27261
|
+
status: "failed",
|
|
27262
|
+
reason: cause instanceof Error ? cause.message : String(cause)
|
|
27263
|
+
});
|
|
27264
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
27265
|
+
for (const edit of edits) try {
|
|
27266
|
+
const target = await resolveWorkflowWritePath(root, edit.path, options);
|
|
27267
|
+
byTarget.set(target, [...byTarget.get(target) ?? [], edit]);
|
|
27268
|
+
} catch (cause) {
|
|
27269
|
+
fail(edit, cause);
|
|
27270
|
+
}
|
|
27271
|
+
for (const [target, targetEdits] of byTarget) {
|
|
27272
|
+
let content;
|
|
27273
|
+
try {
|
|
27274
|
+
content = await readOptional(target);
|
|
27275
|
+
} catch (cause) {
|
|
27276
|
+
for (const edit of targetEdits) fail(edit, cause);
|
|
27277
|
+
continue;
|
|
27278
|
+
}
|
|
27279
|
+
const matched = [];
|
|
27280
|
+
for (const edit of targetEdits) {
|
|
27281
|
+
const stale = (reason) => outcomes.set(edit.id, {
|
|
27282
|
+
id: edit.id,
|
|
27283
|
+
path: edit.path,
|
|
27284
|
+
status: "stale",
|
|
27285
|
+
reason
|
|
27286
|
+
});
|
|
27287
|
+
if (edit.oldText === void 0) {
|
|
27288
|
+
if (content !== void 0) {
|
|
27289
|
+
stale("file already exists");
|
|
27290
|
+
continue;
|
|
27291
|
+
}
|
|
27292
|
+
content = edit.newText;
|
|
27293
|
+
} else {
|
|
27294
|
+
if (content === void 0) {
|
|
27295
|
+
stale("file not found");
|
|
27296
|
+
continue;
|
|
27297
|
+
}
|
|
27298
|
+
const count = occurrences(content, edit.oldText);
|
|
27299
|
+
if (count !== 1) {
|
|
27300
|
+
stale(count === 0 ? "target text not found" : `target text matches ${count} times`);
|
|
27301
|
+
continue;
|
|
27302
|
+
}
|
|
27303
|
+
const index = content.indexOf(edit.oldText);
|
|
27304
|
+
content = content.slice(0, index) + edit.newText + content.slice(index + edit.oldText.length);
|
|
27305
|
+
}
|
|
27306
|
+
matched.push(edit);
|
|
27307
|
+
}
|
|
27308
|
+
if (matched.length === 0) continue;
|
|
27309
|
+
if (!options.check) try {
|
|
27310
|
+
await mkdir(dirname(target), { recursive: true });
|
|
27311
|
+
const writable = await resolveWorkflowWritePath(root, matched[0].path, options);
|
|
27312
|
+
if (writable !== target) throw new Error(`Repository path changed while applying: ${matched[0].path}`);
|
|
27313
|
+
await writeFile(writable, content, "utf8");
|
|
27314
|
+
} catch (cause) {
|
|
27315
|
+
for (const edit of matched) fail(edit, cause);
|
|
27316
|
+
continue;
|
|
27317
|
+
}
|
|
27318
|
+
for (const edit of matched) outcomes.set(edit.id, {
|
|
27319
|
+
id: edit.id,
|
|
27320
|
+
path: edit.path,
|
|
27321
|
+
status: options.check ? "applicable" : "applied"
|
|
27322
|
+
});
|
|
27323
|
+
}
|
|
27324
|
+
return edits.map((edit) => outcomes.get(edit.id));
|
|
27325
|
+
};
|
|
27326
|
+
//#endregion
|
|
26739
27327
|
//#region node_modules/effect/dist/http/HttpBody.js
|
|
26740
27328
|
const TypeId$5 = "~effect/http/HttpBody";
|
|
26741
27329
|
const HttpBodyErrorTypeId = "~effect/http/HttpBody/HttpBodyError";
|
|
@@ -28081,22 +28669,47 @@ const decodeResearchState = (spec, value, limit) => {
|
|
|
28081
28669
|
if (issues.length > 0) throw new Error(issues.join("\n"));
|
|
28082
28670
|
return decoded;
|
|
28083
28671
|
};
|
|
28084
|
-
|
|
28085
|
-
|
|
28086
|
-
|
|
28087
|
-
|
|
28088
|
-
|
|
28089
|
-
|
|
28090
|
-
|
|
28091
|
-
|
|
28092
|
-
|
|
28093
|
-
const
|
|
28094
|
-
|
|
28095
|
-
|
|
28096
|
-
|
|
28097
|
-
|
|
28672
|
+
/** Recover independently valid recommendations while retaining their original item indexes. */
|
|
28673
|
+
const salvageResearchState = (spec, value, limit) => {
|
|
28674
|
+
const normalized = normalizeResearchState(value, limit);
|
|
28675
|
+
if (normalized === null || typeof normalized !== "object" || Array.isArray(normalized)) throw new Error("Workflow result must contain a valid summary and an items or opportunities array.");
|
|
28676
|
+
const record = normalized;
|
|
28677
|
+
const key = Array.isArray(record["opportunities"]) ? "opportunities" : "items";
|
|
28678
|
+
const items = record[key];
|
|
28679
|
+
if (!Array.isArray(items)) throw new Error(`Workflow result requires an ${key} array.`);
|
|
28680
|
+
const sourceItems = value[key];
|
|
28681
|
+
const sourceIndexes = Array.isArray(sourceItems) ? sourceItems.flatMap((item, index) => item === null ? [] : [index]).slice(0, limit) : [];
|
|
28682
|
+
decodeResearchState(spec, {
|
|
28683
|
+
...record,
|
|
28684
|
+
[key]: []
|
|
28685
|
+
}, limit);
|
|
28686
|
+
const valid = [];
|
|
28687
|
+
const rejectedItems = [];
|
|
28688
|
+
for (const [position, item] of items.entries()) {
|
|
28689
|
+
const index = sourceIndexes[position] ?? position;
|
|
28690
|
+
try {
|
|
28691
|
+
decodeResearchState(spec, {
|
|
28692
|
+
...record,
|
|
28693
|
+
[key]: [item]
|
|
28694
|
+
}, limit);
|
|
28695
|
+
valid.push(item);
|
|
28696
|
+
} catch (cause) {
|
|
28697
|
+
rejectedItems.push({
|
|
28698
|
+
index,
|
|
28699
|
+
reason: cause instanceof Error ? cause.message : String(cause)
|
|
28700
|
+
});
|
|
28701
|
+
}
|
|
28702
|
+
}
|
|
28703
|
+
if (valid.length === 0) throw new Error(rejectedItems.map(({ index, reason }) => `${key}[${index}]: ${reason}`).join("\n") || "No valid workflow items were submitted.");
|
|
28704
|
+
return {
|
|
28705
|
+
state: decodeResearchState(spec, {
|
|
28706
|
+
...record,
|
|
28707
|
+
[key]: valid
|
|
28708
|
+
}, limit),
|
|
28709
|
+
rejectedItems
|
|
28710
|
+
};
|
|
28098
28711
|
};
|
|
28099
28712
|
//#endregion
|
|
28100
|
-
export {
|
|
28713
|
+
export { JsonObject as $, getOrUndefined$1 as $i, provideContext as $n, fail$5 as $r, toTransform as $t, writeResearchCheckpoint as A, findFirstIndex as Ai, fn as An, mergeAll as Ar, toCodecStringTree as At, fromEnv as B, Service as Bi, logError as Bn, _await as Br, empty$4 as Bt, readWorkflowEdits as C, isUndefined as Ca, isFinite$1 as Ci, clockWith as Cn, uninterruptibleMask as Cr, is as Ct, resolveWorkflowRepositoryRoot as D, identity as Da, toMillis as Di, ensuring$2 as Dn, catchDone as Dr, suspend as Dt, resolveRepositoryReadPath as E, flow as Ea, seconds as Ei, effectify as En, withSpan as Er, optionalKey as Et, Redacted as F, of as Fi, gen as Fn, Scope as Fr, isRedacted as Ft, DateTimeUtc as G, getUnsafe as Gi, match as Gn, fail$4 as Gr, mkString as Gt, Boolean as H, empty$7 as Hi, logWarning as Hn, isDone as Hr, fromPull as Ht, String$1 as I, reduce as Ii, ignore as In, addFinalizer$1 as Ir, make$10 as It, Error$1 as J, flatMap$2 as Ji, option$1 as Jn, succeed$3 as Jr, splitLines as Jt, Defect as K, make$19 as Ki, matchEffect as Kn, isFailure as Kr, run$1 as Kt, all as L, fail$7 as Li, interrupt$1 as Ln, addFinalizerExit as Lr, value as Lt, writeWorkflowFailure as M, isReadonlyArrayNonEmpty as Mi, forEach as Mn, provideMerge as Mr, toTaggedUnion as Mt, writeWorkflowProgress as N, map$6 as Ni, forever as Nn, succeed$2 as Nr, withConstructorDefault as Nt, createRunId as O, pipe as Oa, empty$6 as Oi, fail$3 as On, effect as Or, tag as Ot, TextTemplate as P, match$3 as Pi, forkScoped as Pn, succeedContext as Pr, withDecodingDefault as Pt, Json as Q, getOrNull as Qi, provide as Qn, done as Qr, mapDone as Qt, option as R, succeed$5 as Ri, isEffect as Rn, close as Rr, callback as Rt, normalizeEditPaths as S, isString as Sa, fromInputUnsafe as Si, catch_ as Sn, uninterruptible as Sr, fromJsonString as St, writeWorkflowEdits as T, dual as Ta, minutes as Ti, contextWith as Tn, withFiber as Tr, optional as Tt, BooleanLiterals as U, get$1 as Ui, map$3 as Un, isDoneUnsafe as Ur, isStream as Ut, ArraySchema as V, add as Vi, logInfo as Vn, doneUnsafe as Vr, fromChannel as Vt, Class as W, getOrUndefined as Wi, mapError as Wn, makeUnsafe$4 as Wr, merge$1 as Wt, Finite as X, fromUndefinedOr as Xi, orElseSucceed as Xn, Done as Xr, unwrap as Xt, FalseLiterals as Y, fromNullishOr as Yi, orDie as Yn, void_$1 as Yr, transduce as Yt, Int as Z, getOrElse as Zi, promise as Zn, UnknownError as Zr, fromTransform as Zt, prependUrl as _, isNotNull as _a, MinimumLogLevel as _i, callback$1 as _n, tapError as _r, decodeUnknownEffect as _t, layer as a, none as aa, LogToStderr as ai, offerUnsafe as an, runPromise as ar, NullOr as at, applyWorkflowEdits as b, isNumber as ba, taggedEnum as bi, catchTag as bn, tryPromise as br, encodeEffect as bt, mapRequest as c, PipeInspectableProto as ca, flatMap$1 as ci, make$15 as cn, scope as cr, Redacted$1 as ct, acceptJson as d, BaseProto as da, succeed$4 as di, runIn as dn, sleep as dr, TaggedError as dt, isNone as ea, findErrorOption as ei, unwrap$1 as en, provideService as er, Literal as et, bearerToken as f, format$2 as fa, succeedNone as fi, acquireRelease as fn, succeed$1 as fr, TaggedStruct as ft, post as g, isFunction as ga, void_$2 as gi, as as gn, tapCause as gr, Unknown as gt, get as h, isBoolean as ha, uninterruptibleMask$1 as hi, andThen as hn, tap as hr, Union as ht, salvageResearchState as i, match$5 as ia, ConsoleRef as ii, offer as in, runForkWith as ir, Null as it, writeRunBundle as j, findLast as ji, fnUntraced as jn, provide$2 as jr, toJsonSchemaDocument as jt, serializeCause as k, pipeArguments as ka, findFirst as ki, flatMap as kn, merge$3 as kr, toCodecJson as kt, retryTransient as l, withFiber$1 as la, getCurrentFiber as li, makeUnsafe$1 as ln, scoped as lr, String$2 as lt, bodyJsonUnsafe as m, hasProperty as ma, sync$1 as mi, addFinalizer as mn, sync as mr, Tuple as mt, dropNulls as n, isSome as na, pretty as ni, failCauseUnsafe as nn, result as nr, MutableJson as nt, HttpClient as o, some as oa, asSome as oi, poll as on, runPromiseExit as or, Number$1 as ot, bodyJson as p, redact$1 as pa, suspend$4 as pi, acquireUseRelease as pn, suspend$3 as pr, TrueLiterals as pt, Duration as q, exists as qi, onExit$1 as qn, isSuccess as qr, runCollect as qt, normalizeResearchState as r, map$9 as ra, squash as ri, make$13 as rn, runFork as rr, Natural as rt, filterStatusOk as s, Prototype as sa, callback$2 as si, take as sn, runSync$1 as sr, Record as st, decodeResearchState as t, isOption as ta, hasInterruptsOnly as ti, endUnsafe as tn, raceFirst as tr, Literals as tt, schemaBodyJson as u, assignProperty as ua, onExitPrimitive as ui, interrupt as un, serviceOption as ur, Struct as ut, setHeaders as v, isNotUndefined as va, Error$2 as vi, catchDefect as vn, tapErrorTag as vr, decodeUnknownOption as vt, workflowEditsArtifact as w, constVoid as wa, millis as wi, context as wn, void_ as wr, mutable as wt, decodeActionState as x, isObject as xa, format$1 as xi, catchTags as xn, try_ as xr, encodeSync as xt, actionStateJsonSchema as y, isNullish as ya, TaggedError$1 as yi, catchFilter as yn, timeoutOption as yr, decodeUnknownSync as yt, ConfigProvider as z, Reference as zi, logDebug as zn, makeUnsafe$3 as zr, decodeText as zt };
|
|
28101
28714
|
|
|
28102
|
-
//# sourceMappingURL=state-
|
|
28715
|
+
//# sourceMappingURL=state-2ikjo7uI.js.map
|