@lsctech/polaris 0.3.29 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-plugin/args.js +77 -0
- package/dist/agent-plugin/claude-generator.js +158 -0
- package/dist/agent-plugin/commands.js +73 -0
- package/dist/agent-plugin/help.js +69 -0
- package/dist/agent-plugin/sync.js +108 -0
- package/dist/autoresearch/dev-gate.js +51 -0
- package/dist/autoresearch/gates.js +310 -0
- package/dist/autoresearch/index.js +20 -0
- package/dist/autoresearch/proposal.js +121 -0
- package/dist/autoresearch/routing.js +180 -0
- package/dist/autoresearch/score.js +213 -0
- package/dist/cli/adopt-approve.js +124 -4
- package/dist/cli/adopt-assets.js +9 -1
- package/dist/cli/adopt-command.js +123 -11
- package/dist/cli/adopt-instructions.js +17 -2
- package/dist/cli/adopt-smartdocs.js +9 -0
- package/dist/cli/adoption-context.js +46 -0
- package/dist/cli/adoption-plan.js +105 -12
- package/dist/cli/agent-setup.js +47 -0
- package/dist/cli/autoresearch.js +96 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/init.js +69 -1
- package/dist/cli/setup-interview/generate.js +380 -0
- package/dist/cli/setup-interview/report.js +138 -0
- package/dist/cli/setup-interview/runner.js +105 -0
- package/dist/cli/setup-interview/schema.js +16 -0
- package/dist/cli/setup-interview/store.js +73 -0
- package/dist/cli/worker.js +18 -8
- package/dist/finalize/index.js +5 -4
- package/dist/loop/adapters/foreman-dispatch.js +65 -0
- package/dist/loop/adapters/index.js +3 -1
- package/dist/loop/bootstrap-packet.js +1 -1
- package/dist/loop/checkpoint.js +120 -1
- package/dist/loop/continue.js +13 -5
- package/dist/loop/parent.js +129 -1
- package/dist/loop/resume.js +14 -8
- package/dist/loop/worker-packet.js +1 -1
- package/dist/skill-packet/generator.js +149 -1
- package/dist/workspace/.polaris/skills/polaris-tools/tools.js +31 -22
- package/package.json +2 -2
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadOperatorContext = loadOperatorContext;
|
|
4
|
+
exports.saveOperatorContext = saveOperatorContext;
|
|
5
|
+
exports.createEmptyOperatorContext = createEmptyOperatorContext;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const ADOPTION_DIR = (0, node_path_1.join)(".polaris", "adoption");
|
|
9
|
+
const CONTEXT_FILE = "operator-context.json";
|
|
10
|
+
function contextPath(repoRoot) {
|
|
11
|
+
return (0, node_path_1.join)(repoRoot, ADOPTION_DIR, CONTEXT_FILE);
|
|
12
|
+
}
|
|
13
|
+
function loadOperatorContext(repoRoot) {
|
|
14
|
+
const path = contextPath(repoRoot);
|
|
15
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
|
|
19
|
+
if (!Array.isArray(parsed?.trusted_docs) ||
|
|
20
|
+
!Array.isArray(parsed?.never_touch) ||
|
|
21
|
+
typeof parsed?.instruction_file_intent !== "object" ||
|
|
22
|
+
parsed?.instruction_file_intent === null ||
|
|
23
|
+
Array.isArray(parsed?.instruction_file_intent)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return parsed;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function saveOperatorContext(repoRoot, context) {
|
|
33
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(repoRoot, ADOPTION_DIR), { recursive: true });
|
|
34
|
+
(0, node_fs_1.writeFileSync)(contextPath(repoRoot), `${JSON.stringify(context, null, 2)}\n`, "utf-8");
|
|
35
|
+
}
|
|
36
|
+
function createEmptyOperatorContext(now) {
|
|
37
|
+
return {
|
|
38
|
+
schema_version: "1.0",
|
|
39
|
+
answered_at: (now ?? new Date()).toISOString(),
|
|
40
|
+
trusted_docs: [],
|
|
41
|
+
stale_docs: [],
|
|
42
|
+
never_touch: [],
|
|
43
|
+
priority_systems: [],
|
|
44
|
+
instruction_file_intent: {},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -11,14 +11,49 @@ function formatPlanId(isoTimestamp) {
|
|
|
11
11
|
function normalizePath(path) {
|
|
12
12
|
return path.endsWith("/") ? path.slice(0, -1) : path;
|
|
13
13
|
}
|
|
14
|
+
function isTrusted(path, operatorContext) {
|
|
15
|
+
const normalized = normalizePath(path);
|
|
16
|
+
return operatorContext?.trusted_docs.some((p) => normalizePath(p) === normalized) ?? false;
|
|
17
|
+
}
|
|
18
|
+
function isStale(path, operatorContext) {
|
|
19
|
+
const normalized = normalizePath(path);
|
|
20
|
+
return operatorContext?.stale_docs.some((p) => normalizePath(p) === normalized) ?? false;
|
|
21
|
+
}
|
|
22
|
+
function isNeverTouch(path, operatorContext) {
|
|
23
|
+
const normalized = normalizePath(path);
|
|
24
|
+
return operatorContext?.never_touch.some((p) => normalizePath(p) === normalized) ?? false;
|
|
25
|
+
}
|
|
26
|
+
function instructionIntent(path, operatorContext) {
|
|
27
|
+
return operatorContext?.instruction_file_intent[path];
|
|
28
|
+
}
|
|
29
|
+
function deriveSmartDocsRouting(candidate, operatorContext) {
|
|
30
|
+
const evidence_refs = [`scan:smartdocs_candidate:${candidate.path}`];
|
|
31
|
+
const operator_refs = [];
|
|
32
|
+
if (isNeverTouch(candidate.path, operatorContext) || isStale(candidate.path, operatorContext)) {
|
|
33
|
+
if (isNeverTouch(candidate.path, operatorContext))
|
|
34
|
+
operator_refs.push(`operator:never_touch:${candidate.path}`);
|
|
35
|
+
if (isStale(candidate.path, operatorContext))
|
|
36
|
+
operator_refs.push(`operator:stale_docs:${candidate.path}`);
|
|
37
|
+
return { routing: "hold", evidence_refs, operator_refs };
|
|
38
|
+
}
|
|
39
|
+
if (isTrusted(candidate.path, operatorContext)) {
|
|
40
|
+
operator_refs.push(`operator:trusted_docs:${candidate.path}`);
|
|
41
|
+
return { routing: "candidate", evidence_refs, operator_refs };
|
|
42
|
+
}
|
|
43
|
+
return { routing: "review-required", evidence_refs, operator_refs };
|
|
44
|
+
}
|
|
14
45
|
function createStep(order, partial) {
|
|
46
|
+
const { evidence_refs, operator_refs, routing, ...rest } = partial;
|
|
15
47
|
return {
|
|
16
|
-
|
|
48
|
+
evidence_refs: evidence_refs ?? [],
|
|
49
|
+
operator_refs: operator_refs ?? [],
|
|
50
|
+
routing: routing ?? "candidate",
|
|
51
|
+
...rest,
|
|
17
52
|
order,
|
|
18
53
|
status: "pending",
|
|
19
54
|
};
|
|
20
55
|
}
|
|
21
|
-
function buildSteps(inventory) {
|
|
56
|
+
function buildSteps(inventory, operatorContext) {
|
|
22
57
|
const steps = [];
|
|
23
58
|
let order = 1;
|
|
24
59
|
steps.push(createStep(order++, {
|
|
@@ -31,6 +66,9 @@ function buildSteps(inventory) {
|
|
|
31
66
|
destructive: true,
|
|
32
67
|
requires_approval: false,
|
|
33
68
|
estimated_risk: "low",
|
|
69
|
+
routing: "candidate",
|
|
70
|
+
evidence_refs: ["adoption:step:provider-config-lock"],
|
|
71
|
+
operator_refs: [],
|
|
34
72
|
}));
|
|
35
73
|
steps.push(createStep(order++, {
|
|
36
74
|
step_id: "adoption-scaffold",
|
|
@@ -42,6 +80,9 @@ function buildSteps(inventory) {
|
|
|
42
80
|
destructive: false,
|
|
43
81
|
requires_approval: false,
|
|
44
82
|
estimated_risk: "low",
|
|
83
|
+
routing: "candidate",
|
|
84
|
+
evidence_refs: ["adoption:step:adoption-scaffold"],
|
|
85
|
+
operator_refs: [],
|
|
45
86
|
}));
|
|
46
87
|
steps.push(createStep(order++, {
|
|
47
88
|
step_id: "workspace-root-surfaces",
|
|
@@ -53,10 +94,15 @@ function buildSteps(inventory) {
|
|
|
53
94
|
destructive: false,
|
|
54
95
|
requires_approval: false,
|
|
55
96
|
estimated_risk: "low",
|
|
97
|
+
routing: "candidate",
|
|
98
|
+
evidence_refs: ["adoption:step:workspace-root-surfaces"],
|
|
99
|
+
operator_refs: [],
|
|
56
100
|
}));
|
|
57
101
|
for (const candidate of inventory.smartdocs_candidates) {
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
const { routing, evidence_refs, operator_refs } = deriveSmartDocsRouting(candidate, operatorContext);
|
|
103
|
+
const stepOrder = order++;
|
|
104
|
+
steps.push(createStep(stepOrder, {
|
|
105
|
+
step_id: `smartdocs-migrate-${stepOrder.toString().padStart(3, "0")}`,
|
|
60
106
|
phase: "C",
|
|
61
107
|
category: "smartdocs-migrate",
|
|
62
108
|
action: "move",
|
|
@@ -66,12 +112,27 @@ function buildSteps(inventory) {
|
|
|
66
112
|
destructive: true,
|
|
67
113
|
requires_approval: true,
|
|
68
114
|
estimated_risk: candidate.estimated_risk,
|
|
115
|
+
routing,
|
|
116
|
+
evidence_refs,
|
|
117
|
+
operator_refs,
|
|
69
118
|
}));
|
|
70
119
|
}
|
|
71
120
|
for (const folder of inventory.likely_canonical_folders) {
|
|
72
121
|
const normalizedFolder = normalizePath(folder);
|
|
73
|
-
|
|
74
|
-
|
|
122
|
+
const evidence_refs = [`scan:canonical_folder:${normalizedFolder}`];
|
|
123
|
+
const operator_refs = [];
|
|
124
|
+
let routing = "raw";
|
|
125
|
+
if (isNeverTouch(normalizedFolder, operatorContext)) {
|
|
126
|
+
routing = "hold";
|
|
127
|
+
operator_refs.push(`operator:never_touch:${normalizedFolder}`);
|
|
128
|
+
}
|
|
129
|
+
else if (isTrusted(normalizedFolder, operatorContext)) {
|
|
130
|
+
routing = "candidate";
|
|
131
|
+
operator_refs.push(`operator:trusted_docs:${normalizedFolder}`);
|
|
132
|
+
}
|
|
133
|
+
const stepOrder = order++;
|
|
134
|
+
steps.push(createStep(stepOrder, {
|
|
135
|
+
step_id: `cognition-generate-${stepOrder.toString().padStart(3, "0")}`,
|
|
75
136
|
phase: "C",
|
|
76
137
|
category: "cognition-generate",
|
|
77
138
|
action: "create",
|
|
@@ -80,6 +141,9 @@ function buildSteps(inventory) {
|
|
|
80
141
|
destructive: false,
|
|
81
142
|
requires_approval: true,
|
|
82
143
|
estimated_risk: "medium",
|
|
144
|
+
routing,
|
|
145
|
+
evidence_refs,
|
|
146
|
+
operator_refs,
|
|
83
147
|
}));
|
|
84
148
|
}
|
|
85
149
|
for (const file of inventory.agent_instruction_files) {
|
|
@@ -90,8 +154,24 @@ function buildSteps(inventory) {
|
|
|
90
154
|
: file.recommendation === "thin-adapter"
|
|
91
155
|
? "medium"
|
|
92
156
|
: "low";
|
|
93
|
-
|
|
94
|
-
|
|
157
|
+
const evidence_refs = [`scan:agent_instruction_file:${file.path}`];
|
|
158
|
+
const operator_refs = [];
|
|
159
|
+
const intent = instructionIntent(file.path, operatorContext);
|
|
160
|
+
let routing;
|
|
161
|
+
if (intent === "preserve") {
|
|
162
|
+
routing = "hold";
|
|
163
|
+
operator_refs.push(`operator:instruction_file_intent:${file.path}:preserve`);
|
|
164
|
+
}
|
|
165
|
+
else if (intent === "migrate" || intent === "thin-adapter") {
|
|
166
|
+
routing = "candidate";
|
|
167
|
+
operator_refs.push(`operator:instruction_file_intent:${file.path}:${intent}`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
routing = "review-required";
|
|
171
|
+
}
|
|
172
|
+
const stepOrder = order++;
|
|
173
|
+
steps.push(createStep(stepOrder, {
|
|
174
|
+
step_id: `instruction-refactor-${stepOrder.toString().padStart(3, "0")}`,
|
|
95
175
|
phase: "C",
|
|
96
176
|
category: "instruction-refactor",
|
|
97
177
|
action,
|
|
@@ -105,11 +185,15 @@ function buildSteps(inventory) {
|
|
|
105
185
|
destructive,
|
|
106
186
|
requires_approval: destructive,
|
|
107
187
|
estimated_risk: risk,
|
|
188
|
+
routing,
|
|
189
|
+
evidence_refs,
|
|
190
|
+
operator_refs,
|
|
108
191
|
}));
|
|
109
192
|
}
|
|
110
193
|
for (const ignorePath of inventory.ignore_candidates) {
|
|
111
|
-
|
|
112
|
-
|
|
194
|
+
const stepOrder = order++;
|
|
195
|
+
steps.push(createStep(stepOrder, {
|
|
196
|
+
step_id: `ignore-rules-${stepOrder.toString().padStart(3, "0")}`,
|
|
113
197
|
phase: "C",
|
|
114
198
|
category: "ignore-rules",
|
|
115
199
|
action: "append",
|
|
@@ -118,6 +202,9 @@ function buildSteps(inventory) {
|
|
|
118
202
|
destructive: true,
|
|
119
203
|
requires_approval: true,
|
|
120
204
|
estimated_risk: "low",
|
|
205
|
+
routing: "candidate",
|
|
206
|
+
evidence_refs: [`scan:ignore_candidate:${ignorePath}`],
|
|
207
|
+
operator_refs: [],
|
|
121
208
|
}));
|
|
122
209
|
}
|
|
123
210
|
steps.push(createStep(order++, {
|
|
@@ -130,6 +217,9 @@ function buildSteps(inventory) {
|
|
|
130
217
|
destructive: true,
|
|
131
218
|
requires_approval: true,
|
|
132
219
|
estimated_risk: "medium",
|
|
220
|
+
routing: "candidate",
|
|
221
|
+
evidence_refs: ["adoption:step:atlas-generate"],
|
|
222
|
+
operator_refs: [],
|
|
133
223
|
}));
|
|
134
224
|
steps.push(createStep(order++, {
|
|
135
225
|
step_id: "stage-adoption",
|
|
@@ -141,6 +231,9 @@ function buildSteps(inventory) {
|
|
|
141
231
|
destructive: true,
|
|
142
232
|
requires_approval: true,
|
|
143
233
|
estimated_risk: "medium",
|
|
234
|
+
routing: "candidate",
|
|
235
|
+
evidence_refs: ["adoption:step:stage-adoption"],
|
|
236
|
+
operator_refs: [],
|
|
144
237
|
}));
|
|
145
238
|
return steps;
|
|
146
239
|
}
|
|
@@ -160,7 +253,7 @@ function buildImpactSummary(steps, inventory) {
|
|
|
160
253
|
}
|
|
161
254
|
function generateAdoptionPlan(inventory, options = {}) {
|
|
162
255
|
const generatedAt = (options.now ?? new Date()).toISOString();
|
|
163
|
-
const steps = buildSteps(inventory);
|
|
256
|
+
const steps = buildSteps(inventory, options.operatorContext);
|
|
164
257
|
return {
|
|
165
258
|
plan_id: formatPlanId(generatedAt),
|
|
166
259
|
generated_at: generatedAt,
|
|
@@ -206,7 +299,7 @@ function renderAdoptionPlanMarkdown(plan) {
|
|
|
206
299
|
for (const step of phaseSteps) {
|
|
207
300
|
const source = step.source_path ? ` source: \`${step.source_path}\`` : "";
|
|
208
301
|
const dest = step.dest_path ? ` destination: \`${step.dest_path}\`` : "";
|
|
209
|
-
lines.push(`- **${step.order}. ${step.step_id}** — ${step.category} / ${step.action} / approval ${step.requires_approval ? "required" : "not required"} / risk ${step.estimated_risk} / status ${step.status}${source}${dest}`);
|
|
302
|
+
lines.push(`- **${step.order}. ${step.step_id}** — ${step.category} / ${step.action} / approval ${step.requires_approval ? "required" : "not required"} / risk ${step.estimated_risk} / routing ${step.routing} / status ${step.status}${source}${dest}`);
|
|
210
303
|
lines.push(` - ${step.description}`);
|
|
211
304
|
}
|
|
212
305
|
lines.push("");
|
package/dist/cli/agent-setup.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.resolveForeman = resolveForeman;
|
|
36
37
|
exports.runAgentSetup = runAgentSetup;
|
|
37
38
|
const node_child_process_1 = require("node:child_process");
|
|
38
39
|
const readline = __importStar(require("node:readline"));
|
|
@@ -86,6 +87,52 @@ async function selectProvider(role, detected, currentProviders) {
|
|
|
86
87
|
});
|
|
87
88
|
});
|
|
88
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolves the Foreman provider for init/adopt.
|
|
92
|
+
*
|
|
93
|
+
* If `execution.providerPolicy.foreman.providers[0]` is already set in config,
|
|
94
|
+
* returns a binding immediately (no prompt). Otherwise prompts once, persists
|
|
95
|
+
* the choice to polaris.config.json, and returns the binding.
|
|
96
|
+
*
|
|
97
|
+
* The binding always references `.polaris/roles/foreman.md` — role text is not
|
|
98
|
+
* duplicated here.
|
|
99
|
+
*/
|
|
100
|
+
async function resolveForeman(repoRoot, config, opts) {
|
|
101
|
+
const execution = config.execution ?? {};
|
|
102
|
+
const providerPolicy = execution.providerPolicy ?? {};
|
|
103
|
+
const foremanPolicy = providerPolicy.foreman ?? {};
|
|
104
|
+
const existing = foremanPolicy.providers?.[0];
|
|
105
|
+
const roleFile = ".polaris/roles/foreman.md";
|
|
106
|
+
if (existing) {
|
|
107
|
+
return { provider: existing, roleFile };
|
|
108
|
+
}
|
|
109
|
+
// Prompt once for Foreman provider
|
|
110
|
+
const detected = opts?.detectProviders?.() ?? detectProviders();
|
|
111
|
+
const chosen = opts?.selectProvider
|
|
112
|
+
? await opts.selectProvider(detected)
|
|
113
|
+
: await selectProvider("foreman", detected, []);
|
|
114
|
+
if (!chosen) {
|
|
115
|
+
throw new Error("No supported agent installed. Cannot assign a Foreman. " +
|
|
116
|
+
"Install one of: " + SUPPORTED_PROVIDERS.map((p) => p.name).join(", "));
|
|
117
|
+
}
|
|
118
|
+
// Persist choice
|
|
119
|
+
const updatedPolicy = {
|
|
120
|
+
...providerPolicy,
|
|
121
|
+
foreman: { ...foremanPolicy, providers: [chosen] },
|
|
122
|
+
};
|
|
123
|
+
const updatedConfig = {
|
|
124
|
+
...config,
|
|
125
|
+
execution: { ...execution, providerPolicy: updatedPolicy },
|
|
126
|
+
};
|
|
127
|
+
const configPath = (0, node_path_1.resolve)(repoRoot, "polaris.config.json");
|
|
128
|
+
if (opts?.writeConfig) {
|
|
129
|
+
opts.writeConfig(configPath, updatedConfig);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
(0, node_fs_1.writeFileSync)(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
133
|
+
}
|
|
134
|
+
return { provider: chosen, roleFile };
|
|
135
|
+
}
|
|
89
136
|
async function runAgentSetup(repoRoot) {
|
|
90
137
|
console.log("\nPolaris Agent Setup — configure one provider per role\n");
|
|
91
138
|
const detected = detectProviders();
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAutoresearchCommand = createAutoresearchCommand;
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
5
|
+
const commander_1 = require("commander");
|
|
6
|
+
const dev_gate_js_1 = require("../autoresearch/dev-gate.js");
|
|
7
|
+
const score_js_1 = require("../autoresearch/score.js");
|
|
8
|
+
const proposal_js_1 = require("../autoresearch/proposal.js");
|
|
9
|
+
const routing_js_1 = require("../autoresearch/routing.js");
|
|
10
|
+
function createAutoresearchCommand(options) {
|
|
11
|
+
const repoRoot = options.repoRoot;
|
|
12
|
+
const autoresearch = new commander_1.Command("autoresearch")
|
|
13
|
+
.description("Autoresearch tools (dev-gated — Polaris development context only)")
|
|
14
|
+
.showHelpAfterError()
|
|
15
|
+
.showSuggestionAfterError();
|
|
16
|
+
autoresearch
|
|
17
|
+
.command("score <run-id>")
|
|
18
|
+
.description("Score a completed Polaris run against the binary gate scorecard and output a diagnosis report")
|
|
19
|
+
.option("-r, --repo-root <path>", "Repository root", repoRoot)
|
|
20
|
+
.option("--json", "Output raw JSON (default: pretty-printed)")
|
|
21
|
+
.action((runId, cmdOptions) => {
|
|
22
|
+
const root = (0, node_path_1.resolve)(cmdOptions.repoRoot ?? repoRoot);
|
|
23
|
+
try {
|
|
24
|
+
(0, dev_gate_js_1.assertPolarisDevContext)(root);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const report = (0, score_js_1.scoreRun)(root, runId);
|
|
32
|
+
const output = cmdOptions.json
|
|
33
|
+
? JSON.stringify(report)
|
|
34
|
+
: JSON.stringify(report, null, 2);
|
|
35
|
+
process.stdout.write(`${output}\n`);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
process.stderr.write(`autoresearch score error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
autoresearch
|
|
43
|
+
.command("propose <diagnosis-file>")
|
|
44
|
+
.description("File Linear improvement proposals from a diagnosis report (dev-gated — never auto-applied)")
|
|
45
|
+
.option("-r, --repo-root <path>", "Repository root", repoRoot)
|
|
46
|
+
.option("--team <team>", "Linear team name or ID to file issues in", "Polaris")
|
|
47
|
+
.option("--dry-run", "Log what would be created without calling Linear")
|
|
48
|
+
.option("--json", "Output raw JSON (default: pretty-printed)")
|
|
49
|
+
.action(async (diagnosisFile, cmdOptions) => {
|
|
50
|
+
const root = (0, node_path_1.resolve)(cmdOptions.repoRoot ?? repoRoot);
|
|
51
|
+
try {
|
|
52
|
+
(0, dev_gate_js_1.assertPolarisDevContext)(root);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
let report;
|
|
59
|
+
try {
|
|
60
|
+
report = (0, proposal_js_1.loadDiagnosisReport)((0, node_path_1.resolve)(diagnosisFile));
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
process.stderr.write(`autoresearch propose: invalid diagnosis file: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const proposals = (0, proposal_js_1.buildProposals)(report);
|
|
67
|
+
if (proposals.length === 0) {
|
|
68
|
+
process.stdout.write("No failed gates with fix zone mappings — nothing to propose.\n");
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
const apiKey = process.env["LINEAR_API_KEY"];
|
|
72
|
+
if (!apiKey && !cmdOptions.dryRun) {
|
|
73
|
+
process.stderr.write("autoresearch propose: LINEAR_API_KEY environment variable is required.\n");
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const result = await (0, routing_js_1.routeProposals)(proposals, {
|
|
78
|
+
apiKey: apiKey ?? "",
|
|
79
|
+
teamKey: cmdOptions.team,
|
|
80
|
+
dryRun: cmdOptions.dryRun,
|
|
81
|
+
});
|
|
82
|
+
const output = cmdOptions.json
|
|
83
|
+
? JSON.stringify(result)
|
|
84
|
+
: JSON.stringify(result, null, 2);
|
|
85
|
+
process.stdout.write(`${output}\n`);
|
|
86
|
+
if (result.total_errors > 0) {
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
process.stderr.write(`autoresearch propose error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return autoresearch;
|
|
96
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -28,6 +28,7 @@ const medic_js_1 = require("./medic.js");
|
|
|
28
28
|
const welfare_js_1 = require("../map/welfare.js");
|
|
29
29
|
const adopt_command_js_1 = require("./adopt-command.js");
|
|
30
30
|
const simplicity_js_1 = require("../loop/simplicity.js");
|
|
31
|
+
const autoresearch_js_1 = require("./autoresearch.js");
|
|
31
32
|
function resolveStateFile(repoRoot, explicit) {
|
|
32
33
|
if (explicit)
|
|
33
34
|
return (0, node_path_1.resolve)(explicit);
|
|
@@ -109,6 +110,7 @@ function createPolarisCommand(options = {}) {
|
|
|
109
110
|
repoRoot,
|
|
110
111
|
}));
|
|
111
112
|
program.addCommand((0, adopt_command_js_1.createAdoptCommand)({ repoRoot }));
|
|
113
|
+
program.addCommand((0, autoresearch_js_1.createAutoresearchCommand)({ repoRoot }));
|
|
112
114
|
program
|
|
113
115
|
.command("simplicity")
|
|
114
116
|
.description("View or override the simplicity discipline mode for the active run")
|
package/dist/cli/init.js
CHANGED
|
@@ -21,9 +21,15 @@ const index_js_1 = require("../map/index.js");
|
|
|
21
21
|
const adopt_instructions_js_1 = require("./adopt-instructions.js");
|
|
22
22
|
const adopt_workspace_js_1 = require("./adopt-workspace.js");
|
|
23
23
|
const adopt_assets_js_1 = require("./adopt-assets.js");
|
|
24
|
+
const agent_setup_js_1 = require("./agent-setup.js");
|
|
25
|
+
const runner_js_1 = require("./setup-interview/runner.js");
|
|
26
|
+
const generate_js_1 = require("./setup-interview/generate.js");
|
|
27
|
+
const generator_js_1 = require("../skill-packet/generator.js");
|
|
28
|
+
const foreman_dispatch_js_1 = require("../loop/adapters/foreman-dispatch.js");
|
|
24
29
|
const adopt_genesis_js_1 = require("./adopt-genesis.js");
|
|
25
30
|
const adopt_report_js_1 = require("./adopt-report.js");
|
|
26
31
|
const artifact_policy_js_1 = require("../finalize/artifact-policy.js");
|
|
32
|
+
const report_js_1 = require("./setup-interview/report.js");
|
|
27
33
|
var init_detect_js_2 = require("./init-detect.js");
|
|
28
34
|
Object.defineProperty(exports, "detectRepoState", { enumerable: true, get: function () { return init_detect_js_2.detectRepoState; } });
|
|
29
35
|
const PLAN_COMPLETE_STATUSES = new Set(["completed", "skipped"]);
|
|
@@ -377,6 +383,50 @@ async function runInit(options = {}) {
|
|
|
377
383
|
process.stdout.write("This repo has existing content. Run `polaris init --adopt` to begin adoption.\nThis repo has existing content. Run polaris init --adopt to begin adoption.\n");
|
|
378
384
|
return;
|
|
379
385
|
}
|
|
386
|
+
// New/empty repo: run the setup interview and generate artifacts behind an approval gate.
|
|
387
|
+
if (!options.adopt && (repoState === "empty" || repoState === "new")) {
|
|
388
|
+
const interviewFn = options.runInterview ?? runner_js_1.runInterview;
|
|
389
|
+
let record;
|
|
390
|
+
try {
|
|
391
|
+
record = await interviewFn(repoRoot, { now: options.now });
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
395
|
+
process.stdout.write(`${msg}\n`);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const detected = detectCompaction(repoRoot);
|
|
399
|
+
const detectedRepoAnalysis = detectRepoAnalysis(repoRoot);
|
|
400
|
+
const generateFn = options.generateSetupArtifacts ?? generate_js_1.generateSetupArtifacts;
|
|
401
|
+
await generateFn(record, {
|
|
402
|
+
repoRoot,
|
|
403
|
+
dryRun: options.dryRun,
|
|
404
|
+
yes: options.yes,
|
|
405
|
+
now: options.now,
|
|
406
|
+
detectedProviders: detected,
|
|
407
|
+
detectedRepoAnalysis,
|
|
408
|
+
scaffoldRootSurfaces: options.scaffoldRootSurfaces,
|
|
409
|
+
generatePolarisRules: options.generatePolarisRules,
|
|
410
|
+
migrateSmartDocs: options.migrateSmartDocs,
|
|
411
|
+
runMapIndex: options.runMapIndex,
|
|
412
|
+
});
|
|
413
|
+
// Post-setup validation and checkpoint report
|
|
414
|
+
if (!options.dryRun) {
|
|
415
|
+
const checkpointReport = (0, report_js_1.buildCheckpointReport)({
|
|
416
|
+
repoRoot,
|
|
417
|
+
record,
|
|
418
|
+
now: options.now,
|
|
419
|
+
});
|
|
420
|
+
(0, report_js_1.writeCheckpointReport)(repoRoot, checkpointReport);
|
|
421
|
+
(0, report_js_1.printCheckpointReport)(checkpointReport);
|
|
422
|
+
// Check for validation failures
|
|
423
|
+
const failedValidations = Object.entries(checkpointReport.validationResults).filter(([_, result]) => !result.passed);
|
|
424
|
+
if (failedValidations.length > 0) {
|
|
425
|
+
process.stdout.write(`\nWarning: ${failedValidations.length} file(s) failed validation. Check the report above for details.\n`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
380
430
|
// Load existing config (if any) so we preserve user-authored fields.
|
|
381
431
|
let existing = {};
|
|
382
432
|
if ((0, node_fs_1.existsSync)(configPath)) {
|
|
@@ -415,6 +465,24 @@ async function runInit(options = {}) {
|
|
|
415
465
|
process.stdout.write(`polaris.config.json written to ${configPath}\n${providerSummary}\n`);
|
|
416
466
|
}
|
|
417
467
|
if (!options.adopt) {
|
|
468
|
+
// Launch Foreman with setup-bootstrap packet when execution providers are configured.
|
|
469
|
+
const initExecution = asRecord(updated.execution);
|
|
470
|
+
const initProviders = asRecord(initExecution.providers);
|
|
471
|
+
if (Object.keys(initProviders).length > 0) {
|
|
472
|
+
try {
|
|
473
|
+
const binding = await (0, agent_setup_js_1.resolveForeman)(repoRoot, updated);
|
|
474
|
+
const setupPacket = (0, generator_js_1.generateSetupBootstrapPacket)("init");
|
|
475
|
+
await (0, foreman_dispatch_js_1.dispatchForeman)({
|
|
476
|
+
packet: setupPacket,
|
|
477
|
+
provider: binding.provider,
|
|
478
|
+
executionConfig: updated.execution,
|
|
479
|
+
dryRun: options.dryRun,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
// Foreman dispatch is best-effort during init — don't block setup.
|
|
484
|
+
}
|
|
485
|
+
}
|
|
418
486
|
return;
|
|
419
487
|
}
|
|
420
488
|
const adoptionPlanPath = (0, node_path_1.join)(repoRoot, ".polaris", "adoption-plan.json");
|
|
@@ -548,7 +616,7 @@ function createInitCommand(options = {}) {
|
|
|
548
616
|
.option("--status", "detect and print current repository state without writing files")
|
|
549
617
|
.option("--adopt", "run existing repository adoption flow")
|
|
550
618
|
.option("--resume", "resume an approved adoption plan without prompting")
|
|
551
|
-
.option("--yes", "auto-approve adoption plan
|
|
619
|
+
.option("--yes", "auto-approve setup or adoption plan without prompting")
|
|
552
620
|
.option("--commit", "create an adoption commit when used with --adopt")
|
|
553
621
|
.action(async (cmdOptions) => {
|
|
554
622
|
await runInit({
|