@lsctech/polaris 0.3.1 → 0.3.3

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.
@@ -52,14 +52,15 @@ function groupAndSort(packets) {
52
52
  * Write _review-queue.json (canonical) and _review-queue.md (display-only) to outputDir.
53
53
  * Markdown is regenerated from JSON — never parse markdown to recover decisions.
54
54
  */
55
- function writeReviewQueue(packets, runId, outputDir) {
55
+ function writeReviewQueue(packets, runId, outputDir, filename = "_review-queue.json") {
56
56
  (0, node_fs_1.mkdirSync)(outputDir, { recursive: true });
57
57
  const queueFile = {
58
58
  generated_at: new Date().toISOString(),
59
59
  run_id: runId,
60
60
  packets,
61
61
  };
62
- (0, node_fs_1.writeFileSync)((0, node_path_1.join)(outputDir, "_review-queue.json"), JSON.stringify(queueFile, null, 2) + "\n", "utf-8");
62
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(outputDir, filename), JSON.stringify(queueFile, null, 2) + "\n", "utf-8");
63
+ const mdFilename = filename.replace(/\.json$/, ".md");
63
64
  const sorted = groupAndSort(packets);
64
65
  const sections = sorted.map(renderPacketMarkdown).join("\n\n---\n\n");
65
66
  const md = [
@@ -69,21 +70,21 @@ function writeReviewQueue(packets, runId, outputDir) {
69
70
  `**Generated:** ${queueFile.generated_at}`,
70
71
  `**Pending review:** ${packets.length} document(s)`,
71
72
  ``,
72
- `> Markdown is display-only. Edit \`_review-queue.json\` to set \`reviewDecision\` fields.`,
73
+ `> Markdown is display-only. Edit \`${filename}\` to set \`reviewDecision\` fields.`,
73
74
  `> Rerun \`polaris docs ingest\` to apply decisions.`,
74
75
  ``,
75
76
  `---`,
76
77
  ``,
77
78
  sections,
78
79
  ].join("\n");
79
- (0, node_fs_1.writeFileSync)((0, node_path_1.join)(outputDir, "_review-queue.md"), md, "utf-8");
80
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(outputDir, mdFilename), md, "utf-8");
80
81
  }
81
82
  /**
82
83
  * Read review queue from JSON. Returns empty array if no queue file exists.
83
84
  * Never reads markdown.
84
85
  */
85
- function readReviewQueue(outputDir) {
86
- const jsonPath = (0, node_path_1.join)(outputDir, "_review-queue.json");
86
+ function readReviewQueue(outputDir, filename = "_review-queue.json") {
87
+ const jsonPath = (0, node_path_1.join)(outputDir, filename);
87
88
  if (!(0, node_fs_1.existsSync)(jsonPath))
88
89
  return [];
89
90
  try {
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.agenticDecideKey = agenticDecideKey;
4
+ const node_fs_1 = require("node:fs");
5
+ async function agenticDecideKey(packet) {
6
+ let docContent = "";
7
+ try {
8
+ if ((0, node_fs_1.existsSync)(packet.sourcePath)) {
9
+ docContent = (0, node_fs_1.readFileSync)(packet.sourcePath, "utf-8").slice(0, 3000);
10
+ }
11
+ }
12
+ catch { /* ignore */ }
13
+ // @ts-ignore: @anthropic-ai/sdk may not be installed as a dependency
14
+ const mod = await import("@anthropic-ai/sdk");
15
+ const Anthropic = mod.default ?? mod.Anthropic;
16
+ const client = new Anthropic();
17
+ const staleSymbols = packet.staleSymbols;
18
+ const triageFlag = packet.triageFlag;
19
+ const prompt = `You are reviewing a candidate documentation file flagged during Polaris docs triage.
20
+
21
+ Flag type: ${String(triageFlag ?? "unknown")}
22
+ Authority risk: ${packet.authorityRisk}
23
+ Recommendation from triage: ${packet.recommendation}
24
+ Reasoning: ${packet.reasoning.join("; ")}
25
+ ${Array.isArray(staleSymbols) ? `Stale symbols (not found in codebase graph): ${staleSymbols.join(", ")}` : ""}
26
+
27
+ Document content:
28
+ ---
29
+ ${docContent}
30
+ ---
31
+
32
+ Decide whether this document should be:
33
+ - approved: doc is valid doctrine and should be promoted to active
34
+ - rejected: doc is outdated, incorrect, or superseded and should be deprecated
35
+ - deferred: uncertain — needs human review
36
+
37
+ Respond with exactly one word: approve, reject, or defer.`;
38
+ const response = await client.messages.create({
39
+ model: "claude-haiku-4-5-20251001",
40
+ max_tokens: 10,
41
+ messages: [{ role: "user", content: prompt }],
42
+ });
43
+ const text = (response.content[0].text ?? "defer").trim().toLowerCase();
44
+ if (text.startsWith("approve"))
45
+ return "a";
46
+ if (text.startsWith("reject"))
47
+ return "r";
48
+ return "d";
49
+ }
@@ -13,6 +13,8 @@ const validate_instructions_js_1 = require("./validate-instructions.js");
13
13
  const doctrine_js_1 = require("./doctrine.js");
14
14
  const audit_js_1 = require("./audit.js");
15
15
  const triage_js_1 = require("./triage.js");
16
+ const adapter_js_1 = require("../graph/store/adapter.js");
17
+ const index_js_1 = require("../graph/query/index.js");
16
18
  /**
17
19
  * Build and return the top-level "docs" Commander command group for Polaris docs lifecycle workflows.
18
20
  *
@@ -140,12 +142,24 @@ function createDocsCommand(options = {}) {
140
142
  .description("Interactively review pending governance decisions in the review queue")
141
143
  .option("--queue <path>", "path to _review-queue.json (default: smartdocs/raw/_review-queue.json)")
142
144
  .option("-r, --repo-root <path>", "Repository root", defaultRepoRoot)
145
+ .option("--agentic", "use LLM agent to make review decisions automatically")
146
+ .option("--triage", "review the triage queue (_triage-queue.json) instead of the review queue")
143
147
  .action(async (opts) => {
148
+ const repoRoot = opts.repoRoot;
149
+ const queueFilename = opts.triage ? "_triage-queue.json" : "_review-queue.json";
150
+ const queueDir = opts.queue
151
+ ? (0, node_path_1.resolve)(opts.repoRoot, opts.queue)
152
+ .replace(/_review-queue\.json$/, "")
153
+ .replace(/_triage-queue\.json$/, "")
154
+ .replace(/\/$/, "")
155
+ : (0, node_path_1.resolve)(repoRoot, "smartdocs", "raw");
156
+ let readKey;
157
+ if (opts.agentic) {
158
+ const { agenticDecideKey } = await import("./agentic-review.js");
159
+ readKey = agenticDecideKey;
160
+ }
144
161
  try {
145
- const queueDir = opts.queue
146
- ? (0, node_path_1.resolve)(opts.repoRoot, opts.queue).replace(/_review-queue\.json$/, "").replace(/\/$/, "")
147
- : (0, node_path_1.resolve)(opts.repoRoot, "smartdocs", "raw");
148
- await (0, review_js_1.runReviewSession)({ repoRoot: opts.repoRoot, queueDir });
162
+ await (0, review_js_1.runReviewSession)({ repoRoot, queueDir, queueFilename, readKey });
149
163
  }
150
164
  catch (err) {
151
165
  console.error(`polaris docs review: ${err instanceof Error ? err.message : String(err)}`);
@@ -160,18 +174,35 @@ function createDocsCommand(options = {}) {
160
174
  .option("--resume", "Resume from last checkpoint (auto-detected by default)")
161
175
  .option("--dry-run", "Plan batches and print cost estimate without calling the LLM")
162
176
  .action(async (options) => {
177
+ const repoRoot = options.repoRoot;
178
+ const dbPath = (0, node_path_1.join)(repoRoot, ".polaris", "graph", "graph.sqlite");
179
+ const graphOutputPath = (0, node_path_1.join)(".polaris", "graph");
180
+ let store = null;
181
+ try {
182
+ store = new adapter_js_1.GraphStoreAdapter({ repoRoot, graphOutputPath, dbPath });
183
+ store.open();
184
+ (0, index_js_1.configureGraphQuery)({ graphStore: store });
185
+ }
186
+ catch {
187
+ (0, index_js_1.configureGraphQuery)({ graphStore: null });
188
+ }
163
189
  try {
164
190
  await (0, triage_js_1.runTriage)({
165
- repoRoot: options.repoRoot,
191
+ repoRoot,
166
192
  batchSize: parseInt(options.batchSize, 10) || 10,
167
193
  resume: options.resume,
168
194
  dryRun: options.dryRun,
195
+ symbolLookup: (name) => (0, index_js_1.lookupSymbol)(name) !== null,
196
+ graphStats: () => (0, index_js_1.getGraphStats)(),
169
197
  });
170
198
  }
171
199
  catch (err) {
172
200
  console.error(`polaris docs triage: ${err instanceof Error ? err.message : String(err)}`);
173
201
  process.exit(1);
174
202
  }
203
+ finally {
204
+ store?.close();
205
+ }
175
206
  });
176
207
  docs
177
208
  .command("migrate")
@@ -84,7 +84,8 @@ function readSingleKey() {
84
84
  async function runReviewSession(options) {
85
85
  const { repoRoot, readKey, getReviewedBy = defaultGetReviewedBy, output = (msg) => process.stdout.write(msg + "\n"), } = options;
86
86
  const queueDir = options.queueDir ?? (0, node_path_1.resolve)(repoRoot, "smartdocs", "raw");
87
- const packets = (0, index_js_1.readReviewQueue)(queueDir);
87
+ const queueFilename = options.queueFilename;
88
+ const packets = (0, index_js_1.readReviewQueue)(queueDir, queueFilename);
88
89
  if (packets.length === 0) {
89
90
  output("No review queue found. Run polaris docs ingest first.");
90
91
  return;
@@ -98,7 +99,7 @@ async function runReviewSession(options) {
98
99
  for (let i = 0; i < undecided.length; i++) {
99
100
  const packet = undecided[i];
100
101
  output(formatPacketCard(packet, i + 1, undecided.length));
101
- const key = readKey ? await readKey() : await readSingleKey();
102
+ const key = readKey ? await readKey(packet) : await readSingleKey();
102
103
  if (key === "q") {
103
104
  const remaining = undecided.length - decided;
104
105
  output(`\nSession ended. ${decided} decision(s) saved, ${remaining} packet(s) still pending.`);
@@ -126,7 +127,7 @@ async function runReviewSession(options) {
126
127
  reviewedBy: getReviewedBy(),
127
128
  };
128
129
  }
129
- (0, index_js_1.writeReviewQueue)(packets, "review-session", queueDir);
130
+ (0, index_js_1.writeReviewQueue)(packets, "review-session", queueDir, queueFilename);
130
131
  decided++;
131
132
  }
132
133
  const approved = packets.filter((p) => p.reviewDecision === "approve").length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsctech/polaris",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Polaris — standalone taskchain orchestration framework for governed AI agent workflows",
5
5
  "bin": {
6
6
  "polaris-cli": "dist/cli/index.js"