@lsctech/polaris 0.4.2 → 0.4.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.
@@ -46,7 +46,7 @@ const commands_js_1 = require("./commands.js");
46
46
  * `.claude/commands/polaris-<verb>.md` file per verb.
47
47
  *
48
48
  * Skill-backed verbs route through the existing packet+chain path:
49
- * 1. Read .polaris/skills/<skill>/SKILL.md
49
+ * 1. Read .polaris/skills/<target-skill>/SKILL.md
50
50
  * 2. Run `polaris skill packet <skill>`
51
51
  * 3. Execute the chain
52
52
  *
@@ -96,8 +96,8 @@ See \`${command.routing}\` for the full routing protocol and skill directory res
96
96
 
97
97
  ## Execution
98
98
 
99
- 1. Look up \`/${command.name}\` in \`${command.routing}\` to find the target skill directory.
100
- 2. Read \`.polaris/skills/<target-skill>/SKILL.md\` — it is the authoritative instruction source.
99
+ 1. Look up \`/${command.name}\` in \`${command.routing}\` to confirm the target skill directory.
100
+ 2. Read \`.polaris/skills/${command.targetSkill}/SKILL.md\` — it is the authoritative instruction source.
101
101
  3. Run the skill bootloader:
102
102
  \`\`\`bash
103
103
  polaris skill packet ${command.skill}${command.args.length > 0 ? " $ARGUMENTS" : ""}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.CODEX_PLUGIN_SKILL_VERSION = void 0;
37
+ exports.generateCodexPluginSkill = generateCodexPluginSkill;
38
+ exports.generateCodexOpenAiYaml = generateCodexOpenAiYaml;
39
+ exports.generateAllCodexPluginSkills = generateAllCodexPluginSkills;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const commands_js_1 = require("./commands.js");
43
+ exports.CODEX_PLUGIN_SKILL_VERSION = "1";
44
+ function skillCommands() {
45
+ return commands_js_1.SLASH_COMMANDS.filter((command) => command.kind === "skill");
46
+ }
47
+ function renderArgs(command) {
48
+ if (command.args.length === 0)
49
+ return "None.";
50
+ return command.args
51
+ .map((arg) => `- \`${arg.name}\`${arg.required ? " (required)" : " (optional)"} - ${arg.description}`)
52
+ .join("\n");
53
+ }
54
+ function renderUsage(command) {
55
+ const argUsage = command.args
56
+ .map((arg) => (arg.required ? `<${arg.name}>` : `[${arg.name}]`))
57
+ .join(" ");
58
+ return argUsage ? `${command.name} ${argUsage}` : command.name;
59
+ }
60
+ function renderBootloaderArgs(command) {
61
+ const argUsage = command.args
62
+ .map((arg) => (arg.required ? `<${arg.name}>` : `[${arg.name}]`))
63
+ .join(" ");
64
+ return argUsage ? ` ${argUsage}` : "";
65
+ }
66
+ function generateCodexPluginSkill(command) {
67
+ return `---
68
+ name: ${command.name}
69
+ description: ${command.description}
70
+ ---
71
+ <!-- polaris-codex-skill-version: ${exports.CODEX_PLUGIN_SKILL_VERSION} -->
72
+
73
+ # ${command.name}
74
+
75
+ ${command.description}
76
+
77
+ This Codex plugin skill is a thin wrapper around the canonical Polaris skill. It does not implement a parallel runtime.
78
+
79
+ ## Usage
80
+
81
+ \`\`\`text
82
+ ${renderUsage(command)}
83
+ \`\`\`
84
+
85
+ ## Arguments
86
+
87
+ ${renderArgs(command)}
88
+
89
+ ## Mandatory Routing
90
+
91
+ 1. Read \`${command.routing}\` and resolve \`${command.name}\` to its target skill.
92
+ 2. Read \`.polaris/skills/${command.targetSkill}/SKILL.md\` before any repo inspection, tracker lookup, or runtime file reads.
93
+ 3. Run the skill bootloader from that canonical \`SKILL.md\`:
94
+ \`\`\`bash
95
+ polaris skill packet ${command.skill}${renderBootloaderArgs(command)}
96
+ \`\`\`
97
+ 4. If no packet is returned, stop and report: \`Blocking: Polaris could not authorize this run.\`
98
+ 5. Execute \`.polaris/skills/${command.targetSkill}/chain.md\` in strict step order.
99
+
100
+ If \`.polaris/skills/${command.targetSkill}/SKILL.md\` is missing, stop and report:
101
+ \`Blocking: skill packet not found at .polaris/skills/${command.targetSkill}/SKILL.md\`
102
+ `;
103
+ }
104
+ function generateCodexOpenAiYaml(command) {
105
+ const displayName = command.name
106
+ .split("-")
107
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
108
+ .join(" ");
109
+ return `interface:
110
+ display_name: "${displayName}"
111
+ short_description: "${command.description.replaceAll('"', '\\"')}"
112
+ brand_color: "#6366F1"
113
+ default_prompt: "Use $${command.name} to ${command.description.charAt(0).toLowerCase()}${command.description.slice(1)}."
114
+ `;
115
+ }
116
+ function generateAllCodexPluginSkills(outDir = ".codex/plugins/polaris/skills") {
117
+ fs.mkdirSync(outDir, { recursive: true });
118
+ const written = [];
119
+ for (const command of skillCommands()) {
120
+ const skillDir = path.join(outDir, command.name);
121
+ const agentsDir = path.join(skillDir, "agents");
122
+ fs.mkdirSync(agentsDir, { recursive: true });
123
+ const skillPath = path.join(skillDir, "SKILL.md");
124
+ fs.writeFileSync(skillPath, generateCodexPluginSkill(command), "utf8");
125
+ written.push(skillPath);
126
+ const yamlPath = path.join(agentsDir, "openai.yaml");
127
+ fs.writeFileSync(yamlPath, generateCodexOpenAiYaml(command), "utf8");
128
+ written.push(yamlPath);
129
+ }
130
+ return written;
131
+ }
@@ -7,6 +7,7 @@ exports.SLASH_COMMANDS = [
7
7
  name: "polaris-run",
8
8
  kind: "skill",
9
9
  skill: "run",
10
+ targetSkill: "polaris-run",
10
11
  routing: ".polaris/skills/ROUTING.md",
11
12
  args: [
12
13
  {
@@ -21,6 +22,7 @@ exports.SLASH_COMMANDS = [
21
22
  name: "polaris-analyze",
22
23
  kind: "skill",
23
24
  skill: "analyze",
25
+ targetSkill: "polaris-analyze",
24
26
  routing: ".polaris/skills/ROUTING.md",
25
27
  args: [
26
28
  {
@@ -31,6 +33,15 @@ exports.SLASH_COMMANDS = [
31
33
  ],
32
34
  description: "Analyze a cluster and produce an implementation plan via the Analyst skill packet",
33
35
  },
36
+ {
37
+ name: "polaris-finalize",
38
+ kind: "skill",
39
+ skill: "run",
40
+ targetSkill: "polaris-run",
41
+ routing: ".polaris/skills/ROUTING.md",
42
+ args: [],
43
+ description: "Finalize the active Polaris run through the Foreman skill packet",
44
+ },
34
45
  {
35
46
  name: "polaris-init",
36
47
  kind: "cli",
@@ -48,7 +59,8 @@ exports.SLASH_COMMANDS = [
48
59
  {
49
60
  name: "polaris-reconcile",
50
61
  kind: "skill",
51
- skill: "triage",
62
+ skill: "reconcile",
63
+ targetSkill: "polaris-reconcile",
52
64
  routing: ".polaris/skills/ROUTING.md",
53
65
  args: [
54
66
  {
@@ -59,6 +71,21 @@ exports.SLASH_COMMANDS = [
59
71
  ],
60
72
  description: "Reconcile project cognition via the triage skill packet",
61
73
  },
74
+ {
75
+ name: "polaris-catalog",
76
+ kind: "skill",
77
+ skill: "catalog",
78
+ targetSkill: "polaris-catalog",
79
+ routing: ".polaris/skills/ROUTING.md",
80
+ args: [
81
+ {
82
+ name: "cluster_id",
83
+ required: true,
84
+ description: "Cluster ID to catalog (e.g., POL-257)",
85
+ },
86
+ ],
87
+ description: "Catalog project cognition and SmartDocs via the catalog skill packet",
88
+ },
62
89
  {
63
90
  name: "polaris-status",
64
91
  kind: "cli",
@@ -66,6 +93,24 @@ exports.SLASH_COMMANDS = [
66
93
  args: [],
67
94
  description: "Print the current Polaris loop run state summary",
68
95
  },
96
+ {
97
+ name: "docs-ingest",
98
+ kind: "skill",
99
+ skill: "ingest",
100
+ targetSkill: "docs-ingest",
101
+ routing: ".polaris/skills/ROUTING.md",
102
+ args: [],
103
+ description: "Ingest raw documentation files through the Polaris SmartDocs skill packet",
104
+ },
105
+ {
106
+ name: "docs-promote",
107
+ kind: "skill",
108
+ skill: "promote",
109
+ targetSkill: "docs-promote",
110
+ routing: ".polaris/skills/ROUTING.md",
111
+ args: [],
112
+ description: "Review and promote candidate SmartDocs through the Polaris governance skill packet",
113
+ },
69
114
  ];
70
115
  exports.SLASH_COMMAND_BY_NAME = Object.fromEntries(exports.SLASH_COMMANDS.map((command) => [command.name, command]));
71
116
  function resolveSlashCommand(name) {
@@ -35,10 +35,12 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.detectShimDrift = detectShimDrift;
37
37
  exports.syncShims = syncShims;
38
+ exports.syncCodexPluginSkills = syncCodexPluginSkills;
38
39
  const fs = __importStar(require("fs"));
39
40
  const path = __importStar(require("path"));
40
41
  const commands_js_1 = require("./commands.js");
41
42
  const claude_generator_js_1 = require("./claude-generator.js");
43
+ const codex_generator_js_1 = require("./codex-generator.js");
42
44
  /**
43
45
  * Workspace sync and versioning for generated agent-plugin shims.
44
46
  *
@@ -106,3 +108,6 @@ function syncShims(outDir = ".claude/commands") {
106
108
  }
107
109
  return { written, drift };
108
110
  }
111
+ function syncCodexPluginSkills(outDir = ".codex/plugins/polaris/skills") {
112
+ return { written: (0, codex_generator_js_1.generateAllCodexPluginSkills)(outDir) };
113
+ }
@@ -86,9 +86,18 @@ function gateUserIntervened(artifacts) {
86
86
  };
87
87
  }
88
88
  /**
89
- * foreman-resent-packet: Was the packet dispatched more than once (dispatch_epoch > 1)?
89
+ * foreman-resent-packet: Was the same child dispatched more than once?
90
90
  *
91
- * Evidence: dispatch_boundary.dispatch_epoch in current-state.json.
91
+ * Evidence:
92
+ * - open_children_meta.<child>.dispatch_record.dispatch_count (if runtime tracks it)
93
+ * - ledger child-dispatched events (issue_id)
94
+ * - telemetry child-dispatched events (child_id)
95
+ *
96
+ * A normal multi-session run has dispatch_epoch > 1 because distinct children are
97
+ * dispatched across sessions. That is expected. The problematic pattern is the
98
+ * foreman re-sending a worker packet to the same child after that child already
99
+ * returned a result. When per-child dispatch count data is unavailable, the gate
100
+ * is skipped rather than failing on dispatch_epoch alone.
92
101
  */
93
102
  function gateForemanResentPacket(artifacts) {
94
103
  const state = artifacts.currentState;
@@ -98,13 +107,57 @@ function gateForemanResentPacket(artifacts) {
98
107
  if (typeof dispatchEpoch !== "number") {
99
108
  return { gate: "foreman-resent-packet", outcome: "skipped", detail: "dispatch_epoch not present in state" };
100
109
  }
101
- const failed = dispatchEpoch > 1;
110
+ const perChildCounts = countChildDispatches(artifacts);
111
+ if (perChildCounts) {
112
+ const reDispatched = Array.from(perChildCounts.entries())
113
+ .filter(([, count]) => count > 1)
114
+ .map(([childId]) => childId);
115
+ const failed = reDispatched.length > 0;
116
+ return {
117
+ gate: "foreman-resent-packet",
118
+ outcome: failed ? "failed" : "passed",
119
+ detail: failed ? `child re-dispatched: ${reDispatched.join(", ")}` : undefined,
120
+ };
121
+ }
122
+ // No per-child dispatch data available. A single epoch cannot contain a re-dispatch.
123
+ if (dispatchEpoch === 1) {
124
+ return { gate: "foreman-resent-packet", outcome: "passed" };
125
+ }
102
126
  return {
103
127
  gate: "foreman-resent-packet",
104
- outcome: failed ? "failed" : "passed",
105
- detail: failed ? `dispatch_epoch=${dispatchEpoch}` : undefined,
128
+ outcome: "skipped",
129
+ detail: "per-child dispatch count data unavailable",
106
130
  };
107
131
  }
132
+ /** Counts per-child dispatches from all available artifact sources, or null if none are present. */
133
+ function countChildDispatches(artifacts) {
134
+ const counts = new Map();
135
+ const state = asRecord(artifacts.currentState);
136
+ const openChildrenMeta = asRecord(state?.["open_children_meta"]);
137
+ for (const [childId, meta] of Object.entries(openChildrenMeta ?? {})) {
138
+ const metaRec = asRecord(meta);
139
+ const dispatchRecord = asRecord(metaRec?.["dispatch_record"]);
140
+ const dispatchCount = dispatchRecord?.["dispatch_count"];
141
+ if (typeof dispatchCount === "number") {
142
+ counts.set(childId, Math.max(counts.get(childId) ?? 0, dispatchCount));
143
+ }
144
+ }
145
+ for (const event of artifacts.ledgerEvents) {
146
+ const rec = asRecord(event);
147
+ if (rec?.["event"] === "child-dispatched" && typeof rec["issue_id"] === "string") {
148
+ const childId = rec["issue_id"];
149
+ counts.set(childId, (counts.get(childId) ?? 0) + 1);
150
+ }
151
+ }
152
+ for (const event of artifacts.telemetryEvents) {
153
+ const rec = asRecord(event);
154
+ if (rec?.["event"] === "child-dispatched" && typeof rec["child_id"] === "string") {
155
+ const childId = rec["child_id"];
156
+ counts.set(childId, (counts.get(childId) ?? 0) + 1);
157
+ }
158
+ }
159
+ return counts.size > 0 ? counts : null;
160
+ }
108
161
  /**
109
162
  * foreman-fixed-worker-output: Did foreman make commits between child-complete
110
163
  * and the next dispatch?
@@ -94,6 +94,7 @@ function safeReaddir(dir) {
94
94
  return [];
95
95
  }
96
96
  }
97
+ const NON_WORKER_PREFIXES = ["librarian-", "CHART-", "medic-result-"];
97
98
  function readResultPackets(clusterDir) {
98
99
  if (!clusterDir)
99
100
  return [];
@@ -101,7 +102,7 @@ function readResultPackets(clusterDir) {
101
102
  if (!(0, node_fs_1.existsSync)(resultsDir))
102
103
  return [];
103
104
  return safeReaddir(resultsDir)
104
- .filter((f) => f.endsWith(".json"))
105
+ .filter((f) => f.endsWith(".json") && !NON_WORKER_PREFIXES.some((p) => f.startsWith(p)))
105
106
  .map((f) => readJson((0, node_path_1.join)(resultsDir, f)))
106
107
  .filter((v) => v !== undefined);
107
108
  }
@@ -158,8 +159,19 @@ function loadRunArtifacts(repoRoot, runId) {
158
159
  const telemetryEvents = telemetryPath ? (0, gates_js_1.readJsonLines)(telemetryPath) : [];
159
160
  // Result packets from cluster results dir
160
161
  const resultPackets = readResultPackets(clusterDir);
161
- // Also check for WorkerResultContracts inside result packets
162
- const workerResultContracts = extractWorkerResultContracts(resultPackets);
162
+ // WorkerResultContracts: prefer completed_children_results from current-state.json (Bug A fix)
163
+ let workerResultContracts;
164
+ const stateRec = currentState && typeof currentState === "object" && currentState !== null
165
+ ? currentState
166
+ : null;
167
+ const completedChildrenResults = stateRec?.["completed_children_results"];
168
+ if (completedChildrenResults && typeof completedChildrenResults === "object" && !Array.isArray(completedChildrenResults)) {
169
+ workerResultContracts = Object.values(completedChildrenResults).filter((v) => v !== null && typeof v === "object" && typeof v["worker_id"] === "string");
170
+ }
171
+ else {
172
+ // Legacy fallback: extract from result packet files
173
+ workerResultContracts = extractWorkerResultContracts(resultPackets);
174
+ }
163
175
  return {
164
176
  runId,
165
177
  runDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsctech/polaris",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Polaris — standalone taskchain orchestration framework for governed AI agent workflows",
5
5
  "bin": {
6
6
  "polaris": "dist/cli/index.js",