@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/SKILL.md +1 -1
- package/dist/{chunk-S5NUHFAD.js → chunk-4GLVJLEQ.js} +5 -5
- package/dist/{chunk-5K725K35.js → chunk-BOTKPLTI.js} +1 -1
- package/dist/{chunk-TPROV45L.js → chunk-DWDEQRWN.js} +12 -1
- package/dist/chunk-UJEQX52M.js +520 -0
- package/dist/{chunk-WRPKAPVE.js → chunk-VDLAAUWV.js} +1 -1
- package/dist/{chunk-CK75QBCB.js → chunk-WELBNODJ.js} +1 -1
- package/dist/daemon/server.js +46 -18
- package/dist/hooks/post-commit.js +2 -2
- package/dist/hooks/post-tool-use.js +2 -2
- package/dist/hooks/pre-commit.js +2 -2
- package/dist/hooks/pre-tool-use.js +1 -1
- package/dist/hooks/prim-hook.js +4 -4
- package/dist/hooks/session-start.js +107 -61
- package/dist/index.js +57 -332
- package/dist/statusline-main.js +3 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
checkAffectedDecisions,
|
|
13
13
|
daemonOrDirectGet,
|
|
14
14
|
formatDecisionsWarning
|
|
15
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
67
|
-
import { dirname as
|
|
68
|
-
import { fileURLToPath as
|
|
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((
|
|
472
|
-
settle =
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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 &&
|
|
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
|
|
5153
|
-
import { dirname as
|
|
5154
|
-
import { fileURLToPath
|
|
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 =
|
|
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
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
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(
|
|
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
|
|
5354
|
-
var pkg = JSON.parse(
|
|
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(
|
package/dist/statusline-main.js
CHANGED
|
@@ -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