codiedev 0.10.0-beta.4 → 0.10.0-beta.6

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.
Files changed (157) hide show
  1. package/README.md +11 -5
  2. package/assets/tui-brand-plugin.tsx +14 -2
  3. package/dist/backup/cache.js +1 -5
  4. package/dist/backup/match.js +0 -6
  5. package/dist/backup/run.js +3 -35
  6. package/dist/captureExclusions.js +0 -12
  7. package/dist/captureLog.js +0 -28
  8. package/dist/captureReadiness.js +0 -58
  9. package/dist/captureSignals.js +68 -3
  10. package/dist/cli.js +75 -64
  11. package/dist/codexHookTrust.js +125 -6
  12. package/dist/codexLimitScan.js +2 -109
  13. package/dist/codie.js +50 -114
  14. package/dist/codieBrandInstall.js +0 -18
  15. package/dist/codieLauncher.js +20 -92
  16. package/dist/codieRuntime.js +19 -23
  17. package/dist/codieRuntimeInstall.js +108 -23
  18. package/dist/codieUsage.js +38 -41
  19. package/dist/commands/agentTemplates.generated.js +136 -0
  20. package/dist/commands/agents.js +1066 -0
  21. package/dist/commands/agentsSdk.generated.js +7 -0
  22. package/dist/commands/ask.js +0 -3
  23. package/dist/commands/capture.js +0 -2
  24. package/dist/commands/createTicket.js +0 -10
  25. package/dist/commands/doctor.js +53 -120
  26. package/dist/commands/evals.js +187 -0
  27. package/dist/commands/inbox.js +0 -2
  28. package/dist/commands/library.js +0 -3
  29. package/dist/commands/pack.js +573 -0
  30. package/dist/commands/ping.js +0 -2
  31. package/dist/commands/pull.js +6 -10
  32. package/dist/commands/push.js +2 -12
  33. package/dist/commands/search.js +0 -4
  34. package/dist/commands/send.js +0 -5
  35. package/dist/commands/share.js +0 -4
  36. package/dist/commands/shared.js +0 -35
  37. package/dist/commands/traces.js +344 -0
  38. package/dist/commands/tracesLabel.js +348 -0
  39. package/dist/configDir.js +0 -10
  40. package/dist/connect.js +19 -116
  41. package/dist/connectFlow.js +0 -9
  42. package/dist/copilotHooks.js +391 -0
  43. package/dist/copilotInstallation.js +64 -0
  44. package/dist/cursorHooks.js +38 -30
  45. package/dist/cursorLifecycle.js +109 -0
  46. package/dist/detection.js +0 -30
  47. package/dist/harnessDirs.js +77 -0
  48. package/dist/hook.js +182 -469
  49. package/dist/inboxFormat.js +0 -24
  50. package/dist/launchContext.js +150 -0
  51. package/dist/launcher.js +140 -0
  52. package/dist/limitEvent.js +41 -35
  53. package/dist/limitEventReporter.js +1 -1
  54. package/dist/managedPi.js +240 -0
  55. package/dist/mcp.js +3 -384
  56. package/dist/nativeSteering.js +24 -0
  57. package/dist/packs/codie.js +182 -0
  58. package/dist/packs/harnesses.js +411 -0
  59. package/dist/packs/hookGate.js +256 -0
  60. package/dist/packs/install.js +286 -0
  61. package/dist/packs/manifest.js +126 -0
  62. package/dist/packs/paths.js +81 -0
  63. package/dist/packs/shim.js +214 -0
  64. package/dist/packs/store.js +155 -0
  65. package/dist/packs/sync.js +170 -0
  66. package/dist/piHooks.js +216 -0
  67. package/dist/piRuntime.js +120 -0
  68. package/dist/repoResolver.js +0 -19
  69. package/dist/secret.js +0 -3
  70. package/dist/selfUpdate.js +376 -0
  71. package/dist/skillMarker.js +23 -0
  72. package/dist/subagents.js +135 -0
  73. package/dist/teamSkillContext.js +10 -0
  74. package/dist/transcriptModels.js +6 -8
  75. package/dist/upgradeNudge.js +0 -30
  76. package/dist/utils.js +494 -824
  77. package/dist/version.js +0 -10
  78. package/dist/versionCheck.js +0 -33
  79. package/package.json +8 -9
  80. package/dist/backup/cache.d.ts +0 -14
  81. package/dist/backup/match.d.ts +0 -2
  82. package/dist/backup/run.d.ts +0 -25
  83. package/dist/captureExclusions.d.ts +0 -30
  84. package/dist/captureLog.d.ts +0 -20
  85. package/dist/captureReadiness.d.ts +0 -65
  86. package/dist/captureSignals.d.ts +0 -19
  87. package/dist/cli.d.ts +0 -16
  88. package/dist/codexHookTrust.d.ts +0 -34
  89. package/dist/codexLimitScan.d.ts +0 -64
  90. package/dist/codie.d.ts +0 -2
  91. package/dist/codieBrandInstall.d.ts +0 -11
  92. package/dist/codieLauncher.d.ts +0 -86
  93. package/dist/codieRuntime.d.ts +0 -29
  94. package/dist/codieRuntimeInstall.d.ts +0 -28
  95. package/dist/codieStartup.d.ts +0 -26
  96. package/dist/codieStartup.js +0 -30
  97. package/dist/codieUsage.d.ts +0 -57
  98. package/dist/commands/ask.d.ts +0 -1
  99. package/dist/commands/capture.d.ts +0 -14
  100. package/dist/commands/createTicket.d.ts +0 -27
  101. package/dist/commands/delete.d.ts +0 -1
  102. package/dist/commands/doctor.d.ts +0 -1
  103. package/dist/commands/inbox.d.ts +0 -3
  104. package/dist/commands/library.d.ts +0 -2
  105. package/dist/commands/note.d.ts +0 -1
  106. package/dist/commands/ping.d.ts +0 -1
  107. package/dist/commands/promote.d.ts +0 -1
  108. package/dist/commands/promote.js +0 -53
  109. package/dist/commands/pull.d.ts +0 -2
  110. package/dist/commands/push.d.ts +0 -33
  111. package/dist/commands/react.d.ts +0 -2
  112. package/dist/commands/react.js +0 -40
  113. package/dist/commands/reverseTicket.d.ts +0 -2
  114. package/dist/commands/reverseTicket.js +0 -477
  115. package/dist/commands/search.d.ts +0 -2
  116. package/dist/commands/security.d.ts +0 -1
  117. package/dist/commands/security.js +0 -156
  118. package/dist/commands/send.d.ts +0 -2
  119. package/dist/commands/share.d.ts +0 -2
  120. package/dist/commands/shared.d.ts +0 -64
  121. package/dist/configDir.d.ts +0 -1
  122. package/dist/connect.d.ts +0 -1
  123. package/dist/connectFlow.d.ts +0 -13
  124. package/dist/cursorHooks.d.ts +0 -23
  125. package/dist/detection.d.ts +0 -30
  126. package/dist/hook.d.ts +0 -6
  127. package/dist/inboxFormat.d.ts +0 -38
  128. package/dist/limitEvent.d.ts +0 -16
  129. package/dist/limitEventReporter.d.ts +0 -21
  130. package/dist/mcp.d.ts +0 -12
  131. package/dist/prUrl.d.ts +0 -9
  132. package/dist/prUrl.js +0 -33
  133. package/dist/repoResolver.d.ts +0 -17
  134. package/dist/secret.d.ts +0 -1
  135. package/dist/security.d.ts +0 -102
  136. package/dist/security.js +0 -437
  137. package/dist/securityDeepScan.d.ts +0 -41
  138. package/dist/securityDeepScan.js +0 -248
  139. package/dist/securityDoctor.d.ts +0 -32
  140. package/dist/securityDoctor.js +0 -63
  141. package/dist/securityFeature.d.ts +0 -5
  142. package/dist/securityFeature.js +0 -7
  143. package/dist/securityInstall.d.ts +0 -63
  144. package/dist/securityInstall.js +0 -239
  145. package/dist/securityInventory.d.ts +0 -54
  146. package/dist/securityInventory.js +0 -556
  147. package/dist/securityPilot.d.ts +0 -19
  148. package/dist/securityPilot.js +0 -61
  149. package/dist/securityPolicy.d.ts +0 -33
  150. package/dist/securityPolicy.js +0 -188
  151. package/dist/securitySession.d.ts +0 -6
  152. package/dist/securitySession.js +0 -72
  153. package/dist/transcriptModels.d.ts +0 -18
  154. package/dist/upgradeNudge.d.ts +0 -25
  155. package/dist/utils.d.ts +0 -346
  156. package/dist/version.d.ts +0 -1
  157. package/dist/versionCheck.d.ts +0 -68
