@primitive.ai/prim 0.1.0-alpha.17 → 0.1.0-alpha.18

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: prim
3
- description: Use the prim CLI for managing Primitive specs, contexts, projects, and pre-commit hooks. TRIGGER when the user mentions Primitive, prim, "specs" (in the Primitive sense), or "contexts" (in the Primitive sense); when the repo's package.json depends on @primitive.ai/prim; when the user asks to sync, map, update, or auto-map a spec; when configuring Primitive pre-commit hooks. SKIP when "spec" means test specs (vitest, jest, rspec), when "context" means React context or LLM context window, or for unrelated CLIs.
3
+ description: Use the prim CLI for Primitive specs, contexts, projects, pre-commit hooks, and the decision graph (passive decision capture, the conflict gate, reconcile, and team presence). TRIGGER when the user mentions Primitive, prim, "specs" or "contexts" (in the Primitive sense), or decisions / the decision graph / a conflict gate / reconcile; when the repo's package.json depends on @primitive.ai/prim; when the user asks to sync, map, update, or auto-map a spec; when an edit is denied or warned by a prior decision; when configuring Primitive hooks. SKIP when "spec" means test specs (vitest, jest, rspec), when "context" means React context or an LLM context window, or for unrelated CLIs.
4
4
  ---
5
5
 
6
6
  # Working with the prim CLI
