@primitive.ai/prim 0.1.0-alpha.61 → 0.1.0-alpha.63
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/{chunk-I3HIPAIR.js → chunk-CPX3BUOC.js} +7 -4
- package/dist/chunk-DA4BMHEB.js +77 -0
- package/dist/{chunk-B4SHJYIN.js → chunk-GF5QII7T.js} +83 -110
- package/dist/{chunk-S4LFRVGD.js → chunk-HIMWM526.js} +1 -1
- package/dist/{chunk-YIMUIPMD.js → chunk-KBFFVYBC.js} +7 -1
- package/dist/{chunk-R4CUX6FY.js → chunk-KHZNYEUV.js} +1 -1
- package/dist/chunk-QGVHLP5J.js +117 -0
- package/dist/{chunk-IMAIBPUC.js → chunk-UVIWZWM6.js} +1 -0
- package/dist/chunk-WNIY6Z6N.js +1244 -0
- package/dist/{chunk-YITJ2H3B.js → chunk-WS3MCNFD.js} +1 -1
- package/dist/chunk-XTNMSS4C.js +283 -0
- package/dist/daemon/server.js +343 -44
- package/dist/hooks/post-commit.js +84 -18
- package/dist/hooks/post-tool-use.js +42 -26
- package/dist/hooks/pre-commit.js +2 -2
- package/dist/hooks/pre-tool-use.js +103 -11
- package/dist/hooks/prim-hook.js +33 -12
- package/dist/hooks/session-start.js +29 -8
- package/dist/index.js +361 -155
- package/dist/statusline-main.js +57 -42
- package/package.json +1 -1
- package/dist/chunk-GUXBUBQ7.js +0 -84
- package/dist/chunk-LDQZASIF.js +0 -166
- package/dist/chunk-N4R7EXZT.js +0 -620
- package/dist/chunk-YDBZTFW5.js +0 -67
package/dist/statusline-main.js
CHANGED
|
@@ -26,10 +26,10 @@ import { dirname, join } from "path";
|
|
|
26
26
|
|
|
27
27
|
// src/client.ts
|
|
28
28
|
var DEFAULT_API_URL = "https://api.getprimitive.ai";
|
|
29
|
-
function loadEnvFile() {
|
|
29
|
+
function loadEnvFile(cwd = process.cwd()) {
|
|
30
30
|
const envVars = {};
|
|
31
31
|
for (const file of [".env.local", ".env"]) {
|
|
32
|
-
const filePath = resolve(
|
|
32
|
+
const filePath = resolve(cwd, file);
|
|
33
33
|
if (!existsSync2(filePath)) continue;
|
|
34
34
|
const content = readFileSync2(filePath, "utf-8");
|
|
35
35
|
for (const line of content.split("\n")) {
|
|
@@ -48,8 +48,11 @@ var TOKEN_EXPIRES_PATH = join2(dirname2(TOKEN_FILE_PATH), "token_expires_at");
|
|
|
48
48
|
var TERMINAL_REFRESH_PATH = join2(dirname2(TOKEN_FILE_PATH), "refresh_terminal");
|
|
49
49
|
var CREDENTIAL_LOCK_PATH = join2(dirname2(TOKEN_FILE_PATH), "credentials.lock");
|
|
50
50
|
function getSiteUrl() {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
return getSiteUrlForCwd(process.cwd(), process.env.PRIM_API_URL);
|
|
52
|
+
}
|
|
53
|
+
function getSiteUrlForCwd(cwd, primApiUrl) {
|
|
54
|
+
if (primApiUrl) return primApiUrl;
|
|
55
|
+
return loadEnvFile(cwd).PRIM_API_URL ?? DEFAULT_API_URL;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
// src/daemon/client.ts
|
|
@@ -140,14 +143,17 @@ import { join as join4 } from "path";
|
|
|
140
143
|
|
|
141
144
|
// src/lib/git.ts
|
|
142
145
|
import { execFileSync } from "child_process";
|
|
146
|
+
import { createHash as createHash2 } from "crypto";
|
|
143
147
|
import { lstatSync, realpathSync } from "fs";
|
|
144
148
|
import { basename, dirname as dirname3, isAbsolute, relative, resolve as resolve2, sep } from "path";
|
|
149
|
+
var GIT_TIMEOUT_MS = 1e3;
|
|
145
150
|
function gitToplevel(cwd) {
|
|
146
151
|
try {
|
|
147
152
|
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
148
153
|
cwd,
|
|
149
154
|
encoding: "utf-8",
|
|
150
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
155
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
156
|
+
timeout: GIT_TIMEOUT_MS
|
|
151
157
|
}).trim();
|
|
152
158
|
} catch {
|
|
153
159
|
return null;
|
|
@@ -156,6 +162,7 @@ function gitToplevel(cwd) {
|
|
|
156
162
|
|
|
157
163
|
// src/lib/activation.ts
|
|
158
164
|
var PRIM_ACTIVE_KEY = "prim.active";
|
|
165
|
+
var GIT_TIMEOUT_MS2 = 1e3;
|
|
159
166
|
var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
|
|
160
167
|
var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
|
|
161
168
|
function repoActiveFlag(cwd) {
|
|
@@ -163,7 +170,8 @@ function repoActiveFlag(cwd) {
|
|
|
163
170
|
const value = execFileSync2("git", ["config", "--get", PRIM_ACTIVE_KEY], {
|
|
164
171
|
cwd,
|
|
165
172
|
encoding: "utf-8",
|
|
166
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
173
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
174
|
+
timeout: GIT_TIMEOUT_MS2
|
|
167
175
|
}).trim();
|
|
168
176
|
if (value === "true") return "true";
|
|
169
177
|
if (value === "false") return "false";
|
|
@@ -268,15 +276,54 @@ function formatTeammatesWithArea(teammates, cap) {
|
|
|
268
276
|
);
|
|
269
277
|
}
|
|
270
278
|
|
|
279
|
+
// src/lib/statusline-render.ts
|
|
280
|
+
var STATUSLINE_NAME_CAP = 3;
|
|
281
|
+
function formatStatusline(version, snapshot, resolveIngestionStatus) {
|
|
282
|
+
if (!snapshot) {
|
|
283
|
+
return `primitive ${version} (daemon: down)`;
|
|
284
|
+
}
|
|
285
|
+
if (snapshot.healthy === false) {
|
|
286
|
+
if (snapshot.needsReauth) {
|
|
287
|
+
return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`)`;
|
|
288
|
+
}
|
|
289
|
+
if (snapshot.ingestion?.healthy === false) {
|
|
290
|
+
const pending = snapshot.ingestion.pendingCount;
|
|
291
|
+
const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
|
|
292
|
+
return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""})`;
|
|
293
|
+
}
|
|
294
|
+
if (snapshot.heartbeat?.healthy === false) {
|
|
295
|
+
return `primitive ${version} (daemon: degraded \xB7 presence: unavailable)`;
|
|
296
|
+
}
|
|
297
|
+
return `primitive ${version} (daemon: starting)`;
|
|
298
|
+
}
|
|
299
|
+
const ingestionStatus = resolveIngestionStatus();
|
|
300
|
+
if (snapshot.envMismatch) {
|
|
301
|
+
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: other env)`;
|
|
302
|
+
}
|
|
303
|
+
if (snapshot.presenceStale) {
|
|
304
|
+
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: stale)`;
|
|
305
|
+
}
|
|
306
|
+
let team;
|
|
307
|
+
if (snapshot.onlineTeammates !== void 0) {
|
|
308
|
+
team = `team: ${formatTeammatesWithArea(snapshot.onlineTeammates, STATUSLINE_NAME_CAP)}`;
|
|
309
|
+
} else if (snapshot.onlineNames !== void 0) {
|
|
310
|
+
team = `team: ${formatTeammates(snapshot.onlineNames, STATUSLINE_NAME_CAP)}`;
|
|
311
|
+
} else if (typeof snapshot.onlineCount === "number") {
|
|
312
|
+
team = `team: ${String(snapshot.onlineCount)} online`;
|
|
313
|
+
} else {
|
|
314
|
+
team = "team: \u2014";
|
|
315
|
+
}
|
|
316
|
+
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 ${team})`;
|
|
317
|
+
}
|
|
318
|
+
|
|
271
319
|
// src/commands/statusline.ts
|
|
272
320
|
var STATUSLINE_TIMEOUT_MS = 200;
|
|
273
|
-
var STATUSLINE_NAME_CAP = 3;
|
|
274
321
|
function readPackageVersion() {
|
|
275
322
|
try {
|
|
276
323
|
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
277
324
|
const candidates = [
|
|
278
|
-
//
|
|
279
|
-
//
|
|
325
|
+
// Schema-v2 runtimes staged a manifest beside this standalone bundle.
|
|
326
|
+
// Keep resolving it while those legacy launchers transition to schema v3.
|
|
280
327
|
resolve3(here, "manifest.json"),
|
|
281
328
|
resolve3(here, "../../package.json"),
|
|
282
329
|
resolve3(here, "../package.json")
|
|
@@ -311,40 +358,8 @@ async function renderStatusline() {
|
|
|
311
358
|
);
|
|
312
359
|
if (!snapshot) {
|
|
313
360
|
debug("daemon snapshot missing");
|
|
314
|
-
return `primitive ${version} (daemon: down)`;
|
|
315
|
-
}
|
|
316
|
-
if (snapshot.healthy === false) {
|
|
317
|
-
if (snapshot.needsReauth) {
|
|
318
|
-
return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`)`;
|
|
319
|
-
}
|
|
320
|
-
if (snapshot.ingestion?.healthy === false) {
|
|
321
|
-
const pending = snapshot.ingestion.pendingCount;
|
|
322
|
-
const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
|
|
323
|
-
return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""})`;
|
|
324
|
-
}
|
|
325
|
-
if (snapshot.heartbeat?.healthy === false) {
|
|
326
|
-
return `primitive ${version} (daemon: degraded \xB7 presence: unavailable)`;
|
|
327
|
-
}
|
|
328
|
-
return `primitive ${version} (daemon: starting)`;
|
|
329
361
|
}
|
|
330
|
-
|
|
331
|
-
if (snapshot.envMismatch) {
|
|
332
|
-
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: other env)`;
|
|
333
|
-
}
|
|
334
|
-
if (snapshot.presenceStale) {
|
|
335
|
-
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: stale)`;
|
|
336
|
-
}
|
|
337
|
-
let team;
|
|
338
|
-
if (snapshot.onlineTeammates !== void 0) {
|
|
339
|
-
team = `team: ${formatTeammatesWithArea(snapshot.onlineTeammates, STATUSLINE_NAME_CAP)}`;
|
|
340
|
-
} else if (snapshot.onlineNames !== void 0) {
|
|
341
|
-
team = `team: ${formatTeammates(snapshot.onlineNames, STATUSLINE_NAME_CAP)}`;
|
|
342
|
-
} else if (typeof snapshot.onlineCount === "number") {
|
|
343
|
-
team = `team: ${String(snapshot.onlineCount)} online`;
|
|
344
|
-
} else {
|
|
345
|
-
team = "team: \u2014";
|
|
346
|
-
}
|
|
347
|
-
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 ${team})`;
|
|
362
|
+
return formatStatusline(version, snapshot, () => decisionIngestionStatus(process.cwd()));
|
|
348
363
|
}
|
|
349
364
|
|
|
350
365
|
// src/statusline-main.ts
|
package/package.json
CHANGED
package/dist/chunk-GUXBUBQ7.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// src/hooks/redact.ts
|
|
2
|
-
import { existsSync, readFileSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
var DEFAULT_RULES = [
|
|
5
|
-
{ pattern: /Bearer\s+[A-Za-z0-9._\-]+/g, reason: "bearer-token" },
|
|
6
|
-
{ pattern: /sk-[A-Za-z0-9]{32,}/g, reason: "sk-api-key" },
|
|
7
|
-
{
|
|
8
|
-
pattern: /-----BEGIN [A-Z ]+PRIVATE KEY-----[\s\S]+?-----END [A-Z ]+PRIVATE KEY-----/g,
|
|
9
|
-
reason: "private-key"
|
|
10
|
-
},
|
|
11
|
-
{ pattern: /xox[abprs]-[A-Za-z0-9-]{10,}/g, reason: "slack-token" },
|
|
12
|
-
{ pattern: /ghp_[A-Za-z0-9]{36,}/g, reason: "github-pat" }
|
|
13
|
-
];
|
|
14
|
-
var MAX_SCRUB_LEN = 256e3;
|
|
15
|
-
var WORKSPACE_FILE = ".prim/redaction.json";
|
|
16
|
-
function debugRedaction(message, err) {
|
|
17
|
-
if (!process.env.PRIM_HOOK_DEBUG) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
21
|
-
process.stderr.write(`[prim-hook] redaction: ${message}: ${detail}
|
|
22
|
-
`);
|
|
23
|
-
}
|
|
24
|
-
function loadWorkspaceRules(cwd) {
|
|
25
|
-
const path = join(cwd, WORKSPACE_FILE);
|
|
26
|
-
if (!existsSync(path)) {
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
let cfg;
|
|
30
|
-
try {
|
|
31
|
-
cfg = JSON.parse(readFileSync(path, "utf-8"));
|
|
32
|
-
} catch (err) {
|
|
33
|
-
debugRedaction(`ignoring unparseable ${WORKSPACE_FILE}`, err);
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
if (!cfg.rules) {
|
|
37
|
-
return [];
|
|
38
|
-
}
|
|
39
|
-
const compiled = [];
|
|
40
|
-
for (const r of cfg.rules) {
|
|
41
|
-
try {
|
|
42
|
-
compiled.push({ pattern: new RegExp(r.pattern, r.flags ?? "g"), reason: r.reason });
|
|
43
|
-
} catch (err) {
|
|
44
|
-
debugRedaction(`skipping invalid redaction rule "${r.reason}"`, err);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return compiled;
|
|
48
|
-
}
|
|
49
|
-
function applyRules(input, rules) {
|
|
50
|
-
if (input.length > MAX_SCRUB_LEN) {
|
|
51
|
-
return "<REDACTED:oversized>";
|
|
52
|
-
}
|
|
53
|
-
let out = input;
|
|
54
|
-
for (const rule of rules) {
|
|
55
|
-
out = out.replace(rule.pattern, `<REDACTED:${rule.reason}>`);
|
|
56
|
-
}
|
|
57
|
-
return out;
|
|
58
|
-
}
|
|
59
|
-
function scrub(value, rules = DEFAULT_RULES) {
|
|
60
|
-
if (typeof value === "string") {
|
|
61
|
-
return applyRules(value, rules);
|
|
62
|
-
}
|
|
63
|
-
if (Array.isArray(value)) {
|
|
64
|
-
return value.map((v) => scrub(v, rules));
|
|
65
|
-
}
|
|
66
|
-
if (value && typeof value === "object") {
|
|
67
|
-
const out = {};
|
|
68
|
-
for (const [k, v] of Object.entries(value)) {
|
|
69
|
-
out[k] = scrub(v, rules);
|
|
70
|
-
}
|
|
71
|
-
return out;
|
|
72
|
-
}
|
|
73
|
-
return value;
|
|
74
|
-
}
|
|
75
|
-
function scrubFromCwd(value, cwd) {
|
|
76
|
-
const rules = [...DEFAULT_RULES, ...loadWorkspaceRules(cwd)];
|
|
77
|
-
return scrub(value, rules);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export {
|
|
81
|
-
DEFAULT_RULES,
|
|
82
|
-
scrub,
|
|
83
|
-
scrubFromCwd
|
|
84
|
-
};
|
package/dist/chunk-LDQZASIF.js
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
// src/lib/activation.ts
|
|
2
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
3
|
-
import { existsSync, readFileSync } from "fs";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
|
|
7
|
-
// src/lib/git.ts
|
|
8
|
-
import { execFileSync } from "child_process";
|
|
9
|
-
import { lstatSync, realpathSync } from "fs";
|
|
10
|
-
import { basename, dirname, isAbsolute, relative, resolve, sep } from "path";
|
|
11
|
-
function gitToplevel(cwd) {
|
|
12
|
-
try {
|
|
13
|
-
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
14
|
-
cwd,
|
|
15
|
-
encoding: "utf-8",
|
|
16
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
17
|
-
}).trim();
|
|
18
|
-
} catch {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function gitValue(cwd, args) {
|
|
23
|
-
try {
|
|
24
|
-
const value = execFileSync("git", args, {
|
|
25
|
-
cwd,
|
|
26
|
-
encoding: "utf-8",
|
|
27
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
28
|
-
}).trim();
|
|
29
|
-
return value || null;
|
|
30
|
-
} catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function githubRepositoryFullName(cwd) {
|
|
35
|
-
const remote = gitValue(cwd, ["config", "--get", "remote.origin.url"]);
|
|
36
|
-
if (!remote || [...remote].some((char) => char < " " || char === "\x7F")) return null;
|
|
37
|
-
const match = /^(?:git@github\.com:([^?#]+)|(?:https|ssh):\/\/(?:[^/@]+@)?github\.com(?::\d+)?\/([^?#]+))$/i.exec(
|
|
38
|
-
remote
|
|
39
|
-
);
|
|
40
|
-
const path = match?.[1] ?? match?.[2];
|
|
41
|
-
if (!path) return null;
|
|
42
|
-
const parts = path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "").split("/");
|
|
43
|
-
if (parts.length !== 2 || parts.some((part) => !part || part !== part.trim())) return null;
|
|
44
|
-
return `${parts[0]}/${parts[1]}`;
|
|
45
|
-
}
|
|
46
|
-
function canonicalGitRoot(cwd) {
|
|
47
|
-
try {
|
|
48
|
-
const top = gitToplevel(cwd);
|
|
49
|
-
return top ? realpathSync.native(top) : null;
|
|
50
|
-
} catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function canonicalRepositoryPath(filePath, cwd, repositoryRoot = canonicalGitRoot(cwd)) {
|
|
55
|
-
if (!repositoryRoot || !filePath || [...filePath].some((char) => char < " " || char === "\x7F" || "~*?[]{}$`\\".includes(char)))
|
|
56
|
-
return null;
|
|
57
|
-
const absolute = resolve(cwd, filePath);
|
|
58
|
-
let target;
|
|
59
|
-
try {
|
|
60
|
-
const stat = lstatSync(absolute);
|
|
61
|
-
if (!stat.isFile() || stat.isSymbolicLink()) return null;
|
|
62
|
-
target = realpathSync.native(absolute);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
if (!(error instanceof Error) || error.code !== "ENOENT") {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const parent = realpathSync.native(dirname(absolute));
|
|
69
|
-
if (!lstatSync(parent).isDirectory()) return null;
|
|
70
|
-
target = resolve(parent, basename(absolute));
|
|
71
|
-
} catch {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const rel = relative(repositoryRoot, target);
|
|
76
|
-
if (!rel || isAbsolute(rel) || rel === ".." || rel.startsWith(`..${sep}`)) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
return sep === "/" ? rel : rel.split(sep).join("/");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// src/lib/activation.ts
|
|
83
|
-
var PRIM_ACTIVE_KEY = "prim.active";
|
|
84
|
-
var PRIM_REPO_SYNC_ID_KEY = "prim.repoSyncId";
|
|
85
|
-
var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
|
|
86
|
-
var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
|
|
87
|
-
function repoActiveFlag(cwd) {
|
|
88
|
-
try {
|
|
89
|
-
const value = execFileSync2("git", ["config", "--get", PRIM_ACTIVE_KEY], {
|
|
90
|
-
cwd,
|
|
91
|
-
encoding: "utf-8",
|
|
92
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
93
|
-
}).trim();
|
|
94
|
-
if (value === "true") return "true";
|
|
95
|
-
if (value === "false") return "false";
|
|
96
|
-
return void 0;
|
|
97
|
-
} catch {
|
|
98
|
-
return void 0;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function isRepoActive(cwd) {
|
|
102
|
-
return repoActiveFlag(cwd) === "true";
|
|
103
|
-
}
|
|
104
|
-
function setRepoActive(cwd, active) {
|
|
105
|
-
execFileSync2("git", ["config", "--local", PRIM_ACTIVE_KEY, active ? "true" : "false"], {
|
|
106
|
-
cwd,
|
|
107
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
function repoSyncId(cwd) {
|
|
111
|
-
try {
|
|
112
|
-
return execFileSync2("git", ["config", "--local", "--get", PRIM_REPO_SYNC_ID_KEY], {
|
|
113
|
-
cwd,
|
|
114
|
-
encoding: "utf-8",
|
|
115
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
116
|
-
}).trim() || void 0;
|
|
117
|
-
} catch {
|
|
118
|
-
return void 0;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
function setRepoSyncId(cwd, value) {
|
|
122
|
-
if (!value || value.includes("\0") || value.includes("\n")) {
|
|
123
|
-
throw new Error("invalid repository binding returned by server");
|
|
124
|
-
}
|
|
125
|
-
execFileSync2("git", ["config", "--local", PRIM_REPO_SYNC_ID_KEY, value], {
|
|
126
|
-
cwd,
|
|
127
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
function hasProjectPrimInstall(cwd) {
|
|
131
|
-
const root = gitToplevel(cwd);
|
|
132
|
-
if (root === null || root === homedir()) return false;
|
|
133
|
-
for (const rel of PROJECT_INSTALL_FILES) {
|
|
134
|
-
const path = join(root, rel);
|
|
135
|
-
if (existsSync(path)) {
|
|
136
|
-
try {
|
|
137
|
-
const content = readFileSync(path, "utf-8");
|
|
138
|
-
if (PRIM_HOOK_BINS.some((bin) => content.includes(bin))) return true;
|
|
139
|
-
} catch {
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
function isRepoActiveForCapture(cwd) {
|
|
146
|
-
const flag = repoActiveFlag(cwd);
|
|
147
|
-
if (flag === "true") return true;
|
|
148
|
-
if (flag === "false") return false;
|
|
149
|
-
return hasProjectPrimInstall(cwd);
|
|
150
|
-
}
|
|
151
|
-
function decisionIngestionStatus(cwd) {
|
|
152
|
-
return isRepoActiveForCapture(cwd) ? "enabled" : "disabled";
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export {
|
|
156
|
-
gitToplevel,
|
|
157
|
-
githubRepositoryFullName,
|
|
158
|
-
canonicalGitRoot,
|
|
159
|
-
canonicalRepositoryPath,
|
|
160
|
-
isRepoActive,
|
|
161
|
-
setRepoActive,
|
|
162
|
-
repoSyncId,
|
|
163
|
-
setRepoSyncId,
|
|
164
|
-
isRepoActiveForCapture,
|
|
165
|
-
decisionIngestionStatus
|
|
166
|
-
};
|