@@ -1,477 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isSafeRef = isSafeRef;
4
- exports.runReverseTicket = runReverseTicket;
5
- const child_process_1 = require("child_process");
6
- const shared_1 = require("./shared");
7
- const prUrl_1 = require("../prUrl");
8
- /**
9
- * Run a binary with an explicit argv, never a shell.
10
- *
11
- * The `gh`/`glab` API paths are built from an owner/repo parsed out of a URL the
12
- * caller pastes in. `parsePrOrMrUrl` only bounds those segments to "no slash",
13
- * so they can still carry `$(…)`, backticks or `;` — which a `shell: true`
14
- * invocation would execute. Passing argv directly means the shell never sees
15
- * them at all.
16
- */
17
- function runArgv(bin, argv, opts = {}) {
18
- const res = (0, child_process_1.spawnSync)(bin, argv, {
19
- stdio: ["pipe", "pipe", "pipe"],
20
- encoding: "utf8",
21
- maxBuffer: opts.maxBuffer ?? 50 * 1024 * 1024,
22
- shell: false,
23
- });
24
- if (res.error)
25
- throw res.error;
26
- if (res.status !== 0) {
27
- throw new Error(`${bin} ${argv.join(" ")} failed (exit ${res.status}): ${(res.stderr || "").trim().slice(0, 500)}`);
28
- }
29
- return res.stdout ?? "";
30
- }
31
- // Git ref names legally contain `$()`, `;`, `|` and backticks, all of which
32
- // break out of the `shell: true` git calls in branch mode below. A ref supplied
33
- // via `--base` is caller-controlled, so bound it to the safe subset before it
34
- // reaches a command line. Mirrors `validate_ref` in modal/runner.py.
35
- const SAFE_REF_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$/;
36
- function isSafeRef(ref) {
37
- if (!ref || ref.startsWith("-"))
38
- return false;
39
- if (ref.includes("..") || ref.includes("@{"))
40
- return false;
41
- if (ref.endsWith("/") || ref.endsWith("."))
42
- return false;
43
- return SAFE_REF_RE.test(ref);
44
- }
45
- async function fetchPrOrMrBundle(parsed, rawUrl, noTruncate) {
46
- console.log(`Fetching ${parsed.provider === "gitlab" ? "MR" : "PR"} ${parsed.owner}/${parsed.repo}#${parsed.number}…`);
47
- if (parsed.provider === "github") {
48
- let prJson;
49
- let filesJson;
50
- let diff;
51
- try {
52
- prJson = ghApi(`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}`);
53
- filesJson = ghApi(`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}/files`);
54
- try {
55
- const rawDiff = ghRaw(`/repos/${parsed.owner}/${parsed.repo}/pulls/${parsed.number}`);
56
- diff = noTruncate ? rawDiff : rawDiff.slice(0, 12_000);
57
- }
58
- catch {
59
- // diff is nice-to-have
60
- }
61
- }
62
- catch (err) {
63
- console.error(`Failed to fetch PR via gh api: ${err.message}`);
64
- process.exit(1);
65
- }
66
- return {
67
- repo: `${parsed.owner}/${parsed.repo}`,
68
- number: parsed.number,
69
- title: prJson.title ?? "",
70
- body: prJson.body ?? "",
71
- author: prJson.user?.login ?? "unknown",
72
- authorEmail: prJson.user?.email ?? undefined,
73
- mergedAt: prJson.merged_at
74
- ? Date.parse(prJson.merged_at)
75
- : prJson.closed_at
76
- ? Date.parse(prJson.closed_at)
77
- : Date.now(),
78
- filesChanged: (filesJson ?? []).map((f) => f.filename),
79
- diff,
80
- htmlUrl: prJson.html_url ?? rawUrl,
81
- };
82
- }
83
- // GitLab path. `glab api projects/<encoded-path>/...` returns the same
84
- // MR shape as the REST API. We pull the diff from `merge_requests/<n>/changes`
85
- // and reassemble a unified diff out of each file's `diff` blob.
86
- const projectPath = `${parsed.owner}/${parsed.repo}`;
87
- let mrJson;
88
- let changesJson;
89
- try {
90
- mrJson = glabApi(projectPath, `merge_requests/${parsed.number}`);
91
- changesJson = glabApi(projectPath, `merge_requests/${parsed.number}/changes`);
92
- }
93
- catch (err) {
94
- console.error(`Failed to fetch MR via glab api: ${err.message}`);
95
- process.exit(1);
96
- }
97
- const changes = (changesJson?.changes ?? []);
98
- const filesChanged = changes
99
- .map((c) => c.new_path ?? c.old_path)
100
- .filter((p) => Boolean(p));
101
- const rawDiff = changes
102
- .map((c) => {
103
- const header = `diff --git a/${c.old_path ?? c.new_path} b/${c.new_path ?? c.old_path}`;
104
- return [header, c.diff ?? ""].join("\n");
105
- })
106
- .join("\n");
107
- const diff = noTruncate ? rawDiff : rawDiff.slice(0, 12_000);
108
- return {
109
- repo: projectPath,
110
- number: parsed.number,
111
- title: mrJson.title ?? "",
112
- body: mrJson.description ?? "",
113
- author: mrJson.author?.username ?? "unknown",
114
- authorEmail: undefined,
115
- mergedAt: mrJson.merged_at
116
- ? Date.parse(mrJson.merged_at)
117
- : mrJson.closed_at
118
- ? Date.parse(mrJson.closed_at)
119
- : Date.now(),
120
- filesChanged,
121
- diff,
122
- htmlUrl: mrJson.web_url ?? rawUrl,
123
- };
124
- }
125
- function checkCli(bin) {
126
- try {
127
- runArgv(bin, ["--version"], { maxBuffer: 1024 * 1024 });
128
- return true;
129
- }
130
- catch {
131
- return false;
132
- }
133
- }
134
- function ghApi(path) {
135
- return JSON.parse(runArgv("gh", ["api", path]));
136
- }
137
- function ghRaw(path) {
138
- return runArgv("gh", [
139
- "api",
140
- "-H",
141
- "Accept: application/vnd.github.v3.diff",
142
- path,
143
- ]);
144
- }
145
- // glab api takes a project path (URL-encoded) or numeric id and a sub-path.
146
- // For self-hosted GitLab, glab respects `GITLAB_HOST` env if the user has
147
- // configured glab against their internal instance.
148
- function glabApi(projectPath, subpath) {
149
- const encoded = encodeURIComponent(projectPath);
150
- return JSON.parse(runArgv("glab", ["api", `projects/${encoded}/${subpath}`]));
151
- }
152
- function parseArgs(args) {
153
- let prUrl;
154
- let base;
155
- let forcedKey;
156
- let noTruncate = false;
157
- for (let i = 0; i < args.length; i++) {
158
- const a = args[i];
159
- if ((a === "--with" || a === "-w") && i + 1 < args.length) {
160
- forcedKey = args[++i];
161
- }
162
- else if (a.startsWith("--with=")) {
163
- forcedKey = a.slice("--with=".length);
164
- }
165
- else if ((a === "--base" || a === "-b") && i + 1 < args.length) {
166
- base = args[++i];
167
- }
168
- else if (a.startsWith("--base=")) {
169
- base = a.slice("--base=".length);
170
- }
171
- else if (a === "--full") {
172
- noTruncate = true;
173
- }
174
- else if (!a.startsWith("--") && !prUrl) {
175
- prUrl = a;
176
- }
177
- }
178
- return { prUrl, base, forcedKey, noTruncate };
179
- }
180
- async function runReverseTicket(args) {
181
- const { prUrl, base, forcedKey, noTruncate } = parseArgs(args);
182
- // No PR URL → branch mode (mid-session, no PR exists yet).
183
- if (!prUrl) {
184
- return runBranchMode({ explicitBase: base, forcedKey });
185
- }
186
- const parsed = (0, prUrl_1.parsePrOrMrUrl)(prUrl);
187
- if (!parsed) {
188
- console.error("Couldn't parse PR/MR URL. Expected formats:");
189
- console.error(" https://github.com/<owner>/<repo>/pull/<number>");
190
- console.error(" https://gitlab.com/<group>/<repo>/-/merge_requests/<number>");
191
- console.error(" (self-hosted GitLab works too — same shape, your host)");
192
- console.error("");
193
- console.error("Run with no arguments for branch mode (uses your current local branch).");
194
- process.exit(1);
195
- }
196
- const requiredCli = parsed.provider === "gitlab" ? "glab" : "gh";
197
- if (!checkCli(requiredCli)) {
198
- console.error(`This command needs the \`${requiredCli}\` CLI installed and authenticated.`);
199
- if (requiredCli === "gh") {
200
- console.error(" brew install gh (macOS)");
201
- console.error(" gh auth login");
202
- }
203
- else {
204
- console.error(" brew install glab (macOS)");
205
- console.error(" glab auth login");
206
- }
207
- process.exit(1);
208
- }
209
- const config = (0, shared_1.requireConfig)();
210
- const bundle = await fetchPrOrMrBundle(parsed, prUrl, noTruncate);
211
- console.log(` title: ${bundle.title}`);
212
- console.log(` author: ${bundle.author}`);
213
- console.log(` files: ${bundle.filesChanged.length}`);
214
- console.log(` merged: ${new Date(bundle.mergedAt).toISOString()}`);
215
- console.log("");
216
- console.log("Generating ticket…");
217
- console.log("");
218
- const start = Date.now();
219
- try {
220
- const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reverseTicket", {
221
- config,
222
- body: {
223
- pr: bundle,
224
- forcedArtifactKey: forcedKey,
225
- },
226
- });
227
- (0, shared_1.recordAgentEvent)(config, {
228
- tool: "codiedev_reverse_ticket",
229
- ok: true,
230
- latencyMs: Date.now() - start,
231
- });
232
- if (res.match) {
233
- console.log(`✓ Matched artifact: ${res.match.key} (score=${res.match.score.toFixed(2)})`);
234
- console.log(` signals · body=${res.match.signals.bodyMention} · files=${res.match.signals.fileOverlap.toFixed(2)} · transcript=${res.match.signals.transcriptEdit}`);
235
- }
236
- else if (res.candidates.length > 0) {
237
- console.log(`? Ambiguous / low confidence. Candidates:`);
238
- for (const c of res.candidates.slice(0, 3)) {
239
- console.log(` - ${c.key} (score=${c.score.toFixed(2)})`);
240
- }
241
- console.log(` Re-run with --with <key> to force a specific artifact.`);
242
- }
243
- else {
244
- console.log("· No matched artifact. Ticket generated from PR diff alone.");
245
- }
246
- console.log(` prompt tokens (est): ${res.tokensInEstimate}`);
247
- console.log("");
248
- console.log("─────────── Generated ticket ───────────");
249
- console.log("");
250
- console.log(res.ticket);
251
- }
252
- catch (err) {
253
- (0, shared_1.recordAgentEvent)(config, {
254
- tool: "codiedev_reverse_ticket",
255
- ok: false,
256
- latencyMs: Date.now() - start,
257
- error: err.message,
258
- });
259
- console.error(`Reverse-ticket failed: ${err.message}`);
260
- process.exit(1);
261
- }
262
- }
263
- function git(cmd) {
264
- try {
265
- return (0, child_process_1.execSync)(`git ${cmd}`, {
266
- stdio: ["pipe", "pipe", "pipe"],
267
- maxBuffer: 32 * 1024 * 1024,
268
- })
269
- .toString("utf8")
270
- .trim();
271
- }
272
- catch (err) {
273
- throw new Error(`git ${cmd} failed: ${err.message}`);
274
- }
275
- }
276
- function safeGit(fn) {
277
- try {
278
- return fn() || undefined;
279
- }
280
- catch {
281
- return undefined;
282
- }
283
- }
284
- async function runBranchMode(opts) {
285
- // Confirm we're in a git repo.
286
- try {
287
- git("rev-parse --is-inside-work-tree");
288
- }
289
- catch {
290
- console.error("Not inside a git repository. Run this from a checked-out repo.");
291
- process.exit(1);
292
- }
293
- // `--base` lands unquoted on a `git` command line below, so reject anything
294
- // outside the safe-ref subset instead of letting the shell interpret it.
295
- if (opts.explicitBase !== undefined && !isSafeRef(opts.explicitBase)) {
296
- console.error(`Invalid --base ref: ${JSON.stringify(opts.explicitBase)}. Expected a plain branch or tag name.`);
297
- process.exit(1);
298
- }
299
- // Resolve base ref — explicit, then origin/main, then origin/master.
300
- const candidates = opts.explicitBase
301
- ? [opts.explicitBase]
302
- : ["origin/main", "origin/master"];
303
- let baseRef = null;
304
- for (const c of candidates) {
305
- try {
306
- git(`rev-parse --verify ${c}`);
307
- baseRef = c;
308
- break;
309
- }
310
- catch {
311
- // try next
312
- }
313
- }
314
- if (!baseRef) {
315
- console.error(`Couldn't find a base ref (tried ${candidates.join(", ")}). Pass --base <ref>.`);
316
- process.exit(1);
317
- }
318
- const branch = git("rev-parse --abbrev-ref HEAD");
319
- if (branch === "HEAD") {
320
- console.error("Detached HEAD — checkout a branch first.");
321
- process.exit(1);
322
- }
323
- const baseSha = git(`merge-base HEAD ${baseRef}`);
324
- const headSha = git("rev-parse HEAD");
325
- // Filter generated/lockfile noise from the diff body. The --stat (collected
326
- // separately) still includes every file untouched, so excluded files still
327
- // surface in the ticket's "Other files touched" section.
328
- const isNoise = (p) => /(^|\/)(node_modules|dist|build|\.next|\.turbo|coverage|out)\//.test(p) ||
329
- /(^|\/)package-lock\.json$/.test(p) ||
330
- /(^|\/)yarn\.lock$/.test(p) ||
331
- /(^|\/)pnpm-lock\.yaml$/.test(p) ||
332
- /(^|\/)bun\.lock(b)?$/.test(p) ||
333
- /(^|\/)Cargo\.lock$/.test(p) ||
334
- /(^|\/)Gemfile\.lock$/.test(p) ||
335
- /(^|\/)poetry\.lock$/.test(p) ||
336
- /(^|\/)go\.sum$/.test(p);
337
- const shellTolerant = (cmd) => {
338
- try {
339
- return (0, child_process_1.execSync)(`${cmd} || true`, {
340
- stdio: ["pipe", "pipe", "pipe"],
341
- maxBuffer: 32 * 1024 * 1024,
342
- })
343
- .toString("utf8")
344
- .trim();
345
- }
346
- catch {
347
- return "";
348
- }
349
- };
350
- const shQuote = (s) => `'${s.replace(/'/g, "'\\''")}'`;
351
- // Capture all work relative to the base ref: committed + uncommitted-tracked
352
- // + new untracked. Matches "ticket my current changes" intent.
353
- const trackedRaw = git(`diff --name-only ${baseSha}`);
354
- const trackedFiles = trackedRaw ? trackedRaw.split("\n").filter(Boolean) : [];
355
- const untrackedRaw = safeGit(() => git("ls-files --others --exclude-standard"));
356
- const untrackedFiles = untrackedRaw
357
- ? untrackedRaw.split("\n").filter(Boolean)
358
- : [];
359
- const filesChanged = Array.from(new Set([...trackedFiles, ...untrackedFiles]));
360
- if (filesChanged.length === 0) {
361
- console.error(`No changes detected between ${baseRef} and your working tree on ${branch}.`);
362
- process.exit(1);
363
- }
364
- let stat = "";
365
- try {
366
- const trackedStat = git(`diff --stat=200 ${baseSha}`);
367
- const untrackedStatLines = untrackedFiles.map((f) => {
368
- const wc = shellTolerant(`wc -l < ${shQuote(f)}`);
369
- const n = parseInt(wc.split(/\s+/)[0] || "0", 10) || 0;
370
- return ` ${f} | ${n} ++++++++++ (new file)`;
371
- });
372
- stat = [trackedStat, ...untrackedStatLines]
373
- .filter(Boolean)
374
- .join("\n")
375
- .slice(0, 8_000);
376
- }
377
- catch {
378
- // best effort
379
- }
380
- let diff = "";
381
- try {
382
- const sourceTracked = trackedFiles.filter((f) => !isNoise(f));
383
- const trackedDiff = sourceTracked.length > 0
384
- ? git(`diff ${baseSha} -- ${sourceTracked.map(shQuote).join(" ")}`)
385
- : git(`diff ${baseSha}`);
386
- const sourceUntracked = untrackedFiles.filter((f) => !isNoise(f));
387
- const untrackedDiffs = sourceUntracked.map((f) => shellTolerant(`git diff --no-index --no-color -- /dev/null ${shQuote(f)}`));
388
- diff = [trackedDiff, ...untrackedDiffs]
389
- .filter(Boolean)
390
- .join("\n")
391
- .slice(0, 40_000);
392
- }
393
- catch {
394
- // best effort
395
- }
396
- let repo;
397
- try {
398
- const remoteUrl = git("config --get remote.origin.url");
399
- const m = remoteUrl.match(/[:/]([^/:]+)\/([^/:]+?)(?:\.git)?$/);
400
- if (!m) {
401
- throw new Error(`Couldn't parse owner/repo from remote: ${remoteUrl}`);
402
- }
403
- repo = `${m[1]}/${m[2]}`;
404
- }
405
- catch (err) {
406
- console.error(`Couldn't read git remote.origin.url: ${err.message}`);
407
- process.exit(1);
408
- }
409
- const title = safeGit(() => git("log -1 --format=%s")) ?? `WIP: ${branch}`;
410
- const author = safeGit(() => git("config --get user.name"));
411
- const authorEmail = safeGit(() => git("config --get user.email"));
412
- console.log(`Branch: ${branch} (${repo})`);
413
- console.log(`Base: ${baseRef} @ ${baseSha.slice(0, 12)}`);
414
- console.log(`Head: ${headSha.slice(0, 12)}`);
415
- console.log(`Files: ${filesChanged.length}`);
416
- console.log("");
417
- console.log("Generating ticket draft…");
418
- console.log("");
419
- const config = (0, shared_1.requireConfig)();
420
- const start = Date.now();
421
- try {
422
- const res = await (0, shared_1.apiRequest)("POST", "/api/cli/reverseTicketFromBranch", {
423
- config,
424
- body: {
425
- branch: {
426
- repo,
427
- branch,
428
- baseSha,
429
- headSha,
430
- title,
431
- author,
432
- authorEmail,
433
- filesChanged,
434
- diff: diff || undefined,
435
- stat: stat || undefined,
436
- },
437
- forcedArtifactKey: opts.forcedKey,
438
- },
439
- });
440
- if (!res.ok || !res.artifactId) {
441
- (0, shared_1.recordAgentEvent)(config, {
442
- tool: "codiedev_reverse_ticket",
443
- ok: false,
444
- latencyMs: Date.now() - start,
445
- error: "no result",
446
- });
447
- console.error("Reverse-ticket generation returned no result. The writer may have skipped due to missing context.");
448
- process.exit(1);
449
- }
450
- (0, shared_1.recordAgentEvent)(config, {
451
- tool: "codiedev_reverse_ticket",
452
- ok: true,
453
- latencyMs: Date.now() - start,
454
- });
455
- const portalHost = (process.env.CODIEDEV_PORTAL_URL || "https://codiedev.com").replace(/\/$/, "");
456
- const portalLink = res.portalUrl.startsWith("http")
457
- ? res.portalUrl
458
- : `${portalHost}${res.portalUrl.startsWith("/") ? "" : "/"}${res.portalUrl}`;
459
- const verb = res.action === "overwritten" ? "Updated" : "Created";
460
- console.log(`✓ ${verb} reverse-ticket draft.`);
461
- console.log(` artifact: ${res.artifactKey ?? res.artifactId}`);
462
- console.log(` portal: ${portalLink}`);
463
- console.log("");
464
- console.log("Open in your portal to review, edit, and push to Jira.");
465
- console.log("Each call creates a fresh draft — clean up duplicates from the portal if needed.");
466
- }
467
- catch (err) {
468
- (0, shared_1.recordAgentEvent)(config, {
469
- tool: "codiedev_reverse_ticket",
470
- ok: false,
471
- latencyMs: Date.now() - start,
472
- error: err.message,
473
- });
474
- console.error(`Reverse-ticket failed: ${err.message}`);
475
- process.exit(1);
476
- }
477
- }
@@ -1,2 +0,0 @@
1
- import type { CodiedevConfig } from "../utils";
2
- export declare function runSearch(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -1 +0,0 @@
1
- export declare function runSecurityCommand(args: string[]): Promise<void>;
@@ -1,156 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runSecurityCommand = runSecurityCommand;
4
- const securityInstall_1 = require("../securityInstall");
5
- const securityPilot_1 = require("../securityPilot");
6
- const securityPolicy_1 = require("../securityPolicy");
7
- const securityInventory_1 = require("../securityInventory");
8
- const securityDeepScan_1 = require("../securityDeepScan");
9
- const utils_1 = require("../utils");
10
- const securityDoctor_1 = require("../securityDoctor");
11
- const securityFeature_1 = require("../securityFeature");
12
- const SECURITY_USAGE = "Usage: codiedev security <doctor|pilot|inventory|scan|sync|rollback> [--json] [--deep] [--connect-mcp] [--supply-chain] [--no-upload] [--yes]";
13
- function printPilot(json) {
14
- const report = (0, securityPilot_1.runSyntheticSecurityPilot)();
15
- if (json) {
16
- console.log(JSON.stringify(report, null, 2));
17
- return report.ok;
18
- }
19
- console.log("\nCodiedev security pilot — synthetic, side-effect-free validation\n");
20
- for (const item of report.cases) {
21
- console.log(`${item.passed ? "✓" : "✗"} ${item.surface}: ${item.name} (${item.actual})`);
22
- }
23
- console.log(`\n${report.ok ? "PASS" : "FAIL"}: ${report.cases.filter((item) => item.passed).length}/${report.cases.length} policy checks matched.`);
24
- console.log("No commands were executed and no real credentials were used.\n");
25
- return report.ok;
26
- }
27
- function printDoctor(json, companyId) {
28
- const result = (0, securityDoctor_1.collectSecurityDoctorReport)(companyId);
29
- if (json) {
30
- console.log(JSON.stringify(result, null, 2));
31
- return result.ok;
32
- }
33
- console.log("\nCodiedev doctor — Agent Security details\n");
34
- for (const check of (0, securityDoctor_1.securityDoctorChecks)(result)) {
35
- const mark = check.status === "pass" ? "✓" : check.status === "warn" ? "!" : "✗";
36
- console.log(`${mark} ${check.name}: ${check.detail}`);
37
- }
38
- console.log(`\n${result.ok ? "PASS" : "FAIL"}: ${result.ok ? "endpoint security is healthy" : "run `codiedev connect`, then repeat this check"}.\n`);
39
- return result.ok;
40
- }
41
- async function runSecurityCommand(args) {
42
- const subcommand = args.find((arg) => !arg.startsWith("-")) ?? "doctor";
43
- const json = args.includes("--json");
44
- if (args.includes("--help") || args.includes("-h") || subcommand === "help") {
45
- console.log(SECURITY_USAGE);
46
- return;
47
- }
48
- const connectedConfig = (0, utils_1.readConfig)();
49
- const requiresEntitlement = !["pilot", "self-test"].includes(subcommand);
50
- if (requiresEntitlement && (!connectedConfig || !(0, securityFeature_1.isAgentSecurityEnabled)(connectedConfig))) {
51
- const detail = connectedConfig
52
- ? `Agent Security is not enabled for ${connectedConfig.companyName}.`
53
- : "Not connected. Run `codiedev connect` first.";
54
- if (json)
55
- console.log(JSON.stringify({ schemaVersion: 1, enabled: false, detail }, null, 2));
56
- else
57
- console.log(`\n${detail}\n`);
58
- return;
59
- }
60
- if (subcommand === "inventory" || subcommand === "scan") {
61
- const workspaceFlag = args.indexOf("--workspace");
62
- const workspace = workspaceFlag >= 0 && args[workspaceFlag + 1]
63
- ? args[workspaceFlag + 1]
64
- : process.cwd();
65
- const inventory = (0, securityInventory_1.buildSecurityInventory)({ workspace });
66
- const deep = subcommand === "scan" && args.includes("--deep")
67
- ? (0, securityDeepScan_1.runDeepSecurityScan)(inventory, {
68
- workspace,
69
- connectMcp: args.includes("--connect-mcp"),
70
- supplyChain: args.includes("--supply-chain"),
71
- })
72
- : undefined;
73
- const uploadableInventory = deep ? (0, securityDeepScan_1.mergeDeepScanFindings)(inventory, deep) : inventory;
74
- let upload;
75
- const config = (0, utils_1.readConfig)();
76
- if (config && !args.includes("--no-upload")) {
77
- try {
78
- upload = await (0, securityInventory_1.uploadSecurityInventory)(uploadableInventory, config);
79
- }
80
- catch (error) {
81
- if (!json)
82
- console.warn(`Inventory upload failed; local scan is still valid: ${error.message}`);
83
- }
84
- }
85
- const output = { inventory: uploadableInventory, scanners: (0, securityInventory_1.scannerAvailability)(), ...(deep ? { deep } : {}), ...(upload ? { upload } : {}) };
86
- if (json)
87
- console.log(JSON.stringify(output, null, 2));
88
- else {
89
- const risky = inventory.components.filter((component) => component.findings.length > 0).length;
90
- console.log(`\nCodiedev security inventory — ${inventory.components.length} components, ${risky} with local findings, ${inventory.drift.length} changed\n`);
91
- const counts = new Map();
92
- for (const component of inventory.components)
93
- counts.set(component.kind, (counts.get(component.kind) ?? 0) + 1);
94
- for (const [kind, count] of [...counts].sort())
95
- console.log(` ${kind}: ${count}`);
96
- if (deep)
97
- for (const run of deep.runs)
98
- console.log(` ${run.scanner}: ${run.status} — ${run.detail}`);
99
- if (upload)
100
- console.log(`\nUploaded ${upload.accepted} component records to the security workspace.`);
101
- console.log("\nUse --json for machine-readable hashes and findings. Use scan --deep for installed OSS scanners; --connect-mcp and --supply-chain are explicit because they start or download third-party code.\n");
102
- }
103
- return;
104
- }
105
- if (subcommand === "sync") {
106
- const config = (0, utils_1.readConfig)();
107
- if (!config) {
108
- console.error("Not connected. Run `codiedev connect` first.");
109
- process.exitCode = 1;
110
- return;
111
- }
112
- try {
113
- const policy = await (0, securityPolicy_1.syncEndpointSecurityPolicy)(config);
114
- if (json)
115
- console.log(JSON.stringify({ ok: true, policy }, null, 2));
116
- else {
117
- const verification = (0, securityPolicy_1.verifyEndpointSecurityPolicySignature)(policy);
118
- console.log(`Security policy v${policy.policyVersion} synced (${policy.enforcementMode} mode; ${verification.detail}).`);
119
- }
120
- }
121
- catch (error) {
122
- console.error(`Security policy sync failed: ${error.message}`);
123
- process.exitCode = 1;
124
- }
125
- return;
126
- }
127
- if (subcommand === "rollback") {
128
- if (!args.includes("--yes")) {
129
- console.error("Rollback overwrites the installed agent hook configurations. Re-run with `codiedev security rollback --yes` after confirming the snapshot shown by `codiedev doctor`.");
130
- process.exitCode = 1;
131
- return;
132
- }
133
- try {
134
- const result = (0, securityInstall_1.restoreSecurityInstallSnapshot)((0, securityInstall_1.readSecurityInstallManifest)());
135
- if (json)
136
- console.log(JSON.stringify({ schemaVersion: 1, ok: true, ...result }, null, 2));
137
- else
138
- console.log(`Restored ${result.restored} hook configuration(s) from snapshot ${result.snapshotId}.`);
139
- }
140
- catch (error) {
141
- console.error(`Rollback failed: ${error.message}`);
142
- process.exitCode = 1;
143
- }
144
- return;
145
- }
146
- const ok = subcommand === "pilot" || subcommand === "self-test"
147
- ? printPilot(json)
148
- : subcommand === "doctor" || subcommand === "status"
149
- ? printDoctor(json, connectedConfig.companyId)
150
- : false;
151
- if (!["pilot", "self-test", "doctor", "status"].includes(subcommand)) {
152
- console.error(SECURITY_USAGE);
153
- }
154
- if (!ok)
155
- process.exitCode = 1;
156
- }
@@ -1,2 +0,0 @@
1
- import type { CodiedevConfig } from "../utils";
2
- export declare function runSend(args: string[], configOverride?: CodiedevConfig): Promise<void>;
@@ -1,2 +0,0 @@
1
- import type { CodiedevConfig } from "../utils";
2
- export declare function runShare(args: string[], configOverride?: CodiedevConfig): Promise<void>;