@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,403 @@
|
|
|
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.TerminalCliAdapter = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const worker_instructions_js_1 = require("./worker-instructions.js");
|
|
12
|
+
const worker_packet_js_1 = require("../worker-packet.js");
|
|
13
|
+
const compact_return_js_1 = require("../compact-return.js");
|
|
14
|
+
/** Expand $VAR and ${VAR} references from process.env. */
|
|
15
|
+
function expandEnvVars(str) {
|
|
16
|
+
return str
|
|
17
|
+
.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/g, (_, name) => process.env[name] ?? '')
|
|
18
|
+
.replace(/\$([A-Z_][A-Z0-9_]*)/g, (_, name) => process.env[name] ?? '');
|
|
19
|
+
}
|
|
20
|
+
/** Substitute {{key}} template variables. Unknown keys are left as-is. */
|
|
21
|
+
function substituteTemplates(str, vars) {
|
|
22
|
+
return str.replace(/\{\{([^}]+)\}\}/g, (original, key) => vars[key.trim()] ?? original);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Shell-quote a single argument for display purposes only.
|
|
26
|
+
* Not used for actual process spawning (which uses the args array directly).
|
|
27
|
+
*/
|
|
28
|
+
function shellQuote(arg) {
|
|
29
|
+
if (/^[a-zA-Z0-9@%+=:,./-]+$/.test(arg))
|
|
30
|
+
return arg;
|
|
31
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
32
|
+
}
|
|
33
|
+
function formatCommandLine(command, args) {
|
|
34
|
+
return [command, ...args].map(shellQuote).join(' ');
|
|
35
|
+
}
|
|
36
|
+
/** Check whether a command is available on PATH or is an accessible file. */
|
|
37
|
+
function resolveCommand(cmd) {
|
|
38
|
+
if (node_path_1.default.isAbsolute(cmd)) {
|
|
39
|
+
return node_fs_1.default.existsSync(cmd);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
(0, node_child_process_1.execFileSync)('which', [cmd], { stdio: 'ignore' });
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
class TerminalCliAdapter {
|
|
50
|
+
config;
|
|
51
|
+
name = 'terminal-cli';
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.config = config;
|
|
54
|
+
}
|
|
55
|
+
getProvider(providerName) {
|
|
56
|
+
const providers = this.config.providers ?? {};
|
|
57
|
+
const cfg = providers[providerName];
|
|
58
|
+
if (!cfg) {
|
|
59
|
+
const available = Object.keys(providers);
|
|
60
|
+
const hint = available.length > 0
|
|
61
|
+
? `Available providers: ${available.join(', ')}`
|
|
62
|
+
: 'No providers configured in polaris.config.json execution.providers';
|
|
63
|
+
throw new Error(`Unknown provider "${providerName}". ${hint}`);
|
|
64
|
+
}
|
|
65
|
+
return cfg;
|
|
66
|
+
}
|
|
67
|
+
buildCommand(providerCfg, packet, workerPrompt, packetFile) {
|
|
68
|
+
const templateVars = {
|
|
69
|
+
active_child: packet.active_child,
|
|
70
|
+
run_id: packet.run_id,
|
|
71
|
+
cluster_id: packet.cluster_id,
|
|
72
|
+
state_file: packet.state_file,
|
|
73
|
+
telemetry_file: packet.telemetry_file,
|
|
74
|
+
model: String(packet.context?.["model"] ?? ""),
|
|
75
|
+
packet_json: JSON.stringify(packet),
|
|
76
|
+
packet_file: packetFile,
|
|
77
|
+
worker_prompt: workerPrompt,
|
|
78
|
+
};
|
|
79
|
+
const rawCommand = providerCfg.command;
|
|
80
|
+
const command = expandEnvVars(substituteTemplates(rawCommand, templateVars));
|
|
81
|
+
// expandEnvVars resolves unset $VAR to '' — detect that case
|
|
82
|
+
if (!command.trim()) {
|
|
83
|
+
throw new Error(`Provider command "${rawCommand}" expanded to an empty string — ` +
|
|
84
|
+
`likely an unset environment variable. ` +
|
|
85
|
+
`Set the environment variable or use a literal command name.`);
|
|
86
|
+
}
|
|
87
|
+
const args = (providerCfg.args ?? []).map((arg) => expandEnvVars(substituteTemplates(arg, templateVars)));
|
|
88
|
+
return { command, args };
|
|
89
|
+
}
|
|
90
|
+
async probe(providerName) {
|
|
91
|
+
try {
|
|
92
|
+
const providerCfg = this.getProvider(providerName);
|
|
93
|
+
const expandedCommand = expandEnvVars(providerCfg.command);
|
|
94
|
+
if (!resolveCommand(expandedCommand.split(' ')[0] ?? expandedCommand)) {
|
|
95
|
+
return { ok: false, error: `Provider command "${providerCfg.command}" not found on PATH` };
|
|
96
|
+
}
|
|
97
|
+
return { ok: true };
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async dispatch(packet, options) {
|
|
104
|
+
const primaryProvider = options.provider || "terminal-cli";
|
|
105
|
+
if ((0, worker_packet_js_1.isWorkerPacket)(packet) && packet.worker_role === "impl") {
|
|
106
|
+
const allowed = Array.isArray(packet.instructions?.allowed_scope) ? packet.instructions.allowed_scope : [];
|
|
107
|
+
if (allowed.length === 0) {
|
|
108
|
+
const blockedMsg = `Worker blocked: impl packet for ${packet.active_child} has empty allowed_scope. Foreman must provide scope or approve override.`;
|
|
109
|
+
return {
|
|
110
|
+
exit_code: 1,
|
|
111
|
+
provider_used: primaryProvider,
|
|
112
|
+
command_run: `terminal-cli:${packet.active_child || "worker"}`,
|
|
113
|
+
summary: JSON.stringify({
|
|
114
|
+
child_id: packet.active_child,
|
|
115
|
+
status: "blocked",
|
|
116
|
+
validation_summary: blockedMsg,
|
|
117
|
+
next_action: "escalate",
|
|
118
|
+
warnings: ["empty-allowed-scope"],
|
|
119
|
+
}),
|
|
120
|
+
stderr: blockedMsg,
|
|
121
|
+
pre_dispatch_failure: true,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Validate primary provider eagerly — throws for unknown/misconfigured primary,
|
|
126
|
+
// preserving the pre-refactor contract for callers specifying invalid providers.
|
|
127
|
+
const primaryCfg = this.getProvider(primaryProvider);
|
|
128
|
+
// Build fallback chain from policy. Only append providers that are configured.
|
|
129
|
+
// Fallback is suppressed when providerPolicy.worker.noFallback is true.
|
|
130
|
+
const workerPolicy = this.config.providerPolicy?.['worker'];
|
|
131
|
+
const canFallback = !(workerPolicy?.noFallback === true);
|
|
132
|
+
const policyProviders = (canFallback && Array.isArray(workerPolicy?.providers))
|
|
133
|
+
? workerPolicy.providers
|
|
134
|
+
: [];
|
|
135
|
+
const providersToTry = [
|
|
136
|
+
{ name: primaryProvider, cfg: primaryCfg, isPrimary: true },
|
|
137
|
+
];
|
|
138
|
+
if (canFallback) {
|
|
139
|
+
for (const p of policyProviders) {
|
|
140
|
+
if (p !== primaryProvider && p in (this.config.providers ?? {})) {
|
|
141
|
+
try {
|
|
142
|
+
providersToTry.push({ name: p, cfg: this.getProvider(p), isPrimary: false });
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// fallback provider not found — skip silently
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const workerPrompt = (0, worker_instructions_js_1.buildWorkerInstructions)(packet);
|
|
151
|
+
// Write packet to a named temp file so args can reference it via {{packet_file}}
|
|
152
|
+
const packetFile = node_path_1.default.join(node_os_1.default.tmpdir(), `polaris-packet-${packet.run_id}.json`);
|
|
153
|
+
node_fs_1.default.writeFileSync(packetFile, JSON.stringify(packet, null, 2), 'utf-8');
|
|
154
|
+
let lastResult;
|
|
155
|
+
try {
|
|
156
|
+
for (const { name: provider, cfg: providerCfg, isPrimary } of providersToTry) {
|
|
157
|
+
let command;
|
|
158
|
+
let args;
|
|
159
|
+
try {
|
|
160
|
+
({ command, args } = this.buildCommand(providerCfg, packet, workerPrompt, packetFile));
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
if (isPrimary)
|
|
164
|
+
throw err; // primary build failures must propagate
|
|
165
|
+
lastResult = {
|
|
166
|
+
exit_code: 1,
|
|
167
|
+
provider_used: provider,
|
|
168
|
+
command_run: provider,
|
|
169
|
+
stderr: err instanceof Error ? err.message : String(err),
|
|
170
|
+
};
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const commandLine = formatCommandLine(command, args);
|
|
174
|
+
if (options.dryRun) {
|
|
175
|
+
return this.dryRun(provider, command, args, commandLine, packet, packetFile, workerPrompt);
|
|
176
|
+
}
|
|
177
|
+
if (!resolveCommand(command)) {
|
|
178
|
+
lastResult = {
|
|
179
|
+
exit_code: 1,
|
|
180
|
+
provider_used: provider,
|
|
181
|
+
command_run: commandLine,
|
|
182
|
+
stderr: `Provider command "${command}" not found on PATH. ` +
|
|
183
|
+
`Install it or update the "command" field for provider "${provider}" in polaris.config.json.`,
|
|
184
|
+
};
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const result = await this.runProcess(command, args, commandLine, packet, packetFile, provider, workerPrompt);
|
|
188
|
+
// Worker succeeded — return immediately.
|
|
189
|
+
if (result.exit_code === 0) {
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
// If the worker wrote a result file it actually ran (and failed) — don't
|
|
193
|
+
// retry with another provider; that would double-dispatch the same child.
|
|
194
|
+
const resultFilePath = (0, worker_packet_js_1.isWorkerPacket)(packet) ? packet.result_file_contract?.result_file : undefined;
|
|
195
|
+
if (resultFilePath && node_fs_1.default.existsSync(resultFilePath)) {
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
// Worker did not start (wrong args, command not found, etc.) — try next.
|
|
199
|
+
lastResult = result;
|
|
200
|
+
}
|
|
201
|
+
return lastResult ?? {
|
|
202
|
+
exit_code: 1,
|
|
203
|
+
provider_used: primaryProvider,
|
|
204
|
+
command_run: '',
|
|
205
|
+
stderr: 'All configured providers exhausted without starting a worker',
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
try {
|
|
210
|
+
node_fs_1.default.unlinkSync(packetFile);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// ignore cleanup errors
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
dryRun(provider, command, args, commandLine, packet, packetFile, workerPrompt) {
|
|
218
|
+
const lines = [
|
|
219
|
+
`[dry-run] Provider: ${provider}`,
|
|
220
|
+
`[dry-run] Command: ${commandLine}`,
|
|
221
|
+
`[dry-run] Stdin: <bootstrap packet JSON>`,
|
|
222
|
+
`[dry-run] Env vars set:`,
|
|
223
|
+
` POLARIS_ACTIVE_CHILD=${packet.active_child}`,
|
|
224
|
+
` POLARIS_RUN_ID=${packet.run_id}`,
|
|
225
|
+
` POLARIS_CLUSTER_ID=${packet.cluster_id}`,
|
|
226
|
+
` POLARIS_STATE_FILE=${packet.state_file}`,
|
|
227
|
+
` POLARIS_TELEMETRY_FILE=${packet.telemetry_file}`,
|
|
228
|
+
` POLARIS_PACKET_FILE=${packetFile}`,
|
|
229
|
+
` POLARIS_PACKET_JSON=<json>`,
|
|
230
|
+
` POLARIS_WORKER_PROMPT=<prompt>`,
|
|
231
|
+
`[dry-run] Worker prompt:`,
|
|
232
|
+
workerPrompt
|
|
233
|
+
.split('\n')
|
|
234
|
+
.map((l) => ` ${l}`)
|
|
235
|
+
.join('\n'),
|
|
236
|
+
`[dry-run] Bootstrap packet:`,
|
|
237
|
+
JSON.stringify(packet, null, 2)
|
|
238
|
+
.split('\n')
|
|
239
|
+
.map((l) => ` ${l}`)
|
|
240
|
+
.join('\n'),
|
|
241
|
+
];
|
|
242
|
+
console.log(lines.join('\n'));
|
|
243
|
+
return {
|
|
244
|
+
exit_code: 0,
|
|
245
|
+
provider_used: provider,
|
|
246
|
+
command_run: commandLine,
|
|
247
|
+
summary: '[dry-run]',
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
runProcess(command, args, commandLine, packet, packetFile, provider, workerPrompt) {
|
|
251
|
+
return new Promise((resolve, reject) => {
|
|
252
|
+
const env = {
|
|
253
|
+
...process.env,
|
|
254
|
+
POLARIS_ACTIVE_CHILD: packet.active_child,
|
|
255
|
+
POLARIS_RUN_ID: packet.run_id,
|
|
256
|
+
POLARIS_CLUSTER_ID: packet.cluster_id,
|
|
257
|
+
POLARIS_STATE_FILE: packet.state_file,
|
|
258
|
+
POLARIS_TELEMETRY_FILE: packet.telemetry_file,
|
|
259
|
+
POLARIS_PACKET_FILE: packetFile,
|
|
260
|
+
POLARIS_PACKET_JSON: JSON.stringify(packet),
|
|
261
|
+
POLARIS_WORKER_PROMPT: workerPrompt,
|
|
262
|
+
};
|
|
263
|
+
const child = (0, node_child_process_1.spawn)(command, args, {
|
|
264
|
+
env,
|
|
265
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
266
|
+
});
|
|
267
|
+
// Deliver bootstrap packet to worker via stdin
|
|
268
|
+
child.stdin.write(JSON.stringify(packet), 'utf-8');
|
|
269
|
+
child.stdin.end();
|
|
270
|
+
const stdoutChunks = [];
|
|
271
|
+
const stderrChunks = [];
|
|
272
|
+
child.stdout.on('data', (chunk) => {
|
|
273
|
+
stdoutChunks.push(chunk);
|
|
274
|
+
});
|
|
275
|
+
child.stderr.on('data', (chunk) => {
|
|
276
|
+
stderrChunks.push(chunk);
|
|
277
|
+
});
|
|
278
|
+
child.on('error', (err) => {
|
|
279
|
+
if (err.code === 'ENOENT') {
|
|
280
|
+
reject(new Error(`Provider command "${command}" not found. ` +
|
|
281
|
+
`Ensure it is installed and on PATH.`));
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
reject(err);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
child.on('close', (exitCode) => {
|
|
288
|
+
const stdout = Buffer.concat(stdoutChunks).toString('utf-8').trim();
|
|
289
|
+
const stderr = Buffer.concat(stderrChunks).toString('utf-8').trim();
|
|
290
|
+
const summary = extractSummary(stdout);
|
|
291
|
+
this.writeSealedResultIfNeeded(packet, summary, stdout, exitCode ?? 1);
|
|
292
|
+
resolve({
|
|
293
|
+
exit_code: exitCode ?? 1,
|
|
294
|
+
provider_used: provider,
|
|
295
|
+
command_run: commandLine,
|
|
296
|
+
stdout,
|
|
297
|
+
summary,
|
|
298
|
+
stderr: stderr || undefined,
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
writeSealedResultIfNeeded(packet, summary, stdout, exitCode) {
|
|
304
|
+
const resultFile = (0, worker_packet_js_1.isWorkerPacket)(packet) ? packet.result_file_contract?.result_file : undefined;
|
|
305
|
+
if (!resultFile || !summary) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
const parsed = JSON.parse(summary);
|
|
310
|
+
// Normalize legacy CompactReturn shapes before validation so that
|
|
311
|
+
// workers using pre-spec formats (status:"success", validation:{passed:[...]})
|
|
312
|
+
// are accepted rather than silently marked as failures.
|
|
313
|
+
const normalized = normalizeLegacyCompactReturn(parsed);
|
|
314
|
+
const compactReturnErrors = (0, compact_return_js_1.validateCompactReturn)(normalized);
|
|
315
|
+
const isValidCompactReturn = compactReturnErrors.length === 0;
|
|
316
|
+
// If the parsed result isn't a valid CompactReturn, treat it as a failure
|
|
317
|
+
// regardless of exit code — this prevents phantom successes from workers
|
|
318
|
+
// that return minimal status objects instead of proper CompactReturn structs.
|
|
319
|
+
const effectiveStatus = (exitCode === 0 && isValidCompactReturn) ? "success" : "failure";
|
|
320
|
+
const sealedResult = {
|
|
321
|
+
...normalized,
|
|
322
|
+
run_id: packet.run_id,
|
|
323
|
+
child_id: String(normalized["child_id"] ?? packet.active_child),
|
|
324
|
+
status: effectiveStatus,
|
|
325
|
+
commit: typeof normalized["commit"] === "string"
|
|
326
|
+
? normalized["commit"]
|
|
327
|
+
: typeof normalized["commit_hash"] === "string"
|
|
328
|
+
? normalized["commit_hash"]
|
|
329
|
+
: undefined,
|
|
330
|
+
validation: normalized["validation"] ?? normalized["validation_summary"],
|
|
331
|
+
error_message: effectiveStatus === "failure"
|
|
332
|
+
? (!isValidCompactReturn
|
|
333
|
+
? `CompactReturn validation failed: ${compactReturnErrors.join("; ")}`
|
|
334
|
+
: typeof normalized["error_message"] === "string"
|
|
335
|
+
? normalized["error_message"]
|
|
336
|
+
: stdout || summary)
|
|
337
|
+
: undefined,
|
|
338
|
+
...(compactReturnErrors.length > 0 ? { compact_return_errors: compactReturnErrors } : {}),
|
|
339
|
+
};
|
|
340
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(resultFile), { recursive: true });
|
|
341
|
+
node_fs_1.default.writeFileSync(resultFile, JSON.stringify(sealedResult, null, 2), "utf-8");
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// If the provider did not emit parseable compact JSON, leave the result
|
|
345
|
+
// file absent so the parent can surface the sealed-result read failure.
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
exports.TerminalCliAdapter = TerminalCliAdapter;
|
|
350
|
+
/**
|
|
351
|
+
* Normalize a legacy CompactReturn shape to the current spec before validation.
|
|
352
|
+
* Handles pre-spec formats produced by older workers:
|
|
353
|
+
* - status:"success"|"completed" → status:"done"
|
|
354
|
+
* - validation:{passed:[...],failed:[...]} → validation:"passed"|"failed"|"skipped"
|
|
355
|
+
* - missing boolean flags → false
|
|
356
|
+
*/
|
|
357
|
+
function normalizeLegacyCompactReturn(raw) {
|
|
358
|
+
const result = { ...raw };
|
|
359
|
+
if (result['status'] === 'success' || result['status'] === 'completed') {
|
|
360
|
+
result['status'] = 'done';
|
|
361
|
+
}
|
|
362
|
+
if (typeof result['validation'] === 'object' && result['validation'] !== null) {
|
|
363
|
+
const v = result['validation'];
|
|
364
|
+
if (Array.isArray(v['failed']) && v['failed'].length > 0) {
|
|
365
|
+
result['validation'] = 'failed';
|
|
366
|
+
}
|
|
367
|
+
else if (Array.isArray(v['passed']) && v['passed'].length > 0) {
|
|
368
|
+
result['validation'] = 'passed';
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
result['validation'] = 'skipped';
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
for (const flag of ['tracker_updated', 'state_updated', 'telemetry_updated']) {
|
|
375
|
+
if (typeof result[flag] !== 'boolean') {
|
|
376
|
+
result[flag] = false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Extract a worker summary from stdout.
|
|
383
|
+
* Looks for the last line that is valid JSON; falls back to the last 500 chars.
|
|
384
|
+
*/
|
|
385
|
+
function extractSummary(stdout) {
|
|
386
|
+
if (!stdout)
|
|
387
|
+
return undefined;
|
|
388
|
+
const lines = stdout.split('\n').reverse();
|
|
389
|
+
for (const line of lines) {
|
|
390
|
+
const trimmed = line.trim();
|
|
391
|
+
if (!trimmed)
|
|
392
|
+
continue;
|
|
393
|
+
try {
|
|
394
|
+
JSON.parse(trimmed);
|
|
395
|
+
return trimmed;
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
// not JSON, keep looking
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// fallback: last 500 characters
|
|
402
|
+
return stdout.length > 500 ? stdout.slice(-500) : stdout;
|
|
403
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildWorkerInstructions = buildWorkerInstructions;
|
|
4
|
+
exports.returnContractFor = returnContractFor;
|
|
5
|
+
const worker_packet_js_1 = require("../worker-packet.js");
|
|
6
|
+
/** Fallback return contract for legacy v1 BootstrapPackets. */
|
|
7
|
+
const LEGACY_RETURN_CONTRACT = [
|
|
8
|
+
"child_id",
|
|
9
|
+
"status",
|
|
10
|
+
"commit_hash",
|
|
11
|
+
"validation_summary",
|
|
12
|
+
"next_action",
|
|
13
|
+
"warnings",
|
|
14
|
+
];
|
|
15
|
+
/** Lifecycle teardown preamble appended to every worker prompt. */
|
|
16
|
+
const LIFECYCLE_TEARDOWN_NOTICE = [
|
|
17
|
+
`LIFECYCLE CONTRACT (mandatory):`,
|
|
18
|
+
` - Execute ONLY the single child or task named in this packet.`,
|
|
19
|
+
` - Your FINAL RESPONSE must be EXCLUSIVELY the compact return JSON object — a single JSON object on one line, nothing else.`,
|
|
20
|
+
` - Do NOT include any preamble, explanation, narration, or text before or after the JSON in your final response.`,
|
|
21
|
+
` - Do NOT summarize what you did. Do NOT say "Here is the compact return:". Output only the raw JSON.`,
|
|
22
|
+
` - The foreman session receives only your final response. Keep it to the JSON alone so it cannot observe your work.`,
|
|
23
|
+
` - Do NOT select, claim, or execute any other child.`,
|
|
24
|
+
` - Do NOT continue looping after one child completes.`,
|
|
25
|
+
` - One worker. One child. One commit. Then exit.`,
|
|
26
|
+
].join("\n");
|
|
27
|
+
/**
|
|
28
|
+
* Build instructions for a compiled WorkerPacket.
|
|
29
|
+
* Uses pre-baked steps from packet.instructions — no skill ingestion.
|
|
30
|
+
*/
|
|
31
|
+
function buildCompiledInstructions(packet) {
|
|
32
|
+
if (!(0, worker_packet_js_1.isWorkerPacket)(packet)) {
|
|
33
|
+
return buildLegacyInstructions(packet);
|
|
34
|
+
}
|
|
35
|
+
const { instructions, lifecycle, return_contract, worker_role, run_id, cluster_id } = packet;
|
|
36
|
+
const lines = [
|
|
37
|
+
`POLARIS WORKER — role: ${worker_role}`,
|
|
38
|
+
`Run: ${run_id} | Cluster: ${cluster_id}`,
|
|
39
|
+
``,
|
|
40
|
+
`OBJECTIVE:`,
|
|
41
|
+
instructions.primary_goal,
|
|
42
|
+
``,
|
|
43
|
+
`EXECUTION STEPS (pre-compiled — do not re-read skill files):`,
|
|
44
|
+
...instructions.steps.map((s, i) => ` ${i + 1}. ${s}`),
|
|
45
|
+
];
|
|
46
|
+
if (instructions.allowed_scope.length > 0) {
|
|
47
|
+
lines.push(``, `ALLOWED SCOPE:`, ...instructions.allowed_scope.map((s) => ` ${s}`));
|
|
48
|
+
}
|
|
49
|
+
if (instructions.validation_commands.length > 0) {
|
|
50
|
+
lines.push(``, `VALIDATION COMMANDS (run before returning):`, ...instructions.validation_commands.map((c) => ` ${c}`));
|
|
51
|
+
}
|
|
52
|
+
lines.push(``, `REQUIRED RETURN FIELDS: ${return_contract.join(", ")}`, `STATE FILE: ${packet.state_file}`, `TELEMETRY FILE: ${packet.telemetry_file}`, `SEALED RESULT FILE: ${packet.result_file_contract.result_file}`, `Write the sealed result file as a JSON object with EXACTLY this shape:`, ` { "run_id": "<run_id>", "child_id": "<child_id>", "status": "success" | "failure",`, ` "commit": "<full 40-char SHA>", "validation": { "passed": ["<cmd>", ...] },`, ` "error_message": "<string or omit if success>" }`, `commit MUST be the full 40-character git SHA (git rev-parse HEAD). Do NOT use a short hash.`, `Your final response MUST be ONLY the compact return JSON — a single JSON object, no other text.`, ``, LIFECYCLE_TEARDOWN_NOTICE, ``, `Session must terminate after max_concurrent=${lifecycle.max_concurrent} active workers.`, `cleanup_on_exit: ${lifecycle.cleanup_on_exit}`);
|
|
53
|
+
return lines.join("\n");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build instructions for a legacy v1 BootstrapPacket.
|
|
57
|
+
* Kept for backward compat; generates generic instructions from packet metadata.
|
|
58
|
+
*/
|
|
59
|
+
function buildLegacyInstructions(packet) {
|
|
60
|
+
return [
|
|
61
|
+
`You are the dedicated Polaris worker subagent for exactly one child issue: ${packet.active_child}.`,
|
|
62
|
+
`Run id: ${packet.run_id}`,
|
|
63
|
+
`Parent cluster: ${packet.cluster_id}`,
|
|
64
|
+
`Execution mode: ephemeral agent subtask.`,
|
|
65
|
+
``,
|
|
66
|
+
`Use the bootstrap packet below as the durable continuation boundary.`,
|
|
67
|
+
`Execute only ${packet.active_child}, update the state and telemetry files named in the packet, and return ONLY the compact JSON as your final response — no preamble, no narration, no other text.`,
|
|
68
|
+
`Do not include a transcript or continue to another child.`,
|
|
69
|
+
``,
|
|
70
|
+
`Required return fields: ${LEGACY_RETURN_CONTRACT.join(", ")}`,
|
|
71
|
+
``,
|
|
72
|
+
LIFECYCLE_TEARDOWN_NOTICE,
|
|
73
|
+
``,
|
|
74
|
+
`Bootstrap packet:`,
|
|
75
|
+
JSON.stringify(packet, null, 2),
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
/** Build terminal/agent worker instructions for this packet. */
|
|
79
|
+
function buildWorkerInstructions(packet) {
|
|
80
|
+
return buildCompiledInstructions(packet);
|
|
81
|
+
}
|
|
82
|
+
/** Returns the return contract for this packet (compiled or legacy). */
|
|
83
|
+
function returnContractFor(packet) {
|
|
84
|
+
return (0, worker_packet_js_1.isWorkerPacket)(packet) ? packet.return_contract : LEGACY_RETURN_CONTRACT;
|
|
85
|
+
}
|