@lsctech/polaris 0.1.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/README.md +87 -0
- package/dist/__mocks__/tool-server-linear.js +34 -0
- package/dist/cli/adopt-approve.js +60 -0
- package/dist/cli/adopt-cognition.js +199 -0
- package/dist/cli/adopt-instructions.js +143 -0
- package/dist/cli/adopt-rules.js +169 -0
- package/dist/cli/adopt-scan.js +25 -0
- package/dist/cli/adopt-smartdocs.js +192 -0
- package/dist/cli/adoption-inventory.js +350 -0
- package/dist/cli/adoption-plan.js +222 -0
- package/dist/cli/args.js +28 -0
- package/dist/cli/args.test.js +30 -0
- package/dist/cli/branding.js +41 -0
- package/dist/cli/graph.js +358 -0
- package/dist/cli/index.js +127 -0
- package/dist/cli/index.test.js +162 -0
- package/dist/cli/init-detect.js +61 -0
- package/dist/cli/init.js +492 -0
- package/dist/cli/init.test.js +259 -0
- package/dist/cli/librarian.js +32 -0
- package/dist/cli/medic.js +96 -0
- package/dist/cli/startup.test.js +23 -0
- package/dist/cli/tracker.js +130 -0
- package/dist/cli/tracker.test.js +126 -0
- package/dist/cli/version.js +10 -0
- package/dist/cli/version.test.js +11 -0
- package/dist/cli/worker.js +287 -0
- package/dist/cluster-state/fixtures/test-clusters.json +19 -0
- package/dist/cluster-state/store.js +302 -0
- package/dist/cluster-state/store.test.js +145 -0
- package/dist/cluster-state/types.js +2 -0
- package/dist/cognition/archive.js +158 -0
- package/dist/cognition/closeout-librarian-types.js +161 -0
- package/dist/cognition/cognition.test.js +623 -0
- package/dist/cognition/index.js +41 -0
- package/dist/cognition/librarian-dispatch.js +391 -0
- package/dist/cognition/librarian-dispatch.test.js +247 -0
- package/dist/cognition/librarian-packet.js +313 -0
- package/dist/cognition/librarian-types.js +57 -0
- package/dist/cognition/route-cognition-delta.js +350 -0
- package/dist/cognition/summary-delta.js +279 -0
- package/dist/cognition/validate.js +162 -0
- package/dist/config/defaults.js +98 -0
- package/dist/config/doctor.js +273 -0
- package/dist/config/index.js +14 -0
- package/dist/config/loader.js +58 -0
- package/dist/config/provider-detect.js +60 -0
- package/dist/config/provider-detect.test.js +119 -0
- package/dist/config/schema.js +2 -0
- package/dist/config/show.js +44 -0
- package/dist/config/show.test.js +42 -0
- package/dist/config/validator.js +675 -0
- package/dist/config/validator.test.js +77 -0
- package/dist/docs/canon-check.js +334 -0
- package/dist/docs/canon-check.test.js +207 -0
- package/dist/docs/doctrine.js +133 -0
- package/dist/docs/doctrine.test.js +139 -0
- package/dist/docs/index.js +168 -0
- package/dist/docs/index.test.js +83 -0
- package/dist/docs/ingest.js +295 -0
- package/dist/docs/ingest.test.js +71 -0
- package/dist/docs/migrate.js +165 -0
- package/dist/docs/migrate.test.js +136 -0
- package/dist/docs/seed-instructions.js +147 -0
- package/dist/docs/seed-instructions.test.js +137 -0
- package/dist/docs/validate-instructions.js +267 -0
- package/dist/docs/validate-instructions.test.js +238 -0
- package/dist/finalize/artifact-policy.js +214 -0
- package/dist/finalize/artifact-policy.test.js +84 -0
- package/dist/finalize/delivery-integrity.js +141 -0
- package/dist/finalize/finalize.test.js +210 -0
- package/dist/finalize/github.js +41 -0
- package/dist/finalize/index.js +474 -0
- package/dist/finalize/linear.js +213 -0
- package/dist/finalize/run-report.js +47 -0
- package/dist/finalize/steps/01-map-update.js +11 -0
- package/dist/finalize/steps/02-map-validate.js +11 -0
- package/dist/finalize/steps/03-schema-validate.js +11 -0
- package/dist/finalize/steps/04-run-checks.js +118 -0
- package/dist/finalize/steps/05-generate-report.js +14 -0
- package/dist/finalize/steps/06-commit.js +39 -0
- package/dist/finalize/steps/07-push.js +10 -0
- package/dist/finalize/steps/08-create-pr.js +9 -0
- package/dist/finalize/steps/09-update-state.js +9 -0
- package/dist/finalize/steps/10-append-jsonl.js +23 -0
- package/dist/finalize/steps/11-update-linear.js +22 -0
- package/dist/finalize/steps/12-archive.js +21 -0
- package/dist/graph/adapter/c/adapter.js +45 -0
- package/dist/graph/adapter/c/extract.js +135 -0
- package/dist/graph/adapter/c/index.js +10 -0
- package/dist/graph/adapter/c/runtime.js +67 -0
- package/dist/graph/adapter/cpp/adapter.js +45 -0
- package/dist/graph/adapter/cpp/extract.js +159 -0
- package/dist/graph/adapter/cpp/index.js +10 -0
- package/dist/graph/adapter/cpp/runtime.js +61 -0
- package/dist/graph/adapter/csharp/adapter.js +45 -0
- package/dist/graph/adapter/csharp/extract.js +127 -0
- package/dist/graph/adapter/csharp/index.js +10 -0
- package/dist/graph/adapter/csharp/runtime.js +61 -0
- package/dist/graph/adapter/dart/adapter.js +56 -0
- package/dist/graph/adapter/dart/extract.js +130 -0
- package/dist/graph/adapter/dart/index.js +10 -0
- package/dist/graph/adapter/dart/runtime.js +61 -0
- package/dist/graph/adapter/go/adapter.js +45 -0
- package/dist/graph/adapter/go/extract.js +112 -0
- package/dist/graph/adapter/go/index.js +10 -0
- package/dist/graph/adapter/go/runtime.js +58 -0
- package/dist/graph/adapter/kotlin-java/extract-common.js +83 -0
- package/dist/graph/adapter/kotlin-java/index.js +15 -0
- package/dist/graph/adapter/kotlin-java/java-adapter.js +45 -0
- package/dist/graph/adapter/kotlin-java/java-extract.js +42 -0
- package/dist/graph/adapter/kotlin-java/kotlin-adapter.js +48 -0
- package/dist/graph/adapter/kotlin-java/kotlin-extract.js +58 -0
- package/dist/graph/adapter/kotlin-java/runtime.js +75 -0
- package/dist/graph/adapter/python/adapter.js +45 -0
- package/dist/graph/adapter/python/extract.js +121 -0
- package/dist/graph/adapter/python/index.js +10 -0
- package/dist/graph/adapter/python/runtime.js +70 -0
- package/dist/graph/adapter/registry.js +82 -0
- package/dist/graph/adapter/rust/adapter.js +45 -0
- package/dist/graph/adapter/rust/extract.js +110 -0
- package/dist/graph/adapter/rust/index.js +10 -0
- package/dist/graph/adapter/rust/runtime.js +74 -0
- package/dist/graph/adapter/shell/adapter.js +34 -0
- package/dist/graph/adapter/shell/extract.js +98 -0
- package/dist/graph/adapter/shell/index.js +8 -0
- package/dist/graph/adapter/svelte/adapter.js +91 -0
- package/dist/graph/adapter/svelte/extract.js +41 -0
- package/dist/graph/adapter/svelte/index.js +8 -0
- package/dist/graph/adapter/swift/adapter.js +45 -0
- package/dist/graph/adapter/swift/extract.js +120 -0
- package/dist/graph/adapter/swift/index.js +10 -0
- package/dist/graph/adapter/swift/runtime.js +70 -0
- package/dist/graph/adapter/types.js +2 -0
- package/dist/graph/adapter/typescript-javascript/adapter.js +72 -0
- package/dist/graph/adapter/typescript-javascript/extract.js +115 -0
- package/dist/graph/adapter/typescript-javascript/index.js +10 -0
- package/dist/graph/adapter/typescript-javascript/runtime.js +97 -0
- package/dist/graph/capability/index.js +105 -0
- package/dist/graph/governance.js +104 -0
- package/dist/graph/parser/extract.js +5 -0
- package/dist/graph/parser/loader.js +2 -0
- package/dist/graph/parser/pipeline.js +194 -0
- package/dist/graph/query/index.js +277 -0
- package/dist/graph/query/types.js +5 -0
- package/dist/graph/resolver/build-edges.js +211 -0
- package/dist/graph/resolver/index.js +23 -0
- package/dist/graph/resolver/resolve-imports.js +168 -0
- package/dist/graph/store/adapter.js +132 -0
- package/dist/graph/store/queries.js +124 -0
- package/dist/graph/store/types.js +4 -0
- package/dist/ignore/defaults.js +41 -0
- package/dist/ignore/parser.js +39 -0
- package/dist/lint/map-reference-validator.js +72 -0
- package/dist/loop/abort.js +188 -0
- package/dist/loop/abort.test.js +151 -0
- package/dist/loop/adapters/__tests__/terminal-cli.test.js +92 -0
- package/dist/loop/adapters/agent-subtask.js +137 -0
- package/dist/loop/adapters/agent-subtask.test.js +151 -0
- package/dist/loop/adapters/cli-subtask-bridge.js +108 -0
- package/dist/loop/adapters/index.js +9 -0
- package/dist/loop/adapters/registry.js +17 -0
- package/dist/loop/adapters/terminal-cli.js +403 -0
- package/dist/loop/adapters/types.js +2 -0
- package/dist/loop/adapters/worker-instructions.js +85 -0
- package/dist/loop/body-parser.js +226 -0
- package/dist/loop/bootstrap-packet.js +97 -0
- package/dist/loop/bootstrap-packet.test.js +171 -0
- package/dist/loop/branch-governance.js +54 -0
- package/dist/loop/budget.js +63 -0
- package/dist/loop/budget.test.js +163 -0
- package/dist/loop/checkpoint.js +325 -0
- package/dist/loop/compact-return.js +59 -0
- package/dist/loop/continue.js +645 -0
- package/dist/loop/continue.test.js +337 -0
- package/dist/loop/dispatch-boundary.js +335 -0
- package/dist/loop/dispatch-state.js +223 -0
- package/dist/loop/dispatch-state.test.js +186 -0
- package/dist/loop/dispatch.js +1236 -0
- package/dist/loop/dispatch.test.js +499 -0
- package/dist/loop/ephemeral-smoke.test.js +160 -0
- package/dist/loop/evidence-backfill.js +216 -0
- package/dist/loop/execution-adapter.js +141 -0
- package/dist/loop/execution-adapter.test.js +66 -0
- package/dist/loop/finalize-evidence.js +169 -0
- package/dist/loop/git-custody.js +250 -0
- package/dist/loop/impl-packet-input.js +38 -0
- package/dist/loop/index.js +270 -0
- package/dist/loop/ledger.js +49 -0
- package/dist/loop/ledger.test.js +127 -0
- package/dist/loop/lifecycle-dispatch.js +348 -0
- package/dist/loop/lifecycle-dispatch.test.js +318 -0
- package/dist/loop/lifecycle.js +93 -0
- package/dist/loop/lifecycle.test.js +150 -0
- package/dist/loop/orphan-recovery.js +276 -0
- package/dist/loop/orphan-recovery.test.js +236 -0
- package/dist/loop/parent.js +1566 -0
- package/dist/loop/parent.test.js +738 -0
- package/dist/loop/provider-sealed-packet.test.js +164 -0
- package/dist/loop/resume.js +295 -0
- package/dist/loop/resume.test.js +172 -0
- package/dist/loop/run-bootstrap.js +234 -0
- package/dist/loop/run-preflight.js +203 -0
- package/dist/loop/status.js +665 -0
- package/dist/loop/status.test.js +235 -0
- package/dist/loop/wait.js +86 -0
- package/dist/loop/worker-packet.js +406 -0
- package/dist/loop/worker-packet.test.js +243 -0
- package/dist/loop/worker-prompt.js +260 -0
- package/dist/loop/worker-prompt.test.js +247 -0
- package/dist/loop/worker.js +498 -0
- package/dist/loop/worker.test.js +372 -0
- package/dist/map/atlas.js +77 -0
- package/dist/map/backfill.js +171 -0
- package/dist/map/backfill.test.js +120 -0
- package/dist/map/index.js +255 -0
- package/dist/map/inference.js +73 -0
- package/dist/map/inference.test.js +35 -0
- package/dist/map/query.js +157 -0
- package/dist/map/query.test.js +174 -0
- package/dist/map/update.js +355 -0
- package/dist/map/update.test.js +67 -0
- package/dist/map/validate.js +153 -0
- package/dist/map/validate.test.js +90 -0
- package/dist/map/welfare.js +86 -0
- package/dist/mcp/lib/invoke.js +35 -0
- package/dist/mcp/lib/redact.js +24 -0
- package/dist/mcp/lib/redact.test.js +112 -0
- package/dist/mcp/lib/root.js +41 -0
- package/dist/mcp/lib/root.test.js +114 -0
- package/dist/mcp/server.js +15 -0
- package/dist/mcp/tools/claim-child.js +119 -0
- package/dist/mcp/tools/claim-child.test.js +69 -0
- package/dist/mcp/tools/current-state.js +73 -0
- package/dist/mcp/tools/current-state.test.js +114 -0
- package/dist/mcp/tools/dispatch-result.js +186 -0
- package/dist/mcp/tools/dispatch-result.test.js +109 -0
- package/dist/mcp/tools/index.js +222 -0
- package/dist/mcp/tools/index.test.js +172 -0
- package/dist/mcp/tools/linear.js +74 -0
- package/dist/mcp/tools/loop-continue.js +159 -0
- package/dist/mcp/tools/loop-continue.test.js +186 -0
- package/dist/mcp/tools/loop-dry-run.js +15 -0
- package/dist/mcp/tools/status.js +65 -0
- package/dist/medic/chart-id.js +75 -0
- package/dist/medic/chart-schema.js +139 -0
- package/dist/runs/index.js +119 -0
- package/dist/runs/index.test.js +184 -0
- package/dist/runs/ledger-tail.js +15 -0
- package/dist/runs/list.js +29 -0
- package/dist/runs/reconcile.js +74 -0
- package/dist/runs/show.js +10 -0
- package/dist/runtime/audit/logger.js +15 -0
- package/dist/runtime/audit/reader.js +42 -0
- package/dist/runtime/checkpoint.js +89 -0
- package/dist/runtime/continuation/confirmed.js +225 -0
- package/dist/runtime/continuation/confirmed.test.js +421 -0
- package/dist/runtime/continuation/dry-run.js +74 -0
- package/dist/runtime/execution-window.js +106 -0
- package/dist/runtime/scheduling/child-selector.js +16 -0
- package/dist/runtime/state.js +43 -0
- package/dist/runtime/status.js +46 -0
- package/dist/runtime/verification/envelope.js +80 -0
- package/dist/runtime/verification/fingerprint.js +26 -0
- package/dist/skill-packet/cli.test.js +105 -0
- package/dist/skill-packet/generator.js +225 -0
- package/dist/skill-packet/generator.test.js +159 -0
- package/dist/skill-packet/index.js +49 -0
- package/dist/skill-packet/types.js +2 -0
- package/dist/smartdocs-engine/audit.js +194 -0
- package/dist/smartdocs-engine/audit.test.js +122 -0
- package/dist/smartdocs-engine/canon-check.js +340 -0
- package/dist/smartdocs-engine/canon-check.test.js +234 -0
- package/dist/smartdocs-engine/doctrine.js +633 -0
- package/dist/smartdocs-engine/doctrine.test.js +374 -0
- package/dist/smartdocs-engine/index.js +456 -0
- package/dist/smartdocs-engine/index.test.js +82 -0
- package/dist/smartdocs-engine/ingest.js +495 -0
- package/dist/smartdocs-engine/ingest.test.js +163 -0
- package/dist/smartdocs-engine/migrate.js +217 -0
- package/dist/smartdocs-engine/migrate.test.js +200 -0
- package/dist/smartdocs-engine/seed-instructions.js +335 -0
- package/dist/smartdocs-engine/seed-instructions.test.js +275 -0
- package/dist/smartdocs-engine/smartdoc-ignore.js +258 -0
- package/dist/smartdocs-engine/smartdoc-ignore.test.js +146 -0
- package/dist/smartdocs-engine/validate-instructions.js +366 -0
- package/dist/smartdocs-engine/validate-instructions.test.js +283 -0
- package/dist/tracker/adapters/github/index.js +305 -0
- package/dist/tracker/adapters/jira/index.js +293 -0
- package/dist/tracker/adapters/linear/http-errors.test.js +51 -0
- package/dist/tracker/adapters/linear/index.js +621 -0
- package/dist/tracker/adapters/linear/index.test.js +238 -0
- package/dist/tracker/adapters/linear.js +50 -0
- package/dist/tracker/adapters/local/index.js +10 -0
- package/dist/tracker/adapters/local-file/index.js +159 -0
- package/dist/tracker/adapters/mcp-bridge.js +158 -0
- package/dist/tracker/adapters/mcp-bridge.test.js +12 -0
- package/dist/tracker/adapters/spec/index.js +146 -0
- package/dist/tracker/capabilities.js +2 -0
- package/dist/tracker/index.js +49 -0
- package/dist/tracker/lifecycle-policy.js +139 -0
- package/dist/tracker/lifecycle-transition.js +164 -0
- package/dist/tracker/local-graph.js +98 -0
- package/dist/tracker/migration.js +56 -0
- package/dist/tracker/schema.js +86 -0
- package/dist/tracker/sync/index.js +404 -0
- package/dist/tracker/sync/queue-store.js +95 -0
- package/dist/tracker/sync/queue-store.test.js +104 -0
- package/dist/tracker/types.js +11 -0
- package/dist/types/linear.js +3 -0
- package/dist/types/result-packet.js +12 -0
- package/dist/types/runtime-state.js +2 -0
- package/dist/types/work-contract.js +2 -0
- package/dist/utils/monotonic-timestamp.js +13 -0
- package/dist/utils/monotonic-timestamp.test.js +19 -0
- package/package.json +64 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeDryRun = executeDryRun;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const state_js_1 = require("../state.js");
|
|
6
|
+
const fingerprint_js_1 = require("../verification/fingerprint.js");
|
|
7
|
+
const child_selector_js_1 = require("../scheduling/child-selector.js");
|
|
8
|
+
const logger_js_1 = require("../audit/logger.js");
|
|
9
|
+
async function executeDryRun(request) {
|
|
10
|
+
const state = await (0, state_js_1.loadState)(request.artifact_dir);
|
|
11
|
+
if (state === null) {
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
rejection: {
|
|
15
|
+
reason: "run_not_found",
|
|
16
|
+
detail: `No state found in .taskchain_artifacts/${request.artifact_dir}`,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (state.status !== "running") {
|
|
21
|
+
return {
|
|
22
|
+
ok: false,
|
|
23
|
+
rejection: { reason: "run_not_continuable", expected: "running", actual: state.status },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const activeChild = state.active_child ?? "";
|
|
27
|
+
if (activeChild !== "") {
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
rejection: { reason: "concurrent_execution", detail: `active_child is set: ${activeChild}` },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (state.step_cursor !== request.expected_step_cursor) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
rejection: {
|
|
37
|
+
reason: "step_cursor_mismatch",
|
|
38
|
+
expected: request.expected_step_cursor,
|
|
39
|
+
actual: state.step_cursor ?? undefined,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const nextChild = (0, child_selector_js_1.selectNextChild)(state);
|
|
44
|
+
if (nextChild === null) {
|
|
45
|
+
return { ok: false, rejection: { reason: "no_open_children" } };
|
|
46
|
+
}
|
|
47
|
+
// Nonce ties this fingerprint to a single approval issuance — prevents replay
|
|
48
|
+
const nonce = (0, node_crypto_1.randomUUID)();
|
|
49
|
+
const fingerprint = (0, fingerprint_js_1.computeStateFingerprint)({ state, approvalNonce: nonce });
|
|
50
|
+
await (0, logger_js_1.appendAuditEvent)(request.artifact_dir, {
|
|
51
|
+
event_type: "dry_run_executed",
|
|
52
|
+
run_id: state.run_id,
|
|
53
|
+
step_cursor: state.step_cursor ?? "",
|
|
54
|
+
operator: "mcp",
|
|
55
|
+
operation: "loop_continue_dry_run",
|
|
56
|
+
child_id: nextChild,
|
|
57
|
+
result: "preview",
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
ok: true,
|
|
61
|
+
preview: {
|
|
62
|
+
next_child: nextChild,
|
|
63
|
+
fingerprint,
|
|
64
|
+
approval_template: {
|
|
65
|
+
run_id: state.run_id,
|
|
66
|
+
expected_step_cursor: state.step_cursor ?? "",
|
|
67
|
+
fingerprint,
|
|
68
|
+
runtime_generation: state.runtime_generation ?? 0,
|
|
69
|
+
nonce,
|
|
70
|
+
requested_action: "loop_continue",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* execution-window.ts — Execution window support for Alice/Delegator
|
|
4
|
+
*
|
|
5
|
+
* Alice/Delegator compatibility principles:
|
|
6
|
+
*
|
|
7
|
+
* 1. Approval tokens must be provider-agnostic (no Alice-specific fields).
|
|
8
|
+
* ExecutionWindow carries only generic orchestration fields; Alice is one
|
|
9
|
+
* possible issuer, not the assumed issuer.
|
|
10
|
+
*
|
|
11
|
+
* 2. Dry-run contract must remain stable — Alice implements against it without
|
|
12
|
+
* version coupling. The shape of ExecutionWindow and WindowValidationResult
|
|
13
|
+
* must not change in a breaking way without a schema_version bump in the
|
|
14
|
+
* broader protocol.
|
|
15
|
+
*
|
|
16
|
+
* 3. Fingerprint must be deterministic — Alice can re-run the dry-run for the
|
|
17
|
+
* same state and obtain the same fingerprint. This is guaranteed by
|
|
18
|
+
* computeStateFingerprint in src/runtime/verification/fingerprint.ts.
|
|
19
|
+
*
|
|
20
|
+
* 4. Confirmations must be idempotent at protocol level — validateWindow is
|
|
21
|
+
* pure and side-effect-free; calling it multiple times for the same inputs
|
|
22
|
+
* yields the same result. Callers are responsible for persisting
|
|
23
|
+
* decremented windows exactly once.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.validateWindow = validateWindow;
|
|
27
|
+
exports.decrementWindow = decrementWindow;
|
|
28
|
+
/**
|
|
29
|
+
* Validates an ExecutionWindow against the current runtime state and
|
|
30
|
+
* fingerprint. All checks must pass for the result to be `{ ok: true }`.
|
|
31
|
+
*
|
|
32
|
+
* Checks performed (in order):
|
|
33
|
+
* 1. run_id_mismatch — window.run_id must equal state.run_id
|
|
34
|
+
* 2. window_not_yet_valid — valid_from must be in the past or now
|
|
35
|
+
* 3. window_expired — valid_until must be strictly in the future
|
|
36
|
+
* 4. window_exhausted — max_continuations must be > 0
|
|
37
|
+
* 5. state_fingerprint_drifted — currentFingerprint must exactly match
|
|
38
|
+
* window.state_fingerprint_at_issue
|
|
39
|
+
*
|
|
40
|
+
* Note: allowed_child_types is validated against the proposed continuation's
|
|
41
|
+
* child type once that information is threaded through to this call site.
|
|
42
|
+
* The field is intentionally included in ExecutionWindow now so that the
|
|
43
|
+
* protocol shape is stable when that check is wired in. Until then, a
|
|
44
|
+
* non-empty allowed_child_types list is accepted without failing — see
|
|
45
|
+
* the inline comment near the check location.
|
|
46
|
+
*/
|
|
47
|
+
function validateWindow(state, window, currentFingerprint) {
|
|
48
|
+
// 1. run_id must match
|
|
49
|
+
if (window.run_id !== state.run_id) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
reason: "run_id_mismatch",
|
|
53
|
+
detail: `window.run_id=${window.run_id} state.run_id=${state.run_id}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const now = new Date();
|
|
57
|
+
// 2. Window must have started
|
|
58
|
+
if (new Date(window.valid_from) > now) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
reason: "window_not_yet_valid",
|
|
62
|
+
detail: `valid_from=${window.valid_from} now=${now.toISOString()}`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// 3. Window must not have expired
|
|
66
|
+
if (new Date(window.valid_until) <= now) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
reason: "window_expired",
|
|
70
|
+
detail: `valid_until=${window.valid_until} now=${now.toISOString()}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// 4. Continuations remaining
|
|
74
|
+
if (window.max_continuations <= 0) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
reason: "window_exhausted",
|
|
78
|
+
detail: `max_continuations=${window.max_continuations}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// 5. Fingerprint must match exactly — no tolerance
|
|
82
|
+
if (currentFingerprint !== window.state_fingerprint_at_issue) {
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
reason: "state_fingerprint_drifted",
|
|
86
|
+
detail: `expected=${window.state_fingerprint_at_issue} got=${currentFingerprint}`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// allowed_child_types check deferred — child type not yet threaded through at call site.
|
|
90
|
+
// If allowed_child_types is non-empty, we skip the check rather than fail, because the
|
|
91
|
+
// child-type information is not yet available here. This preserves protocol shape for
|
|
92
|
+
// future wiring without blocking windows that specify allowed_child_types today.
|
|
93
|
+
return { ok: true };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns a new ExecutionWindow with max_continuations decremented by 1.
|
|
97
|
+
*
|
|
98
|
+
* Does NOT mutate the input window. The caller is responsible for persisting
|
|
99
|
+
* the returned window exactly once to ensure idempotency at the protocol level.
|
|
100
|
+
*/
|
|
101
|
+
function decrementWindow(window) {
|
|
102
|
+
return {
|
|
103
|
+
...window,
|
|
104
|
+
max_continuations: window.max_continuations - 1,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectNextChild = selectNextChild;
|
|
4
|
+
/**
|
|
5
|
+
* Select the next child to execute.
|
|
6
|
+
*
|
|
7
|
+
* TODO: TEMPORARY — lexical sort of issue IDs is a placeholder only.
|
|
8
|
+
* Real scheduling must come from runtime orchestration policy (priority,
|
|
9
|
+
* dependencies, cycle assignment, etc.). Do not treat this ordering as
|
|
10
|
+
* authoritative. Replace with a SchedulingService in a future cluster.
|
|
11
|
+
*/
|
|
12
|
+
function selectNextChild(state) {
|
|
13
|
+
if (state.open_children.length === 0)
|
|
14
|
+
return null;
|
|
15
|
+
return [...state.open_children].sort()[0] ?? null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getArtifactsDir = getArtifactsDir;
|
|
7
|
+
exports.getArtifactDir = getArtifactDir;
|
|
8
|
+
exports.getStateFilePath = getStateFilePath;
|
|
9
|
+
exports.loadState = loadState;
|
|
10
|
+
exports.writeState = writeState;
|
|
11
|
+
exports.listArtifactDirs = listArtifactDirs;
|
|
12
|
+
const promises_1 = require("node:fs/promises");
|
|
13
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
+
function getArtifactsDir() {
|
|
15
|
+
return node_path_1.default.join(process.cwd(), ".taskchain_artifacts");
|
|
16
|
+
}
|
|
17
|
+
function getArtifactDir(artifactDir) {
|
|
18
|
+
return node_path_1.default.join(getArtifactsDir(), artifactDir);
|
|
19
|
+
}
|
|
20
|
+
function getStateFilePath(artifactDir) {
|
|
21
|
+
return node_path_1.default.join(getArtifactDir(artifactDir), "current-state.json");
|
|
22
|
+
}
|
|
23
|
+
async function loadState(artifactDir) {
|
|
24
|
+
try {
|
|
25
|
+
const raw = await (0, promises_1.readFile)(getStateFilePath(artifactDir), "utf-8");
|
|
26
|
+
return JSON.parse(raw);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function writeState(artifactDir, state) {
|
|
33
|
+
await (0, promises_1.writeFile)(getStateFilePath(artifactDir), JSON.stringify(state, null, 2) + "\n", "utf-8");
|
|
34
|
+
}
|
|
35
|
+
async function listArtifactDirs() {
|
|
36
|
+
try {
|
|
37
|
+
const entries = await (0, promises_1.readdir)(getArtifactsDir(), { withFileTypes: true });
|
|
38
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOverallStatus = getOverallStatus;
|
|
4
|
+
exports.getLoopStatus = getLoopStatus;
|
|
5
|
+
exports.getCurrentState = getCurrentState;
|
|
6
|
+
const state_js_1 = require("./state.js");
|
|
7
|
+
async function getOverallStatus() {
|
|
8
|
+
const dirs = await (0, state_js_1.listArtifactDirs)();
|
|
9
|
+
const runs = await Promise.all(dirs.map(async (dir) => {
|
|
10
|
+
const state = await (0, state_js_1.loadState)(dir);
|
|
11
|
+
return state
|
|
12
|
+
? {
|
|
13
|
+
artifact_dir: dir,
|
|
14
|
+
run_id: state.run_id,
|
|
15
|
+
status: state.status,
|
|
16
|
+
step_cursor: state.step_cursor,
|
|
17
|
+
cluster_id: state.cluster_id,
|
|
18
|
+
open_children_count: state.open_children.length,
|
|
19
|
+
completed_children_count: state.completed_children.length,
|
|
20
|
+
}
|
|
21
|
+
: { artifact_dir: dir, status: "unreadable" };
|
|
22
|
+
}));
|
|
23
|
+
return { runs };
|
|
24
|
+
}
|
|
25
|
+
async function getLoopStatus(artifactDir) {
|
|
26
|
+
const state = await (0, state_js_1.loadState)(artifactDir);
|
|
27
|
+
if (!state)
|
|
28
|
+
return null;
|
|
29
|
+
return {
|
|
30
|
+
artifact_dir: artifactDir,
|
|
31
|
+
run_id: state.run_id,
|
|
32
|
+
cluster_id: state.cluster_id,
|
|
33
|
+
status: state.status,
|
|
34
|
+
step_cursor: state.step_cursor,
|
|
35
|
+
active_child: state.active_child,
|
|
36
|
+
open_children: state.open_children,
|
|
37
|
+
completed_children: state.completed_children,
|
|
38
|
+
context_budget: state.context_budget,
|
|
39
|
+
runtime_generation: state.runtime_generation,
|
|
40
|
+
orchestration_mode: state.orchestration_mode,
|
|
41
|
+
continuation_epoch: state.continuation_epoch,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async function getCurrentState(artifactDir) {
|
|
45
|
+
return (0, state_js_1.loadState)(artifactDir);
|
|
46
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateEnvelope = validateEnvelope;
|
|
4
|
+
const fingerprint_js_1 = require("./fingerprint.js");
|
|
5
|
+
const child_selector_js_1 = require("../scheduling/child-selector.js");
|
|
6
|
+
function validateEnvelope(state, envelope) {
|
|
7
|
+
if (envelope.requested_action !== "loop_continue") {
|
|
8
|
+
return {
|
|
9
|
+
ok: false,
|
|
10
|
+
failure: {
|
|
11
|
+
check: "requested_action",
|
|
12
|
+
reason: "unsupported_action",
|
|
13
|
+
expected: "loop_continue",
|
|
14
|
+
actual: envelope.requested_action,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (state.status !== "running") {
|
|
19
|
+
return {
|
|
20
|
+
ok: false,
|
|
21
|
+
failure: { check: "status", reason: "run_not_continuable", actual: state.status },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const activeChild = state.active_child ?? "";
|
|
25
|
+
if (activeChild !== "") {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
failure: { check: "active_child", reason: "concurrent_execution", actual: activeChild },
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (state.run_id !== envelope.run_id) {
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
failure: {
|
|
35
|
+
check: "run_id",
|
|
36
|
+
reason: "run_id_mismatch",
|
|
37
|
+
expected: envelope.run_id,
|
|
38
|
+
actual: state.run_id,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (state.step_cursor !== envelope.expected_step_cursor) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
failure: {
|
|
46
|
+
check: "step_cursor",
|
|
47
|
+
reason: "step_cursor_mismatch",
|
|
48
|
+
expected: envelope.expected_step_cursor,
|
|
49
|
+
actual: state.step_cursor,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const stateGeneration = state.runtime_generation ?? 0;
|
|
54
|
+
if (stateGeneration !== envelope.runtime_generation) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
failure: {
|
|
58
|
+
check: "runtime_generation",
|
|
59
|
+
reason: "runtime_generation_mismatch",
|
|
60
|
+
expected: String(envelope.runtime_generation),
|
|
61
|
+
actual: String(stateGeneration),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const currentFingerprint = (0, fingerprint_js_1.computeStateFingerprint)({ state, approvalNonce: envelope.nonce });
|
|
66
|
+
if (currentFingerprint !== envelope.fingerprint) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
failure: { check: "fingerprint", reason: "state_mutated_since_approval" },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const nextChild = (0, child_selector_js_1.selectNextChild)(state);
|
|
73
|
+
if (nextChild === null) {
|
|
74
|
+
return { ok: false, failure: { check: "next_child", reason: "no_open_children" } };
|
|
75
|
+
}
|
|
76
|
+
if (new Date(envelope.expires_at) <= new Date()) {
|
|
77
|
+
return { ok: false, failure: { check: "expires_at", reason: "approval_expired" } };
|
|
78
|
+
}
|
|
79
|
+
return { ok: true, next_child: nextChild };
|
|
80
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeStateFingerprint = computeStateFingerprint;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
/**
|
|
6
|
+
* Compute a replay-resistant state fingerprint.
|
|
7
|
+
*
|
|
8
|
+
* Scope includes all fields that must not change between dry-run issuance and
|
|
9
|
+
* confirmed continuation. The approval_nonce (when present) ties the fingerprint
|
|
10
|
+
* to a specific approval issuance, preventing pre-computation and replay attacks.
|
|
11
|
+
*/
|
|
12
|
+
function computeStateFingerprint({ state, approvalNonce }) {
|
|
13
|
+
const canonical = JSON.stringify({
|
|
14
|
+
schema_version: state.schema_version,
|
|
15
|
+
runtime_generation: state.runtime_generation ?? 0,
|
|
16
|
+
run_id: state.run_id,
|
|
17
|
+
step_cursor: state.step_cursor,
|
|
18
|
+
active_child: state.active_child ?? null,
|
|
19
|
+
status: state.status,
|
|
20
|
+
orchestration_mode: state.orchestration_mode ?? "bootstrap",
|
|
21
|
+
continuation_epoch: state.continuation_epoch ?? 0,
|
|
22
|
+
open_children: [...state.open_children].sort(),
|
|
23
|
+
approval_nonce: approvalNonce ?? null,
|
|
24
|
+
});
|
|
25
|
+
return (0, node_crypto_1.createHash)("sha256").update(canonical).digest("hex");
|
|
26
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const index_js_1 = require("./index.js");
|
|
5
|
+
vitest_1.vi.mock("../config/loader.js", () => ({
|
|
6
|
+
loadConfig: () => ({
|
|
7
|
+
skill_packet: {
|
|
8
|
+
analysis_confidence_threshold: 85,
|
|
9
|
+
auto_deep_analysis: false,
|
|
10
|
+
allow_cross_provider_delegation: false,
|
|
11
|
+
},
|
|
12
|
+
}),
|
|
13
|
+
}));
|
|
14
|
+
function configureForTest(program, output) {
|
|
15
|
+
program.exitOverride();
|
|
16
|
+
program.configureOutput({
|
|
17
|
+
writeOut: (value) => {
|
|
18
|
+
output.stdout += value;
|
|
19
|
+
},
|
|
20
|
+
writeErr: (value) => {
|
|
21
|
+
output.stderr += value;
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
for (const command of program.commands) {
|
|
25
|
+
configureForTest(command, output);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function runSkillCommand(argv) {
|
|
29
|
+
const output = { stdout: "", stderr: "" };
|
|
30
|
+
let exitCode = 0;
|
|
31
|
+
const stdoutSpy = vitest_1.vi.spyOn(process.stdout, "write").mockImplementation((chunk) => {
|
|
32
|
+
output.stdout += String(chunk);
|
|
33
|
+
return true;
|
|
34
|
+
});
|
|
35
|
+
const stderrSpy = vitest_1.vi.spyOn(process.stderr, "write").mockImplementation((chunk) => {
|
|
36
|
+
output.stderr += String(chunk);
|
|
37
|
+
return true;
|
|
38
|
+
});
|
|
39
|
+
const exitSpy = vitest_1.vi.spyOn(process, "exit").mockImplementation((code) => {
|
|
40
|
+
exitCode = typeof code === "number" ? code : 0;
|
|
41
|
+
throw new Error(`process.exit(${code})`);
|
|
42
|
+
});
|
|
43
|
+
const command = (0, index_js_1.createSkillCommand)({ repoRoot: "/repo" });
|
|
44
|
+
configureForTest(command, output);
|
|
45
|
+
try {
|
|
46
|
+
await command.parseAsync(["node", "polaris-skill", ...argv], { from: "node" });
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof Error && "exitCode" in error) {
|
|
50
|
+
exitCode = Number(error.exitCode);
|
|
51
|
+
}
|
|
52
|
+
else if (error instanceof Error && error.message.startsWith("process.exit(")) {
|
|
53
|
+
// swallow process.exit mock throws
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
stdoutSpy.mockRestore();
|
|
61
|
+
stderrSpy.mockRestore();
|
|
62
|
+
exitSpy.mockRestore();
|
|
63
|
+
}
|
|
64
|
+
return { ...output, exitCode };
|
|
65
|
+
}
|
|
66
|
+
(0, vitest_1.describe)("polaris skill packet CLI", () => {
|
|
67
|
+
(0, vitest_1.it)("prints skill help when no subcommand is given", async () => {
|
|
68
|
+
const result = await runSkillCommand(["--help"]);
|
|
69
|
+
(0, vitest_1.expect)(result.stdout).toContain("skill packet");
|
|
70
|
+
});
|
|
71
|
+
vitest_1.it.each(["analyze", "run", "ingest", "promote"])("generates a valid JSON packet for %s", async (skill) => {
|
|
72
|
+
const result = await runSkillCommand(["packet", skill]);
|
|
73
|
+
const packet = JSON.parse(result.stdout);
|
|
74
|
+
(0, vitest_1.expect)(packet.skill_name).toBe(skill);
|
|
75
|
+
(0, vitest_1.expect)(typeof packet.packet_id).toBe("string");
|
|
76
|
+
(0, vitest_1.expect)(typeof packet.active_role).toBe("string");
|
|
77
|
+
(0, vitest_1.expect)(typeof packet.role_summary).toBe("string");
|
|
78
|
+
(0, vitest_1.expect)(Array.isArray(packet.authority_boundaries)).toBe(true);
|
|
79
|
+
(0, vitest_1.expect)(Array.isArray(packet.prohibited_actions)).toBe(true);
|
|
80
|
+
(0, vitest_1.expect)(Array.isArray(packet.allowed_outputs)).toBe(true);
|
|
81
|
+
(0, vitest_1.expect)(Array.isArray(packet.deliverables)).toBe(true);
|
|
82
|
+
(0, vitest_1.expect)(Array.isArray(packet.stop_conditions)).toBe(true);
|
|
83
|
+
(0, vitest_1.expect)(typeof packet.generated_at).toBe("string");
|
|
84
|
+
});
|
|
85
|
+
(0, vitest_1.it)("writes error and exits for unknown skill", async () => {
|
|
86
|
+
const result = await runSkillCommand(["packet", "unknown-skill"]);
|
|
87
|
+
(0, vitest_1.expect)(result.stderr).toContain("Unknown skill");
|
|
88
|
+
(0, vitest_1.expect)(result.stderr).toContain("analyze");
|
|
89
|
+
(0, vitest_1.expect)(result.exitCode).toBe(1);
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)("analyze packet includes confidence_policy", async () => {
|
|
92
|
+
const result = await runSkillCommand(["packet", "analyze"]);
|
|
93
|
+
const packet = JSON.parse(result.stdout);
|
|
94
|
+
const policy = packet.confidence_policy;
|
|
95
|
+
(0, vitest_1.expect)(policy).toBeDefined();
|
|
96
|
+
(0, vitest_1.expect)(policy.threshold).toBe(85);
|
|
97
|
+
(0, vitest_1.expect)(policy.auto_deep_analysis).toBe(false);
|
|
98
|
+
(0, vitest_1.expect)(policy.on_below_threshold).toBe("ask_user");
|
|
99
|
+
});
|
|
100
|
+
(0, vitest_1.it)("run packet does not include confidence_policy", async () => {
|
|
101
|
+
const result = await runSkillCommand(["packet", "run"]);
|
|
102
|
+
const packet = JSON.parse(result.stdout);
|
|
103
|
+
(0, vitest_1.expect)(packet.confidence_policy).toBeUndefined();
|
|
104
|
+
});
|
|
105
|
+
});
|