alp-code 0.9.0
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 +770 -0
- package/LICENSE +21 -0
- package/README.md +295 -0
- package/alp.config.yaml +5 -0
- package/dist/src/agents/agent-definition.js +28 -0
- package/dist/src/agents/capability-catalog.js +33 -0
- package/dist/src/agents/compaction.js +36 -0
- package/dist/src/agents/errors.js +12 -0
- package/dist/src/agents/librarian.js +38 -0
- package/dist/src/agents/main.js +37 -0
- package/dist/src/agents/memory-grant.js +29 -0
- package/dist/src/agents/model-context.js +70 -0
- package/dist/src/agents/modes.js +134 -0
- package/dist/src/agents/oracle.js +36 -0
- package/dist/src/agents/read-thread.js +38 -0
- package/dist/src/agents/registry.js +238 -0
- package/dist/src/agents/render-identity.js +38 -0
- package/dist/src/agents/review.js +37 -0
- package/dist/src/agents/search.js +37 -0
- package/dist/src/agents/shared/house-rules.js +33 -0
- package/dist/src/agents/shared/principal.js +18 -0
- package/dist/src/agents/shared/voice.js +29 -0
- package/dist/src/agents/titling.js +32 -0
- package/dist/src/agents/types.js +15 -0
- package/dist/src/backend/execution-backend.js +2 -0
- package/dist/src/backend/local-execution-store.js +144 -0
- package/dist/src/backend/local-process-backend.js +533 -0
- package/dist/src/backend/local-supervisor.js +104 -0
- package/dist/src/cli/alp.js +380 -0
- package/dist/src/cli/commands/context.js +203 -0
- package/dist/src/cli/commands/delegate.js +136 -0
- package/dist/src/cli/commands/identity-sync.js +31 -0
- package/dist/src/cli/commands/init.js +184 -0
- package/dist/src/cli/commands/mode.js +22 -0
- package/dist/src/cli/commands/principal.js +114 -0
- package/dist/src/cli/commands/run-main.js +90 -0
- package/dist/src/cli/commands/runtime.js +21 -0
- package/dist/src/cli/mode-preference-store.js +62 -0
- package/dist/src/cli/mode-selector.js +178 -0
- package/dist/src/cli/update-check.js +77 -0
- package/dist/src/context/checkpoint.js +134 -0
- package/dist/src/context/compact-journal.js +153 -0
- package/dist/src/context/compact-payload.js +121 -0
- package/dist/src/context/continuity.js +70 -0
- package/dist/src/context/types.js +2 -0
- package/dist/src/delegation/backend-registry.js +40 -0
- package/dist/src/delegation/delegation-service.js +300 -0
- package/dist/src/delegation/types.js +12 -0
- package/dist/src/execution/execution-policy.js +96 -0
- package/dist/src/execution/execution-service.js +115 -0
- package/dist/src/execution/execution-store.js +78 -0
- package/dist/src/execution/identity-capsule.js +65 -0
- package/dist/src/execution/types.js +12 -0
- package/dist/src/hooks/execution-bridge.js +84 -0
- package/dist/src/index.js +4 -0
- package/dist/src/memory/adapters/markdown-file-store.js +257 -0
- package/dist/src/memory/adapters/memory-api-client.js +2 -0
- package/dist/src/memory/adapters/memory-path-mapper.js +76 -0
- package/dist/src/memory/adapters/remote-api-store.js +25 -0
- package/dist/src/memory/context-ranker.js +21 -0
- package/dist/src/memory/errors.js +58 -0
- package/dist/src/memory/memory-service.js +149 -0
- package/dist/src/memory/memory-store.js +2 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/policy/capability-policy.js +29 -0
- package/dist/src/policy/delegation-policy.js +25 -0
- package/dist/src/policy/errors.js +10 -0
- package/dist/src/policy/invariants.js +31 -0
- package/dist/src/policy/memory-policy.js +22 -0
- package/dist/src/policy/policy-engine.js +85 -0
- package/dist/src/policy/types.js +8 -0
- package/dist/src/policy/workspace-policy.js +77 -0
- package/dist/src/principal/principal-profile-store.js +89 -0
- package/dist/src/runtime/adapter-files.js +147 -0
- package/dist/src/runtime/claude-adapter.js +177 -0
- package/dist/src/runtime/codex-adapter.js +169 -0
- package/dist/src/runtime/permission-rules.js +156 -0
- package/dist/src/runtime/render-session-context.js +124 -0
- package/dist/src/runtime/render-task-input.js +33 -0
- package/dist/src/runtime/runtime-adapter.js +2 -0
- package/dist/src/runtime/runtime-preference-store.js +66 -0
- package/dist/src/runtime/runtime-selector.js +178 -0
- package/dist/src/runtime/types.js +2 -0
- package/dist/src/runtime/windows-shim.js +57 -0
- package/dist/src/state-paths.js +49 -0
- package/dist/src/workflow/output-validator.js +27 -0
- package/dist/src/workflow/repair-policy.js +8 -0
- package/dist/src/workflow/types.js +22 -0
- package/dist/src/workflow/workflow-runner.js +81 -0
- package/hooks/compact-record.cjs +109 -0
- package/hooks/session-boot.cjs +112 -0
- package/hooks/session-end.cjs +34 -0
- package/package.json +48 -0
- package/scaffold/memory/INDEX.md +27 -0
- package/scaffold/memory/README.md +76 -0
- package/scaffold/memory/projects/INDEX.md +22 -0
- package/scaffold/memory/projects/PROTOCOL.md +128 -0
- package/scaffold/memory/projects/_template/PROJECT.md +45 -0
- package/scripts/alp.cjs +126 -0
- package/scripts/alp.ps1 +4 -0
- package/scripts/alp.sh +3 -0
- package/scripts/bootstrap.cjs +144 -0
- package/scripts/checkout-release.cjs +30 -0
- package/scripts/delegate.cjs +19 -0
- package/scripts/doctor.cjs +158 -0
- package/scripts/doctor.sh +3 -0
- package/scripts/ensure-state.cjs +22 -0
- package/scripts/lib/cli-link.cjs +375 -0
- package/scripts/lib/codex-role.cjs +18 -0
- package/scripts/lib/delegation/command-runner.cjs +108 -0
- package/scripts/lib/delegation/config.cjs +81 -0
- package/scripts/lib/install-paths.cjs +154 -0
- package/scripts/lib/release-manifest.cjs +42 -0
- package/scripts/lib/semver-lite.cjs +20 -0
- package/scripts/lib/state.cjs +274 -0
- package/scripts/lib/uninstall.cjs +252 -0
- package/scripts/lib/update-check-worker.cjs +21 -0
- package/scripts/lib/update.cjs +395 -0
- package/scripts/run-role.cjs +42 -0
- package/scripts/run-role.ps1 +4 -0
- package/scripts/run-role.sh +3 -0
- package/scripts/sync-project-index.sh +167 -0
- package/skills/agent-memory/SKILL.md +109 -0
- package/skills/alp-debug/SKILL.md +90 -0
- package/skills/alp-debug/references/defense-in-depth.md +118 -0
- package/skills/alp-debug/references/investigation-methodology.md +106 -0
- package/skills/alp-debug/references/log-and-ci-analysis.md +96 -0
- package/skills/alp-debug/references/performance-diagnostics.md +112 -0
- package/skills/alp-debug/references/reporting-standards.md +120 -0
- package/skills/alp-debug/references/root-cause-tracing.md +134 -0
- package/skills/alp-debug/references/systematic-debugging.md +93 -0
- package/skills/alp-debug/references/verification.md +86 -0
- package/skills/alp-debug/scripts/find-polluter.sh +63 -0
- package/skills/alp-debug/scripts/find-polluter.test.md +102 -0
- package/skills/alp-plan/SKILL.md +128 -0
- package/skills/alp-plan/references/archive-workflow.md +77 -0
- package/skills/alp-plan/references/codebase-understanding.md +55 -0
- package/skills/alp-plan/references/output-standards.md +96 -0
- package/skills/alp-plan/references/plan-organization.md +129 -0
- package/skills/alp-plan/references/red-team-personas.md +76 -0
- package/skills/alp-plan/references/red-team-workflow.md +81 -0
- package/skills/alp-plan/references/research-phase.md +57 -0
- package/skills/alp-plan/references/scope-challenge.md +82 -0
- package/skills/alp-plan/references/solution-design.md +76 -0
- package/skills/alp-plan/references/validate-question-framework.md +89 -0
- package/skills/alp-plan/references/validate-workflow.md +83 -0
- package/skills/alp-predict/SKILL.md +98 -0
- package/skills/alp-scenario/SKILL.md +86 -0
- package/skills/code-review/SKILL.md +111 -0
- package/skills/code-review/references/code-review-reception.md +114 -0
- package/skills/code-review/references/edge-case-scouting.md +78 -0
- package/skills/code-review/references/verification-before-completion.md +117 -0
- package/skills/delegation/SKILL.md +46 -0
- package/skills/docs-seeker/.env.example +15 -0
- package/skills/docs-seeker/SKILL.md +87 -0
- package/skills/docs-seeker/package.json +25 -0
- package/skills/docs-seeker/references/advanced.md +82 -0
- package/skills/docs-seeker/references/context7-patterns.md +68 -0
- package/skills/docs-seeker/references/errors.md +72 -0
- package/skills/docs-seeker/scripts/analyze-llms-txt.js +211 -0
- package/skills/docs-seeker/scripts/detect-topic.js +172 -0
- package/skills/docs-seeker/scripts/fetch-docs.js +213 -0
- package/skills/docs-seeker/scripts/tests/run-tests.js +72 -0
- package/skills/docs-seeker/scripts/tests/test-analyze-llms.js +119 -0
- package/skills/docs-seeker/scripts/tests/test-detect-topic.js +112 -0
- package/skills/docs-seeker/scripts/tests/test-fetch-docs.js +84 -0
- package/skills/docs-seeker/scripts/utils/env-loader.js +94 -0
- package/skills/docs-seeker/workflows/library-search.md +73 -0
- package/skills/docs-seeker/workflows/repo-analysis.md +90 -0
- package/skills/docs-seeker/workflows/topic-search.md +69 -0
- package/skills/git/SKILL.md +121 -0
- package/skills/git/references/branch-management.md +90 -0
- package/skills/git/references/commit-standards.md +82 -0
- package/skills/git/references/gh-cli-guide.md +132 -0
- package/skills/git/references/safety-protocols.md +86 -0
- package/skills/git/references/workflow-commit.md +89 -0
- package/skills/git/references/workflow-merge.md +63 -0
- package/skills/git/references/workflow-pr.md +70 -0
- package/skills/git/references/workflow-push.md +62 -0
- package/skills/gkg/SKILL.md +87 -0
- package/skills/gkg/references/cli-commands.md +92 -0
- package/skills/gkg/references/http-api.md +99 -0
- package/skills/gkg/references/language-support.md +54 -0
- package/skills/problem-solving/SKILL.md +86 -0
- package/skills/problem-solving/references/attribution.md +48 -0
- package/skills/problem-solving/references/collision-zone-thinking.md +71 -0
- package/skills/problem-solving/references/inversion-exercise.md +88 -0
- package/skills/problem-solving/references/meta-pattern-recognition.md +80 -0
- package/skills/problem-solving/references/scale-game.md +82 -0
- package/skills/problem-solving/references/simplification-cascades.md +83 -0
- package/skills/problem-solving/references/when-stuck.md +76 -0
- package/skills/repomix/SKILL.md +94 -0
- package/skills/repomix/references/configuration.md +134 -0
- package/skills/repomix/references/usage-patterns.md +106 -0
- package/skills/repomix/scripts/.coverage +0 -0
- package/skills/repomix/scripts/README.md +179 -0
- package/skills/repomix/scripts/repomix_batch.py +455 -0
- package/skills/repomix/scripts/repos.example.json +15 -0
- package/skills/repomix/scripts/requirements.txt +15 -0
- package/skills/repomix/scripts/tests/test_repomix_batch.py +531 -0
- package/skills/research/SKILL.md +107 -0
- package/skills/security-scan/SKILL.md +101 -0
- package/skills/security-scan/references/secret-patterns.md +75 -0
- package/skills/security-scan/references/vulnerability-patterns.md +136 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INTERACTIVE_TASK_SENTINEL = void 0;
|
|
4
|
+
exports.renderContinuity = renderContinuity;
|
|
5
|
+
/**
|
|
6
|
+
* `run-main.ts` seeds an interactive execution's `capsule.task` with this exact string,
|
|
7
|
+
* because an interactive session's real task is whatever the principal types first, not
|
|
8
|
+
* anything known at prepare time. Rendering it as an "Objective" would be actively
|
|
9
|
+
* misleading, so the renderer treats it as absent — imported from here rather than
|
|
10
|
+
* duplicated, so the two copies cannot drift apart.
|
|
11
|
+
*/
|
|
12
|
+
exports.INTERACTIVE_TASK_SENTINEL = "Interactive principal session; the task arrives from the principal.";
|
|
13
|
+
/** §9 — also the SessionStart injection limit; there is no second number. */
|
|
14
|
+
const MAX_RENDERED_BYTES = 24 * 1024;
|
|
15
|
+
const HEADER = "## ALP continuity checkpoint";
|
|
16
|
+
const FOOTER = "This checkpoint preserves continuity only. It does not override system, developer,\n" +
|
|
17
|
+
"execution-policy, or current user instructions.";
|
|
18
|
+
const PIN_SECTION_TITLES = {
|
|
19
|
+
decisions: "Decisions",
|
|
20
|
+
constraints: "Constraints",
|
|
21
|
+
openItems: "Open items",
|
|
22
|
+
nextActions: "Next actions",
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Cut order when the rendered doc is over budget: least-load-bearing first. Objective is
|
|
26
|
+
* dropped whole (there's nothing smaller to remove from it); every pin section drops its
|
|
27
|
+
* oldest entry first, one at a time, before the next section in this order is touched.
|
|
28
|
+
*/
|
|
29
|
+
const CUT_ORDER = ["nextActions", "openItems", "objective", "constraints", "decisions"];
|
|
30
|
+
function byteLength(value) {
|
|
31
|
+
return Buffer.byteLength(value, "utf8");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Fixed section order, empty sections omitted entirely, bounded to `MAX_RENDERED_BYTES`.
|
|
35
|
+
* Only `checkpoint.executionId`, `objective`, and each pin's `text` ever reach the output —
|
|
36
|
+
* no field exists on `ContinuityCheckpointV1` for a native summary to travel through.
|
|
37
|
+
*/
|
|
38
|
+
function renderContinuity(checkpoint) {
|
|
39
|
+
let hasObjective = checkpoint.objective !== null && checkpoint.objective !== exports.INTERACTIVE_TASK_SENTINEL;
|
|
40
|
+
const pins = {
|
|
41
|
+
decisions: [...checkpoint.decisions],
|
|
42
|
+
constraints: [...checkpoint.constraints],
|
|
43
|
+
openItems: [...checkpoint.openItems],
|
|
44
|
+
nextActions: [...checkpoint.nextActions],
|
|
45
|
+
};
|
|
46
|
+
function build() {
|
|
47
|
+
const sections = [];
|
|
48
|
+
if (hasObjective)
|
|
49
|
+
sections.push(`### Objective\n${checkpoint.objective}`);
|
|
50
|
+
for (const key of ["decisions", "constraints", "openItems", "nextActions"]) {
|
|
51
|
+
const list = pins[key];
|
|
52
|
+
if (list.length > 0)
|
|
53
|
+
sections.push(`### ${PIN_SECTION_TITLES[key]}\n${list.map((pin) => `- ${pin.text}`).join("\n")}`);
|
|
54
|
+
}
|
|
55
|
+
if (sections.length === 0)
|
|
56
|
+
return "";
|
|
57
|
+
return `${[HEADER, "", `Execution: \`${checkpoint.executionId}\``, "", sections.join("\n\n"), "", FOOTER].join("\n")}\n`;
|
|
58
|
+
}
|
|
59
|
+
let guard = 0;
|
|
60
|
+
while (byteLength(build()) > MAX_RENDERED_BYTES && guard++ < 10_000) {
|
|
61
|
+
const cut = CUT_ORDER.find((key) => (key === "objective" ? hasObjective : pins[key].length > 0));
|
|
62
|
+
if (cut === undefined)
|
|
63
|
+
break;
|
|
64
|
+
if (cut === "objective")
|
|
65
|
+
hasObjective = false;
|
|
66
|
+
else
|
|
67
|
+
pins[cut].shift();
|
|
68
|
+
}
|
|
69
|
+
return build();
|
|
70
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackendRegistry = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
const REQUIRED_METHODS = [
|
|
6
|
+
"healthCheck",
|
|
7
|
+
"spawn",
|
|
8
|
+
"status",
|
|
9
|
+
"wait",
|
|
10
|
+
"cancel",
|
|
11
|
+
"cleanup",
|
|
12
|
+
];
|
|
13
|
+
class BackendRegistry {
|
|
14
|
+
backends = new Map();
|
|
15
|
+
register(backend) {
|
|
16
|
+
if (!backend.name.trim())
|
|
17
|
+
throw new types_1.DelegationError("INVALID_REQUEST", "backend name cannot be empty");
|
|
18
|
+
if (this.backends.has(backend.name)) {
|
|
19
|
+
throw new types_1.DelegationError("INVALID_REQUEST", `backend \`${backend.name}\` is already registered`);
|
|
20
|
+
}
|
|
21
|
+
for (const method of REQUIRED_METHODS) {
|
|
22
|
+
if (typeof backend[method] !== "function") {
|
|
23
|
+
throw new types_1.DelegationError("INVALID_REQUEST", `backend \`${backend.name}\` is missing ${method}()`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
this.backends.set(backend.name, backend);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
resolve(name) {
|
|
30
|
+
const backend = this.backends.get(name);
|
|
31
|
+
if (!backend) {
|
|
32
|
+
throw new types_1.DelegationError("BACKEND_UNAVAILABLE", `backend \`${name}\` is not registered (available: ${this.names().join(", ") || "none"})`);
|
|
33
|
+
}
|
|
34
|
+
return backend;
|
|
35
|
+
}
|
|
36
|
+
names() {
|
|
37
|
+
return Object.freeze([...this.backends.keys()]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.BackendRegistry = BackendRegistry;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DelegationService = exports.FileDelegationExecutionStore = exports.InMemoryDelegationExecutionStore = void 0;
|
|
4
|
+
const modes_1 = require("../agents/modes");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const types_1 = require("./types");
|
|
10
|
+
function defaultIds() {
|
|
11
|
+
return {
|
|
12
|
+
request: () => `req_${(0, node_crypto_1.randomUUID)().replaceAll("-", "").slice(0, 20)}`,
|
|
13
|
+
execution: () => `exec_${(0, node_crypto_1.randomUUID)().replaceAll("-", "").slice(0, 20)}`,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function normalizeRequest(input, ids) {
|
|
17
|
+
for (const [name, value] of [
|
|
18
|
+
["parentRole", input?.parentRole],
|
|
19
|
+
["targetRole", input?.targetRole],
|
|
20
|
+
["task", input?.task],
|
|
21
|
+
["workspace", input?.workspace],
|
|
22
|
+
]) {
|
|
23
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
24
|
+
throw new types_1.DelegationError("INVALID_REQUEST", `delegation request requires ${name}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const timeoutMs = input.executionOptions?.timeoutMs ?? null;
|
|
28
|
+
if (timeoutMs !== null && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {
|
|
29
|
+
throw new types_1.DelegationError("INVALID_REQUEST", "timeoutMs must be positive");
|
|
30
|
+
}
|
|
31
|
+
return Object.freeze({
|
|
32
|
+
requestId: input.requestId?.trim() || ids.request(),
|
|
33
|
+
parentRole: input.parentRole.trim(),
|
|
34
|
+
parentExecutionId: input.parentExecutionId?.trim() || null,
|
|
35
|
+
targetRole: input.targetRole.trim(),
|
|
36
|
+
task: input.task.trim(),
|
|
37
|
+
workspace: input.workspace,
|
|
38
|
+
workspaceMode: input.workspaceMode ?? "read-only",
|
|
39
|
+
metadata: Object.freeze({ ...(input.metadata ?? {}) }),
|
|
40
|
+
executionOptions: Object.freeze({
|
|
41
|
+
background: Boolean(input.executionOptions?.background),
|
|
42
|
+
interactive: Boolean(input.executionOptions?.interactive),
|
|
43
|
+
timeoutMs,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async function removeTemporaryFiles(spec) {
|
|
48
|
+
await Promise.all(spec.temporaryFiles.map((file) => (0, promises_1.rm)(file, { force: true })));
|
|
49
|
+
}
|
|
50
|
+
class InMemoryDelegationExecutionStore {
|
|
51
|
+
records = new Map();
|
|
52
|
+
put(record) {
|
|
53
|
+
if (this.records.has(record.executionId))
|
|
54
|
+
throw new Error(`duplicate execution \`${record.executionId}\``);
|
|
55
|
+
this.records.set(record.executionId, Object.freeze({ ...record }));
|
|
56
|
+
}
|
|
57
|
+
get(executionId) {
|
|
58
|
+
return this.records.get(executionId) ?? null;
|
|
59
|
+
}
|
|
60
|
+
update(executionId, patch) {
|
|
61
|
+
const current = this.records.get(executionId);
|
|
62
|
+
if (!current)
|
|
63
|
+
throw new types_1.DelegationError("EXECUTION_NOT_FOUND", `execution \`${executionId}\` does not exist`);
|
|
64
|
+
this.records.set(executionId, Object.freeze({ ...current, ...patch }));
|
|
65
|
+
}
|
|
66
|
+
list() {
|
|
67
|
+
return Object.freeze([...this.records.values()]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.InMemoryDelegationExecutionStore = InMemoryDelegationExecutionStore;
|
|
71
|
+
class FileDelegationExecutionStore {
|
|
72
|
+
file;
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.file = options.file;
|
|
75
|
+
}
|
|
76
|
+
put(record) {
|
|
77
|
+
const records = this.read();
|
|
78
|
+
if (records.some((entry) => entry.executionId === record.executionId)) {
|
|
79
|
+
throw new Error(`duplicate execution \`${record.executionId}\``);
|
|
80
|
+
}
|
|
81
|
+
records.push(Object.freeze({ ...record }));
|
|
82
|
+
this.write(records);
|
|
83
|
+
}
|
|
84
|
+
get(executionId) {
|
|
85
|
+
return this.read().find((record) => record.executionId === executionId) ?? null;
|
|
86
|
+
}
|
|
87
|
+
update(executionId, patch) {
|
|
88
|
+
const records = this.read();
|
|
89
|
+
const index = records.findIndex((record) => record.executionId === executionId);
|
|
90
|
+
if (index < 0)
|
|
91
|
+
throw new types_1.DelegationError("EXECUTION_NOT_FOUND", `execution \`${executionId}\` does not exist`);
|
|
92
|
+
records[index] = Object.freeze({ ...records[index], ...patch });
|
|
93
|
+
this.write(records);
|
|
94
|
+
}
|
|
95
|
+
list() {
|
|
96
|
+
return Object.freeze(this.read());
|
|
97
|
+
}
|
|
98
|
+
read() {
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(this.file, "utf8"));
|
|
101
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.executions))
|
|
102
|
+
throw new Error("invalid delegation execution store");
|
|
103
|
+
return parsed.executions.map((record) => Object.freeze({ ...record }));
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error.code === "ENOENT")
|
|
107
|
+
return [];
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
write(records) {
|
|
112
|
+
const directory = (0, node_path_1.dirname)(this.file);
|
|
113
|
+
(0, node_fs_1.mkdirSync)(directory, { recursive: true, mode: 0o700 });
|
|
114
|
+
(0, node_fs_1.chmodSync)(directory, 0o700);
|
|
115
|
+
const temporary = (0, node_path_1.join)(directory, `.${(0, node_crypto_1.randomUUID)()}.executions.tmp`);
|
|
116
|
+
try {
|
|
117
|
+
(0, node_fs_1.writeFileSync)(temporary, `${JSON.stringify({ version: 1, executions: records }, null, 2)}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
118
|
+
(0, node_fs_1.renameSync)(temporary, this.file);
|
|
119
|
+
(0, node_fs_1.chmodSync)(this.file, 0o600);
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
(0, node_fs_1.rmSync)(temporary, { force: true });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.FileDelegationExecutionStore = FileDelegationExecutionStore;
|
|
127
|
+
class DelegationService {
|
|
128
|
+
config;
|
|
129
|
+
registry;
|
|
130
|
+
policy;
|
|
131
|
+
memory;
|
|
132
|
+
executionService;
|
|
133
|
+
runtimeAdapters;
|
|
134
|
+
backend;
|
|
135
|
+
executionStore;
|
|
136
|
+
ids;
|
|
137
|
+
now;
|
|
138
|
+
constructor(options) {
|
|
139
|
+
this.registry = options.registry;
|
|
140
|
+
this.policy = options.policy;
|
|
141
|
+
this.memory = options.memory;
|
|
142
|
+
this.executionService = options.executionService;
|
|
143
|
+
this.runtimeAdapters = options.runtimeAdapters;
|
|
144
|
+
this.backend = options.backend;
|
|
145
|
+
this.executionStore = options.executionStore;
|
|
146
|
+
this.config = options.config;
|
|
147
|
+
this.ids = options.ids ?? defaultIds();
|
|
148
|
+
this.now = options.now ?? (() => new Date());
|
|
149
|
+
}
|
|
150
|
+
async prepare(input) {
|
|
151
|
+
const request = normalizeRequest(input, this.ids);
|
|
152
|
+
const executionId = this.ids.execution();
|
|
153
|
+
// ExecutionService owns the deny-first ordering and is deliberately invoked before
|
|
154
|
+
// runtime lookup, backend health, launch translation, or execution tracking.
|
|
155
|
+
const execution = await this.executionService.prepare({
|
|
156
|
+
executionId,
|
|
157
|
+
parent: request.parentRole,
|
|
158
|
+
target: request.targetRole,
|
|
159
|
+
task: request.task,
|
|
160
|
+
workspace: request.workspace,
|
|
161
|
+
workspaceMode: request.workspaceMode,
|
|
162
|
+
...(this.config.mode === undefined ? {} : { mode: this.config.mode }),
|
|
163
|
+
memoryQueries: [],
|
|
164
|
+
characterBudget: 0,
|
|
165
|
+
invariantContext: "ALP execution policy is authoritative and fails closed.",
|
|
166
|
+
policyContext: "Use only the tools and workspace granted by the immutable execution snapshot.",
|
|
167
|
+
});
|
|
168
|
+
void this.policy;
|
|
169
|
+
void this.memory;
|
|
170
|
+
const definition = this.registry.get(request.targetRole);
|
|
171
|
+
const mode = this.config.mode ?? modes_1.DEFAULT_MODE;
|
|
172
|
+
// Nấc ghim một model cho vai đích, và model quyết định CLI — không còn ai chọn runtime
|
|
173
|
+
// rồi mới tra model, nên một nấc có thể phóng hai CLI khác nhau cho hai vai khác nhau.
|
|
174
|
+
const runtime = (0, modes_1.runtimeForMode)(definition, mode);
|
|
175
|
+
const adapter = this.runtimeAdapters.get(runtime);
|
|
176
|
+
if (!adapter) {
|
|
177
|
+
throw new types_1.DelegationError("RUNTIME_UNAVAILABLE", `runtime \`${runtime}\` is not registered`);
|
|
178
|
+
}
|
|
179
|
+
const launchSpec = await adapter.prepare({
|
|
180
|
+
execution,
|
|
181
|
+
model: (0, modes_1.modelForMode)(definition, mode),
|
|
182
|
+
reasoningEffort: (0, modes_1.reasoningEffortForMode)(definition, mode),
|
|
183
|
+
interactive: request.executionOptions.interactive,
|
|
184
|
+
});
|
|
185
|
+
return Object.freeze({ request, executionId, execution, runtime, launchSpec, backend: this.backend });
|
|
186
|
+
}
|
|
187
|
+
async delegate(input) {
|
|
188
|
+
const prepared = await this.prepare(input);
|
|
189
|
+
const { request, executionId, execution, runtime, launchSpec, backend } = prepared;
|
|
190
|
+
// Preconditions, after authorization and before the execution record exists. The backend
|
|
191
|
+
// registry used to health-check as part of picking a backend; with one backend there is
|
|
192
|
+
// nothing to pick, but the question it answered still needs asking — otherwise a machine
|
|
193
|
+
// with no runtime installed fails inside `spawn` as a bare ENOENT, and the execution is
|
|
194
|
+
// recorded as `failed` for a reason that names a path instead of the missing CLI.
|
|
195
|
+
const health = await backend.healthCheck();
|
|
196
|
+
if (!health.ok) {
|
|
197
|
+
await removeTemporaryFiles(launchSpec).catch(() => undefined);
|
|
198
|
+
throw new types_1.DelegationError("BACKEND_UNAVAILABLE", health.message);
|
|
199
|
+
}
|
|
200
|
+
this.executionStore.put({
|
|
201
|
+
executionId,
|
|
202
|
+
requestId: request.requestId,
|
|
203
|
+
parentExecutionId: request.parentExecutionId,
|
|
204
|
+
parentRole: request.parentRole,
|
|
205
|
+
targetRole: request.targetRole,
|
|
206
|
+
workspace: execution.policy.workspace,
|
|
207
|
+
runtime,
|
|
208
|
+
backend: backend.name,
|
|
209
|
+
createdAt: this.now().toISOString(),
|
|
210
|
+
status: "queued",
|
|
211
|
+
executionStateFile: execution.artifacts.stateFile,
|
|
212
|
+
});
|
|
213
|
+
try {
|
|
214
|
+
const spawned = await backend.spawn({
|
|
215
|
+
executionId,
|
|
216
|
+
launchSpec,
|
|
217
|
+
lifecycle: {
|
|
218
|
+
requestId: request.requestId,
|
|
219
|
+
parentExecutionId: request.parentExecutionId,
|
|
220
|
+
background: request.executionOptions.background,
|
|
221
|
+
interactive: request.executionOptions.interactive,
|
|
222
|
+
timeoutMs: request.executionOptions.timeoutMs,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
this.executionStore.update(executionId, { status: spawned.status });
|
|
226
|
+
return this.result(this.executionStore.get(executionId), spawned);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
this.executionStore.update(executionId, {
|
|
230
|
+
status: "failed",
|
|
231
|
+
error: error instanceof Error ? error.message : String(error),
|
|
232
|
+
});
|
|
233
|
+
await removeTemporaryFiles(launchSpec).catch(() => undefined);
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async status(executionId) {
|
|
238
|
+
const record = this.record(executionId);
|
|
239
|
+
const value = await this.backend.status(executionId);
|
|
240
|
+
const result = this.result(record, value);
|
|
241
|
+
this.executionStore.update(executionId, { status: result.status });
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
async wait(executionId, options = {}) {
|
|
245
|
+
const record = this.record(executionId);
|
|
246
|
+
const value = await this.backend.wait(executionId, options);
|
|
247
|
+
const result = this.result(record, value);
|
|
248
|
+
this.executionStore.update(executionId, { status: result.status });
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
async cancel(executionId) {
|
|
252
|
+
const record = this.record(executionId);
|
|
253
|
+
const value = await this.backend.cancel(executionId);
|
|
254
|
+
this.executionStore.update(executionId, { status: value.status });
|
|
255
|
+
return this.result(this.record(executionId), value);
|
|
256
|
+
}
|
|
257
|
+
async cleanup(executionId) {
|
|
258
|
+
const record = this.record(executionId);
|
|
259
|
+
await this.backend.cleanup(executionId);
|
|
260
|
+
return this.result(record, { executionId, status: record.status });
|
|
261
|
+
}
|
|
262
|
+
listExecutions() {
|
|
263
|
+
return this.executionStore.list();
|
|
264
|
+
}
|
|
265
|
+
record(executionId) {
|
|
266
|
+
const record = this.executionStore.get(executionId);
|
|
267
|
+
if (!record)
|
|
268
|
+
throw new types_1.DelegationError("EXECUTION_NOT_FOUND", `execution \`${executionId}\` does not exist`);
|
|
269
|
+
return record;
|
|
270
|
+
}
|
|
271
|
+
result(record, value) {
|
|
272
|
+
let status = value.status;
|
|
273
|
+
let output = value.output;
|
|
274
|
+
if (["completed", "failed", "cancelled"].includes(value.status) && record.executionStateFile) {
|
|
275
|
+
try {
|
|
276
|
+
const state = JSON.parse((0, node_fs_1.readFileSync)(record.executionStateFile, "utf8"));
|
|
277
|
+
if (["completed", "failed", "cancelled"].includes(String(state.status))) {
|
|
278
|
+
status = state.status;
|
|
279
|
+
}
|
|
280
|
+
// Roles answer in prose, so the common case is already a string. Wrapping it in
|
|
281
|
+
// JSON would hand the caller an escaped blob instead of the report.
|
|
282
|
+
if (state.output !== undefined) {
|
|
283
|
+
output = typeof state.output === "string" ? state.output : JSON.stringify(state.output);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch { /* backend result remains authoritative when state is unavailable */ }
|
|
287
|
+
}
|
|
288
|
+
return Object.freeze({
|
|
289
|
+
executionId: record.executionId,
|
|
290
|
+
requestId: record.requestId,
|
|
291
|
+
status,
|
|
292
|
+
...(output === undefined ? {} : { output }),
|
|
293
|
+
...(value.exitCode === undefined ? {} : { exitCode: value.exitCode }),
|
|
294
|
+
...(value.signal === undefined ? {} : { signal: value.signal }),
|
|
295
|
+
...(value.error === undefined ? {} : { error: value.error }),
|
|
296
|
+
metadata: Object.freeze({ ...(value.metadata ?? {}), backend: record.backend, runtime: record.runtime }),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
exports.DelegationService = DelegationService;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DelegationError = void 0;
|
|
4
|
+
class DelegationError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(code, message, options) {
|
|
7
|
+
super(message, options);
|
|
8
|
+
this.name = "DelegationError";
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.DelegationError = DelegationError;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashAgentDefinition = hashAgentDefinition;
|
|
4
|
+
exports.createExecutionPolicy = createExecutionPolicy;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const capability_catalog_1 = require("../agents/capability-catalog");
|
|
7
|
+
const modes_1 = require("../agents/modes");
|
|
8
|
+
const types_1 = require("../agents/types");
|
|
9
|
+
const types_2 = require("./types");
|
|
10
|
+
function canonicalize(value) {
|
|
11
|
+
if (typeof value === "function")
|
|
12
|
+
return value.toString();
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return value.map(canonicalize);
|
|
15
|
+
if (value !== null && typeof value === "object") {
|
|
16
|
+
return Object.fromEntries(Object.entries(value)
|
|
17
|
+
.filter(([, child]) => child !== undefined)
|
|
18
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
19
|
+
.map(([key, child]) => [key, canonicalize(child)]));
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function sha256(value) {
|
|
24
|
+
return (0, node_crypto_1.createHash)("sha256")
|
|
25
|
+
.update(JSON.stringify(canonicalize(value)))
|
|
26
|
+
.digest("hex");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The declared budget with one entry per runtime, present or not. Normalised in one place so
|
|
30
|
+
* the hash cannot move just because a definition spelled the same budget with a key missing
|
|
31
|
+
* rather than set to nothing.
|
|
32
|
+
*/
|
|
33
|
+
function declaredAutoCompactTokens(definition) {
|
|
34
|
+
return Object.fromEntries(types_1.RUNTIME_IDS.map((runtime) => [runtime, definition.autoCompactTokens?.[runtime] ?? null]));
|
|
35
|
+
}
|
|
36
|
+
function hashAgentDefinition(definition) {
|
|
37
|
+
return sha256({
|
|
38
|
+
id: definition.id,
|
|
39
|
+
displayName: definition.displayName,
|
|
40
|
+
model: definition.model,
|
|
41
|
+
reasoningEffort: definition.reasoningEffort,
|
|
42
|
+
reportsTo: definition.reportsTo,
|
|
43
|
+
delegatesTo: definition.delegatesTo,
|
|
44
|
+
capabilities: definition.capabilities,
|
|
45
|
+
autoCompactTokens: declaredAutoCompactTokens(definition),
|
|
46
|
+
instructions: definition.instructions,
|
|
47
|
+
workflow: definition.workflow,
|
|
48
|
+
output: {
|
|
49
|
+
name: definition.output.name,
|
|
50
|
+
schema: definition.output.schema,
|
|
51
|
+
validate: definition.output.validate,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function createExecutionPolicy(input) {
|
|
56
|
+
const definitionHash = hashAgentDefinition(input.definition);
|
|
57
|
+
const catalog = input.catalog ?? capability_catalog_1.capabilityCatalog;
|
|
58
|
+
const capabilities = input.definition.capabilities;
|
|
59
|
+
// Names were checked against this catalog at registry load; a miss here would mean the
|
|
60
|
+
// catalog changed underneath a definition, and an execution is not the place to find out.
|
|
61
|
+
const resolve = (kind, names, entries) => names.map((name) => {
|
|
62
|
+
const entry = entries[name];
|
|
63
|
+
if (entry === undefined) {
|
|
64
|
+
throw new Error(`unknown ${kind} \`${name}\` granted to \`${input.definition.id}\``);
|
|
65
|
+
}
|
|
66
|
+
return { name, ...entry };
|
|
67
|
+
});
|
|
68
|
+
const snapshot = {
|
|
69
|
+
executionId: input.executionId,
|
|
70
|
+
role: input.definition.id,
|
|
71
|
+
workspace: input.workspace,
|
|
72
|
+
workspaceMode: input.workspaceMode,
|
|
73
|
+
// Trong snapshot chứ không trong `definitionHash`: nấc là lựa chọn lúc phóng, không phải
|
|
74
|
+
// một vai khác. Definition không đổi, execution thì có.
|
|
75
|
+
mode: input.mode ?? modes_1.DEFAULT_MODE,
|
|
76
|
+
workspaceAccess: input.definition.capabilities.workspace.readRoots.length > 0
|
|
77
|
+
? "granted"
|
|
78
|
+
: "none",
|
|
79
|
+
allowedTools: [...capabilities.tools],
|
|
80
|
+
skills: [...capabilities.skills],
|
|
81
|
+
subagents: resolve("subagent", capabilities.subagents, catalog.subagents),
|
|
82
|
+
mcpServers: resolve("mcp server", capabilities.mcpServers, catalog.mcpServers),
|
|
83
|
+
autoCompactTokens: declaredAutoCompactTokens(input.definition),
|
|
84
|
+
memory: {
|
|
85
|
+
read: [...input.definition.capabilities.memory.read],
|
|
86
|
+
write: [...input.definition.capabilities.memory.write],
|
|
87
|
+
},
|
|
88
|
+
delegatesTo: [...input.definition.delegatesTo],
|
|
89
|
+
createdAt: input.createdAt,
|
|
90
|
+
definitionHash,
|
|
91
|
+
};
|
|
92
|
+
return (0, types_2.deepFreezeExecutionValue)({
|
|
93
|
+
...snapshot,
|
|
94
|
+
policyHash: sha256(snapshot),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExecutionService = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const checkpoint_1 = require("../context/checkpoint");
|
|
6
|
+
const continuity_1 = require("../context/continuity");
|
|
7
|
+
const adapter_files_1 = require("../runtime/adapter-files");
|
|
8
|
+
const execution_policy_1 = require("./execution-policy");
|
|
9
|
+
const identity_capsule_1 = require("./identity-capsule");
|
|
10
|
+
const types_1 = require("./types");
|
|
11
|
+
function requireAuthorization(kind, authorization) {
|
|
12
|
+
if (!authorization.allowed) {
|
|
13
|
+
throw new Error(`${kind} authorization failed (${authorization.code}): ${authorization.reason}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
class ExecutionService {
|
|
17
|
+
registry;
|
|
18
|
+
policy;
|
|
19
|
+
memory;
|
|
20
|
+
workflowRunner;
|
|
21
|
+
store;
|
|
22
|
+
resolveWorkspace;
|
|
23
|
+
now;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.registry = options.registry;
|
|
26
|
+
this.policy = options.policy;
|
|
27
|
+
this.memory = options.memory;
|
|
28
|
+
this.workflowRunner = options.workflowRunner;
|
|
29
|
+
this.store = options.store;
|
|
30
|
+
this.resolveWorkspace = options.resolveWorkspace ?? promises_1.realpath;
|
|
31
|
+
this.now = options.now ?? (() => new Date());
|
|
32
|
+
}
|
|
33
|
+
async prepare(input) {
|
|
34
|
+
let parent = input.parent;
|
|
35
|
+
if (parent !== "principal") {
|
|
36
|
+
parent = this.registry.get(parent).id;
|
|
37
|
+
}
|
|
38
|
+
const definition = this.registry.get(input.target);
|
|
39
|
+
if (parent === "principal") {
|
|
40
|
+
if (definition.reportsTo !== "principal") {
|
|
41
|
+
throw new Error(`delegation authorization failed: \`${definition.id}\` does not report to principal`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
requireAuthorization("delegation", this.policy.authorize({
|
|
46
|
+
type: "delegation",
|
|
47
|
+
actor: parent,
|
|
48
|
+
target: definition.id,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
const workspace = await this.resolveWorkspace(input.workspace);
|
|
52
|
+
// A role that declares no workspace root (read-thread, compaction, titling) reads memory,
|
|
53
|
+
// not the tree: there is no path for policy to authorize, and asking about one could only
|
|
54
|
+
// ever come back WORKSPACE_NOT_GRANTED — which is why those three could not be launched
|
|
55
|
+
// at all. A *write* request is still asked, because that is a grant they genuinely lack;
|
|
56
|
+
// the deny it returns is the right answer rather than an artefact of the question.
|
|
57
|
+
const grantsWorkspace = definition.capabilities.workspace.readRoots.length > 0;
|
|
58
|
+
if (grantsWorkspace || input.workspaceMode === "workspace-write") {
|
|
59
|
+
requireAuthorization("workspace", this.policy.authorize({
|
|
60
|
+
type: "workspace",
|
|
61
|
+
actor: definition.id,
|
|
62
|
+
operation: input.workspaceMode === "workspace-write" ? "write" : "read",
|
|
63
|
+
path: workspace,
|
|
64
|
+
execution: {
|
|
65
|
+
activeWorkspace: workspace,
|
|
66
|
+
workspaceMode: input.workspaceMode,
|
|
67
|
+
delegated: parent !== "principal",
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
const memoryContext = await this.memory.buildContext({
|
|
72
|
+
actor: definition.id,
|
|
73
|
+
queries: input.memoryQueries,
|
|
74
|
+
characterBudget: input.characterBudget,
|
|
75
|
+
invariantContext: input.invariantContext,
|
|
76
|
+
policyContext: input.policyContext,
|
|
77
|
+
});
|
|
78
|
+
const workflowState = this.workflowRunner.initialize(definition.workflow);
|
|
79
|
+
const createdAt = this.now().toISOString();
|
|
80
|
+
const policy = (0, execution_policy_1.createExecutionPolicy)({
|
|
81
|
+
executionId: input.executionId,
|
|
82
|
+
definition,
|
|
83
|
+
workspace,
|
|
84
|
+
workspaceMode: input.workspaceMode,
|
|
85
|
+
...(input.mode === undefined ? {} : { mode: input.mode }),
|
|
86
|
+
createdAt,
|
|
87
|
+
});
|
|
88
|
+
const capsule = (0, identity_capsule_1.createIdentityCapsule)({
|
|
89
|
+
definition,
|
|
90
|
+
policy,
|
|
91
|
+
task: input.task,
|
|
92
|
+
memoryContext,
|
|
93
|
+
workflowState,
|
|
94
|
+
});
|
|
95
|
+
const state = (0, types_1.deepFreezeExecutionValue)({
|
|
96
|
+
executionId: input.executionId,
|
|
97
|
+
status: "prepared",
|
|
98
|
+
workflow: { ...workflowState },
|
|
99
|
+
policyHash: policy.policyHash,
|
|
100
|
+
createdAt,
|
|
101
|
+
});
|
|
102
|
+
const artifacts = await this.store.create({ policy, state });
|
|
103
|
+
// §8.1: seed the checkpoint here, not lazily on first pin, so a fresh execution's
|
|
104
|
+
// continuity is never empty by omission — the objective alone is worth reinjecting.
|
|
105
|
+
const checkpoint = await (0, checkpoint_1.writeCheckpoint)(artifacts.checkpointFile, (0, checkpoint_1.seedCheckpoint)({
|
|
106
|
+
executionId: input.executionId,
|
|
107
|
+
policyHash: policy.policyHash,
|
|
108
|
+
objective: capsule.task,
|
|
109
|
+
now: () => createdAt,
|
|
110
|
+
}));
|
|
111
|
+
await (0, adapter_files_1.atomicRuntimeFile)(artifacts.continuityFile, (0, continuity_1.renderContinuity)(checkpoint));
|
|
112
|
+
return (0, types_1.deepFreezeExecutionValue)({ capsule, policy, state, artifacts });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.ExecutionService = ExecutionService;
|