@primitive.ai/prim 0.1.0-alpha.1 → 0.1.0-alpha.11
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/README.md +18 -18
- package/dist/hooks/pre-commit.js +56 -16
- package/dist/index.js +53 -48
- package/package.json +17 -16
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @primitive.ai/prim
|
|
2
2
|
|
|
3
|
-
The official CLI for [Primitive](https://getprimitive.ai). Manage specs, contexts,
|
|
3
|
+
The official CLI for [Primitive](https://getprimitive.ai). Manage specs, contexts, projects, and git hooks from the command line.
|
|
4
4
|
|
|
5
5
|
> [!WARNING]
|
|
6
6
|
> This project is in **alpha**. Commands and APIs may change between releases.
|
|
@@ -45,16 +45,16 @@ prim auth status # Check authentication status
|
|
|
45
45
|
|
|
46
46
|
### Specs
|
|
47
47
|
|
|
48
|
-
Specs are documents that drive implementation. They can be synced to a
|
|
48
|
+
Specs are documents that drive implementation. They can be synced to a project DAG and mapped to file patterns for automatic pre-commit hook integration.
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
51
|
prim spec list # List all specs
|
|
52
|
-
prim spec list --
|
|
52
|
+
prim spec list --project-id <id> # Find spec for a root project
|
|
53
53
|
prim spec get <id> # Show spec details
|
|
54
54
|
prim spec get <id> --text-only # Print raw spec text
|
|
55
55
|
prim spec update <id> --file spec.md # Update spec from file
|
|
56
56
|
prim spec update <id> --name "New" # Rename a spec
|
|
57
|
-
prim spec sync <id> # Trigger spec-to-
|
|
57
|
+
prim spec sync <id> # Trigger spec-to-project sync
|
|
58
58
|
prim spec map <id> -p "src/auth/**" # Map file patterns to a spec
|
|
59
59
|
prim spec unmap <id> # Clear all file patterns
|
|
60
60
|
prim spec unmap <id> -p "src/auth/**" # Remove specific pattern
|
|
@@ -64,24 +64,24 @@ prim spec auto-map <id> # Auto-detect file patterns
|
|
|
64
64
|
### Contexts
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
prim context list
|
|
68
|
-
prim context list --scope
|
|
69
|
-
prim context list --
|
|
70
|
-
prim context get <id>
|
|
71
|
-
prim context create -s
|
|
72
|
-
prim context create -s
|
|
73
|
-
prim context update <id> --name "New"
|
|
74
|
-
prim context delete <id>
|
|
75
|
-
prim context link <id> --
|
|
76
|
-
prim context unlink <id> --
|
|
67
|
+
prim context list # List all contexts
|
|
68
|
+
prim context list --scope project # Filter by scope
|
|
69
|
+
prim context list --project-id <id> # List contexts for a project
|
|
70
|
+
prim context get <id> # Get context details
|
|
71
|
+
prim context create -s project -n "Name" # Create a context
|
|
72
|
+
prim context create -s project -n "Name" --file path/to/file
|
|
73
|
+
prim context update <id> --name "New" # Update a context
|
|
74
|
+
prim context delete <id> # Delete a context
|
|
75
|
+
prim context link <id> --project <pid> # Link context to project
|
|
76
|
+
prim context unlink <id> --project <pid> # Unlink context from project
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
###
|
|
79
|
+
### Projects
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
prim
|
|
83
|
-
prim
|
|
84
|
-
prim
|
|
82
|
+
prim project create -n "Project name" # Create a project
|
|
83
|
+
prim project create -n "Project name" -d "Description" # Create with description
|
|
84
|
+
prim project create -n "Project name" --spec <contextId> # Create and link a spec
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
### Hooks
|
package/dist/hooks/pre-commit.js
CHANGED
|
@@ -11,6 +11,11 @@ function getStagedFiles() {
|
|
|
11
11
|
});
|
|
12
12
|
return output.trim().split("\n").filter((f) => f.length > 0);
|
|
13
13
|
}
|
|
14
|
+
function getStagedDiff(files) {
|
|
15
|
+
return execSync(`git diff --cached -- ${files.map((f) => `"${f}"`).join(" ")}`, {
|
|
16
|
+
encoding: "utf-8"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
14
19
|
function matchPattern(filePath, pattern) {
|
|
15
20
|
const regexStr = pattern.replaceAll("**", "\xA7GLOBSTAR\xA7").replaceAll("*", "[^/]*").replaceAll("\xA7GLOBSTAR\xA7", ".*");
|
|
16
21
|
const regex = new RegExp(`^${regexStr}$`);
|
|
@@ -39,29 +44,35 @@ function findAffectedContexts(stagedFiles, specs) {
|
|
|
39
44
|
return affected;
|
|
40
45
|
}
|
|
41
46
|
var HOOK_TIMEOUT_MS = 1e4;
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
var defaultDeps = {
|
|
48
|
+
getClient,
|
|
49
|
+
getStagedFiles,
|
|
50
|
+
getStagedDiff
|
|
51
|
+
};
|
|
52
|
+
async function syncAffectedSpecs(deps = defaultDeps) {
|
|
53
|
+
const stagedFiles = deps.getStagedFiles();
|
|
44
54
|
if (stagedFiles.length === 0) {
|
|
45
|
-
|
|
55
|
+
return [];
|
|
46
56
|
}
|
|
47
|
-
const client = getClient();
|
|
57
|
+
const client = deps.getClient();
|
|
48
58
|
let mappings = [];
|
|
49
59
|
try {
|
|
50
60
|
mappings = await client.get("/api/cli/specs/mappings", {
|
|
51
61
|
signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
|
|
52
62
|
});
|
|
53
63
|
} catch {
|
|
54
|
-
|
|
64
|
+
return [];
|
|
55
65
|
}
|
|
56
66
|
if (mappings.length === 0) {
|
|
57
|
-
|
|
67
|
+
return [];
|
|
58
68
|
}
|
|
59
69
|
const affectedContexts = findAffectedContexts(stagedFiles, mappings);
|
|
60
70
|
if (affectedContexts.size === 0) {
|
|
61
|
-
|
|
71
|
+
return [];
|
|
62
72
|
}
|
|
63
73
|
console.log(`[prim] ${String(affectedContexts.size)} spec(s) affected by staged changes:`);
|
|
64
|
-
|
|
74
|
+
const synced = [];
|
|
75
|
+
for (const [contextId, affected] of affectedContexts) {
|
|
65
76
|
try {
|
|
66
77
|
const ctx = await client.get(`/api/cli/contexts/${contextId}`, {
|
|
67
78
|
signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
|
|
@@ -74,18 +85,47 @@ async function main() {
|
|
|
74
85
|
console.log(` [skip] ${contextId} \u2014 not a spec document`);
|
|
75
86
|
continue;
|
|
76
87
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
const diffContent = deps.getStagedDiff(affected.matchedFiles);
|
|
89
|
+
if (!diffContent) {
|
|
90
|
+
console.log(` [skip] ${contextId} \u2014 no diff content`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const response = await client.post(
|
|
94
|
+
`/api/cli/contexts/${contextId}/sync-diff`,
|
|
95
|
+
{ diffContent, affectedFiles: affected.matchedFiles },
|
|
96
|
+
{ signal: AbortSignal.timeout(HOOK_TIMEOUT_MS) }
|
|
97
|
+
);
|
|
98
|
+
const name = ctx.name ?? "(unnamed)";
|
|
99
|
+
if (response.truncated && response.sizeChars && response.limitChars) {
|
|
100
|
+
const sizeKiB = Math.round(response.sizeChars / 1024);
|
|
101
|
+
const limitKiB = Math.round(response.limitChars / 1024);
|
|
102
|
+
console.log(
|
|
103
|
+
` [synced] ${contextId} \u2014 ${name} (truncated: ${String(sizeKiB)} KiB \u2192 ${String(limitKiB)} KiB analyzed)`
|
|
104
|
+
);
|
|
105
|
+
} else {
|
|
106
|
+
console.log(` [synced] ${contextId} \u2014 ${name}`);
|
|
107
|
+
}
|
|
108
|
+
synced.push(contextId);
|
|
81
109
|
} catch (error) {
|
|
82
110
|
const message = error instanceof Error ? error.message : String(error);
|
|
83
111
|
console.error(` [error] ${contextId} \u2014 ${message}`);
|
|
84
112
|
}
|
|
85
113
|
}
|
|
86
|
-
|
|
114
|
+
return synced;
|
|
87
115
|
}
|
|
88
|
-
main()
|
|
89
|
-
|
|
116
|
+
async function main() {
|
|
117
|
+
await syncAffectedSpecs();
|
|
90
118
|
process.exit(0);
|
|
91
|
-
}
|
|
119
|
+
}
|
|
120
|
+
if (!process.env.VITEST) {
|
|
121
|
+
main().catch((error) => {
|
|
122
|
+
console.error("[prim] Pre-commit hook error:", error);
|
|
123
|
+
process.exit(0);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
HOOK_TIMEOUT_MS,
|
|
128
|
+
findAffectedContexts,
|
|
129
|
+
matchPattern,
|
|
130
|
+
syncAffectedSpecs
|
|
131
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
} from "./chunk-3APLWTLB.js";
|
|
12
12
|
|
|
13
13
|
// src/index.ts
|
|
14
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
15
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
14
17
|
import { Command } from "commander";
|
|
15
18
|
|
|
16
19
|
// src/commands/auth.ts
|
|
@@ -100,10 +103,10 @@ function registerAuthCommands(program2) {
|
|
|
100
103
|
process.exit(1);
|
|
101
104
|
});
|
|
102
105
|
});
|
|
103
|
-
const port = await new Promise((
|
|
106
|
+
const port = await new Promise((resolve3) => {
|
|
104
107
|
server.listen(CALLBACK_PORT, LOCALHOST, () => {
|
|
105
108
|
const addr = server.address();
|
|
106
|
-
|
|
109
|
+
resolve3(typeof addr === "object" && addr ? addr.port : 0);
|
|
107
110
|
});
|
|
108
111
|
});
|
|
109
112
|
const redirectUri = `http://${LOCALHOST}:${port}/callback`;
|
|
@@ -234,14 +237,14 @@ async function exchangeCode(siteUrl, code, codeVerifier, redirectUri) {
|
|
|
234
237
|
import { readFileSync as readFileSync2 } from "fs";
|
|
235
238
|
function registerContextCommands(program2) {
|
|
236
239
|
const context = program2.command("context").description("Manage contexts");
|
|
237
|
-
context.command("list").description("List contexts").option("-s, --scope <scope>", "Filter by scope:
|
|
240
|
+
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").action(async (opts) => {
|
|
238
241
|
const client = getClient();
|
|
239
242
|
const params = new URLSearchParams();
|
|
240
|
-
if (opts.
|
|
241
|
-
params.set("taskId", opts.
|
|
243
|
+
if (opts.projectId) {
|
|
244
|
+
params.set("taskId", opts.projectId);
|
|
242
245
|
}
|
|
243
246
|
if (opts.scope) {
|
|
244
|
-
params.set("scope", opts.scope);
|
|
247
|
+
params.set("scope", opts.scope === "project" ? "task" : opts.scope);
|
|
245
248
|
}
|
|
246
249
|
const contexts = await client.get(`/api/cli/contexts?${params.toString()}`);
|
|
247
250
|
printContextList(contexts);
|
|
@@ -251,16 +254,16 @@ function registerContextCommands(program2) {
|
|
|
251
254
|
const ctx = await client.get(`/api/cli/contexts/${contextId}`);
|
|
252
255
|
console.log(JSON.stringify(ctx, null, 2));
|
|
253
256
|
});
|
|
254
|
-
context.command("create").description("Create a new context").requiredOption("-s, --scope <scope>", "Scope:
|
|
257
|
+
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").action(
|
|
255
258
|
async (opts) => {
|
|
256
259
|
const client = getClient();
|
|
257
260
|
let text = opts.text;
|
|
258
261
|
if (opts.file) {
|
|
259
262
|
text = readFileSync2(opts.file, "utf-8");
|
|
260
263
|
}
|
|
261
|
-
const taskIds = opts.
|
|
264
|
+
const taskIds = opts.projectId ? opts.projectId.split(",").map((id) => id.trim()) : void 0;
|
|
262
265
|
const result = await client.post("/api/cli/contexts", {
|
|
263
|
-
scope: opts.scope,
|
|
266
|
+
scope: opts.scope === "project" ? "task" : opts.scope,
|
|
264
267
|
name: opts.name,
|
|
265
268
|
text,
|
|
266
269
|
taskIds,
|
|
@@ -286,19 +289,19 @@ function registerContextCommands(program2) {
|
|
|
286
289
|
await client.delete(`/api/cli/contexts/${contextId}`);
|
|
287
290
|
console.log(`Deleted context: ${contextId}`);
|
|
288
291
|
});
|
|
289
|
-
context.command("link <contextId>").description("Link a context to a
|
|
292
|
+
context.command("link <contextId>").description("Link a context to a project").requiredOption("--project <projectId>", "Project ID to link to").action(async (contextId, opts) => {
|
|
290
293
|
const client = getClient();
|
|
291
294
|
await client.post(`/api/cli/contexts/${contextId}/link`, {
|
|
292
|
-
taskId: opts.
|
|
295
|
+
taskId: opts.project
|
|
293
296
|
});
|
|
294
|
-
console.log(`Linked context ${contextId} to
|
|
297
|
+
console.log(`Linked context ${contextId} to project ${opts.project}`);
|
|
295
298
|
});
|
|
296
|
-
context.command("unlink <contextId>").description("Unlink a context from a
|
|
299
|
+
context.command("unlink <contextId>").description("Unlink a context from a project").requiredOption("--project <projectId>", "Project ID to unlink from").action(async (contextId, opts) => {
|
|
297
300
|
const client = getClient();
|
|
298
301
|
await client.post(`/api/cli/contexts/${contextId}/unlink`, {
|
|
299
|
-
taskId: opts.
|
|
302
|
+
taskId: opts.project
|
|
300
303
|
});
|
|
301
|
-
console.log(`Unlinked context ${contextId} from
|
|
304
|
+
console.log(`Unlinked context ${contextId} from project ${opts.project}`);
|
|
302
305
|
});
|
|
303
306
|
}
|
|
304
307
|
function printContextList(contexts) {
|
|
@@ -307,7 +310,7 @@ function printContextList(contexts) {
|
|
|
307
310
|
return;
|
|
308
311
|
}
|
|
309
312
|
for (const ctx of contexts) {
|
|
310
|
-
const scope = ctx.scope
|
|
313
|
+
const scope = ctx.scope === "task" ? "project" : ctx.scope ?? "project";
|
|
311
314
|
const spec = ctx.isSpecDocument ? " [SPEC]" : "";
|
|
312
315
|
const name = ctx.name ?? ctx.title ?? "(unnamed)";
|
|
313
316
|
console.log(`${ctx._id} ${scope.padEnd(8)} ${name}${spec}`);
|
|
@@ -330,7 +333,7 @@ if command -v prim-pre-commit >/dev/null 2>&1; then
|
|
|
330
333
|
elif [ -f "./node_modules/.bin/prim-pre-commit" ]; then
|
|
331
334
|
./node_modules/.bin/prim-pre-commit
|
|
332
335
|
else
|
|
333
|
-
npx --yes @primitive.ai/prim pre-commit
|
|
336
|
+
npx --yes -p @primitive.ai/prim prim-pre-commit 2>/dev/null || true
|
|
334
337
|
fi
|
|
335
338
|
`;
|
|
336
339
|
var PRIM_BLOCK_START = "# >>> prim pre-commit hook >>>";
|
|
@@ -341,7 +344,7 @@ if command -v prim-pre-commit >/dev/null 2>&1; then
|
|
|
341
344
|
elif [ -f "./node_modules/.bin/prim-pre-commit" ]; then
|
|
342
345
|
./node_modules/.bin/prim-pre-commit
|
|
343
346
|
else
|
|
344
|
-
npx --yes @primitive.ai/prim pre-commit
|
|
347
|
+
npx --yes -p @primitive.ai/prim prim-pre-commit 2>/dev/null || true
|
|
345
348
|
fi
|
|
346
349
|
${PRIM_BLOCK_END}`;
|
|
347
350
|
function getGitRoot() {
|
|
@@ -357,8 +360,8 @@ function detectHusky(gitRoot) {
|
|
|
357
360
|
const pkgPath = resolve(gitRoot, "package.json");
|
|
358
361
|
if (existsSync2(pkgPath)) {
|
|
359
362
|
try {
|
|
360
|
-
const
|
|
361
|
-
const scripts =
|
|
363
|
+
const pkg2 = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
364
|
+
const scripts = pkg2.scripts ?? {};
|
|
362
365
|
if (/husky/i.test(scripts.prepare ?? "") || /husky/i.test(scripts.postinstall ?? "")) {
|
|
363
366
|
return true;
|
|
364
367
|
}
|
|
@@ -453,16 +456,33 @@ function registerHooksCommands(program2) {
|
|
|
453
456
|
});
|
|
454
457
|
}
|
|
455
458
|
|
|
459
|
+
// src/commands/project.ts
|
|
460
|
+
function registerProjectCommands(program2) {
|
|
461
|
+
const project = program2.command("project").description("Manage projects");
|
|
462
|
+
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").action(async (opts) => {
|
|
463
|
+
const client = getClient();
|
|
464
|
+
const result = await client.post("/api/cli/tasks", {
|
|
465
|
+
name: opts.name,
|
|
466
|
+
description: opts.description,
|
|
467
|
+
specContextId: opts.spec
|
|
468
|
+
});
|
|
469
|
+
console.log(`Created project: ${result._id}`);
|
|
470
|
+
if (opts.spec) {
|
|
471
|
+
console.log(`Linked spec: ${opts.spec}`);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
456
476
|
// src/commands/spec.ts
|
|
457
477
|
import { readFileSync as readFileSync4 } from "fs";
|
|
458
478
|
function registerSpecCommands(program2) {
|
|
459
479
|
const spec = program2.command("spec").description("Manage spec documents");
|
|
460
|
-
spec.command("list").description("List spec documents").option("-t, --
|
|
480
|
+
spec.command("list").description("List spec documents").option("-t, --project-id <projectId>", "List spec for a specific root project").action(async (opts) => {
|
|
461
481
|
const client = getClient();
|
|
462
|
-
if (opts.
|
|
463
|
-
const specs = await client.get(`/api/cli/specs?rootTaskId=${opts.
|
|
482
|
+
if (opts.projectId) {
|
|
483
|
+
const specs = await client.get(`/api/cli/specs?rootTaskId=${opts.projectId}`);
|
|
464
484
|
if (specs.length === 0) {
|
|
465
|
-
console.log("No spec document found for this
|
|
485
|
+
console.log("No spec document found for this project.");
|
|
466
486
|
return;
|
|
467
487
|
}
|
|
468
488
|
printSpec(specs[0]);
|
|
@@ -474,7 +494,7 @@ function registerSpecCommands(program2) {
|
|
|
474
494
|
return;
|
|
475
495
|
}
|
|
476
496
|
for (const ctx of contexts) {
|
|
477
|
-
const scope = ctx.scope
|
|
497
|
+
const scope = ctx.scope === "task" ? "project" : ctx.scope ?? "project";
|
|
478
498
|
const review = ctx.specReviewStatus ?? "\u2014";
|
|
479
499
|
const name = ctx.name ?? "(unnamed)";
|
|
480
500
|
console.log(`${ctx._id} ${scope.padEnd(8)} ${String(review).padEnd(10)} ${name}`);
|
|
@@ -511,7 +531,7 @@ ${contexts.length} spec(s)`);
|
|
|
511
531
|
}
|
|
512
532
|
console.log(`Updated spec: ${contextId}`);
|
|
513
533
|
});
|
|
514
|
-
spec.command("sync <contextId>").description("Trigger spec \u2194
|
|
534
|
+
spec.command("sync <contextId>").description("Trigger spec \u2194 project DAG synchronization").action(async (contextId) => {
|
|
515
535
|
const client = getClient();
|
|
516
536
|
const ctx = await client.get(`/api/cli/contexts/${contextId}`);
|
|
517
537
|
if (!ctx.isSpecDocument) {
|
|
@@ -521,7 +541,7 @@ ${contexts.length} spec(s)`);
|
|
|
521
541
|
await client.post(`/api/cli/contexts/${contextId}/sync`);
|
|
522
542
|
console.log(`Triggered sync for spec: ${contextId}`);
|
|
523
543
|
if (ctx.specRootTaskId) {
|
|
524
|
-
console.log(`Root
|
|
544
|
+
console.log(`Root project: ${ctx.specRootTaskId}`);
|
|
525
545
|
}
|
|
526
546
|
});
|
|
527
547
|
spec.command("map <contextId>").description("Map file patterns to a spec (used by pre-commit hook to detect affected specs)").requiredOption(
|
|
@@ -563,9 +583,9 @@ function printSpec(ctx) {
|
|
|
563
583
|
const patterns = ctx.filePatterns;
|
|
564
584
|
console.log(`ID: ${ctx._id}`);
|
|
565
585
|
console.log(`Name: ${name}`);
|
|
566
|
-
console.log(`Scope: ${ctx.scope
|
|
586
|
+
console.log(`Scope: ${ctx.scope === "task" ? "project" : ctx.scope ?? "project"}`);
|
|
567
587
|
console.log(`Review Status: ${review}`);
|
|
568
|
-
console.log(`Root
|
|
588
|
+
console.log(`Root Project: ${ctx.specRootTaskId ?? "\u2014"}`);
|
|
569
589
|
console.log(`Sync Version: ${ctx.syncVersion ?? 0}`);
|
|
570
590
|
console.log(`Index Status: ${ctx.indexStatus ?? "\u2014"}`);
|
|
571
591
|
console.log(`File Patterns: ${patterns?.length ? patterns.join(", ") : "\u2014"}`);
|
|
@@ -578,30 +598,15 @@ ${preview}`);
|
|
|
578
598
|
}
|
|
579
599
|
}
|
|
580
600
|
|
|
581
|
-
// src/commands/task.ts
|
|
582
|
-
function registerTaskCommands(program2) {
|
|
583
|
-
const task = program2.command("task").description("Manage tasks");
|
|
584
|
-
task.command("create").description("Create a new task").requiredOption("-n, --name <name>", "Task name").option("-d, --description <description>", "Task description").option("--spec <contextId>", "Link an existing spec as this task's spec").action(async (opts) => {
|
|
585
|
-
const client = getClient();
|
|
586
|
-
const result = await client.post("/api/cli/tasks", {
|
|
587
|
-
name: opts.name,
|
|
588
|
-
description: opts.description,
|
|
589
|
-
specContextId: opts.spec
|
|
590
|
-
});
|
|
591
|
-
console.log(`Created task: ${result._id}`);
|
|
592
|
-
if (opts.spec) {
|
|
593
|
-
console.log(`Linked spec: ${opts.spec}`);
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
|
|
598
601
|
// src/index.ts
|
|
602
|
+
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
603
|
+
var pkg = JSON.parse(readFileSync5(resolve2(__dirname, "../package.json"), "utf-8"));
|
|
599
604
|
var program = new Command();
|
|
600
|
-
program.name("prim").description("CLI for managing Primitive specs and contexts").version(
|
|
605
|
+
program.name("prim").description("CLI for managing Primitive specs and contexts").version(pkg.version);
|
|
601
606
|
registerAuthCommands(program);
|
|
602
607
|
registerContextCommands(program);
|
|
603
608
|
registerSpecCommands(program);
|
|
604
|
-
|
|
609
|
+
registerProjectCommands(program);
|
|
605
610
|
registerHooksCommands(program);
|
|
606
611
|
process.on("unhandledRejection", (err) => {
|
|
607
612
|
const msg = err instanceof Error ? err.message : String(err);
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitive.ai/prim",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.11",
|
|
4
4
|
"description": "CLI for managing Primitive specs, contexts, and git hooks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/campus-ai/prim.git"
|
|
9
|
+
"url": "git+https://github.com/campus-ai/prim.git"
|
|
10
10
|
},
|
|
11
11
|
"homepage": "https://github.com/campus-ai/prim#readme",
|
|
12
12
|
"bugs": {
|
|
@@ -26,9 +26,10 @@
|
|
|
26
26
|
"engines": {
|
|
27
27
|
"node": ">=20.0.0"
|
|
28
28
|
},
|
|
29
|
+
"packageManager": "pnpm@9.15.9",
|
|
29
30
|
"bin": {
|
|
30
|
-
"prim": "
|
|
31
|
-
"prim-pre-commit": "
|
|
31
|
+
"prim": "dist/index.js",
|
|
32
|
+
"prim-pre-commit": "dist/hooks/pre-commit.js"
|
|
32
33
|
},
|
|
33
34
|
"main": "./dist/index.js",
|
|
34
35
|
"files": [
|
|
@@ -36,17 +37,6 @@
|
|
|
36
37
|
"LICENSE",
|
|
37
38
|
"README.md"
|
|
38
39
|
],
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"commander": "^12.1.0"
|
|
41
|
-
},
|
|
42
|
-
"devDependencies": {
|
|
43
|
-
"@biomejs/biome": "^1.9.0",
|
|
44
|
-
"@types/node": "^25.5.0",
|
|
45
|
-
"@vitest/coverage-v8": "^3.1.0",
|
|
46
|
-
"tsup": "^8.0.0",
|
|
47
|
-
"typescript": "^5.5.0",
|
|
48
|
-
"vitest": "^3.1.0"
|
|
49
|
-
},
|
|
50
40
|
"scripts": {
|
|
51
41
|
"build": "tsup src/index.ts src/hooks/pre-commit.ts --format esm --clean",
|
|
52
42
|
"postbuild": "chmod +x ./dist/index.js ./dist/hooks/pre-commit.js",
|
|
@@ -59,5 +49,16 @@
|
|
|
59
49
|
"test": "vitest run",
|
|
60
50
|
"test:watch": "vitest",
|
|
61
51
|
"test:coverage": "vitest run --coverage"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"commander": "^12.1.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@biomejs/biome": "^1.9.0",
|
|
58
|
+
"@types/node": "^25.5.0",
|
|
59
|
+
"@vitest/coverage-v8": "^3.1.0",
|
|
60
|
+
"tsup": "^8.0.0",
|
|
61
|
+
"typescript": "^5.5.0",
|
|
62
|
+
"vitest": "^3.1.0"
|
|
62
63
|
}
|
|
63
|
-
}
|
|
64
|
+
}
|