@primitive.ai/prim 0.1.0-alpha.49 → 0.1.0-alpha.51

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/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  checkAffectedDecisions,
13
13
  daemonOrDirectGet,
14
14
  formatDecisionsWarning
15
- } from "./chunk-WRPKAPVE.js";
15
+ } from "./chunk-VDLAAUWV.js";
16
16
  import {
17
17
  JOURNAL_DIR,
18
18
  SESSIONS_DIR,
@@ -21,10 +21,14 @@ import {
21
21
  listFlushing,
22
22
  pendingJournalStats,
23
23
  readMovesFromPath
24
- } from "./chunk-5K725K35.js";
24
+ } from "./chunk-BOTKPLTI.js";
25
+ import {
26
+ printJson,
27
+ registerSkillCommands
28
+ } from "./chunk-UJEQX52M.js";
25
29
  import {
26
30
  fetchFeedbackCapability
27
- } from "./chunk-CK75QBCB.js";
31
+ } from "./chunk-WELBNODJ.js";
28
32
  import {
29
33
  inspectWorkspaceId
30
34
  } from "./chunk-IMAIBPUC.js";
@@ -56,24 +60,19 @@ import {
56
60
  resolveAuthCredential,
57
61
  setStoredToken,
58
62
  withFileLock
59
- } from "./chunk-TPROV45L.js";
63
+ } from "./chunk-DWDEQRWN.js";
60
64
  import {
61
65
  daemonIsLive,
62
66
  daemonRequest
63
67
  } from "./chunk-UTKQTZHL.js";
64
68
 
65
69
  // src/index.ts
66
- import { readFileSync as readFileSync12 } from "fs";
67
- import { dirname as dirname8, resolve as resolve6 } from "path";
68
- import { fileURLToPath as fileURLToPath4 } from "url";
70
+ import { readFileSync as readFileSync10 } from "fs";
71
+ import { dirname as dirname7, resolve as resolve4 } from "path";
72
+ import { fileURLToPath as fileURLToPath2 } from "url";
69
73
  import { Command } from "commander";
70
74
  import updateNotifier from "update-notifier";
71
75
 
72
- // src/output.ts
73
- function printJson(data) {
74
- console.log(JSON.stringify(data, null, 2));
75
- }
76
-
77
76
  // src/commands/activation.ts
