@primitive.ai/prim 0.1.0-alpha.18 → 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.
@@ -1,12 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  checkAffectedDecisions,
4
- formatDecisionsWarning,
5
- getGitContext
6
- } from "../chunk-TPQ3X244.js";
7
- import {
8
- getClient
9
- } from "../chunk-6SIEWWUL.js";
4
+ formatDecisionsWarning
5
+ } from "../chunk-E5UZXMZL.js";
6
+ import "../chunk-26VA3ADF.js";
10
7
  import "../chunk-UTKQTZHL.js";
11
8
 
12
9
  // src/hooks/pre-commit.ts
@@ -17,150 +14,6 @@ function getStagedFiles() {
17
14
  });
18
15
  return output.trim().split("\n").filter((f) => f.length > 0);
19
16
  }
20
- function getStagedDiff(files) {
21
- return execSync(`git diff --cached -- ${files.map((f) => `"${f}"`).join(" ")}`, {
22
- encoding: "utf-8"
23
- });
24
- }
25
- function matchPattern(filePath, pattern) {
26
- const regexStr = pattern.replaceAll("**", "\xA7GLOBSTAR\xA7").replaceAll("*", "[^/]*").replaceAll("\xA7GLOBSTAR\xA7", ".*");
27
- const regex = new RegExp(`^${regexStr}$`);
28
- return regex.test(filePath);
29
- }
30
- function findAffectedContexts(stagedFiles, specs) {
31
- const affected = /* @__PURE__ */ new Map();
32
- for (const file of stagedFiles) {
33
- for (const spec of specs) {
34
- for (const pattern of spec.filePatterns) {
35
- if (matchPattern(file, pattern)) {
36
- const existing = affected.get(spec._id);
37
- if (existing) {
38
- existing.matchedFiles.push(file);
39
- } else {
40
- affected.set(spec._id, {
41
- contextId: spec._id,
42
- matchedFiles: [file]
43
- });
44
- }
45
- break;
46
- }
47
- }
48
- }
49
- }
50
- return affected;
51
- }
52
- var HOOK_TIMEOUT_MS = 1e4;
53
- var defaultDeps = {
54
- getClient,
55
- getStagedFiles,
56
- getStagedDiff,
57
- getGitContext
58
- };
59
- async function syncAffectedSpecs(deps = defaultDeps) {
60
- const stagedFiles = deps.getStagedFiles();
61
- if (stagedFiles.length === 0) {
62
- return [];
63
- }
64
- const client = deps.getClient();
65
- const gitCtx = deps.getGitContext();
66
- let mappingsUrl = "/api/cli/specs/mappings";
67
- if (gitCtx.repoFullName && gitCtx.branch) {
68
- const params = new URLSearchParams({
69
- repoFullName: gitCtx.repoFullName,
70
- branch: gitCtx.branch
71
- });
72
- mappingsUrl = `${mappingsUrl}?${params.toString()}`;
73
- }
74
- let mappings = [];
75
- try {
76
- mappings = await client.get(mappingsUrl, {
77
- signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
78
- });
79
- } catch {
80
- return [];
81
- }
82
- if (mappings.length === 0) {
83
- return [];
84
- }
85
- const specsById = new Map(mappings.map((s) => [s._id, s]));
86
- const affectedContexts = findAffectedContexts(stagedFiles, mappings);
87
- if (affectedContexts.size === 0) {
88
- return [];
89
- }
90
- console.log(`[prim] ${String(affectedContexts.size)} spec(s) affected by staged changes:`);
91
- const synced = [];
92
- for (const [contextId, affected] of affectedContexts) {
93
- try {
94
- const ctx = await client.get(`/api/cli/contexts/${contextId}`, {
95
- signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
96
- });
97
- if (!ctx._id) {
98
- console.log(` [skip] ${contextId} \u2014 not found`);
99
- continue;
100
- }
101
- if (!ctx.isSpecDocument) {
102
- console.log(` [skip] ${contextId} \u2014 not a spec document`);
103
- continue;
104
- }
105
- const diffContent = deps.getStagedDiff(affected.matchedFiles);
106
- if (!diffContent) {
107
- console.log(` [skip] ${contextId} \u2014 no diff content`);
108
- continue;
109
- }
110
- const body = {
111
- diffContent,
112
- affectedFiles: affected.matchedFiles
113
- };
114
- if (gitCtx.branch) body.branch = gitCtx.branch;
115
- if (gitCtx.sha) body.sha = gitCtx.sha;
116
- if (gitCtx.repoFullName) body.repoFullName = gitCtx.repoFullName;
117
- if (gitCtx.prNumber !== null) body.prNumber = gitCtx.prNumber;
118
- const response = await client.post(`/api/cli/contexts/${contextId}/sync-diff`, body, {
119
- signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
120
- });
121
- const name = ctx.name ?? "(unnamed)";
122
- if (!response.analyzing && response.reason === "not_linked") {
123
- console.log(
124
- ` [skip] ${contextId} \u2014 ${name} \u2014 not linked to ${gitCtx.branch ?? "(no branch)"}`
125
- );
126
- continue;
127
- }
128
- const spec = specsById.get(contextId);
129
- const link = spec?.linkedBranches?.find((l) => l.branch === gitCtx.branch);
130
- let linkSuffix = "";
131
- if (link) {
132
- const prBits = link.prNumber ? ` #${String(link.prNumber)}${link.prState ? ` ${link.prState}` : ""}` : "";
133
- linkSuffix = ` (linked to ${link.branch}${prBits})`;
134
- } else if (gitCtx.branch && spec?.linkedBranches?.length === 0) {
135
- linkSuffix = ` (auto-linking to ${gitCtx.branch})`;
136
- }
137
- const review = link?.latestReviewSummary;
138
- let reviewSuffix = "";
139
- if (review?.status === "completed") {
140
- const n = review.findingsCount ?? 0;
141
- const urlSuffix = review.prCommentUrl ? ` \u2192 ${review.prCommentUrl.replace(/^https?:\/\//, "")}` : "";
142
- reviewSuffix = ` (reviewed: ${String(n)} finding${n === 1 ? "" : "s"}${urlSuffix})`;
143
- } else if (review?.status === "failed") {
144
- reviewSuffix = " (review failed)";
145
- }
146
- linkSuffix += reviewSuffix;
147
- if (response.truncated && response.sizeChars && response.limitChars) {
148
- const sizeKiB = Math.round(response.sizeChars / 1024);
149
- const limitKiB = Math.round(response.limitChars / 1024);
150
- console.log(
151
- ` [synced] ${contextId} \u2014 ${name} (truncated: ${String(sizeKiB)} KiB \u2192 ${String(limitKiB)} KiB analyzed)${linkSuffix}`
152
- );
153
- } else {
154
- console.log(` [synced] ${contextId} \u2014 ${name}${linkSuffix}`);
155
- }
156
- synced.push(contextId);
157
- } catch (error) {
158
- const message = error instanceof Error ? error.message : String(error);
159
- console.error(` [error] ${contextId} \u2014 ${message}`);
160
- }
161
- }
162
- return synced;
163
- }
164
17
  async function runDecisionsCheck() {
165
18
  const stagedFiles = getStagedFiles();
166
19
  if (stagedFiles.length === 0) {
@@ -169,7 +22,7 @@ async function runDecisionsCheck() {
169
22
  return checkAffectedDecisions(stagedFiles);
170
23
  }
171
24
  async function main() {
172
- const [, decisionsResult] = await Promise.all([syncAffectedSpecs(), runDecisionsCheck()]);
25
+ const decisionsResult = await runDecisionsCheck();
173
26
  const warning = formatDecisionsWarning(decisionsResult);
174
27
  if (warning) {
175
28
  console.error(warning);
@@ -182,9 +35,3 @@ if (!process.env.VITEST) {
182
35
  process.exit(0);
183
36
  });
184
37
  }
185
- export {
186
- HOOK_TIMEOUT_MS,
187
- findAffectedContexts,
188
- matchPattern,
189
- syncAffectedSpecs
190
- };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getClient
4
- } from "../chunk-6SIEWWUL.js";
4
+ } from "../chunk-26VA3ADF.js";
5
5
  import {
6
6
  parseAgent
7
7
  } from "../chunk-7YRBACIE.js";