@primitive.ai/prim 0.1.0-alpha.19 → 0.1.0-alpha.20

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
@@ -7,9 +7,8 @@ import {
7
7
  import {
8
8
  checkAffectedDecisions,
9
9
  daemonOrDirectGet,
10
- formatDecisionsWarning,
11
- getGitContext
12
- } from "./chunk-TPQ3X244.js";
10
+ formatDecisionsWarning
11
+ } from "./chunk-E5UZXMZL.js";
13
12
  import {
14
13
  HttpError,
15
14
  REFRESH_TOKEN_PATH,
@@ -20,7 +19,7 @@ import {
20
19
  getSiteUrl,
21
20
  getTokenExpiresAt,
22
21
  saveTokenExpiry
23
- } from "./chunk-6SIEWWUL.js";
22
+ } from "./chunk-26VA3ADF.js";
24
23
  import {
25
24
  JOURNAL_DIR,
26
25
  SESSIONS_DIR,
@@ -34,7 +33,7 @@ import {
34
33
  } from "./chunk-UTKQTZHL.js";
35
34
 
36
35
  // src/index.ts
37
- import { readFileSync as readFileSync11 } from "fs";
36
+ import { readFileSync as readFileSync9 } from "fs";
38
37
  import { dirname as dirname6, resolve as resolve4 } from "path";
39
38
  import { fileURLToPath as fileURLToPath4 } from "url";
40
39
  import { Command } from "commander";
@@ -747,126 +746,9 @@ ${line("project", result.project)}`);
747
746
  });
748
747
  }
749
748
 
750
- // src/commands/context.ts
751
- import { readFileSync as readFileSync4 } from "fs";
752
- function registerContextCommands(program2) {
753
- const context = program2.command("context").description("Manage contexts");
754
- context.command("list").description("List contexts").option("-s, --scope <scope>", "Filter by scope: project, global, external").option("-t, --project-id <projectId>", "List contexts linked to a specific project").option("--json", "Output as JSON").action(async (opts) => {
755
- const client = getClient();
756
- const params = new URLSearchParams();
757
- if (opts.projectId) {
758
- params.set("taskId", opts.projectId);
759
- }
760
- if (opts.scope) {
761
- params.set("scope", opts.scope === "project" ? "task" : opts.scope);
762
- }
763
- const contexts = await client.get(`/api/cli/contexts?${params.toString()}`);
764
- if (opts.json) {
765
- printJson(contexts);
766
- return;
767
- }
768
- printContextList(contexts);
769
- });
770
- context.command("get <contextId>").description("Get a context by ID").option("--json", "Output as JSON (default behavior; accepted for symmetry)").action(async (contextId) => {
771
- const client = getClient();
772
- const ctx = await client.get(`/api/cli/contexts/${contextId}`);
773
- printJson(ctx);
774
- });
775
- context.command("create").description("Create a new context").requiredOption("-s, --scope <scope>", "Scope: project, global, external").requiredOption("-n, --name <name>", "Context name").option("-t, --text <text>", "Context text content").option("-f, --file <path>", "Read text content from file").option("--project-id <projectId>", "Link to project(s), comma-separated").option("--spec", "Mark as a spec document").option("--json", "Output as JSON").action(
776
- async (opts) => {
777
- const client = getClient();
778
- let text = opts.text;
779
- if (opts.file) {
780
- text = readFileSync4(opts.file, "utf-8");
781
- }
782
- const taskIds = opts.projectId ? opts.projectId.split(",").map((id) => id.trim()) : void 0;
783
- const result = await client.post("/api/cli/contexts", {
784
- scope: opts.scope === "project" ? "task" : opts.scope,
785
- name: opts.name,
786
- text,
787
- taskIds,
788
- isSpecDocument: opts.spec ?? false
789
- });
790
- if (opts.json) {
791
- printJson({ _id: result._id });
792
- return;
793
- }
794
- console.error(`Created context: ${result._id}`);
795
- console.log(result._id);
796
- }
797
- );
798
- context.command("update <contextId>").description("Update a context").option("-n, --name <name>", "New name").option("-t, --text <text>", "New text content").option("-f, --file <path>", "Read text content from file").option("--json", "Output as JSON").action(
799
- async (contextId, opts) => {
800
- const client = getClient();
801
- let text = opts.text;
802
- if (opts.file) {
803
- text = readFileSync4(opts.file, "utf-8");
804
- }
805
- await client.patch(`/api/cli/contexts/${contextId}`, {
806
- name: opts.name,
807
- text
808
- });
809
- if (opts.json) {
810
- printJson({ _id: contextId });
811
- return;
812
- }
813
- console.error(`Updated context: ${contextId}`);
814
- console.log(contextId);
815
- }
816
- );
817
- context.command("delete <contextId>").description("Delete a context").option("--json", "Output as JSON").action(async (contextId, opts) => {
818
- const client = getClient();
819
- await client.delete(`/api/cli/contexts/${contextId}`);
820
- if (opts.json) {
821
- printJson({ _id: contextId });
822
- return;
823
- }
824
- console.error(`Deleted context: ${contextId}`);
825
- console.log(contextId);
826
- });
827
- context.command("link <contextId>").description("Link a context to a project").requiredOption("--project <projectId>", "Project ID to link to").option("--json", "Output as JSON").action(async (contextId, opts) => {
828
- const client = getClient();
829
- await client.post(`/api/cli/contexts/${contextId}/link`, {
830
- taskId: opts.project
831
- });
832
- if (opts.json) {
833
- printJson({ _id: contextId, project: opts.project });
834
- return;
835
- }
836
- console.error(`Linked context ${contextId} to project ${opts.project}`);
837
- console.log(contextId);
838
- });
839
- context.command("unlink <contextId>").description("Unlink a context from a project").requiredOption("--project <projectId>", "Project ID to unlink from").option("--json", "Output as JSON").action(async (contextId, opts) => {
840
- const client = getClient();
841
- await client.post(`/api/cli/contexts/${contextId}/unlink`, {
842
- taskId: opts.project
843
- });
844
- if (opts.json) {
845
- printJson({ _id: contextId, project: opts.project });
846
- return;
847
- }
848
- console.error(`Unlinked context ${contextId} from project ${opts.project}`);
849
- console.log(contextId);
850
- });
851
- }
852
- function printContextList(contexts) {
853
- if (contexts.length === 0) {
854
- console.error("No contexts found.");
855
- return;
856
- }
857
- for (const ctx of contexts) {
858
- const scope = ctx.scope === "task" ? "project" : ctx.scope ?? "project";
859
- const spec = ctx.isSpecDocument ? " [SPEC]" : "";
860
- const name = ctx.name ?? ctx.title ?? "(unnamed)";
861
- console.log(`${ctx._id} ${scope.padEnd(8)} ${name}${spec}`);
862
- }
863
- console.error(`
864
- ${contexts.length} context(s)`);
865
- }
866
-
867
749
  // src/commands/daemon.ts
868
750
  import { spawn } from "child_process";
869
- import { existsSync as existsSync4, readFileSync as readFileSync5, unlinkSync } from "fs";
751
+ import { existsSync as existsSync4, readFileSync as readFileSync4, unlinkSync } from "fs";
870
752
  import { homedir as homedir3 } from "os";
871
753
  import { join as join4 } from "path";
872
754
  var DAEMON_BIN = "prim-daemon-server";
@@ -885,7 +767,7 @@ function readPidfile() {
885
767
  if (!existsSync4(PID_PATH)) {
886
768
  return null;
887
769
  }
888
- const raw = readFileSync5(PID_PATH, "utf-8").trim();
770
+ const raw = readFileSync4(PID_PATH, "utf-8").trim();
889
771
  const pid = Number(raw);
890
772
  if (!Number.isInteger(pid) || pid <= 0) {
891
773
  return null;
@@ -1668,7 +1550,7 @@ function registerDecisionsCommands(program2) {
1668
1550
 
1669
1551
  // src/commands/hooks.ts
1670
1552
  import { execSync } from "child_process";
1671
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
1553
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
1672
1554
  import { resolve } from "path";
1673
1555
  import { Option } from "commander";
1674
1556
  var PRE_COMMIT = { hookName: "pre-commit", binName: "prim-pre-commit" };
@@ -1717,7 +1599,7 @@ function detectHusky(gitRoot) {
1717
1599
  const pkgPath = resolve(gitRoot, "package.json");
1718
1600
  if (existsSync5(pkgPath)) {
1719
1601
  try {
1720
- const pkg2 = JSON.parse(readFileSync6(pkgPath, "utf-8"));
1602
+ const pkg2 = JSON.parse(readFileSync5(pkgPath, "utf-8"));
1721
1603
  const scripts = pkg2.scripts ?? {};
1722
1604
  if (/husky/i.test(scripts.prepare ?? "") || /husky/i.test(scripts.postinstall ?? "")) {
1723
1605
  return true;
@@ -1745,7 +1627,7 @@ async function askConfirmation(question) {
1745
1627
  function installToHusky(gitRoot, spec = PRE_COMMIT) {
1746
1628
  const hookPath = resolve(gitRoot, ".husky", spec.hookName);
1747
1629
  if (existsSync5(hookPath)) {
1748
- const existing = readFileSync6(hookPath, "utf-8");
1630
+ const existing = readFileSync5(hookPath, "utf-8");
1749
1631
  if (containsPrimHook(existing, spec.binName)) {
1750
1632
  console.log(`Prim ${spec.hookName} hook is already installed in .husky/${spec.hookName}.`);
1751
1633
  return;
@@ -1773,7 +1655,7 @@ function installToDotGit(gitRoot, spec = PRE_COMMIT) {
1773
1655
  mkdirSync3(hooksDir, { recursive: true });
1774
1656
  }
1775
1657
  if (existsSync5(hookPath)) {
1776
- const existing = readFileSync6(hookPath, "utf-8");
1658
+ const existing = readFileSync5(hookPath, "utf-8");
1777
1659
  if (containsPrimHook(existing, spec.binName)) {
1778
1660
  console.log(`Prim ${spec.hookName} hook is already installed at ${hookPath}.`);
1779
1661
  return;
@@ -1840,7 +1722,7 @@ function registerHooksCommands(program2) {
1840
1722
  console.log(`No ${spec.hookName} hook found.`);
1841
1723
  continue;
1842
1724
  }
1843
- if (containsPrimHook(readFileSync6(hookPath, "utf-8"), spec.binName)) {
1725
+ if (containsPrimHook(readFileSync5(hookPath, "utf-8"), spec.binName)) {
1844
1726
  unlinkSync2(hookPath);
1845
1727
  console.log(`Removed ${spec.hookName} hook at ${hookPath}`);
1846
1728
  } else {
@@ -1982,28 +1864,6 @@ function registerMovesCommands(program2) {
1982
1864
  });
1983
1865
  }
1984
1866
 
1985
- // src/commands/project.ts
1986
- function registerProjectCommands(program2) {
1987
- const project = program2.command("project").description("Manage projects");
1988
- project.command("create").description("Create a new project").requiredOption("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("--spec <contextId>", "Link an existing spec as this project's spec").option("--json", "Output as JSON").action(async (opts) => {
1989
- const client = getClient();
1990
- const result = await client.post("/api/cli/tasks", {
1991
- name: opts.name,
1992
- description: opts.description,
1993
- specContextId: opts.spec
1994
- });
1995
- if (opts.json) {
1996
- printJson(opts.spec ? { _id: result._id, spec: opts.spec } : { _id: result._id });
1997
- return;
1998
- }
1999
- console.error(`Created project: ${result._id}`);
2000
- if (opts.spec) {
2001
- console.error(`Linked spec: ${opts.spec}`);
2002
- }
2003
- console.log(result._id);
2004
- });
2005
- }
2006
-
2007
1867
  // src/commands/reconcile.ts
2008
1868
  var EXIT_OK2 = 0;
2009
1869
  var EXIT_USAGE = 2;
@@ -2090,7 +1950,7 @@ function registerReconcileCommands(program2) {
2090
1950
  import {
2091
1951
  existsSync as existsSync7,
2092
1952
  mkdirSync as mkdirSync5,
2093
- readFileSync as readFileSync7,
1953
+ readFileSync as readFileSync6,
2094
1954
  readdirSync,
2095
1955
  unlinkSync as unlinkSync5,
2096
1956
  writeFileSync as writeFileSync5
@@ -2132,7 +1992,7 @@ function registerSessionCommands(program2) {
2132
1992
  for (const f of files) {
2133
1993
  const sessionId = f.replace(/\.json$/, "");
2134
1994
  try {
2135
- const m = JSON.parse(readFileSync7(join6(SESSIONS_DIR, f), "utf-8"));
1995
+ const m = JSON.parse(readFileSync6(join6(SESSIONS_DIR, f), "utf-8"));
2136
1996
  console.log(`${sessionId} org=${m.orgId}`);
2137
1997
  } catch {
2138
1998
  }
@@ -2155,7 +2015,7 @@ import {
2155
2015
  existsSync as existsSync8,
2156
2016
  fsyncSync as fsyncSync2,
2157
2017
  openSync as openSync2,
2158
- readFileSync as readFileSync8,
2018
+ readFileSync as readFileSync7,
2159
2019
  renameSync as renameSync3,
2160
2020
  writeFileSync as writeFileSync6
2161
2021
  } from "fs";
@@ -2177,7 +2037,7 @@ function loadSkill() {
2177
2037
  let dir = __dirname;
2178
2038
  while (dir !== dirname4(dir)) {
2179
2039
  const p = resolve2(dir, "SKILL.md");
2180
- if (existsSync8(p)) return readFileSync8(p, "utf-8");
2040
+ if (existsSync8(p)) return readFileSync7(p, "utf-8");
2181
2041
  dir = dirname4(dir);
2182
2042
  }
2183
2043
  throw new Error("SKILL.md not found in package");
@@ -2232,7 +2092,7 @@ function resolveTarget(cwd, override) {
2232
2092
  function runInstall(cwd, opts) {
2233
2093
  const target = resolveTarget(cwd, opts.target);
2234
2094
  if (target === null) return 1;
2235
- const existing = existsSync8(target) ? readFileSync8(target, "utf-8") : "";
2095
+ const existing = existsSync8(target) ? readFileSync7(target, "utf-8") : "";
2236
2096
  const eol = existing ? detectNewline(existing) : "\n";
2237
2097
  const block = composeBlock(loadSkill(), eol);
2238
2098
  const next = applyBlock(existing, block, eol);
@@ -2255,7 +2115,7 @@ function runUninstall(cwd, opts) {
2255
2115
  console.log(`Skill block not present at ${target}`);
2256
2116
  return 0;
2257
2117
  }
2258
- const existing = readFileSync8(target, "utf-8");
2118
+ const existing = readFileSync7(target, "utf-8");
2259
2119
  const next = removeBlock(existing);
2260
2120
  if (next === null) {
2261
2121
  console.log(`Skill block not present at ${target}`);
@@ -2271,7 +2131,7 @@ function runStatus(cwd, opts) {
2271
2131
  const fileExists = existsSync8(target);
2272
2132
  let installed = false;
2273
2133
  if (fileExists) {
2274
- const content = readFileSync8(target, "utf-8");
2134
+ const content = readFileSync7(target, "utf-8");
2275
2135
  installed = content.includes(SKILL_BEGIN) && content.includes(SKILL_END);
2276
2136
  }
2277
2137
  if (opts.json) {
@@ -2307,274 +2167,8 @@ function registerSkillCommands(program2) {
2307
2167
  });
2308
2168
  }
2309
2169
 
2310
- // src/commands/spec.ts
2311
- import { readFileSync as readFileSync9 } from "fs";
2312
- function registerSpecCommands(program2) {
2313
- const spec = program2.command("spec").description("Manage spec documents");
2314
- spec.command("list").description("List spec documents").option("-t, --project-id <projectId>", "List spec for a specific root project").option("--json", "Output as JSON").action(async (opts) => {
2315
- const client = getClient();
2316
- if (opts.projectId) {
2317
- const specs = await client.get(`/api/cli/specs?rootTaskId=${opts.projectId}`);
2318
- if (opts.json) {
2319
- printJson(specs[0] ?? null);
2320
- return;
2321
- }
2322
- if (specs.length === 0) {
2323
- console.error("No spec document found for this project.");
2324
- return;
2325
- }
2326
- printSpec(specs[0]);
2327
- return;
2328
- }
2329
- const contexts = await client.get("/api/cli/specs");
2330
- if (opts.json) {
2331
- printJson(contexts);
2332
- return;
2333
- }
2334
- if (contexts.length === 0) {
2335
- console.error("No spec documents found.");
2336
- return;
2337
- }
2338
- for (const ctx of contexts) {
2339
- const scope = ctx.scope === "task" ? "project" : ctx.scope ?? "project";
2340
- const review = ctx.specReviewStatus ?? "\u2014";
2341
- const name = ctx.name ?? "(unnamed)";
2342
- console.log(`${ctx._id} ${scope.padEnd(8)} ${String(review).padEnd(10)} ${name}`);
2343
- }
2344
- console.error(`
2345
- ${contexts.length} spec(s)`);
2346
- });
2347
- spec.command("get <contextId>").description("Get a spec document by ID").option("--text-only", "Print only the text content (no metadata)").option("--json", "Output as JSON (overrides --text-only)").action(async (contextId, opts) => {
2348
- const client = getClient();
2349
- const ctx = await client.get(`/api/cli/contexts/${contextId}`);
2350
- if (opts.json) {
2351
- printJson(ctx);
2352
- return;
2353
- }
2354
- if (opts.textOnly) {
2355
- console.log(ctx.text ?? "");
2356
- return;
2357
- }
2358
- printSpec(ctx);
2359
- });
2360
- spec.command("create").description("Create a new spec document").requiredOption("-s, --scope <scope>", "Scope: project, global, external").requiredOption("-n, --name <name>", "Spec name").option("-t, --text <text>", "Spec text content").option("-f, --file <path>", "Read text content from file").option("--project-id <projectId>", "Link to project(s), comma-separated").option("--branch <branch>", "Link spec to this branch on the current repo").option("--pr <prNumber>", "Optional PR number to attach to the link").option("--json", "Output as JSON").action(
2361
- async (opts) => {
2362
- const client = getClient();
2363
- let text = opts.text;
2364
- if (opts.file) {
2365
- text = readFileSync9(opts.file, "utf-8");
2366
- }
2367
- const taskIds = opts.projectId ? opts.projectId.split(",").map((id) => id.trim()) : void 0;
2368
- let linkedBranch;
2369
- if (opts.branch) {
2370
- const { repoFullName } = getGitContext();
2371
- if (!repoFullName) {
2372
- console.warn(
2373
- "[prim] --branch supplied but origin remote is not GitHub; skipping link."
2374
- );
2375
- } else {
2376
- linkedBranch = { repoFullName, branch: opts.branch };
2377
- if (opts.pr) {
2378
- const n = Number.parseInt(opts.pr, 10);
2379
- if (Number.isFinite(n)) linkedBranch.prNumber = n;
2380
- }
2381
- }
2382
- }
2383
- const result = await client.post("/api/cli/contexts", {
2384
- scope: opts.scope === "project" ? "task" : opts.scope,
2385
- name: opts.name,
2386
- text,
2387
- taskIds,
2388
- isSpecDocument: true,
2389
- linkedBranch
2390
- });
2391
- if (opts.json) {
2392
- printJson({ _id: result._id });
2393
- return;
2394
- }
2395
- console.error(
2396
- `Created spec: ${result._id}${linkedBranch ? ` (linked to ${linkedBranch.branch})` : ""}`
2397
- );
2398
- console.log(result._id);
2399
- }
2400
- );
2401
- spec.command("update <contextId>").description("Update a spec document's text content").option("-t, --text <text>", "New text content").option("-f, --file <path>", "Read text content from file").option("-n, --name <name>", "New name").option("--json", "Output as JSON").action(
2402
- async (contextId, opts) => {
2403
- const client = getClient();
2404
- let text = opts.text;
2405
- if (opts.file) {
2406
- text = readFileSync9(opts.file, "utf-8");
2407
- }
2408
- if (!(text || opts.name)) {
2409
- console.error("Provide --text, --file, or --name to update.");
2410
- process.exit(1);
2411
- }
2412
- await client.patch(`/api/cli/contexts/${contextId}`, {
2413
- name: opts.name,
2414
- text,
2415
- skipTiptapLifecycle: !!text
2416
- });
2417
- if (text) {
2418
- await client.post(`/api/cli/contexts/${contextId}/inject`);
2419
- }
2420
- if (opts.json) {
2421
- printJson({ _id: contextId });
2422
- return;
2423
- }
2424
- console.error(`Updated spec: ${contextId}`);
2425
- console.log(contextId);
2426
- }
2427
- );
2428
- spec.command("sync <contextId>").description("Trigger spec \u2194 project DAG synchronization").option("--json", "Output as JSON").action(async (contextId, opts) => {
2429
- const client = getClient();
2430
- const ctx = await client.get(`/api/cli/contexts/${contextId}`);
2431
- if (!ctx.isSpecDocument) {
2432
- console.error("Context is not a spec document. Use `prim context` instead.");
2433
- process.exit(1);
2434
- }
2435
- await client.post(`/api/cli/contexts/${contextId}/sync`);
2436
- if (opts.json) {
2437
- printJson(
2438
- ctx.specRootTaskId ? { _id: contextId, specRootTaskId: ctx.specRootTaskId } : { _id: contextId }
2439
- );
2440
- return;
2441
- }
2442
- console.error(`Triggered sync for spec: ${contextId}`);
2443
- if (ctx.specRootTaskId) {
2444
- console.error(`Root project: ${ctx.specRootTaskId}`);
2445
- }
2446
- console.log(contextId);
2447
- });
2448
- spec.command("review <contextId>").description("Manually trigger the PR Intent Review bot for a spec").requiredOption("--pr <prNumber>", "PR number to review against").option("--sha <headSha>", "Commit SHA the review runs against (defaults to current HEAD)").action(async (contextId, opts) => {
2449
- const prNumber = Number.parseInt(opts.pr, 10);
2450
- if (!Number.isFinite(prNumber)) {
2451
- console.error("--pr must be an integer.");
2452
- process.exit(1);
2453
- }
2454
- const headSha = opts.sha ?? getGitContext().sha;
2455
- if (!headSha) {
2456
- console.error("Could not determine head SHA \u2014 pass --sha or run inside a git checkout.");
2457
- process.exit(1);
2458
- }
2459
- const client = getClient();
2460
- await client.post(`/api/cli/contexts/${contextId}/review`, {
2461
- prNumber,
2462
- headSha
2463
- });
2464
- console.log(
2465
- `Scheduled review: ${contextId} against PR #${String(prNumber)} @ ${headSha.slice(0, 7)}`
2466
- );
2467
- });
2468
- spec.command("drift <contextId>").description("Dispatch the Claude Code drift-fix workflow against a PR").requiredOption("--pr <prNumber>", "PR number to dispatch the drift-fix workflow against").action(async (contextId, opts) => {
2469
- const prNumber = Number.parseInt(opts.pr, 10);
2470
- if (!Number.isFinite(prNumber)) {
2471
- console.error("--pr must be an integer.");
2472
- process.exit(1);
2473
- }
2474
- const client = getClient();
2475
- const result = await client.post(`/api/cli/contexts/${contextId}/drift`, {
2476
- prNumber
2477
- });
2478
- if (result.dispatched) {
2479
- const ref = result.runUrl ? `: ${result.runUrl}` : "";
2480
- console.log(`Dispatched drift-fix workflow${ref}`);
2481
- } else {
2482
- console.error(
2483
- "Drift-fix dispatch failed. Likely causes: actions:write App scope not granted, primitive-drift-fix.yml workflow file missing, or no findings on the latest review."
2484
- );
2485
- process.exit(1);
2486
- }
2487
- });
2488
- spec.command("status <taskId>").description(
2489
- "Show task status, auto-complete suppression flag, and the most-recent bot auto-completion"
2490
- ).action(async (taskId) => {
2491
- const client = getClient();
2492
- const result = await client.get(`/api/cli/tasks/${taskId}/status`);
2493
- console.log(`status: ${result.status}`);
2494
- console.log(`auto-complete suppressed: ${result.autoCompleteSuppressed ? "yes" : "no"}`);
2495
- const last = result.lastAutoCompleteActivity;
2496
- if (last) {
2497
- const when = last.createdAt ? new Date(last.createdAt).toISOString() : "\u2014";
2498
- const pr = last.prNumber ? `#${String(last.prNumber)}` : "\u2014";
2499
- console.log(`last auto-complete: ${when} (PR ${pr})`);
2500
- if (last.explanation) {
2501
- console.log(` ${last.explanation}`);
2502
- }
2503
- } else {
2504
- console.log("last auto-complete: \u2014");
2505
- }
2506
- });
2507
- spec.command("map <contextId>").description("Map file patterns to a spec (used by pre-commit hook to detect affected specs)").requiredOption(
2508
- "-p, --pattern <patterns...>",
2509
- 'Glob pattern(s) to associate, e.g. "src/auth/**"'
2510
- ).option("--json", "Output as JSON").action(async (contextId, opts) => {
2511
- const client = getClient();
2512
- const result = await client.post(`/api/cli/contexts/${contextId}/map`, {
2513
- patterns: opts.pattern
2514
- });
2515
- if (opts.json) {
2516
- printJson({ _id: contextId, filePatterns: result.filePatterns });
2517
- return;
2518
- }
2519
- console.error(`Mapped patterns to spec ${contextId}:`);
2520
- for (const p of result.filePatterns) {
2521
- console.error(` ${p}`);
2522
- }
2523
- console.log(contextId);
2524
- });
2525
- spec.command("unmap <contextId>").description("Remove file pattern mappings from a spec (omit --pattern to clear all)").option("-p, --pattern <patterns...>", "Specific pattern(s) to remove (omit to clear all)").option("--json", "Output as JSON").action(async (contextId, opts) => {
2526
- const client = getClient();
2527
- const result = await client.post(`/api/cli/contexts/${contextId}/unmap`, {
2528
- patterns: opts.pattern
2529
- });
2530
- if (opts.json) {
2531
- printJson({ _id: contextId, filePatterns: result.filePatterns });
2532
- return;
2533
- }
2534
- if (result.filePatterns.length === 0) {
2535
- console.error(`Cleared all file patterns from spec ${contextId}`);
2536
- } else {
2537
- console.error(`Updated patterns for spec ${contextId}:`);
2538
- for (const p of result.filePatterns) {
2539
- console.error(` ${p}`);
2540
- }
2541
- }
2542
- console.log(contextId);
2543
- });
2544
- spec.command("auto-map <contextId>").description("Trigger auto-mapping of file patterns for a spec").option("--json", "Output as JSON").action(async (contextId, opts) => {
2545
- const client = getClient();
2546
- await client.post(`/api/cli/contexts/${contextId}/auto-map`);
2547
- if (opts.json) {
2548
- printJson({ _id: contextId });
2549
- return;
2550
- }
2551
- console.error(`Auto-mapping triggered for spec: ${contextId}`);
2552
- console.log(contextId);
2553
- });
2554
- }
2555
- function printSpec(ctx) {
2556
- const name = ctx.name ?? ctx.title ?? "(unnamed)";
2557
- const review = ctx.specReviewStatus ?? "\u2014";
2558
- const patterns = ctx.filePatterns;
2559
- console.log(`ID: ${ctx._id}`);
2560
- console.log(`Name: ${name}`);
2561
- console.log(`Scope: ${ctx.scope === "task" ? "project" : ctx.scope ?? "project"}`);
2562
- console.log(`Review Status: ${review}`);
2563
- console.log(`Root Project: ${ctx.specRootTaskId ?? "\u2014"}`);
2564
- console.log(`Sync Version: ${ctx.syncVersion ?? 0}`);
2565
- console.log(`Index Status: ${ctx.indexStatus ?? "\u2014"}`);
2566
- console.log(`File Patterns: ${patterns?.length ? patterns.join(", ") : "\u2014"}`);
2567
- if (ctx.text) {
2568
- const text = ctx.text;
2569
- const preview = text.length > 500 ? `${text.slice(0, 500)}\u2026` : text;
2570
- console.log(`
2571
- --- Text ---
2572
- ${preview}`);
2573
- }
2574
- }
2575
-
2576
2170
  // src/commands/statusline.ts