78
77
  function applyActivation(active) {
79
78
  const root = gitToplevel();
@@ -468,8 +467,8 @@ function registerAuthCommands(program2) {
468
467
  const state = base64url(randomBytes(16));
469
468
  const redirectUri = `http://${LOCALHOST}:${CALLBACK_PORT}/callback`;
470
469
  let settle;
471
- const outcome = new Promise((resolve7) => {
472
- settle = resolve7;
470
+ const outcome = new Promise((resolve5) => {
471
+ settle = resolve5;
473
472
  });
474
473
  const server = createServer((req, res) => {
475
474
  const url = new URL(req.url ?? "/", `http://${LOCALHOST}`);
@@ -483,12 +482,12 @@ function registerAuthCommands(program2) {
483
482
  res.end(page.html, () => settle(page.result));
484
483
  });
485
484
  try {
486
- await new Promise((resolve7, reject) => {
485
+ await new Promise((resolve5, reject) => {
487
486
  const onError = (err) => reject(err);
488
487
  server.once("error", onError);
489
488
  server.listen(CALLBACK_PORT, LOCALHOST, () => {
490
489
  server.removeListener("error", onError);
491
- resolve7();
490
+ resolve5();
492
491
  });
493
492
  });
494
493
  } catch (err) {
@@ -1767,7 +1766,7 @@ function clearStaleArtifacts() {
1767
1766
  }
1768
1767
  }
1769
1768
  function sleep(ms) {
1770
- return new Promise((resolve7) => setTimeout(resolve7, ms));
1769
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
1771
1770
  }
1772
1771
  function spawnDaemon(options) {
1773
1772
  const file = binFile(DAEMON_BIN);
@@ -4241,10 +4240,11 @@ function registerHooksCommands(program2) {
4241
4240
 
4242
4241
  // src/commands/moves.ts
4243
4242
  import { existsSync as existsSync8, mkdirSync as mkdirSync6, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "fs";
4244
- import { join as join7 } from "path";
4243
+ import { join as join8 } from "path";
4245
4244
 
4246
4245
  // src/flusher.ts
4247
4246
  import { createReadStream, renameSync as renameSync4, unlinkSync as unlinkSync3 } from "fs";
4247
+ import { dirname as dirname5, join as join7 } from "path";
4248
4248
  import { createInterface } from "readline";
4249
4249
  var BATCH_SIZE = 500;
4250
4250
  var HTTP_TIMEOUT_MS = 1e4;
@@ -4368,11 +4368,23 @@ async function flushOnce() {
4368
4368
  return { flushed: total };
4369
4369
  }
4370
4370
  var flushInFlight;
4371
+ var FLUSH_LOCK_PATH = join7(dirname5(JOURNAL_DIR), ".flush.lock");
4372
+ var FLUSH_LOCK_TIMEOUT_MS = 250;
4373
+ function isFlushLockContended(error) {
4374
+ return error instanceof Error && error.message.startsWith("timed out waiting for file lock");
4375
+ }
4371
4376
  function flush() {
4372
4377
  if (flushInFlight) {
4373
4378
  return flushInFlight;
4374
4379
  }
4375
- const attempt = flushOnce().finally(() => {
4380
+ const attempt = withFileLock(FLUSH_LOCK_PATH, flushOnce, {
4381
+ timeoutMs: FLUSH_LOCK_TIMEOUT_MS
4382
+ }).catch((error) => {
4383
+ if (isFlushLockContended(error)) {
4384
+ return { flushed: 0, skipped: true };
4385
+ }
4386
+ throw error;
4387
+ }).finally(() => {
4376
4388
  if (flushInFlight === attempt) {
4377
4389
  flushInFlight = void 0;
4378
4390
  }
@@ -4410,7 +4422,11 @@ var WORKSPACE_FILE = ".prim/workspace.json";
4410
4422
  function registerMovesCommands(program2) {
4411
4423
  const moves = program2.command("moves").description("Decision Event Pipeline \u2014 local journal");
4412
4424
  moves.command("flush").description("Drain all local move journals to the server").action(async () => {
4413
- const { flushed } = await flush();
4425
+ const { flushed, skipped } = await flush();
4426
+ if (skipped) {
4427
+ console.log("[prim] another flush is already draining; moves left journaled");
4428
+ return;
4429
+ }
4414
4430
  console.log(`[prim] flushed ${String(flushed)} move${flushed === 1 ? "" : "s"}`);
4415
4431
  });
4416
4432
  moves.command("status").description("Show per-bucket pending stats").action(() => {
@@ -4469,18 +4485,18 @@ function registerMovesCommands(program2) {
4469
4485
  }
4470
4486
  });
4471
4487
  moves.command("bind").description("Pin the current directory to an org via .prim/workspace.json").requiredOption("--orgId <orgId>", "Convex organization id").action((opts) => {
4472
- const dir = join7(process.cwd(), ".prim");
4488
+ const dir = join8(process.cwd(), ".prim");
4473
4489
  if (!existsSync8(dir)) {
4474
4490
  mkdirSync6(dir, { recursive: true, mode: DIR_MODE });
4475
4491
  }
4476
- const file = join7(process.cwd(), WORKSPACE_FILE);
4492
+ const file = join8(process.cwd(), WORKSPACE_FILE);
4477
4493
  writeFileSync5(file, JSON.stringify({ orgId: opts.orgId, boundAt: Date.now() }, null, 2), {
4478
4494
  mode: FILE_MODE
4479
4495
  });
4480
4496
  console.log(`[prim] bound ${process.cwd()} to org ${opts.orgId}`);
4481
4497
  });
4482
4498
  moves.command("drop").description("Remove the .prim/workspace.json binding from the cwd").action(() => {
4483
- const file = join7(process.cwd(), WORKSPACE_FILE);
4499
+ const file = join8(process.cwd(), WORKSPACE_FILE);
4484
4500
  if (!existsSync8(file)) {
4485
4501
  console.log("[prim] no workspace binding in cwd");
4486
4502
  return;
@@ -4581,7 +4597,7 @@ import {
4581
4597
  unlinkSync as unlinkSync5,
4582
4598
  writeFileSync as writeFileSync6
4583
4599
  } from "fs";
4584
- import { join as join8 } from "path";
4600
+ import { join as join9 } from "path";
4585
4601
  var DIR_MODE2 = 448;
4586
4602
  var FILE_MODE2 = 384;
4587
4603
  function ensureDir() {
@@ -4590,7 +4606,7 @@ function ensureDir() {
4590
4606
  }
4591
4607
  }
4592
4608
  function markerPath(sessionId) {
4593
- return join8(SESSIONS_DIR, `${sessionId}.json`);
4609
+ return join9(SESSIONS_DIR, `${sessionId}.json`);
4594
4610
  }
4595
4611
  function registerSessionCommands(program2) {
4596
4612
  const session = program2.command("session").description("Decision Event Pipeline \u2014 session binding markers");
@@ -4618,7 +4634,7 @@ function registerSessionCommands(program2) {
4618
4634
  for (const f of files) {
4619
4635
  const sessionId = f.replace(/\.json$/, "");
4620
4636
  try {
4621
- const m = JSON.parse(readFileSync7(join8(SESSIONS_DIR, f), "utf-8"));
4637
+ const m = JSON.parse(readFileSync7(join9(SESSIONS_DIR, f), "utf-8"));
4622
4638
  console.log(`${sessionId} org=${m.orgId}`);
4623
4639
  } catch {
4624
4640
  }
@@ -4638,7 +4654,7 @@ function registerSessionCommands(program2) {
4638
4654
  // src/commands/setup.ts
4639
4655
  import { spawnSync as spawnSync2 } from "child_process";
4640
4656
  import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
4641
- import { join as join9 } from "path";
4657
+ import { join as join10 } from "path";
4642
4658
  var EXIT_INCOMPLETE = 1;
4643
4659
  var EXIT_USAGE3 = 2;
4644
4660
  var SESSION_LABELS = {
@@ -4714,7 +4730,7 @@ function detectProjectConflicts(agent, run) {
4714
4730
  }
4715
4731
  try {
4716
4732
  const root = gitToplevel();
4717
- const preCommit = root && join9(root, ".git", "hooks", "pre-commit");
4733
+ const preCommit = root && join10(root, ".git", "hooks", "pre-commit");
4718
4734
  if (preCommit && existsSync10(preCommit) && readFileSync8(preCommit, "utf-8").includes("prim-pre-commit")) {
4719
4735
  conflicts.push(CONFLICT_HOOKS);
4720
4736
  }
@@ -4854,319 +4870,25 @@ function registerSetupCommand(program2, dependencies = {}) {
4854
4870
  });
4855
4871
  }
4856
4872
 
4857
- // src/commands/skill.ts
4858
- import {
4859
- closeSync as closeSync4,
4860
- existsSync as existsSync12,
4861
- fsyncSync as fsyncSync3,
4862
- openSync as openSync4,
4863
- readFileSync as readFileSync10,
4864
- renameSync as renameSync5,
4865
- writeFileSync as writeFileSync7
4866
- } from "fs";
4867
- import { homedir as homedir8 } from "os";
4868
- import { dirname as dirname6, join as join11, resolve as resolve4 } from "path";
4869
- import { fileURLToPath as fileURLToPath2 } from "url";
4870
- import { createPatch } from "diff";
4871
-
4872
- // src/commands/claude-plugin.ts
4873
- import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync9, readdirSync as readdirSync2, rmSync as rmSync3, rmdirSync } from "fs";
4874
- import { homedir as homedir7 } from "os";
4875
- import { dirname as dirname5, join as join10, resolve as resolve3 } from "path";
4876
- import { fileURLToPath } from "url";
4877
- var __dirname = dirname5(fileURLToPath(import.meta.url));
4878
- var PLUGIN_DESCRIPTION = "Primitive decision-graph guidance for the prim CLI \u2014 a model-invoked skill installed by prim skill install.";
4879
- function resolvePluginDir(cwd, scope) {
4880
- if (scope && scope !== "user" && scope !== "project") {
4881
- console.error(`Unknown --scope "${scope}" (expected user or project)`);
4882
- return null;
4883
- }
4884
- const base = scope === "user" ? join10(homedir7(), ".claude") : join10(gitToplevel(cwd) ?? cwd, ".claude");
4885
- return join10(base, "skills", "prim");
4886
- }
4887
- function packageVersion() {
4888
- let dir = __dirname;
4889
- while (dir !== dirname5(dir)) {
4890
- const p = resolve3(dir, "package.json");
4891
- if (existsSync11(p)) return JSON.parse(readFileSync9(p, "utf-8")).version;
4892
- dir = dirname5(dir);
4893
- }
4894
- return "0.0.0";
4895
- }
4896
- function pluginManifest() {
4897
- const manifest = { name: "prim", description: PLUGIN_DESCRIPTION, version: packageVersion() };
4898
- return `${JSON.stringify(manifest, null, 2)}
4899
- `;
4900
- }
4901
- function removeDirIfEmpty(dir) {
4902
- if (existsSync11(dir) && readdirSync2(dir).length === 0) rmdirSync(dir);
4903
- }
4904
- function pluginPaths(dir) {
4905
- return {
4906
- manifestPath: join10(dir, ".claude-plugin", "plugin.json"),
4907
- skillPath: join10(dir, "SKILL.md")
4908
- };
4909
- }
4910
- function installClaudePlugin(cwd, opts) {
4911
- const dir = resolvePluginDir(cwd, opts.scope);
4912
- if (dir === null) return 1;
4913
- const { manifestPath, skillPath } = pluginPaths(dir);
4914
- const manifest = pluginManifest();
4915
- const skill = loadSkill();
4916
- const manifestCurrent = existsSync11(manifestPath) ? readFileSync9(manifestPath, "utf-8") : null;
4917
- const skillCurrent = existsSync11(skillPath) ? readFileSync9(skillPath, "utf-8") : null;
4918
- if (manifestCurrent === manifest && skillCurrent === skill) {
4919
- console.log("No changes \u2014 prim skill plugin already up to date.");
4920
- return 0;
4921
- }
4922
- if (opts.dryRun) {
4923
- console.log(`Would write plugin to ${dir} (.claude-plugin/plugin.json + SKILL.md)`);
4924
- return 0;
4925
- }
4926
- mkdirSync8(join10(dir, ".claude-plugin"), { recursive: true });
4927
- atomicWrite3(manifestPath, manifest);
4928
- atomicWrite3(skillPath, skill);
4929
- console.log(`Installed prim skill plugin at ${dir}`);
4930
- console.log("Restart Claude Code or run /reload-plugins to load it.");
4931
- if (opts.scope !== "user") {
4932
- console.log("Project-scope plugins load only when Claude Code launches from this directory.");
4933
- }
4934
- return 0;
4935
- }
4936
- function uninstallClaudePlugin(cwd, opts) {
4937
- const dir = resolvePluginDir(cwd, opts.scope);
4938
- if (dir === null) return 1;
4939
- const { manifestPath, skillPath } = pluginPaths(dir);
4940
- if (!existsSync11(manifestPath) && !existsSync11(skillPath)) {
4941
- console.log(`prim skill plugin not present at ${dir}`);
4942
- return 0;
4943
- }
4944
- rmSync3(manifestPath, { force: true });
4945
- rmSync3(skillPath, { force: true });
4946
- removeDirIfEmpty(join10(dir, ".claude-plugin"));
4947
- removeDirIfEmpty(dir);
4948
- console.log(`Removed prim skill plugin from ${dir}`);
4949
- return 0;
4950
- }
4951
- function statusClaudePlugin(cwd, opts) {
4952
- const dir = resolvePluginDir(cwd, opts.scope);
4953
- if (dir === null) return 1;
4954
- const { skillPath } = pluginPaths(dir);
4955
- const installed = existsSync11(skillPath);
4956
- if (opts.json) {
4957
- printJson({ installed, target: dir });
4958
- return installed ? 0 : 1;
4959
- }
4960
- if (installed) {
4961
- console.log(`prim skill plugin installed at ${dir}`);
4962
- return 0;
4963
- }
4964
- console.log(`No prim skill plugin at ${dir}`);
4965
- return 1;
4966
- }
4967
-
4968
- // src/commands/skill.ts
4969
- var __dirname2 = dirname6(fileURLToPath2(import.meta.url));
4970
- var SKILL_BEGIN = "<!-- BEGIN PRIM SKILL v1 -->";
4971
- var SKILL_END = "<!-- END PRIM SKILL v1 -->";
4972
- var TARGET_CANDIDATES = [
4973
- "CLAUDE.md",
4974
- "AGENTS.md",
4975
- ".hermes.md",
4976
- ".cursor/rules",
4977
- ".windsurfrules",
4978
- ".github/instructions/primitive.md"
4979
- ];
4980
- var DEFAULT_TARGET = "CLAUDE.md";
4981
- var AGENT_TARGET = {
4982
- claude: "CLAUDE.md",
4983
- codex: "AGENTS.md",
4984
- hermes: ".hermes.md"
4985
- };
4986
- function userTargetFor(agent) {
4987
- if (agent === "claude") return join11(homedir8(), ".claude", "CLAUDE.md");
4988
- if (agent === "codex") return join11(homedir8(), ".codex", "AGENTS.md");
4989
- if (agent === "hermes") {
4990
- return join11(process.env.HERMES_HOME ?? join11(homedir8(), ".hermes"), ".hermes.md");
4991
- }
4992
- return null;
4993
- }
4994
- function loadSkill() {
4995
- let dir = __dirname2;
4996
- while (dir !== dirname6(dir)) {
4997
- const p = resolve4(dir, "SKILL.md");
4998
- if (existsSync12(p)) return readFileSync10(p, "utf-8");
4999
- dir = dirname6(dir);
5000
- }
5001
- throw new Error("SKILL.md not found in package");
5002
- }
5003
- function detectTargets(cwd) {
5004
- return TARGET_CANDIDATES.filter((p) => existsSync12(resolve4(cwd, p)));
5005
- }
5006
- function detectNewline(content) {
5007
- return content.includes("\r\n") ? "\r\n" : "\n";
5008
- }
5009
- function composeBlock(skill, eol) {
5010
- const body = skill.replace(/\r?\n/g, eol);
5011
- return `${SKILL_BEGIN}${eol}${body}${eol}${SKILL_END}`;
5012
- }
5013
- function applyBlock(existing, block, eol) {
5014
- const b = existing.indexOf(SKILL_BEGIN);
5015
- const e = existing.indexOf(SKILL_END);
5016
- if (b !== -1 && e !== -1) {
5017
- return existing.slice(0, b) + block + existing.slice(e + SKILL_END.length);
5018
- }
5019
- if (existing.length === 0) return `${block}${eol}`;
5020
- const sep = existing.endsWith(eol) ? "" : eol;
5021
- return `${existing}${sep}${block}${eol}`;
5022
- }
5023
- function removeBlock(existing) {
5024
- const b = existing.indexOf(SKILL_BEGIN);
5025
- const e = existing.indexOf(SKILL_END);
5026
- if (b === -1 || e === -1) return null;
5027
- const out = existing.slice(0, b) + existing.slice(e + SKILL_END.length);
5028
- return out.replace(/(\r?\n){2,}$/, "$1");
5029
- }
5030
- function atomicWrite3(target, content) {
5031
- const tmp = `${target}.tmp`;
5032
- writeFileSync7(tmp, content);
5033
- const fd = openSync4(tmp, "r+");
5034
- try {
5035
- fsyncSync3(fd);
5036
- } finally {
5037
- closeSync4(fd);
5038
- }
5039
- renameSync5(tmp, target);
5040
- }
5041
- function resolveTarget(cwd, opts) {
5042
- if (opts.scope && opts.scope !== "user" && opts.scope !== "project") {
5043
- console.error(`Unknown --scope "${opts.scope}" (expected user or project)`);
5044
- return null;
5045
- }
5046
- if (opts.target) return resolve4(cwd, opts.target);
5047
- if (opts.scope === "user") {
5048
- if (!opts.agent) {
5049
- console.error("--scope user requires --agent (claude, codex, or hermes)");
5050
- return null;
5051
- }
5052
- const userTarget = userTargetFor(opts.agent);
5053
- if (userTarget) return userTarget;
5054
- console.error(`Unknown --agent "${opts.agent}" (expected claude, codex, or hermes)`);
5055
- return null;
5056
- }
5057
- if (opts.agent) {
5058
- const mapped = AGENT_TARGET[opts.agent];
5059
- if (typeof mapped === "string") return resolve4(cwd, mapped);
5060
- console.error(`Unknown --agent "${opts.agent}" (expected claude, codex, or hermes)`);
5061
- return null;
5062
- }
5063
- const matches = detectTargets(cwd);
5064
- if (matches.length === 0) return resolve4(cwd, DEFAULT_TARGET);
5065
- if (matches.length === 1) return resolve4(cwd, matches[0]);
5066
- console.error("Multiple rules files detected. Use --target to disambiguate:");
5067
- for (const m of matches) console.error(` ${m}`);
5068
- return null;
5069
- }
5070
- function runInstall(cwd, opts) {
5071
- if (opts.agent === "claude" && !opts.target) return installClaudePlugin(cwd, opts);
5072
- const target = resolveTarget(cwd, opts);
5073
- if (target === null) return 1;
5074
- const existing = existsSync12(target) ? readFileSync10(target, "utf-8") : "";
5075
- const eol = existing ? detectNewline(existing) : "\n";
5076
- const block = composeBlock(loadSkill(), eol);
5077
- const next = applyBlock(existing, block, eol);
5078
- if (next === existing) {
5079
- console.log("No changes \u2014 skill block already up to date.");
5080
- return 0;
5081
- }
5082
- if (opts.dryRun) {
5083
- process.stdout.write(createPatch(target, existing, next, "current", "proposed"));
5084
- return 0;
5085
- }
5086
- atomicWrite3(target, next);
5087
- console.log(`Wrote ${Buffer.byteLength(next)} bytes to ${target}`);
5088
- return 0;
5089
- }
5090
- function runUninstall(cwd, opts) {
5091
- if (opts.agent === "claude" && !opts.target) return uninstallClaudePlugin(cwd, opts);
5092
- const target = resolveTarget(cwd, opts);
5093
- if (target === null) return 1;
5094
- if (!existsSync12(target)) {
5095
- console.log(`Skill block not present at ${target}`);
5096
- return 0;
5097
- }
5098
- const existing = readFileSync10(target, "utf-8");
5099
- const next = removeBlock(existing);
5100
- if (next === null) {
5101
- console.log(`Skill block not present at ${target}`);
5102
- return 0;
5103
- }
5104
- atomicWrite3(target, next);
5105
- console.log(`Removed skill block from ${target}`);
5106
- return 0;
5107
- }
5108
- function runStatus(cwd, opts) {
5109
- if (opts.agent === "claude" && !opts.target) return statusClaudePlugin(cwd, opts);
5110
- const target = resolveTarget(cwd, opts);
5111
- if (target === null) return 1;
5112
- const fileExists = existsSync12(target);
5113
- let installed = false;
5114
- if (fileExists) {
5115
- const content = readFileSync10(target, "utf-8");
5116
- installed = content.includes(SKILL_BEGIN) && content.includes(SKILL_END);
5117
- }
5118
- if (opts.json) {
5119
- printJson({ installed, target });
5120
- return installed ? 0 : 1;
5121
- }
5122
- if (!fileExists) {
5123
- console.log(`No rules file at ${target}`);
5124
- return 1;
5125
- }
5126
- if (installed) {
5127
- console.log(`PRIM SKILL v1 installed at ${target}`);
5128
- return 0;
5129
- }
5130
- console.log(`No PRIM SKILL block at ${target}`);
5131
- return 1;
5132
- }
5133
- function registerSkillCommands(program2) {
5134
- const skill = program2.command("skill").description("Manage the prim skill in your project rules file");
5135
- skill.command("install").description("Install the prim skill block into your project rules file").option("--target <path>", "Path to the rules file (overrides auto-detection)").option("--agent <agent>", "claude, codex, or hermes (selects the default rules file)").option("--scope <scope>", "project (default, this repo) or user (machine-global \u2014 every repo)").option("--dry-run", "Print a unified diff without writing").action((opts) => {
5136
- try {
5137
- process.exit(runInstall(process.cwd(), opts));
5138
- } catch (err) {
5139
- console.error(err instanceof Error ? err.message : String(err));
5140
- process.exit(2);
5141
- }
5142
- });
5143
- skill.command("uninstall").description("Remove the prim skill block from your project rules file").option("--target <path>", "Path to the rules file (overrides auto-detection)").option("--agent <agent>", "claude, codex, or hermes (selects the default rules file)").option("--scope <scope>", "project (default, this repo) or user (machine-global \u2014 every repo)").action((opts) => {
5144
- process.exit(runUninstall(process.cwd(), opts));
5145
- });
5146
- skill.command("status").description("Report whether the prim skill block is installed").option("--target <path>", "Path to the rules file (overrides auto-detection)").option("--agent <agent>", "claude, codex, or hermes (selects the default rules file)").option("--scope <scope>", "project (default, this repo) or user (machine-global \u2014 every repo)").option("--json", "Output as JSON").action((opts) => {
5147
- process.exit(runStatus(process.cwd(), opts));
5148
- });
5149
- }
5150
-
5151
4873
  // src/commands/statusline.ts
5152
- import { readFileSync as readFileSync11 } from "fs";
5153
- import { dirname as dirname7, resolve as resolve5 } from "path";
5154
- import { fileURLToPath as fileURLToPath3 } from "url";
4874
+ import { readFileSync as readFileSync9 } from "fs";
4875
+ import { dirname as dirname6, resolve as resolve3 } from "path";
4876
+ import { fileURLToPath } from "url";
5155
4877
  var STATUSLINE_TIMEOUT_MS = 200;
5156
4878
  var STATUSLINE_NAME_CAP = 3;
5157
4879
  function readPackageVersion() {
5158
4880
  try {
5159
- const here = dirname7(fileURLToPath3(import.meta.url));
4881
+ const here = dirname6(fileURLToPath(import.meta.url));
5160
4882
  const candidates = [
5161
4883
  // The supervised runtime stages a tiny manifest beside the standalone
5162
4884
  // statusline bundle, so it remains versioned without loading the package.
5163
- resolve5(here, "manifest.json"),
5164
- resolve5(here, "../../package.json"),
5165
- resolve5(here, "../package.json")
4885
+ resolve3(here, "manifest.json"),
4886
+ resolve3(here, "../../package.json"),
4887
+ resolve3(here, "../package.json")
5166
4888
  ];
5167
4889
  for (const path of candidates) {
5168
4890
  try {
5169
- const pkg2 = JSON.parse(readFileSync11(path, "utf-8"));
4891
+ const pkg2 = JSON.parse(readFileSync9(path, "utf-8"));
5170
4892
  if (pkg2.version) {
5171
4893
  return pkg2.version;
5172
4894
  }
@@ -5197,6 +4919,9 @@ async function renderStatusline() {
5197
4919
  return `primitive ${version} (daemon: down)`;
5198
4920
  }
5199
4921
  if (snapshot.healthy === false) {
4922
+ if (snapshot.needsReauth) {
4923
+ return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`)`;
4924
+ }
5200
4925
  if (snapshot.ingestion?.healthy === false) {
5201
4926
  const pending = snapshot.ingestion.pendingCount;
5202
4927
  const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
@@ -5350,8 +5075,8 @@ function registerWelcomeCommand(program2, deps = { getClient }) {
5350
5075
  }
5351
5076
 
5352
5077
  // src/index.ts
5353
- var __dirname3 = dirname8(fileURLToPath4(import.meta.url));
5354
- var pkg = JSON.parse(readFileSync12(resolve6(__dirname3, "../package.json"), "utf-8"));
5078
+ var __dirname = dirname7(fileURLToPath2(import.meta.url));
5079
+ var pkg = JSON.parse(readFileSync10(resolve4(__dirname, "../package.json"), "utf-8"));
5355
5080
  updateNotifier({ pkg }).notify();
5356
5081
  var program = new Command();
5357
5082
  program.name("prim").description("CLI for Primitive's decision graph").version(pkg.version).option("-y, --yes", "auto-confirm prompts").option(
@@ -312,6 +312,9 @@ async function renderStatusline() {
312
312
  return `primitive ${version} (daemon: down)`;
313
313
  }
314
314
  if (snapshot.healthy === false) {
315
+ if (snapshot.needsReauth) {
316
+ return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`)`;
317
+ }
315
318
  if (snapshot.ingestion?.healthy === false) {
316
319
  const pending = snapshot.ingestion.pendingCount;
317
320
  const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitive.ai/prim",
3
- "version": "0.1.0-alpha.49",
3
+ "version": "0.1.0-alpha.51",
4
4
  "description": "CLI for Primitive's decision graph — passive decision capture, conflict gate, and team presence",
5
5
  "type": "module",
6
6
  "license": "MIT",