@caupulican/pi-adaptative 0.93.3 → 0.93.4
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/CHANGELOG.md +16 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +15 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts +1 -0
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
- package/dist/core/autonomy/approval-gate.js +4 -1
- package/dist/core/autonomy/approval-gate.js.map +1 -1
- package/dist/core/autonomy/composite-tool-gate.d.ts +13 -0
- package/dist/core/autonomy/composite-tool-gate.d.ts.map +1 -0
- package/dist/core/autonomy/composite-tool-gate.js +44 -0
- package/dist/core/autonomy/composite-tool-gate.js.map +1 -0
- package/dist/core/autonomy/envelope-enforcement.d.ts +2 -0
- package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.js +48 -7
- package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +48 -76
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/autonomy/path-scope.d.ts.map +1 -1
- package/dist/core/autonomy/path-scope.js +7 -7
- package/dist/core/autonomy/path-scope.js.map +1 -1
- package/dist/core/background-tool-task-controller.d.ts +2 -0
- package/dist/core/background-tool-task-controller.d.ts.map +1 -1
- package/dist/core/background-tool-task-controller.js +13 -5
- package/dist/core/background-tool-task-controller.js.map +1 -1
- package/dist/core/compaction-controller.d.ts +3 -0
- package/dist/core/compaction-controller.d.ts.map +1 -1
- package/dist/core/compaction-controller.js +132 -97
- package/dist/core/compaction-controller.js.map +1 -1
- package/dist/core/delegation/session-root-mailbox.d.ts.map +1 -1
- package/dist/core/delegation/session-root-mailbox.js +14 -1
- package/dist/core/delegation/session-root-mailbox.js.map +1 -1
- package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-agent-control-coordinator.js +6 -9
- package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-authority-resolver.d.ts.map +1 -1
- package/dist/core/delegation/worker-authority-resolver.js +3 -2
- package/dist/core/delegation/worker-authority-resolver.js.map +1 -1
- package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -1
- package/dist/core/delegation/worker-execution-policy.js +10 -8
- package/dist/core/delegation/worker-execution-policy.js.map +1 -1
- package/dist/core/foreground-recovery-controller.d.ts +2 -0
- package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
- package/dist/core/foreground-recovery-controller.js +18 -9
- package/dist/core/foreground-recovery-controller.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +3 -5
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-auto-continue-controller.js +6 -0
- package/dist/core/goals/goal-auto-continue-controller.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +1 -0
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +2 -0
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +1 -1
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/orchestration/capability-gateway.d.ts.map +1 -1
- package/dist/core/orchestration/capability-gateway.js +32 -9
- package/dist/core/orchestration/capability-gateway.js.map +1 -1
- package/dist/core/orchestration/lane-tool-manifests.js +5 -5
- package/dist/core/orchestration/lane-tool-manifests.js.map +1 -1
- package/dist/core/orchestration/policy-compiler.d.ts.map +1 -1
- package/dist/core/orchestration/policy-compiler.js +7 -0
- package/dist/core/orchestration/policy-compiler.js.map +1 -1
- package/dist/core/orchestration/profile-registry.js +2 -2
- package/dist/core/orchestration/profile-registry.js.map +1 -1
- package/dist/core/pipelines/active-context.d.ts +16 -0
- package/dist/core/pipelines/active-context.d.ts.map +1 -0
- package/dist/core/pipelines/active-context.js +29 -0
- package/dist/core/pipelines/active-context.js.map +1 -0
- package/dist/core/pipelines/context.d.ts +1 -1
- package/dist/core/pipelines/context.d.ts.map +1 -1
- package/dist/core/pipelines/context.js +40 -31
- package/dist/core/pipelines/context.js.map +1 -1
- package/dist/core/pipelines/discover.d.ts +5 -1
- package/dist/core/pipelines/discover.d.ts.map +1 -1
- package/dist/core/pipelines/discover.js +91 -33
- package/dist/core/pipelines/discover.js.map +1 -1
- package/dist/core/pipelines/increment.d.ts +0 -2
- package/dist/core/pipelines/increment.d.ts.map +1 -1
- package/dist/core/pipelines/increment.js +35 -13
- package/dist/core/pipelines/increment.js.map +1 -1
- package/dist/core/pipelines/index.d.ts +4 -3
- package/dist/core/pipelines/index.d.ts.map +1 -1
- package/dist/core/pipelines/index.js +4 -3
- package/dist/core/pipelines/index.js.map +1 -1
- package/dist/core/pipelines/run-state.d.ts +8 -0
- package/dist/core/pipelines/run-state.d.ts.map +1 -1
- package/dist/core/pipelines/run-state.js +172 -38
- package/dist/core/pipelines/run-state.js.map +1 -1
- package/dist/core/pipelines/types.d.ts +2 -0
- package/dist/core/pipelines/types.d.ts.map +1 -1
- package/dist/core/pipelines/types.js +21 -4
- package/dist/core/pipelines/types.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +2 -1
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +46 -10
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +1 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.js +25 -1
- package/dist/core/system-prompt-builder.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +6 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/task-projection.d.ts +2 -0
- package/dist/core/tasks/task-projection.d.ts.map +1 -1
- package/dist/core/tasks/task-projection.js +2 -0
- package/dist/core/tasks/task-projection.js.map +1 -1
- package/dist/core/tasks/task-state.d.ts +10 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +43 -2
- package/dist/core/tasks/task-state.js.map +1 -1
- package/dist/core/tool-capability-policy.d.ts +13 -3
- package/dist/core/tool-capability-policy.d.ts.map +1 -1
- package/dist/core/tool-capability-policy.js +136 -28
- package/dist/core/tool-capability-policy.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +45 -7
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +4 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +17 -1
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
- package/dist/core/tools/orchestration-panel.js +1 -0
- package/dist/core/tools/orchestration-panel.js.map +1 -1
- package/dist/core/tools/persistent-process-coordinator.d.ts.map +1 -1
- package/dist/core/tools/persistent-process-coordinator.js +12 -7
- package/dist/core/tools/persistent-process-coordinator.js.map +1 -1
- package/dist/core/tools/pipeline.d.ts +1 -0
- package/dist/core/tools/pipeline.d.ts.map +1 -1
- package/dist/core/tools/pipeline.js +95 -44
- package/dist/core/tools/pipeline.js.map +1 -1
- package/dist/core/tools/secret-store.d.ts.map +1 -1
- package/dist/core/tools/secret-store.js +2 -1
- package/dist/core/tools/secret-store.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts.map +1 -1
- package/dist/core/tools/shell-session.js +6 -1
- package/dist/core/tools/shell-session.js.map +1 -1
- package/dist/core/tools/task-steps.d.ts +10 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +70 -29
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
- package/dist/core/tools/windows-shell-engine.js +6 -1
- package/dist/core/tools/windows-shell-engine.js.map +1 -1
- package/dist/core/util/bounded-file.d.ts +8 -0
- package/dist/core/util/bounded-file.d.ts.map +1 -1
- package/dist/core/util/bounded-file.js +81 -16
- package/dist/core/util/bounded-file.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createCustomMessage } from "@caupulican/pi-agent-core";
|
|
2
|
+
import { formatActivePipelineContext } from "./context.js";
|
|
3
|
+
import { resolvePipelineDefinitionForRun } from "./discover.js";
|
|
4
|
+
import { resolveCurrentProjectPipelineRun } from "./run-state.js";
|
|
5
|
+
/** Resolve durable run identity, definition ownership, and bounded prompt text through one path. */
|
|
6
|
+
export function resolveActivePipelineContext(options, snapshot) {
|
|
7
|
+
const run = resolveCurrentProjectPipelineRun(options.cwd, snapshot);
|
|
8
|
+
if (!run)
|
|
9
|
+
return undefined;
|
|
10
|
+
const definition = resolvePipelineDefinitionForRun(options, run);
|
|
11
|
+
if (!definition)
|
|
12
|
+
return undefined;
|
|
13
|
+
const text = formatActivePipelineContext(definition, run);
|
|
14
|
+
return text ? { run, text } : undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Build the optional per-turn pipeline message without leaking discovery failures into prompt admission. */
|
|
17
|
+
export function createActivePipelineContextMessage(args) {
|
|
18
|
+
try {
|
|
19
|
+
const context = resolveActivePipelineContext(args.options, args.snapshot);
|
|
20
|
+
return context
|
|
21
|
+
? createCustomMessage("pipeline_context", context.text, false, { revision: context.run.revision }, new Date().toISOString())
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
args.onError(`Pipeline context unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=active-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"active-context.js","sourceRoot":"","sources":["../../../src/core/pipelines/active-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAgC,+BAA+B,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAQlE,oGAAoG;AACpG,MAAM,UAAU,4BAA4B,CAC3C,OAAgC,EAChC,QAAsB;IAEtB,MAAM,GAAG,GAAG,gCAAgC,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACpE,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,UAAU,GAAG,+BAA+B,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACjE,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,IAAI,GAAG,2BAA2B,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACzC,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,kCAAkC,CAAC,IAIlD;IACA,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,4BAA4B,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1E,OAAO,OAAO;YACb,CAAC,CAAC,mBAAmB,CACnB,kBAAkB,EAClB,OAAO,CAAC,IAAI,EACZ,KAAK,EACL,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAClC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CACxB;YACF,CAAC,CAAC,SAAS,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,CAAC,iCAAiC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxG,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC","sourcesContent":["import { createCustomMessage } from \"@caupulican/pi-agent-core\";\nimport { formatActivePipelineContext } from \"./context.ts\";\nimport { type DiscoverPipelineOptions, resolvePipelineDefinitionForRun } from \"./discover.ts\";\nimport { resolveCurrentProjectPipelineRun } from \"./run-state.ts\";\nimport type { PipelineRun } from \"./types.ts\";\n\nexport interface ActivePipelineContext {\n\trun: PipelineRun;\n\ttext: string;\n}\n\n/** Resolve durable run identity, definition ownership, and bounded prompt text through one path. */\nexport function resolveActivePipelineContext(\n\toptions: DiscoverPipelineOptions,\n\tsnapshot?: PipelineRun,\n): ActivePipelineContext | undefined {\n\tconst run = resolveCurrentProjectPipelineRun(options.cwd, snapshot);\n\tif (!run) return undefined;\n\tconst definition = resolvePipelineDefinitionForRun(options, run);\n\tif (!definition) return undefined;\n\tconst text = formatActivePipelineContext(definition, run);\n\treturn text ? { run, text } : undefined;\n}\n\n/** Build the optional per-turn pipeline message without leaking discovery failures into prompt admission. */\nexport function createActivePipelineContextMessage(args: {\n\toptions: DiscoverPipelineOptions;\n\tsnapshot?: PipelineRun;\n\tonError(message: string): void;\n}): ReturnType<typeof createCustomMessage> | undefined {\n\ttry {\n\t\tconst context = resolveActivePipelineContext(args.options, args.snapshot);\n\t\treturn context\n\t\t\t? createCustomMessage(\n\t\t\t\t\t\"pipeline_context\",\n\t\t\t\t\tcontext.text,\n\t\t\t\t\tfalse,\n\t\t\t\t\t{ revision: context.run.revision },\n\t\t\t\t\tnew Date().toISOString(),\n\t\t\t\t)\n\t\t\t: undefined;\n\t} catch (error) {\n\t\targs.onError(`Pipeline context unavailable: ${error instanceof Error ? error.message : String(error)}`);\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -2,5 +2,5 @@ import { type AssembledStageContext, type PipelineDefinition, type PipelineRun,
|
|
|
2
2
|
export declare function currentPipelineStage(definition: PipelineDefinition, run: PipelineRun): PipelineStage | undefined;
|
|
3
3
|
export declare function assembleStageContext(definition: PipelineDefinition, run: PipelineRun, stage?: PipelineStage): AssembledStageContext;
|
|
4
4
|
export declare function formatPipelineContext(definition: PipelineDefinition, run: PipelineRun, assembled: AssembledStageContext): string;
|
|
5
|
-
export declare function formatActivePipelineContext(run: PipelineRun): string | undefined;
|
|
5
|
+
export declare function formatActivePipelineContext(definition: PipelineDefinition, run: PipelineRun): string | undefined;
|
|
6
6
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/core/pipelines/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAEN,KAAK,qBAAqB,EAK1B,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/core/pipelines/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAEN,KAAK,qBAAqB,EAK1B,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,MAAM,YAAY,CAAC;AAqDpB,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAEhH;AAED,wBAAgB,oBAAoB,CACnC,UAAU,EAAE,kBAAkB,EAC9B,GAAG,EAAE,WAAW,EAChB,KAAK,CAAC,EAAE,aAAa,GACnB,qBAAqB,CAuCvB;AAED,wBAAgB,qBAAqB,CACpC,UAAU,EAAE,kBAAkB,EAC9B,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,qBAAqB,GAC9B,MAAM,CAWR;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAGhH"}
|
|
@@ -1,70 +1,82 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { isAbsolute, join, normalize, resolve } from "node:path";
|
|
2
|
+
import { isPathWithinScope, safeRealpathSync } from "../autonomy/path-scope.js";
|
|
3
|
+
import { readFilePrefixSync } from "../util/bounded-file.js";
|
|
4
4
|
import { isPipelineRunActive, MAX_LAYER_FILE_CHARS, MAX_STAGE_CONTEXT_CHARS, } from "./types.js";
|
|
5
5
|
const CHARS_PER_TOKEN = 4;
|
|
6
|
-
function isInsideRoot(root, candidate) {
|
|
7
|
-
const rel = relative(resolve(root), resolve(candidate));
|
|
8
|
-
return rel === "" || (!rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel));
|
|
9
|
-
}
|
|
10
6
|
function resolveUnder(baseDir, sandboxRoot, rawPath) {
|
|
11
7
|
const trimmed = rawPath.trim();
|
|
12
8
|
if (!trimmed)
|
|
13
9
|
return undefined;
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
try {
|
|
11
|
+
const lexicalPath = resolve(isAbsolute(trimmed) ? trimmed : join(baseDir, trimmed));
|
|
12
|
+
if (!isPathWithinScope(lexicalPath, resolve(sandboxRoot)))
|
|
13
|
+
return undefined;
|
|
14
|
+
const resolved = safeRealpathSync(lexicalPath);
|
|
15
|
+
if (!isPathWithinScope(resolved, safeRealpathSync(sandboxRoot)))
|
|
16
|
+
return undefined;
|
|
17
|
+
return normalize(resolved);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
16
20
|
return undefined;
|
|
17
|
-
|
|
21
|
+
}
|
|
18
22
|
}
|
|
19
|
-
function readBounded(path, maxChars) {
|
|
23
|
+
function readBounded(path, scopeRoot, maxChars) {
|
|
20
24
|
try {
|
|
21
|
-
|
|
25
|
+
const resolvedPath = safeRealpathSync(path);
|
|
26
|
+
if (!isPathWithinScope(resolvedPath, safeRealpathSync(scopeRoot))) {
|
|
22
27
|
return { text: `(missing: ${path})`, truncated: false };
|
|
23
28
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
29
|
+
const maxBytes = Math.max(1, maxChars * 4);
|
|
30
|
+
const prefix = readFilePrefixSync(resolvedPath, maxBytes, "Pipeline context file");
|
|
31
|
+
const raw = prefix.content.toString("utf8");
|
|
32
|
+
const truncated = prefix.truncated || raw.length > maxChars;
|
|
33
|
+
if (!truncated)
|
|
26
34
|
return { text: raw, truncated: false };
|
|
27
|
-
return { text: `${raw.slice(0, maxChars)}\n…[truncated
|
|
35
|
+
return { text: `${raw.slice(0, maxChars)}\n…[truncated]`, truncated: true };
|
|
28
36
|
}
|
|
29
37
|
catch (error) {
|
|
30
38
|
return { text: `(unreadable: ${error instanceof Error ? error.message : String(error)})`, truncated: false };
|
|
31
39
|
}
|
|
32
40
|
}
|
|
33
|
-
function pushLayer(layers, layer, path, label, remaining) {
|
|
41
|
+
function pushLayer(layers, layer, path, scopeRoot, label, remaining) {
|
|
34
42
|
if (remaining <= 0) {
|
|
35
43
|
layers.push({ layer, path, label, text: "(omitted: stage context budget)", truncated: true });
|
|
36
44
|
return 0;
|
|
37
45
|
}
|
|
38
46
|
const budget = Math.min(MAX_LAYER_FILE_CHARS, remaining);
|
|
39
|
-
const read = readBounded(path, budget);
|
|
47
|
+
const read = readBounded(path, scopeRoot, budget);
|
|
40
48
|
layers.push({ layer, path, label, text: read.text, truncated: read.truncated });
|
|
41
49
|
return remaining - read.text.length;
|
|
42
50
|
}
|
|
43
51
|
export function currentPipelineStage(definition, run) {
|
|
44
52
|
return definition.stages.find((stage) => stage.id === run.currentStageId);
|
|
45
53
|
}
|
|
46
|
-
export function assembleStageContext(definition, run, stage
|
|
54
|
+
export function assembleStageContext(definition, run, stage) {
|
|
55
|
+
const currentStage = stage ?? currentPipelineStage(definition, run);
|
|
56
|
+
if (!currentStage) {
|
|
57
|
+
throw new Error(`Current pipeline stage '${run.currentStageId}' is missing from definition '${definition.name}'.`);
|
|
58
|
+
}
|
|
47
59
|
const layers = [];
|
|
48
60
|
let remaining = MAX_STAGE_CONTEXT_CHARS;
|
|
49
|
-
remaining = pushLayer(layers, 0, definition.entryFile, "L0 entry", remaining);
|
|
61
|
+
remaining = pushLayer(layers, 0, definition.entryFile, definition.rootDir, "L0 entry", remaining);
|
|
50
62
|
if (definition.routingPath !== definition.entryFile) {
|
|
51
|
-
remaining = pushLayer(layers, 1, definition.routingPath, "L1 routing", remaining);
|
|
63
|
+
remaining = pushLayer(layers, 1, definition.routingPath, definition.rootDir, "L1 routing", remaining);
|
|
52
64
|
}
|
|
53
|
-
remaining = pushLayer(layers, 2,
|
|
54
|
-
const definitionStageDir = join(definition.stagesDir,
|
|
55
|
-
const runStageDir = join(run.runRoot,
|
|
56
|
-
for (const input of
|
|
65
|
+
remaining = pushLayer(layers, 2, currentStage.contractPath, definition.rootDir, "L2 stage contract", remaining);
|
|
66
|
+
const definitionStageDir = join(definition.stagesDir, currentStage.folderName);
|
|
67
|
+
const runStageDir = join(run.runRoot, currentStage.folderName);
|
|
68
|
+
for (const input of currentStage.contract.inputs) {
|
|
57
69
|
if (input.kind === "reference") {
|
|
58
70
|
const path = resolveUnder(definitionStageDir, definition.rootDir, input.path);
|
|
59
71
|
if (!path)
|
|
60
72
|
continue;
|
|
61
|
-
remaining = pushLayer(layers, 3, path, `L3 ${input.path}`, remaining);
|
|
73
|
+
remaining = pushLayer(layers, 3, path, definition.rootDir, `L3 ${input.path}`, remaining);
|
|
62
74
|
}
|
|
63
75
|
else {
|
|
64
76
|
const path = resolveUnder(runStageDir, run.runRoot, input.path);
|
|
65
77
|
if (!path)
|
|
66
78
|
continue;
|
|
67
|
-
remaining = pushLayer(layers, 4, path, `L4 ${input.path}`, remaining);
|
|
79
|
+
remaining = pushLayer(layers, 4, path, run.runRoot, `L4 ${input.path}`, remaining);
|
|
68
80
|
}
|
|
69
81
|
}
|
|
70
82
|
const text = layers
|
|
@@ -72,7 +84,7 @@ export function assembleStageContext(definition, run, stage = currentPipelineSta
|
|
|
72
84
|
.join("\n\n")
|
|
73
85
|
.slice(0, MAX_STAGE_CONTEXT_CHARS);
|
|
74
86
|
return {
|
|
75
|
-
stageId:
|
|
87
|
+
stageId: currentStage.id,
|
|
76
88
|
layers,
|
|
77
89
|
text,
|
|
78
90
|
tokenEstimate: Math.ceil(text.length / CHARS_PER_TOKEN),
|
|
@@ -90,12 +102,9 @@ export function formatPipelineContext(definition, run, assembled) {
|
|
|
90
102
|
].filter((line) => line.length > 0);
|
|
91
103
|
return `${PIPELINE_CONTEXT_OPEN} revision=${run.revision}>\n${lines.join("\n")}\n</pipeline_context>`;
|
|
92
104
|
}
|
|
93
|
-
export function formatActivePipelineContext(run) {
|
|
105
|
+
export function formatActivePipelineContext(definition, run) {
|
|
94
106
|
if (!isPipelineRunActive(run))
|
|
95
107
|
return undefined;
|
|
96
|
-
const definition = loadPipelineDefinition(run.definitionPath);
|
|
97
|
-
if (!definition)
|
|
98
|
-
return undefined;
|
|
99
108
|
return formatPipelineContext(definition, run, assembleStageContext(definition, run));
|
|
100
109
|
}
|
|
101
110
|
const PIPELINE_CONTEXT_OPEN = "<pipeline_context";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/core/pipelines/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { isAbsolute, join, normalize, relative, resolve, sep } from \"node:path\";\nimport { loadPipelineDefinition } from \"./discover.ts\";\nimport {\n\ttype AssembledLayer,\n\ttype AssembledStageContext,\n\ttype ContextLayer,\n\tisPipelineRunActive,\n\tMAX_LAYER_FILE_CHARS,\n\tMAX_STAGE_CONTEXT_CHARS,\n\ttype PipelineDefinition,\n\ttype PipelineRun,\n\ttype PipelineStage,\n} from \"./types.ts\";\n\nconst CHARS_PER_TOKEN = 4;\n\nfunction isInsideRoot(root: string, candidate: string): boolean {\n\tconst rel = relative(resolve(root), resolve(candidate));\n\treturn rel === \"\" || (!rel.startsWith(`..${sep}`) && rel !== \"..\" && !isAbsolute(rel));\n}\n\nfunction resolveUnder(baseDir: string, sandboxRoot: string, rawPath: string): string | undefined {\n\tconst trimmed = rawPath.trim();\n\tif (!trimmed) return undefined;\n\tconst resolved = resolve(isAbsolute(trimmed) ? trimmed : join(baseDir, trimmed));\n\tif (!isInsideRoot(sandboxRoot, resolved)) return undefined;\n\treturn normalize(resolved);\n}\n\nfunction readBounded(path: string, maxChars: number): { text: string; truncated: boolean } {\n\ttry {\n\t\tif (!existsSync(path) || !statSync(path).isFile()) {\n\t\t\treturn { text: `(missing: ${path})`, truncated: false };\n\t\t}\n\t\tconst raw = readFileSync(path, \"utf8\");\n\t\tif (raw.length <= maxChars) return { text: raw, truncated: false };\n\t\treturn { text: `${raw.slice(0, maxChars)}\\n…[truncated ${raw.length - maxChars} chars]`, truncated: true };\n\t} catch (error) {\n\t\treturn { text: `(unreadable: ${error instanceof Error ? error.message : String(error)})`, truncated: false };\n\t}\n}\n\nfunction pushLayer(\n\tlayers: AssembledLayer[],\n\tlayer: ContextLayer,\n\tpath: string,\n\tlabel: string,\n\tremaining: number,\n): number {\n\tif (remaining <= 0) {\n\t\tlayers.push({ layer, path, label, text: \"(omitted: stage context budget)\", truncated: true });\n\t\treturn 0;\n\t}\n\tconst budget = Math.min(MAX_LAYER_FILE_CHARS, remaining);\n\tconst read = readBounded(path, budget);\n\tlayers.push({ layer, path, label, text: read.text, truncated: read.truncated });\n\treturn remaining - read.text.length;\n}\n\nexport function currentPipelineStage(definition: PipelineDefinition, run: PipelineRun): PipelineStage | undefined {\n\treturn definition.stages.find((stage) => stage.id === run.currentStageId);\n}\n\nexport function assembleStageContext(\n\tdefinition: PipelineDefinition,\n\trun: PipelineRun,\n\tstage: PipelineStage = currentPipelineStage(definition, run) ?? definition.stages[0]!,\n): AssembledStageContext {\n\tconst layers: AssembledLayer[] = [];\n\tlet remaining = MAX_STAGE_CONTEXT_CHARS;\n\tremaining = pushLayer(layers, 0, definition.entryFile, \"L0 entry\", remaining);\n\tif (definition.routingPath !== definition.entryFile) {\n\t\tremaining = pushLayer(layers, 1, definition.routingPath, \"L1 routing\", remaining);\n\t}\n\tremaining = pushLayer(layers, 2, stage.contractPath, \"L2 stage contract\", remaining);\n\n\tconst definitionStageDir = join(definition.stagesDir, stage.folderName);\n\tconst runStageDir = join(run.runRoot, stage.folderName);\n\tfor (const input of stage.contract.inputs) {\n\t\tif (input.kind === \"reference\") {\n\t\t\tconst path = resolveUnder(definitionStageDir, definition.rootDir, input.path);\n\t\t\tif (!path) continue;\n\t\t\tremaining = pushLayer(layers, 3, path, `L3 ${input.path}`, remaining);\n\t\t} else {\n\t\t\tconst path = resolveUnder(runStageDir, run.runRoot, input.path);\n\t\t\tif (!path) continue;\n\t\t\tremaining = pushLayer(layers, 4, path, `L4 ${input.path}`, remaining);\n\t\t}\n\t}\n\n\tconst text = layers\n\t\t.map((item) => `### ${item.label}\\npath: ${item.path}\\n${item.text}`)\n\t\t.join(\"\\n\\n\")\n\t\t.slice(0, MAX_STAGE_CONTEXT_CHARS);\n\treturn {\n\t\tstageId: stage.id,\n\t\tlayers,\n\t\ttext,\n\t\ttokenEstimate: Math.ceil(text.length / CHARS_PER_TOKEN),\n\t};\n}\n\nexport function formatPipelineContext(\n\tdefinition: PipelineDefinition,\n\trun: PipelineRun,\n\tassembled: AssembledStageContext,\n): string {\n\tconst stage = currentPipelineStage(definition, run);\n\tconst humanCheck = stage?.contract.humanCheck.trim();\n\tconst lines = [\n\t\t`PIPELINE ${definition.name} run=${run.runId} status=${run.status} stage=${run.currentStageId}`,\n\t\tstage ? `ONE JOB: ${stage.contract.oneJob || stage.contract.title || stage.id}` : \"\",\n\t\thumanCheck ? `HUMAN CHECK: ${humanCheck}` : \"\",\n\t\t`Increment completes this stage after output/ has files, then starts the next. Status is the files on disk.`,\n\t\tassembled.text,\n\t].filter((line) => line.length > 0);\n\treturn `${PIPELINE_CONTEXT_OPEN} revision=${run.revision}>\\n${lines.join(\"\\n\")}\\n</pipeline_context>`;\n}\n\nexport function formatActivePipelineContext(run: PipelineRun): string | undefined {\n\tif (!isPipelineRunActive(run)) return undefined;\n\tconst definition = loadPipelineDefinition(run.definitionPath);\n\tif (!definition) return undefined;\n\treturn formatPipelineContext(definition, run, assembleStageContext(definition, run));\n}\n\nconst PIPELINE_CONTEXT_OPEN = \"<pipeline_context\";\n"]}
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/core/pipelines/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, join, normalize, resolve } from \"node:path\";\nimport { isPathWithinScope, safeRealpathSync } from \"../autonomy/path-scope.ts\";\nimport { readFilePrefixSync } from \"../util/bounded-file.ts\";\nimport {\n\ttype AssembledLayer,\n\ttype AssembledStageContext,\n\ttype ContextLayer,\n\tisPipelineRunActive,\n\tMAX_LAYER_FILE_CHARS,\n\tMAX_STAGE_CONTEXT_CHARS,\n\ttype PipelineDefinition,\n\ttype PipelineRun,\n\ttype PipelineStage,\n} from \"./types.ts\";\n\nconst CHARS_PER_TOKEN = 4;\n\nfunction resolveUnder(baseDir: string, sandboxRoot: string, rawPath: string): string | undefined {\n\tconst trimmed = rawPath.trim();\n\tif (!trimmed) return undefined;\n\ttry {\n\t\tconst lexicalPath = resolve(isAbsolute(trimmed) ? trimmed : join(baseDir, trimmed));\n\t\tif (!isPathWithinScope(lexicalPath, resolve(sandboxRoot))) return undefined;\n\t\tconst resolved = safeRealpathSync(lexicalPath);\n\t\tif (!isPathWithinScope(resolved, safeRealpathSync(sandboxRoot))) return undefined;\n\t\treturn normalize(resolved);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction readBounded(path: string, scopeRoot: string, maxChars: number): { text: string; truncated: boolean } {\n\ttry {\n\t\tconst resolvedPath = safeRealpathSync(path);\n\t\tif (!isPathWithinScope(resolvedPath, safeRealpathSync(scopeRoot))) {\n\t\t\treturn { text: `(missing: ${path})`, truncated: false };\n\t\t}\n\t\tconst maxBytes = Math.max(1, maxChars * 4);\n\t\tconst prefix = readFilePrefixSync(resolvedPath, maxBytes, \"Pipeline context file\");\n\t\tconst raw = prefix.content.toString(\"utf8\");\n\t\tconst truncated = prefix.truncated || raw.length > maxChars;\n\t\tif (!truncated) return { text: raw, truncated: false };\n\t\treturn { text: `${raw.slice(0, maxChars)}\\n…[truncated]`, truncated: true };\n\t} catch (error) {\n\t\treturn { text: `(unreadable: ${error instanceof Error ? error.message : String(error)})`, truncated: false };\n\t}\n}\n\nfunction pushLayer(\n\tlayers: AssembledLayer[],\n\tlayer: ContextLayer,\n\tpath: string,\n\tscopeRoot: string,\n\tlabel: string,\n\tremaining: number,\n): number {\n\tif (remaining <= 0) {\n\t\tlayers.push({ layer, path, label, text: \"(omitted: stage context budget)\", truncated: true });\n\t\treturn 0;\n\t}\n\tconst budget = Math.min(MAX_LAYER_FILE_CHARS, remaining);\n\tconst read = readBounded(path, scopeRoot, budget);\n\tlayers.push({ layer, path, label, text: read.text, truncated: read.truncated });\n\treturn remaining - read.text.length;\n}\n\nexport function currentPipelineStage(definition: PipelineDefinition, run: PipelineRun): PipelineStage | undefined {\n\treturn definition.stages.find((stage) => stage.id === run.currentStageId);\n}\n\nexport function assembleStageContext(\n\tdefinition: PipelineDefinition,\n\trun: PipelineRun,\n\tstage?: PipelineStage,\n): AssembledStageContext {\n\tconst currentStage = stage ?? currentPipelineStage(definition, run);\n\tif (!currentStage) {\n\t\tthrow new Error(\n\t\t\t`Current pipeline stage '${run.currentStageId}' is missing from definition '${definition.name}'.`,\n\t\t);\n\t}\n\tconst layers: AssembledLayer[] = [];\n\tlet remaining = MAX_STAGE_CONTEXT_CHARS;\n\tremaining = pushLayer(layers, 0, definition.entryFile, definition.rootDir, \"L0 entry\", remaining);\n\tif (definition.routingPath !== definition.entryFile) {\n\t\tremaining = pushLayer(layers, 1, definition.routingPath, definition.rootDir, \"L1 routing\", remaining);\n\t}\n\tremaining = pushLayer(layers, 2, currentStage.contractPath, definition.rootDir, \"L2 stage contract\", remaining);\n\n\tconst definitionStageDir = join(definition.stagesDir, currentStage.folderName);\n\tconst runStageDir = join(run.runRoot, currentStage.folderName);\n\tfor (const input of currentStage.contract.inputs) {\n\t\tif (input.kind === \"reference\") {\n\t\t\tconst path = resolveUnder(definitionStageDir, definition.rootDir, input.path);\n\t\t\tif (!path) continue;\n\t\t\tremaining = pushLayer(layers, 3, path, definition.rootDir, `L3 ${input.path}`, remaining);\n\t\t} else {\n\t\t\tconst path = resolveUnder(runStageDir, run.runRoot, input.path);\n\t\t\tif (!path) continue;\n\t\t\tremaining = pushLayer(layers, 4, path, run.runRoot, `L4 ${input.path}`, remaining);\n\t\t}\n\t}\n\n\tconst text = layers\n\t\t.map((item) => `### ${item.label}\\npath: ${item.path}\\n${item.text}`)\n\t\t.join(\"\\n\\n\")\n\t\t.slice(0, MAX_STAGE_CONTEXT_CHARS);\n\treturn {\n\t\tstageId: currentStage.id,\n\t\tlayers,\n\t\ttext,\n\t\ttokenEstimate: Math.ceil(text.length / CHARS_PER_TOKEN),\n\t};\n}\n\nexport function formatPipelineContext(\n\tdefinition: PipelineDefinition,\n\trun: PipelineRun,\n\tassembled: AssembledStageContext,\n): string {\n\tconst stage = currentPipelineStage(definition, run);\n\tconst humanCheck = stage?.contract.humanCheck.trim();\n\tconst lines = [\n\t\t`PIPELINE ${definition.name} run=${run.runId} status=${run.status} stage=${run.currentStageId}`,\n\t\tstage ? `ONE JOB: ${stage.contract.oneJob || stage.contract.title || stage.id}` : \"\",\n\t\thumanCheck ? `HUMAN CHECK: ${humanCheck}` : \"\",\n\t\t`Increment completes this stage after output/ has files, then starts the next. Status is the files on disk.`,\n\t\tassembled.text,\n\t].filter((line) => line.length > 0);\n\treturn `${PIPELINE_CONTEXT_OPEN} revision=${run.revision}>\\n${lines.join(\"\\n\")}\\n</pipeline_context>`;\n}\n\nexport function formatActivePipelineContext(definition: PipelineDefinition, run: PipelineRun): string | undefined {\n\tif (!isPipelineRunActive(run)) return undefined;\n\treturn formatPipelineContext(definition, run, assembleStageContext(definition, run));\n}\n\nconst PIPELINE_CONTEXT_OPEN = \"<pipeline_context\";\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { type PipelineDefinition } from "./types.ts";
|
|
1
|
+
import { type PipelineDefinition, type PipelineRun } from "./types.ts";
|
|
2
2
|
export declare function projectPipelinesDir(cwd: string): string;
|
|
3
3
|
export declare function projectPipelineRunsDir(cwd: string): string;
|
|
4
|
+
/** Validate one project-owned pipeline storage root without following a managed symlink first. */
|
|
5
|
+
export declare function assertProjectPipelineDirectory(cwd: string, name: "pipelines" | "pipeline-runs"): string;
|
|
4
6
|
export interface DiscoverPipelineOptions {
|
|
5
7
|
agentPipelinesDir: string;
|
|
6
8
|
cwd: string;
|
|
@@ -8,4 +10,6 @@ export interface DiscoverPipelineOptions {
|
|
|
8
10
|
export declare function loadPipelineDefinition(rootDir: string): PipelineDefinition | undefined;
|
|
9
11
|
export declare function discoverPipelineDefinitions(options: DiscoverPipelineOptions): PipelineDefinition[];
|
|
10
12
|
export declare function findPipelineDefinition(options: DiscoverPipelineOptions, name: string): PipelineDefinition | undefined;
|
|
13
|
+
/** Resolve a run's immutable definition path, with the normal discovery roots as a move-safe fallback. */
|
|
14
|
+
export declare function resolvePipelineDefinitionForRun(options: DiscoverPipelineOptions, run: Pick<PipelineRun, "definitionPath" | "pipelineName">): PipelineDefinition | undefined;
|
|
11
15
|
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/core/pipelines/discover.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/core/pipelines/discover.ts"],"names":[],"mappings":"AAKA,OAAO,EAIN,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAEhB,MAAM,YAAY,CAAC;AAUpB,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,kGAAkG;AAClG,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,eAAe,GAAG,MAAM,CAsBvG;AAED,MAAM,WAAW,uBAAuB;IACvC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;CACZ;AAyFD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAyBtF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,uBAAuB,GAAG,kBAAkB,EAAE,CAsBlG;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAIrH;AAED,0GAA0G;AAC1G,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,uBAAuB,EAChC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,gBAAgB,GAAG,cAAc,CAAC,GACvD,kBAAkB,GAAG,SAAS,CAOhC"}
|
|
@@ -1,20 +1,57 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { lstatSync } from "node:fs";
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
|
+
import { canonicalPathScopeIdentity, isPathWithinScope, safeRealpathSync } from "../autonomy/path-scope.js";
|
|
4
|
+
import { readBoundedDirectoryNamesSync, readBoundedTextFileSync } from "../util/bounded-file.js";
|
|
3
5
|
import { parseStageContract, parseWorkspaceFrontmatter } from "./parse-contract.js";
|
|
4
6
|
import { MAX_PIPELINE_NAME_LENGTH, MAX_PIPELINE_STAGES, PIPELINE_STAGE_FOLDER_RE, } from "./types.js";
|
|
5
7
|
const ENTRY_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
6
8
|
const ROUTING_FILE = "CONTEXT.md";
|
|
7
9
|
const CONTRACT_FILE = "CONTEXT.md";
|
|
8
10
|
const FACTORY_DIRS = ["_shared", "references"];
|
|
11
|
+
const MAX_PIPELINE_DEFINITION_FILE_BYTES = 64 * 1024;
|
|
12
|
+
const MAX_PIPELINE_DIRECTORY_ENTRIES = 1_024;
|
|
13
|
+
const MAX_PIPELINE_DEFINITIONS = 64;
|
|
9
14
|
export function projectPipelinesDir(cwd) {
|
|
10
15
|
return join(cwd, ".pi", "pipelines");
|
|
11
16
|
}
|
|
12
17
|
export function projectPipelineRunsDir(cwd) {
|
|
13
18
|
return join(cwd, ".pi", "pipeline-runs");
|
|
14
19
|
}
|
|
15
|
-
|
|
20
|
+
/** Validate one project-owned pipeline storage root without following a managed symlink first. */
|
|
21
|
+
export function assertProjectPipelineDirectory(cwd, name) {
|
|
22
|
+
const piRoot = join(cwd, ".pi");
|
|
23
|
+
const directory = join(piRoot, name);
|
|
24
|
+
for (const [path, label] of [
|
|
25
|
+
[piRoot, "Project .pi path"],
|
|
26
|
+
[directory, `Project ${name} path`],
|
|
27
|
+
]) {
|
|
28
|
+
let stats;
|
|
29
|
+
try {
|
|
30
|
+
stats = lstatSync(path);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code === "ENOENT")
|
|
34
|
+
continue;
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
38
|
+
throw new Error(`${label} is not a real directory: ${path}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!isPathWithinScope(safeRealpathSync(directory), safeRealpathSync(cwd))) {
|
|
42
|
+
throw new Error(`Project ${name} directory escapes the working directory.`);
|
|
43
|
+
}
|
|
44
|
+
return directory;
|
|
45
|
+
}
|
|
46
|
+
function readText(path, rootDir) {
|
|
16
47
|
try {
|
|
17
|
-
|
|
48
|
+
const stats = lstatSync(path);
|
|
49
|
+
if (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_PIPELINE_DEFINITION_FILE_BYTES) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
if (!isPathWithinScope(safeRealpathSync(path), safeRealpathSync(rootDir)))
|
|
53
|
+
return undefined;
|
|
54
|
+
return readBoundedTextFileSync(path, MAX_PIPELINE_DEFINITION_FILE_BYTES, "Pipeline definition file");
|
|
18
55
|
}
|
|
19
56
|
catch {
|
|
20
57
|
return undefined;
|
|
@@ -22,7 +59,8 @@ function readText(path) {
|
|
|
22
59
|
}
|
|
23
60
|
function isDir(path) {
|
|
24
61
|
try {
|
|
25
|
-
|
|
62
|
+
const stats = lstatSync(path);
|
|
63
|
+
return stats.isDirectory() && !stats.isSymbolicLink();
|
|
26
64
|
}
|
|
27
65
|
catch {
|
|
28
66
|
return false;
|
|
@@ -32,9 +70,8 @@ function listDirs(path) {
|
|
|
32
70
|
if (!isDir(path))
|
|
33
71
|
return [];
|
|
34
72
|
try {
|
|
35
|
-
return
|
|
36
|
-
.filter((
|
|
37
|
-
.map((entry) => entry.name)
|
|
73
|
+
return readBoundedDirectoryNamesSync(path, MAX_PIPELINE_DIRECTORY_ENTRIES, "Pipeline directory")
|
|
74
|
+
.filter((name) => !name.startsWith(".") && isDir(join(path, name)))
|
|
38
75
|
.sort();
|
|
39
76
|
}
|
|
40
77
|
catch {
|
|
@@ -44,7 +81,7 @@ function listDirs(path) {
|
|
|
44
81
|
function pickEntryFile(rootDir) {
|
|
45
82
|
for (const name of ENTRY_FILES) {
|
|
46
83
|
const path = join(rootDir, name);
|
|
47
|
-
if (
|
|
84
|
+
if (readText(path, rootDir) !== undefined)
|
|
48
85
|
return path;
|
|
49
86
|
}
|
|
50
87
|
return undefined;
|
|
@@ -63,12 +100,12 @@ function parseStageFolder(name) {
|
|
|
63
100
|
return undefined;
|
|
64
101
|
return { ordinal: Number(match[1]), slug: match[2] };
|
|
65
102
|
}
|
|
66
|
-
function loadStage(stagesDir, folderName) {
|
|
103
|
+
function loadStage(rootDir, stagesDir, folderName) {
|
|
67
104
|
const parsed = parseStageFolder(folderName);
|
|
68
105
|
if (!parsed)
|
|
69
106
|
return undefined;
|
|
70
107
|
const contractPath = join(stagesDir, folderName, CONTRACT_FILE);
|
|
71
|
-
const content = readText(contractPath);
|
|
108
|
+
const content = readText(contractPath, rootDir);
|
|
72
109
|
if (content === undefined)
|
|
73
110
|
return undefined;
|
|
74
111
|
const contract = parseStageContract(content);
|
|
@@ -87,7 +124,7 @@ function collectStages(rootDir) {
|
|
|
87
124
|
const stagesDir = isDir(nested) && listDirs(nested).some((name) => PIPELINE_STAGE_FOLDER_RE.test(name)) ? nested : rootDir;
|
|
88
125
|
const stages = [];
|
|
89
126
|
for (const name of listDirs(stagesDir)) {
|
|
90
|
-
const stage = loadStage(stagesDir, name);
|
|
127
|
+
const stage = loadStage(rootDir, stagesDir, name);
|
|
91
128
|
if (stage)
|
|
92
129
|
stages.push(stage);
|
|
93
130
|
if (stages.length >= MAX_PIPELINE_STAGES)
|
|
@@ -97,35 +134,49 @@ function collectStages(rootDir) {
|
|
|
97
134
|
return { stagesDir, stages };
|
|
98
135
|
}
|
|
99
136
|
export function loadPipelineDefinition(rootDir) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
137
|
+
try {
|
|
138
|
+
if (!isDir(rootDir))
|
|
139
|
+
return undefined;
|
|
140
|
+
const { stagesDir, stages } = collectStages(rootDir);
|
|
141
|
+
if (stages.length === 0)
|
|
142
|
+
return undefined;
|
|
143
|
+
const routingPath = join(rootDir, ROUTING_FILE);
|
|
144
|
+
const routing = readText(routingPath, rootDir);
|
|
145
|
+
const parsed = routing !== undefined ? parseWorkspaceFrontmatter(routing) : undefined;
|
|
146
|
+
const folderName = basename(rootDir).slice(0, MAX_PIPELINE_NAME_LENGTH);
|
|
147
|
+
const name = (parsed?.name || folderName).slice(0, MAX_PIPELINE_NAME_LENGTH);
|
|
148
|
+
const entryFile = pickEntryFile(rootDir) ?? routingPath;
|
|
149
|
+
return {
|
|
150
|
+
name,
|
|
151
|
+
description: parsed?.description ?? "",
|
|
152
|
+
form: parsed?.form ?? "pipeline",
|
|
153
|
+
rootDir,
|
|
154
|
+
entryFile,
|
|
155
|
+
routingPath: routing !== undefined ? routingPath : entryFile,
|
|
156
|
+
factoryDir: pickFactoryDir(rootDir),
|
|
157
|
+
stagesDir,
|
|
158
|
+
stages,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
104
162
|
return undefined;
|
|
105
|
-
|
|
106
|
-
const routing = readText(routingPath);
|
|
107
|
-
const parsed = routing !== undefined ? parseWorkspaceFrontmatter(routing) : undefined;
|
|
108
|
-
const folderName = basename(rootDir).slice(0, MAX_PIPELINE_NAME_LENGTH);
|
|
109
|
-
const name = (parsed?.name || folderName).slice(0, MAX_PIPELINE_NAME_LENGTH);
|
|
110
|
-
const entryFile = pickEntryFile(rootDir) ?? routingPath;
|
|
111
|
-
return {
|
|
112
|
-
name,
|
|
113
|
-
description: parsed?.description ?? "",
|
|
114
|
-
form: parsed?.form ?? "pipeline",
|
|
115
|
-
rootDir,
|
|
116
|
-
entryFile,
|
|
117
|
-
routingPath: existsSync(routingPath) ? routingPath : entryFile,
|
|
118
|
-
factoryDir: pickFactoryDir(rootDir),
|
|
119
|
-
stagesDir,
|
|
120
|
-
stages,
|
|
121
|
-
};
|
|
163
|
+
}
|
|
122
164
|
}
|
|
123
165
|
export function discoverPipelineDefinitions(options) {
|
|
124
|
-
|
|
166
|
+
let projectRoot;
|
|
167
|
+
try {
|
|
168
|
+
projectRoot = assertProjectPipelineDirectory(options.cwd, "pipelines");
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
projectRoot = undefined;
|
|
172
|
+
}
|
|
173
|
+
const roots = [options.agentPipelinesDir, ...(projectRoot ? [projectRoot] : [])];
|
|
125
174
|
const seen = new Set();
|
|
126
175
|
const definitions = [];
|
|
127
176
|
for (const root of roots) {
|
|
128
177
|
for (const name of listDirs(root)) {
|
|
178
|
+
if (definitions.length >= MAX_PIPELINE_DEFINITIONS)
|
|
179
|
+
return definitions;
|
|
129
180
|
const path = join(root, name);
|
|
130
181
|
if (seen.has(path))
|
|
131
182
|
continue;
|
|
@@ -144,4 +195,11 @@ export function findPipelineDefinition(options, name) {
|
|
|
144
195
|
return undefined;
|
|
145
196
|
return discoverPipelineDefinitions(options).find((definition) => definition.name.toLocaleLowerCase() === wanted);
|
|
146
197
|
}
|
|
198
|
+
/** Resolve a run's immutable definition path, with the normal discovery roots as a move-safe fallback. */
|
|
199
|
+
export function resolvePipelineDefinitionForRun(options, run) {
|
|
200
|
+
const definitions = discoverPipelineDefinitions(options);
|
|
201
|
+
const storedPath = canonicalPathScopeIdentity(run.definitionPath);
|
|
202
|
+
return (definitions.find((definition) => canonicalPathScopeIdentity(definition.rootDir) === storedPath) ??
|
|
203
|
+
definitions.find((definition) => definition.name.toLocaleLowerCase() === run.pipelineName.toLocaleLowerCase()));
|
|
204
|
+
}
|
|
147
205
|
//# sourceMappingURL=discover.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/core/pipelines/discover.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { parseStageContract, parseWorkspaceFrontmatter } from \"./parse-contract.ts\";\nimport {\n\tMAX_PIPELINE_NAME_LENGTH,\n\tMAX_PIPELINE_STAGES,\n\tPIPELINE_STAGE_FOLDER_RE,\n\ttype PipelineDefinition,\n\ttype PipelineStage,\n} from \"./types.ts\";\n\nconst ENTRY_FILES = [\"AGENTS.md\", \"CLAUDE.md\"] as const;\nconst ROUTING_FILE = \"CONTEXT.md\";\nconst CONTRACT_FILE = \"CONTEXT.md\";\nconst FACTORY_DIRS = [\"_shared\", \"references\"] as const;\n\nexport function projectPipelinesDir(cwd: string): string {\n\treturn join(cwd, \".pi\", \"pipelines\");\n}\n\nexport function projectPipelineRunsDir(cwd: string): string {\n\treturn join(cwd, \".pi\", \"pipeline-runs\");\n}\n\nexport interface DiscoverPipelineOptions {\n\tagentPipelinesDir: string;\n\tcwd: string;\n}\n\nfunction readText(path: string): string | undefined {\n\ttry {\n\t\treturn readFileSync(path, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction isDir(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction listDirs(path: string): string[] {\n\tif (!isDir(path)) return [];\n\ttry {\n\t\treturn readdirSync(path, { withFileTypes: true })\n\t\t\t.filter((entry) => entry.isDirectory() && !entry.name.startsWith(\".\"))\n\t\t\t.map((entry) => entry.name)\n\t\t\t.sort();\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction pickEntryFile(rootDir: string): string | undefined {\n\tfor (const name of ENTRY_FILES) {\n\t\tconst path = join(rootDir, name);\n\t\tif (existsSync(path)) return path;\n\t}\n\treturn undefined;\n}\n\nfunction pickFactoryDir(rootDir: string): string {\n\tfor (const name of FACTORY_DIRS) {\n\t\tconst path = join(rootDir, name);\n\t\tif (isDir(path)) return path;\n\t}\n\treturn join(rootDir, \"_shared\");\n}\n\nfunction parseStageFolder(name: string): { ordinal: number; slug: string } | undefined {\n\tconst match = name.match(PIPELINE_STAGE_FOLDER_RE);\n\tif (!match) return undefined;\n\treturn { ordinal: Number(match[1]), slug: match[2] };\n}\n\nfunction loadStage(stagesDir: string, folderName: string): PipelineStage | undefined {\n\tconst parsed = parseStageFolder(folderName);\n\tif (!parsed) return undefined;\n\tconst contractPath = join(stagesDir, folderName, CONTRACT_FILE);\n\tconst content = readText(contractPath);\n\tif (content === undefined) return undefined;\n\tconst contract = parseStageContract(content);\n\treturn {\n\t\tid: `${String(parsed.ordinal).padStart(2, \"0\")}_${parsed.slug}`,\n\t\tordinal: parsed.ordinal,\n\t\tslug: parsed.slug,\n\t\tfolderName,\n\t\tcontractPath,\n\t\toutputDir: join(stagesDir, folderName, \"output\"),\n\t\tcontract,\n\t};\n}\n\nfunction collectStages(rootDir: string): { stagesDir: string; stages: PipelineStage[] } {\n\tconst nested = join(rootDir, \"stages\");\n\tconst stagesDir =\n\t\tisDir(nested) && listDirs(nested).some((name) => PIPELINE_STAGE_FOLDER_RE.test(name)) ? nested : rootDir;\n\tconst stages: PipelineStage[] = [];\n\tfor (const name of listDirs(stagesDir)) {\n\t\tconst stage = loadStage(stagesDir, name);\n\t\tif (stage) stages.push(stage);\n\t\tif (stages.length >= MAX_PIPELINE_STAGES) break;\n\t}\n\tstages.sort((left, right) => left.ordinal - right.ordinal || left.slug.localeCompare(right.slug));\n\treturn { stagesDir, stages };\n}\n\nexport function loadPipelineDefinition(rootDir: string): PipelineDefinition | undefined {\n\tif (!isDir(rootDir)) return undefined;\n\tconst { stagesDir, stages } = collectStages(rootDir);\n\tif (stages.length === 0) return undefined;\n\tconst routingPath = join(rootDir, ROUTING_FILE);\n\tconst routing = readText(routingPath);\n\tconst parsed = routing !== undefined ? parseWorkspaceFrontmatter(routing) : undefined;\n\tconst folderName = basename(rootDir).slice(0, MAX_PIPELINE_NAME_LENGTH);\n\tconst name = (parsed?.name || folderName).slice(0, MAX_PIPELINE_NAME_LENGTH);\n\tconst entryFile = pickEntryFile(rootDir) ?? routingPath;\n\treturn {\n\t\tname,\n\t\tdescription: parsed?.description ?? \"\",\n\t\tform: parsed?.form ?? \"pipeline\",\n\t\trootDir,\n\t\tentryFile,\n\t\troutingPath: existsSync(routingPath) ? routingPath : entryFile,\n\t\tfactoryDir: pickFactoryDir(rootDir),\n\t\tstagesDir,\n\t\tstages,\n\t};\n}\n\nexport function discoverPipelineDefinitions(options: DiscoverPipelineOptions): PipelineDefinition[] {\n\tconst roots = [options.agentPipelinesDir, projectPipelinesDir(options.cwd)];\n\tconst seen = new Set<string>();\n\tconst definitions: PipelineDefinition[] = [];\n\tfor (const root of roots) {\n\t\tfor (const name of listDirs(root)) {\n\t\t\tconst path = join(root, name);\n\t\t\tif (seen.has(path)) continue;\n\t\t\tconst definition = loadPipelineDefinition(path);\n\t\t\tif (!definition) continue;\n\t\t\tseen.add(path);\n\t\t\tdefinitions.push(definition);\n\t\t}\n\t}\n\treturn definitions;\n}\n\nexport function findPipelineDefinition(options: DiscoverPipelineOptions, name: string): PipelineDefinition | undefined {\n\tconst wanted = name.trim().toLocaleLowerCase();\n\tif (!wanted) return undefined;\n\treturn discoverPipelineDefinitions(options).find((definition) => definition.name.toLocaleLowerCase() === wanted);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/core/pipelines/discover.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstatSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { canonicalPathScopeIdentity, isPathWithinScope, safeRealpathSync } from \"../autonomy/path-scope.ts\";\nimport { readBoundedDirectoryNamesSync, readBoundedTextFileSync } from \"../util/bounded-file.ts\";\nimport { parseStageContract, parseWorkspaceFrontmatter } from \"./parse-contract.ts\";\nimport {\n\tMAX_PIPELINE_NAME_LENGTH,\n\tMAX_PIPELINE_STAGES,\n\tPIPELINE_STAGE_FOLDER_RE,\n\ttype PipelineDefinition,\n\ttype PipelineRun,\n\ttype PipelineStage,\n} from \"./types.ts\";\n\nconst ENTRY_FILES = [\"AGENTS.md\", \"CLAUDE.md\"] as const;\nconst ROUTING_FILE = \"CONTEXT.md\";\nconst CONTRACT_FILE = \"CONTEXT.md\";\nconst FACTORY_DIRS = [\"_shared\", \"references\"] as const;\nconst MAX_PIPELINE_DEFINITION_FILE_BYTES = 64 * 1024;\nconst MAX_PIPELINE_DIRECTORY_ENTRIES = 1_024;\nconst MAX_PIPELINE_DEFINITIONS = 64;\n\nexport function projectPipelinesDir(cwd: string): string {\n\treturn join(cwd, \".pi\", \"pipelines\");\n}\n\nexport function projectPipelineRunsDir(cwd: string): string {\n\treturn join(cwd, \".pi\", \"pipeline-runs\");\n}\n\n/** Validate one project-owned pipeline storage root without following a managed symlink first. */\nexport function assertProjectPipelineDirectory(cwd: string, name: \"pipelines\" | \"pipeline-runs\"): string {\n\tconst piRoot = join(cwd, \".pi\");\n\tconst directory = join(piRoot, name);\n\tfor (const [path, label] of [\n\t\t[piRoot, \"Project .pi path\"],\n\t\t[directory, `Project ${name} path`],\n\t] as const) {\n\t\tlet stats: ReturnType<typeof lstatSync>;\n\t\ttry {\n\t\t\tstats = lstatSync(path);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n\t\t\tthrow error;\n\t\t}\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\t\tthrow new Error(`${label} is not a real directory: ${path}`);\n\t\t}\n\t}\n\tif (!isPathWithinScope(safeRealpathSync(directory), safeRealpathSync(cwd))) {\n\t\tthrow new Error(`Project ${name} directory escapes the working directory.`);\n\t}\n\treturn directory;\n}\n\nexport interface DiscoverPipelineOptions {\n\tagentPipelinesDir: string;\n\tcwd: string;\n}\n\nfunction readText(path: string, rootDir: string): string | undefined {\n\ttry {\n\t\tconst stats = lstatSync(path);\n\t\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_PIPELINE_DEFINITION_FILE_BYTES) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!isPathWithinScope(safeRealpathSync(path), safeRealpathSync(rootDir))) return undefined;\n\t\treturn readBoundedTextFileSync(path, MAX_PIPELINE_DEFINITION_FILE_BYTES, \"Pipeline definition file\");\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction isDir(path: string): boolean {\n\ttry {\n\t\tconst stats = lstatSync(path);\n\t\treturn stats.isDirectory() && !stats.isSymbolicLink();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction listDirs(path: string): string[] {\n\tif (!isDir(path)) return [];\n\ttry {\n\t\treturn readBoundedDirectoryNamesSync(path, MAX_PIPELINE_DIRECTORY_ENTRIES, \"Pipeline directory\")\n\t\t\t.filter((name) => !name.startsWith(\".\") && isDir(join(path, name)))\n\t\t\t.sort();\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction pickEntryFile(rootDir: string): string | undefined {\n\tfor (const name of ENTRY_FILES) {\n\t\tconst path = join(rootDir, name);\n\t\tif (readText(path, rootDir) !== undefined) return path;\n\t}\n\treturn undefined;\n}\n\nfunction pickFactoryDir(rootDir: string): string {\n\tfor (const name of FACTORY_DIRS) {\n\t\tconst path = join(rootDir, name);\n\t\tif (isDir(path)) return path;\n\t}\n\treturn join(rootDir, \"_shared\");\n}\n\nfunction parseStageFolder(name: string): { ordinal: number; slug: string } | undefined {\n\tconst match = name.match(PIPELINE_STAGE_FOLDER_RE);\n\tif (!match) return undefined;\n\treturn { ordinal: Number(match[1]), slug: match[2] };\n}\n\nfunction loadStage(rootDir: string, stagesDir: string, folderName: string): PipelineStage | undefined {\n\tconst parsed = parseStageFolder(folderName);\n\tif (!parsed) return undefined;\n\tconst contractPath = join(stagesDir, folderName, CONTRACT_FILE);\n\tconst content = readText(contractPath, rootDir);\n\tif (content === undefined) return undefined;\n\tconst contract = parseStageContract(content);\n\treturn {\n\t\tid: `${String(parsed.ordinal).padStart(2, \"0\")}_${parsed.slug}`,\n\t\tordinal: parsed.ordinal,\n\t\tslug: parsed.slug,\n\t\tfolderName,\n\t\tcontractPath,\n\t\toutputDir: join(stagesDir, folderName, \"output\"),\n\t\tcontract,\n\t};\n}\n\nfunction collectStages(rootDir: string): { stagesDir: string; stages: PipelineStage[] } {\n\tconst nested = join(rootDir, \"stages\");\n\tconst stagesDir =\n\t\tisDir(nested) && listDirs(nested).some((name) => PIPELINE_STAGE_FOLDER_RE.test(name)) ? nested : rootDir;\n\tconst stages: PipelineStage[] = [];\n\tfor (const name of listDirs(stagesDir)) {\n\t\tconst stage = loadStage(rootDir, stagesDir, name);\n\t\tif (stage) stages.push(stage);\n\t\tif (stages.length >= MAX_PIPELINE_STAGES) break;\n\t}\n\tstages.sort((left, right) => left.ordinal - right.ordinal || left.slug.localeCompare(right.slug));\n\treturn { stagesDir, stages };\n}\n\nexport function loadPipelineDefinition(rootDir: string): PipelineDefinition | undefined {\n\ttry {\n\t\tif (!isDir(rootDir)) return undefined;\n\t\tconst { stagesDir, stages } = collectStages(rootDir);\n\t\tif (stages.length === 0) return undefined;\n\t\tconst routingPath = join(rootDir, ROUTING_FILE);\n\t\tconst routing = readText(routingPath, rootDir);\n\t\tconst parsed = routing !== undefined ? parseWorkspaceFrontmatter(routing) : undefined;\n\t\tconst folderName = basename(rootDir).slice(0, MAX_PIPELINE_NAME_LENGTH);\n\t\tconst name = (parsed?.name || folderName).slice(0, MAX_PIPELINE_NAME_LENGTH);\n\t\tconst entryFile = pickEntryFile(rootDir) ?? routingPath;\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription: parsed?.description ?? \"\",\n\t\t\tform: parsed?.form ?? \"pipeline\",\n\t\t\trootDir,\n\t\t\tentryFile,\n\t\t\troutingPath: routing !== undefined ? routingPath : entryFile,\n\t\t\tfactoryDir: pickFactoryDir(rootDir),\n\t\t\tstagesDir,\n\t\t\tstages,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function discoverPipelineDefinitions(options: DiscoverPipelineOptions): PipelineDefinition[] {\n\tlet projectRoot: string | undefined;\n\ttry {\n\t\tprojectRoot = assertProjectPipelineDirectory(options.cwd, \"pipelines\");\n\t} catch {\n\t\tprojectRoot = undefined;\n\t}\n\tconst roots = [options.agentPipelinesDir, ...(projectRoot ? [projectRoot] : [])];\n\tconst seen = new Set<string>();\n\tconst definitions: PipelineDefinition[] = [];\n\tfor (const root of roots) {\n\t\tfor (const name of listDirs(root)) {\n\t\t\tif (definitions.length >= MAX_PIPELINE_DEFINITIONS) return definitions;\n\t\t\tconst path = join(root, name);\n\t\t\tif (seen.has(path)) continue;\n\t\t\tconst definition = loadPipelineDefinition(path);\n\t\t\tif (!definition) continue;\n\t\t\tseen.add(path);\n\t\t\tdefinitions.push(definition);\n\t\t}\n\t}\n\treturn definitions;\n}\n\nexport function findPipelineDefinition(options: DiscoverPipelineOptions, name: string): PipelineDefinition | undefined {\n\tconst wanted = name.trim().toLocaleLowerCase();\n\tif (!wanted) return undefined;\n\treturn discoverPipelineDefinitions(options).find((definition) => definition.name.toLocaleLowerCase() === wanted);\n}\n\n/** Resolve a run's immutable definition path, with the normal discovery roots as a move-safe fallback. */\nexport function resolvePipelineDefinitionForRun(\n\toptions: DiscoverPipelineOptions,\n\trun: Pick<PipelineRun, \"definitionPath\" | \"pipelineName\">,\n): PipelineDefinition | undefined {\n\tconst definitions = discoverPipelineDefinitions(options);\n\tconst storedPath = canonicalPathScopeIdentity(run.definitionPath);\n\treturn (\n\t\tdefinitions.find((definition) => canonicalPathScopeIdentity(definition.rootDir) === storedPath) ??\n\t\tdefinitions.find((definition) => definition.name.toLocaleLowerCase() === run.pipelineName.toLocaleLowerCase())\n\t);\n}\n"]}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { BackgroundToolTaskRef } from "../background-tool-task-controller.ts";
|
|
2
|
-
import type { GoalState } from "../goals/goal-state.ts";
|
|
3
2
|
import type { OpenTaskStepRef } from "../goals/goal-tool-core.ts";
|
|
4
3
|
import { type TaskStep, type TaskStepsState } from "../tasks/task-state.ts";
|
|
5
4
|
import { type IncrementResult, type PipelineDefinition, type PipelineRun } from "./types.ts";
|
|
6
5
|
export interface PipelineIncrementJoin {
|
|
7
|
-
goal?: GoalState;
|
|
8
6
|
openTaskSteps?: readonly OpenTaskStepRef[];
|
|
9
7
|
backgroundToolTasks?: readonly BackgroundToolTaskRef[];
|
|
10
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"increment.d.ts","sourceRoot":"","sources":["../../../src/core/pipelines/increment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"increment.d.ts","sourceRoot":"","sources":["../../../src/core/pipelines/increment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAG5F,OAAO,EACN,KAAK,eAAe,EAEpB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAEhB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACrC,aAAa,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC3C,mBAAmB,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;CACvD;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAChD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD;AAgBD,wBAAgB,oBAAoB,CACnC,UAAU,EAAE,kBAAkB,EAC9B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,qBAA0B,GAC9B;IAAE,GAAG,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAmD/C;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAG7E;AAED,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,MAAM,GACT;IACF,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,eAAe,CAAC;CACxB,CAgEA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,GAAG,SAAS,CAEpF"}
|