2577
- import { readFileSync as readFileSync10 } from "fs";
2171
+ import { readFileSync as readFileSync8 } from "fs";
2578
2172
  import { dirname as dirname5, resolve as resolve3 } from "path";
2579
2173
  import { fileURLToPath as fileURLToPath3 } from "url";
2580
2174
  var STATUSLINE_TIMEOUT_MS = 200;
@@ -2584,7 +2178,7 @@ function readPackageVersion() {
2584
2178
  const candidates = [resolve3(here, "../../package.json"), resolve3(here, "../package.json")];
2585
2179
  for (const path of candidates) {
2586
2180
  try {
2587
- const pkg2 = JSON.parse(readFileSync10(path, "utf-8"));
2181
+ const pkg2 = JSON.parse(readFileSync8(path, "utf-8"));
2588
2182
  if (pkg2.version) {
2589
2183
  return pkg2.version;
2590
2184
  }
@@ -2630,17 +2224,14 @@ function registerStatuslineCommands(program2) {
2630
2224
 
2631
2225
  // src/index.ts
2632
2226
  var __dirname2 = dirname6(fileURLToPath4(import.meta.url));
2633
- var pkg = JSON.parse(readFileSync11(resolve4(__dirname2, "../package.json"), "utf-8"));
2227
+ var pkg = JSON.parse(readFileSync9(resolve4(__dirname2, "../package.json"), "utf-8"));
2634
2228
  updateNotifier({ pkg }).notify();
2635
2229
  var program = new Command();
2636
- program.name("prim").description("CLI for managing Primitive specs and contexts").version(pkg.version).option("-y, --yes", "auto-confirm prompts").option(
2230
+ program.name("prim").description("CLI for Primitive's decision graph").version(pkg.version).option("-y, --yes", "auto-confirm prompts").option(
2637
2231
  "--non-interactive",
2638
2232
  "fail fast instead of prompting (also: CI=1, PRIM_NON_INTERACTIVE=1)"
2639
2233
  );
2640
2234
  registerAuthCommands(program);
2641
- registerContextCommands(program);
2642
- registerSpecCommands(program);
2643
- registerProjectCommands(program);
2644
2235
  registerHooksCommands(program);
2645
2236
  registerSkillCommands(program);
2646
2237
  registerMovesCommands(program);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@primitive.ai/prim",
3
- "version": "0.1.0-alpha.19",
4
- "description": "CLI for managing Primitive specs, contexts, and git hooks",
3
+ "version": "0.1.0-alpha.20",
4
+ "description": "CLI for Primitive's decision graph — passive decision capture, conflict gate, and team presence",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -19,8 +19,8 @@
19
19
  "primitive",
20
20
  "prim",
21
21
  "cli",
22
- "specs",
23
- "contexts",
22
+ "decisions",
23
+ "decision-graph",
24
24
  "pre-commit"
25
25
  ],
26
26
  "engines": {