@@ -35,6 +35,36 @@ The CLI auto-refreshes expired tokens. On unrecoverable expiry it throws `Authen
35
35
  2. Every command accepts `--help`. When unsure of flags, run `npx --yes @primitive.ai/prim <cmd> --help` rather than guessing.
36
36
  3. The CLI prints API errors as one-liners to stderr and exits non-zero. Treat any non-zero exit as actionable. If a command fails with an unrecognized error, re-run with `--help` to check your flags. If auth-related, re-check `auth status`.
37
37
 
38
+ ## Working with the decision graph
39
+
40
+ Separate from specs, prim passively captures the decisions you make during a coding session -- which library, which pattern, which config value -- into a queryable decision graph, and actively **gates** edits that would conflict with a load-bearing prior decision. Capture and the gate run automatically through the session hooks installed by `npx --yes @primitive.ai/prim claude install` (Claude Code) or `npx --yes @primitive.ai/prim codex install` (Codex). You never invoke capture; you *respond* to the gate and *read* the graph.
41
+
42
+ ### Heed the conflict gate
43
+ Before an edit (Claude Code: Edit/Write/MultiEdit; Codex: apply_patch) a PreToolUse hook scores the target file against the graph:
44
+
45
+ - **deny** -- the edit is blocked: it conflicts with a load-bearing prior decision. Don't fight it. Read the reason line; it names the decision id. If you genuinely intend to override that decision, run `npx --yes @primitive.ai/prim reconcile dec_<shortId>`, then retry the edit once. Otherwise choose an approach that respects the decision.
46
+ - **warn / additional context** -- the edit proceeds, but a relevant prior decision is surfaced. Read it. On Codex a would-be `ask` is delivered as allow-plus-context (Codex can't pause mid-tool), so that context is your only signal -- read it before continuing.
47
+ - **"decision check skipped / not verified" or "... partial / truncated"** -- the check could not fully run. Treat constraints as UNKNOWN, not clear; never read silence as approval.
48
+
49
+ The gate fail-opens on its *own* infrastructure errors (no daemon, network blip, org-unbound token) -- a setup problem never blocks your edit. That is exactly why an "unavailable" note matters: it is the honest signal that the check, not your edit, is what failed.
50
+
51
+ ### Read the graph before large or load-bearing edits
52
+ - `npx --yes @primitive.ai/prim decisions check --files "src/a.ts,src/b.ts"` -- which active decisions reference the files you're about to touch (comma-separated paths, one `--files` value). Run it before a big change.
53
+ - `npx --yes @primitive.ai/prim decisions recent` -- the team's recent decisions, each row badged by author and agent (`Your Claude Code` / `Your Codex`); `--limit <n>` and `--since <dur>` narrow it.
54
+ - `npx --yes @primitive.ai/prim decisions show <idOrShortId>` and `npx --yes @primitive.ai/prim decisions cascade <idOrShortId>` -- full detail, and the downstream blast radius a change would disturb.
55
+
56
+ ### Reconcile and the verdict footer
57
+ `npx --yes @primitive.ai/prim reconcile <idOrShortId>` mints a single-use bypass for the named decision -- it prints `[prim] reconcile bypass issued for dec_<short> (expires in ...)` to STDERR, with the bypass JSON on STDOUT. Your *next* edit to the governed file then goes through, and on that edit prim prints a verdict footer to STDERR -- confirmation the override was recorded, not silently dropped:
58
+
59
+ ```
60
+ ✓ Conflict caught before merge · N decisions saved · <author>'s intent preserved
61
+ ```
62
+
63
+ `N` is the reconciled decision's downstream live-dependent count, shown as `N+` when the server caps it.
64
+
65
+ ### Presence
66
+ With the daemon running (`npx --yes @primitive.ai/prim daemon start`), `npx --yes @primitive.ai/prim daemon status` includes the live online count in its STDOUT JSON (when presence is fresh); Claude Code surfaces it in the statusline as `team: N online`. Your captured decisions are attributed to your agent automatically -- no flag required.
67
+
38
68
  ## Common workflows
39
69
 
40
70
  ### Read a spec's current text (do this before any partial edit)
@@ -1,34 +1,3 @@
1
- // src/hooks/prim-hook-core.ts
2
- import { randomUUID } from "crypto";
3
- import { platform } from "os";
4
-
5
- // src/protocol/move.ts
6
- var ENVELOPE_VERSION = 1;
7
-
8
- // src/hooks/prim-hook-core.ts
9
- function toMove(parsed, cliVersion, agent = "claude_code") {
10
- return {
11
- moveId: randomUUID(),
12
- capturedAt: Date.now(),
13
- sessionId: parsed.session_id ?? "",
14
- eventType: parsed.hook_event_name ?? "unknown",
15
- payload: parsed,
16
- env: {
17
- cwd: parsed.cwd ?? process.cwd(),
18
- cliVersion,
19
- osPlatform: platform()
20
- },
21
- envelopeVersion: ENVELOPE_VERSION,
22
- // Stamp the producer only for Codex; Claude Code moves omit it (the
23
- // backend defaults an absent value to "claude_code"), keeping the
24
- // Claude wire shape byte-identical.
25
- ...agent === "codex" ? { producer: "codex" } : {}
26
- };
27
- }
28
- function shouldFlushAfter(eventType) {
29
- return eventType === "SessionEnd";
30
- }
31
-
32
1
  // src/hooks/redact.ts
33
2
  import { existsSync, readFileSync } from "fs";
34
3
  import { join } from "path";
@@ -109,7 +78,5 @@ function scrubFromCwd(value, cwd) {
109
78
  }
110
79
 
111
80
  export {
112
- toMove,
113
- shouldFlushAfter,
114
81
  scrubFromCwd
115
82
  };
@@ -0,0 +1,57 @@
1
+ // src/hooks/prim-hook-core.ts
2
+ import { randomUUID } from "crypto";
3
+ import { platform } from "os";
4
+
5
+ // src/protocol/move.ts
6
+ var ENVELOPE_VERSION = 1;
7
+
8
+ // src/hooks/prim-hook-core.ts
9
+ function toMove(parsed, cliVersion, agent = "claude_code") {
10
+ return {
11
+ moveId: randomUUID(),
12
+ capturedAt: Date.now(),
13
+ sessionId: parsed.session_id ?? "",
14
+ eventType: parsed.hook_event_name ?? "unknown",
15
+ payload: parsed,
16
+ env: {
17
+ cwd: parsed.cwd ?? process.cwd(),
18
+ cliVersion,
19
+ osPlatform: platform()
20
+ },
21
+ envelopeVersion: ENVELOPE_VERSION,
22
+ // Stamp the producer only for Codex; Claude Code moves omit it (the
23
+ // backend defaults an absent value to "claude_code"), keeping the
24
+ // Claude wire shape byte-identical.
25
+ ...agent === "codex" ? { producer: "codex" } : {}
26
+ };
27
+ }
28
+ function toCommitMove(commit, cliVersion, cwd) {
29
+ return {
30
+ moveId: `commit:${commit.sha}`,
31
+ capturedAt: Date.now(),
32
+ sessionId: "",
33
+ eventType: "git.commit",
34
+ payload: {
35
+ kind: "git.commit",
36
+ sha: commit.sha,
37
+ parentSha: commit.parentSha,
38
+ branch: commit.branch,
39
+ files: commit.files
40
+ },
41
+ env: {
42
+ cwd,
43
+ cliVersion,
44
+ osPlatform: platform()
45
+ },
46
+ envelopeVersion: ENVELOPE_VERSION
47
+ };
48
+ }
49
+ function shouldFlushAfter(eventType) {
50
+ return eventType === "SessionEnd";
51
+ }
52
+
53
+ export {
54
+ toMove,
55
+ toCommitMove,
56
+ shouldFlushAfter
57
+ };
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ appendMove,
4
+ resolveOrg
5
+ } from "../chunk-JZGWQDM5.js";
6
+ import {
7
+ toCommitMove
8
+ } from "../chunk-7GHOFNJ2.js";
9
+
10
+ // src/hooks/post-commit.ts
11
+ import { execSync, spawn } from "child_process";
12
+ import { readFileSync } from "fs";
13
+ import { dirname, join } from "path";
14
+ import { fileURLToPath } from "url";
15
+ var here = dirname(fileURLToPath(import.meta.url));
16
+ function git(args) {
17
+ try {
18
+ return execSync(`git ${args}`, {
19
+ encoding: "utf-8",
20
+ stdio: ["ignore", "pipe", "ignore"]
21
+ }).trim();
22
+ } catch {
23
+ return;
24
+ }
25
+ }
26
+ function readCommit() {
27
+ const sha = git("rev-parse HEAD");
28
+ if (!sha) {
29
+ return null;
30
+ }
31
+ const branch = git("rev-parse --abbrev-ref HEAD");
32
+ const files = (git("diff-tree --no-commit-id --name-only -r -m --root HEAD") ?? "").split("\n").filter((f) => f.length > 0);
33
+ return {
34
+ sha,
35
+ parentSha: git("rev-parse --verify --quiet HEAD^") || void 0,
36
+ branch: branch && branch !== "HEAD" ? branch : void 0,
37
+ files
38
+ };
39
+ }
40
+ function resolveCliVersion() {
41
+ try {
42
+ const pkg = JSON.parse(readFileSync(join(here, "..", "..", "package.json"), "utf-8"));
43
+ return pkg.version ?? "unknown";
44
+ } catch {
45
+ return "unknown";
46
+ }
47
+ }
48
+ function spawnBackgroundFlush() {
49
+ const entry = join(here, "..", "index.js");
50
+ spawn(process.execPath, [entry, "moves", "flush"], {
51
+ detached: true,
52
+ stdio: "ignore"
53
+ }).unref();
54
+ }
55
+ try {
56
+ const commit = readCommit();
57
+ if (commit) {
58
+ const cwd = git("rev-parse --show-toplevel") ?? process.cwd();
59
+ const move = toCommitMove(commit, resolveCliVersion(), cwd);
60
+ const { orgId } = resolveOrg({ sessionId: "", cwd });
61
+ appendMove(move, orgId);
62
+ spawnBackgroundFlush();
63
+ }
64
+ } catch (err) {
65
+ if (process.env.PRIM_HOOK_DEBUG) {
66
+ const detail = err instanceof Error ? err.message : String(err);
67
+ process.stderr.write(`[prim-post-commit] capture failed: ${detail}
68
+ `);
69
+ }
70
+ }
71
+ process.exit(0);
@@ -7,9 +7,11 @@ import {
7
7
  getClient
8
8
  } from "../chunk-6SIEWWUL.js";
9
9
  import {
10
- scrubFromCwd,
10
+ scrubFromCwd
11
+ } from "../chunk-6LAQVM26.js";
12
+ import {
11
13
  toMove
12
- } from "../chunk-LCC66K45.js";
14
+ } from "../chunk-7GHOFNJ2.js";
13
15
  import {
14
16
  parseAgent
15
17
  } from "../chunk-7YRBACIE.js";
@@ -4,10 +4,12 @@ import {
4
4
  resolveOrg
5
5
  } from "../chunk-JZGWQDM5.js";
6
6
  import {
7
- scrubFromCwd,
7
+ scrubFromCwd
8
+ } from "../chunk-6LAQVM26.js";
9
+ import {
8
10
  shouldFlushAfter,
9
11
  toMove
10
- } from "../chunk-LCC66K45.js";
12
+ } from "../chunk-7GHOFNJ2.js";
11
13
  import {
12
14
  parseAgent
13
15
  } from "../chunk-7YRBACIE.js";
package/dist/index.js CHANGED
@@ -1577,30 +1577,39 @@ import { execSync } from "child_process";
1577
1577
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
1578
1578
  import { resolve } from "path";
1579
1579
  import { Option } from "commander";
1580
- var HOOK_SCRIPT = `#!/bin/sh
1581
- # prim pre-commit hook \u2014 auto-syncs affected specs on commit
1582
- # Installed by: prim hooks install
1583
-
1584
- # Find the nearest node_modules/.bin with prim, or use npx
1585
- if command -v prim-pre-commit >/dev/null 2>&1; then
1586
- prim-pre-commit
1587
- elif [ -f "./node_modules/.bin/prim-pre-commit" ]; then
1588
- ./node_modules/.bin/prim-pre-commit
1580
+ var PRE_COMMIT = { hookName: "pre-commit", binName: "prim-pre-commit" };
1581
+ var POST_COMMIT = { hookName: "post-commit", binName: "prim-post-commit" };
1582
+ var HOOKS = [PRE_COMMIT, POST_COMMIT];
1583
+ function blockMarkers(spec) {
1584
+ return {
1585
+ start: `# >>> prim ${spec.hookName} hook >>>`,
1586
+ end: `# <<< prim ${spec.hookName} hook <<<`
1587
+ };
1588
+ }
1589
+ var PRIM_BLOCK_START = blockMarkers(PRE_COMMIT).start;
1590
+ var PRIM_BLOCK_END = blockMarkers(PRE_COMMIT).end;
1591
+ function hookShim(binName) {
1592
+ return `if command -v ${binName} >/dev/null 2>&1; then
1593
+ ${binName}
1594
+ elif [ -f "./node_modules/.bin/${binName}" ]; then
1595
+ ./node_modules/.bin/${binName}
1589
1596
  else
1590
- npx --yes -p @primitive.ai/prim prim-pre-commit 2>/dev/null || true
1591
- fi
1597
+ npx --yes -p @primitive.ai/prim ${binName} 2>/dev/null || true
1598
+ fi`;
1599
+ }
1600
+ function dotGitScript(spec) {
1601
+ return `#!/bin/sh
1602
+ # prim ${spec.hookName} hook \u2014 installed by: prim hooks install
1603
+
1604
+ ${hookShim(spec.binName)}
1592
1605
  `;
1593
- var PRIM_BLOCK_START = "# >>> prim pre-commit hook >>>";
1594
- var PRIM_BLOCK_END = "# <<< prim pre-commit hook <<<";
1595
- var PRIM_HUSKY_BLOCK = `${PRIM_BLOCK_START}
1596
- if command -v prim-pre-commit >/dev/null 2>&1; then
1597
- prim-pre-commit
1598
- elif [ -f "./node_modules/.bin/prim-pre-commit" ]; then
1599
- ./node_modules/.bin/prim-pre-commit
1600
- else
1601
- npx --yes -p @primitive.ai/prim prim-pre-commit 2>/dev/null || true
1602
- fi
1603
- ${PRIM_BLOCK_END}`;
1606
+ }
1607
+ function huskyBlock(spec) {
1608
+ const { start, end } = blockMarkers(spec);
1609
+ return `${start}
1610
+ ${hookShim(spec.binName)}
1611
+ ${end}`;
1612
+ }
1604
1613
  function getGitRoot() {
1605
1614
  return execSync("git rev-parse --show-toplevel", {
1606
1615
  encoding: "utf-8"
@@ -1624,8 +1633,8 @@ function detectHusky(gitRoot) {
1624
1633
  }
1625
1634
  return false;
1626
1635
  }
1627
- function containsPrimHook(content) {
1628
- return content.includes("prim-pre-commit");
1636
+ function containsPrimHook(content, binName = PRE_COMMIT.binName) {
1637
+ return content.includes(binName);
1629
1638
  }
1630
1639
  async function askConfirmation(question) {
1631
1640
  if (!process.stdin.isTTY) return false;
@@ -1639,52 +1648,63 @@ async function askConfirmation(question) {
1639
1648
  rl.close();
1640
1649
  }
1641
1650
  }
1642
- function installToHusky(gitRoot) {
1643
- const hookPath = resolve(gitRoot, ".husky", "pre-commit");
1651
+ function installToHusky(gitRoot, spec = PRE_COMMIT) {
1652
+ const hookPath = resolve(gitRoot, ".husky", spec.hookName);
1644
1653
  if (existsSync4(hookPath)) {
1645
1654
  const existing = readFileSync5(hookPath, "utf-8");
1646
- if (containsPrimHook(existing)) {
1647
- console.log("Prim pre-commit hook is already installed in .husky/pre-commit.");
1655
+ if (containsPrimHook(existing, spec.binName)) {
1656
+ console.log(`Prim ${spec.hookName} hook is already installed in .husky/${spec.hookName}.`);
1648
1657
  return;
1649
1658
  }
1650
1659
  const separator = existing.endsWith("\n") ? "\n" : "\n\n";
1651
- writeFileSync3(hookPath, `${existing}${separator}${PRIM_HUSKY_BLOCK}
1660
+ writeFileSync3(hookPath, `${existing}${separator}${huskyBlock(spec)}
1652
1661
  `, {
1653
1662
  mode: 493
1654
1663
  });
1655
- console.log("Appended prim hook block to .husky/pre-commit.");
1664
+ console.log(`Appended prim hook block to .husky/${spec.hookName}.`);
1656
1665
  } else {
1657
1666
  writeFileSync3(hookPath, `#!/bin/sh
1658
1667
 
1659
- ${PRIM_HUSKY_BLOCK}
1668
+ ${huskyBlock(spec)}
1660
1669
  `, {
1661
1670
  mode: 493
1662
1671
  });
1663
- console.log("Created .husky/pre-commit with prim hook block.");
1672
+ console.log(`Created .husky/${spec.hookName} with prim hook block.`);
1664
1673
  }
1665
1674
  }
1666
- function installToDotGit(gitRoot) {
1675
+ function installToDotGit(gitRoot, spec = PRE_COMMIT) {
1667
1676
  const hooksDir = resolve(gitRoot, ".git", "hooks");
1668
- const hookPath = resolve(hooksDir, "pre-commit");
1677
+ const hookPath = resolve(hooksDir, spec.hookName);
1669
1678
  if (!existsSync4(hooksDir)) {
1670
1679
  mkdirSync3(hooksDir, { recursive: true });
1671
1680
  }
1672
1681
  if (existsSync4(hookPath)) {
1673
1682
  const existing = readFileSync5(hookPath, "utf-8");
1674
- if (containsPrimHook(existing)) {
1675
- console.log("Prim pre-commit hook is already installed at .git/hooks/pre-commit.");
1683
+ if (containsPrimHook(existing, spec.binName)) {
1684
+ console.log(`Prim ${spec.hookName} hook is already installed at ${hookPath}.`);
1676
1685
  return;
1677
1686
  }
1678
- console.log(`A pre-commit hook already exists at ${hookPath}.`);
1687
+ console.log(`A ${spec.hookName} hook already exists at ${hookPath}.`);
1679
1688
  console.log("To replace it, run: prim hooks uninstall && prim hooks install");
1680
1689
  return;
1681
1690
  }
1682
- writeFileSync3(hookPath, HOOK_SCRIPT, { mode: 493 });
1683
- console.log(`Installed pre-commit hook at ${hookPath}`);
1691
+ writeFileSync3(hookPath, dotGitScript(spec), { mode: 493 });
1692
+ console.log(`Installed ${spec.hookName} hook at ${hookPath}`);
1693
+ }
1694
+ function installHooks(gitRoot, target) {
1695
+ for (const spec of HOOKS) {
1696
+ if (target === "husky") {
1697
+ installToHusky(gitRoot, spec);
1698
+ } else {
1699
+ installToDotGit(gitRoot, spec);
1700
+ }
1701
+ }
1684
1702
  }
1685
1703
  function registerHooksCommands(program2) {
1686
1704
  const hooks = program2.command("hooks").description("Manage git hooks");
1687
- hooks.command("install").description("Install the prim pre-commit hook (auto-detects Husky; use --target to override)").addOption(
1705
+ hooks.command("install").description(
1706
+ "Install the prim git hooks \u2014 pre-commit + post-commit (auto-detects Husky; use --target to override)"
1707
+ ).addOption(
1688
1708
  new Option("--target <where>", "install destination; bypasses Husky detection").choices([
1689
1709
  "husky",
1690
1710
  "git-hooks"
@@ -1695,10 +1715,10 @@ function registerHooksCommands(program2) {
1695
1715
  globals.nonInteractive || process.env.CI || process.env.PRIM_NON_INTERACTIVE
1696
1716
  );
1697
1717
  const gitRoot = getGitRoot();
1698
- if (opts.target === "husky") return installToHusky(gitRoot);
1699
- if (opts.target === "git-hooks") return installToDotGit(gitRoot);
1718
+ if (opts.target === "husky") return installHooks(gitRoot, "husky");
1719
+ if (opts.target === "git-hooks") return installHooks(gitRoot, "git-hooks");
1700
1720
  if (detectHusky(gitRoot)) {
1701
- if (globals.yes) return installToHusky(gitRoot);
1721
+ if (globals.yes) return installHooks(gitRoot, "husky");
1702
1722
  if (nonInteractive) {
1703
1723
  throw new Error(
1704
1724
  "--non-interactive set, refusing to prompt for Husky-hook installation. Pass --yes to confirm or --target=git-hooks to choose."
@@ -1709,24 +1729,30 @@ function registerHooksCommands(program2) {
1709
1729
  "Note: Husky detected but stdin is not a TTY \u2014 falling back to .git/hooks. Pass --yes for Husky or --non-interactive to fail fast."
1710
1730
  );
1711
1731
  } else if (await askConfirmation(
1712
- "Husky detected. Install prim hook into .husky/pre-commit instead of .git/hooks/pre-commit?"
1732
+ "Husky detected. Install prim hooks into .husky/ instead of .git/hooks/?"
1713
1733
  )) {
1714
- return installToHusky(gitRoot);
1734
+ return installHooks(gitRoot, "husky");
1715
1735
  } else {
1716
- console.log("Falling back to .git/hooks/pre-commit install.");
1736
+ console.log("Falling back to .git/hooks install.");
1717
1737
  }
1718
1738
  }
1719
- installToDotGit(gitRoot);
1739
+ installHooks(gitRoot, "git-hooks");
1720
1740
  });
1721
- hooks.command("uninstall").description("Remove the prim pre-commit hook").action(() => {
1741
+ hooks.command("uninstall").description("Remove the prim git hooks (.git/hooks)").action(() => {
1722
1742
  const gitRoot = getGitRoot();
1723
- const hookPath = resolve(gitRoot, ".git", "hooks", "pre-commit");
1724
- if (!existsSync4(hookPath)) {
1725
- console.log("No pre-commit hook found.");
1726
- return;
1743
+ for (const spec of HOOKS) {
1744
+ const hookPath = resolve(gitRoot, ".git", "hooks", spec.hookName);
1745
+ if (!existsSync4(hookPath)) {
1746
+ console.log(`No ${spec.hookName} hook found.`);
1747
+ continue;
1748
+ }
1749
+ if (containsPrimHook(readFileSync5(hookPath, "utf-8"), spec.binName)) {
1750
+ unlinkSync2(hookPath);
1751
+ console.log(`Removed ${spec.hookName} hook at ${hookPath}`);
1752
+ } else {
1753
+ console.log(`Left ${spec.hookName} hook at ${hookPath} untouched (not a prim hook).`);
1754
+ }
1727
1755
  }
1728
- unlinkSync2(hookPath);
1729
- console.log(`Removed pre-commit hook at ${hookPath}`);
1730
1756
  });
1731
1757
  }
1732
1758
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitive.ai/prim",
3
- "version": "0.1.0-alpha.17",
3
+ "version": "0.1.0-alpha.18",
4
4
  "description": "CLI for managing Primitive specs, contexts, and git hooks",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,6 +30,7 @@
30
30
  "bin": {
31
31
  "prim": "dist/index.js",
32
32
  "prim-pre-commit": "dist/hooks/pre-commit.js",
33
+ "prim-post-commit": "dist/hooks/post-commit.js",
33
34
  "prim-hook": "dist/hooks/prim-hook.js",
34
35
  "prim-pre-tool-use": "dist/hooks/pre-tool-use.js",
35
36
  "prim-post-tool-use": "dist/hooks/post-tool-use.js",
@@ -45,9 +46,9 @@
45
46
  "SKILL.md"
46
47
  ],
47
48
  "scripts": {
48
- "build": "tsup src/index.ts src/hooks/pre-commit.ts src/hooks/prim-hook.ts src/hooks/pre-tool-use.ts src/hooks/post-tool-use.ts src/hooks/session-start.ts src/hooks/session-end.ts src/daemon/server.ts --format esm --clean",
49
- "postbuild": "chmod +x ./dist/index.js ./dist/hooks/pre-commit.js ./dist/hooks/prim-hook.js ./dist/hooks/pre-tool-use.js ./dist/hooks/post-tool-use.js ./dist/hooks/session-start.js ./dist/hooks/session-end.js ./dist/daemon/server.js",
50
- "dev": "tsup src/index.ts src/hooks/pre-commit.ts src/hooks/prim-hook.ts src/hooks/pre-tool-use.ts src/hooks/post-tool-use.ts src/hooks/session-start.ts src/hooks/session-end.ts src/daemon/server.ts --format esm --watch --clean",
49
+ "build": "tsup src/index.ts src/hooks/pre-commit.ts src/hooks/post-commit.ts src/hooks/prim-hook.ts src/hooks/pre-tool-use.ts src/hooks/post-tool-use.ts src/hooks/session-start.ts src/hooks/session-end.ts src/daemon/server.ts --format esm --clean",
50
+ "postbuild": "chmod +x ./dist/index.js ./dist/hooks/pre-commit.js ./dist/hooks/post-commit.js ./dist/hooks/prim-hook.js ./dist/hooks/pre-tool-use.js ./dist/hooks/post-tool-use.js ./dist/hooks/session-start.js ./dist/hooks/session-end.js ./dist/daemon/server.js",
51
+ "dev": "tsup src/index.ts src/hooks/pre-commit.ts src/hooks/post-commit.ts src/hooks/prim-hook.ts src/hooks/pre-tool-use.ts src/hooks/post-tool-use.ts src/hooks/session-start.ts src/hooks/session-end.ts src/daemon/server.ts --format esm --watch --clean",
51
52
  "clean": "rm -rf dist coverage",
52
53
  "lint": "biome check src/",
53
54
  "format": "biome check --fix src/",