codiedev 0.10.0-beta.1 → 0.10.0-beta.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.
Files changed (155) hide show
  1. package/README.md +11 -5
  2. package/assets/opencode-plugin.mjs +6 -0
  3. package/assets/session-key.mjs +48 -0
  4. package/assets/tui-brand-plugin.tsx +73 -0
  5. package/dist/backup/cache.js +1 -5
  6. package/dist/backup/match.js +0 -6
  7. package/dist/backup/run.js +3 -35
  8. package/dist/captureExclusions.js +0 -12
  9. package/dist/captureLog.js +0 -28
  10. package/dist/captureReadiness.js +0 -58
  11. package/dist/captureSignals.js +184 -0
  12. package/dist/cli.js +135 -72
  13. package/dist/cliSession.js +456 -0
  14. package/dist/codexHookTrust.js +125 -6
  15. package/dist/codexLimitScan.js +359 -0
  16. package/dist/codie.js +77 -130
  17. package/dist/codieBrandInstall.js +80 -0
  18. package/dist/codieLauncher.js +76 -79
  19. package/dist/codieRuntime.js +19 -23
  20. package/dist/codieRuntimeInstall.js +108 -23
  21. package/dist/codieUsage.js +181 -0
  22. package/dist/commands/agentTemplates.generated.js +136 -0
  23. package/dist/commands/agents.js +1101 -0
  24. package/dist/commands/agentsSdk.generated.js +7 -0
  25. package/dist/commands/ask.js +0 -3
  26. package/dist/commands/capture.js +0 -2
  27. package/dist/commands/createTicket.js +0 -10
  28. package/dist/commands/doctor.js +53 -120
  29. package/dist/commands/evals.js +187 -0
  30. package/dist/commands/inbox.js +0 -2
  31. package/dist/commands/library.js +0 -3
  32. package/dist/commands/pack.js +573 -0
  33. package/dist/commands/ping.js +0 -2
  34. package/dist/commands/pull.js +6 -10
  35. package/dist/commands/push.js +2 -12
  36. package/dist/commands/search.js +0 -4
  37. package/dist/commands/send.js +0 -5
  38. package/dist/commands/share.js +0 -4
  39. package/dist/commands/shared.js +0 -35
  40. package/dist/commands/traces.js +344 -0
  41. package/dist/commands/tracesLabel.js +348 -0
  42. package/dist/configDir.js +18 -11
  43. package/dist/connect.js +55 -118
  44. package/dist/connectFlow.js +35 -9
  45. package/dist/copilotHooks.js +391 -0
  46. package/dist/copilotInstallation.js +64 -0
  47. package/dist/cursorHooks.js +38 -30
  48. package/dist/cursorLifecycle.js +109 -0
  49. package/dist/detection.js +0 -30
  50. package/dist/harnessDirs.js +77 -0
  51. package/dist/hook.js +256 -445
  52. package/dist/inboxFormat.js +0 -24
  53. package/dist/launchContext.js +150 -0
  54. package/dist/launcher.js +168 -0
  55. package/dist/limitEvent.js +44 -13
  56. package/dist/limitEventReporter.js +1 -1
  57. package/dist/managedPi.js +256 -0
  58. package/dist/mcp.js +5 -384
  59. package/dist/nativeSteering.js +24 -0
  60. package/dist/packs/codie.js +182 -0
  61. package/dist/packs/harnesses.js +411 -0
  62. package/dist/packs/hookGate.js +256 -0
  63. package/dist/packs/install.js +286 -0
  64. package/dist/packs/manifest.js +126 -0
  65. package/dist/packs/paths.js +81 -0
  66. package/dist/packs/shim.js +214 -0
  67. package/dist/packs/store.js +155 -0
  68. package/dist/packs/sync.js +170 -0
  69. package/dist/piHooks.js +216 -0
  70. package/dist/piRuntime.js +120 -0
  71. package/dist/repoResolver.js +0 -19
  72. package/dist/secret.js +0 -3
  73. package/dist/selfUpdate.js +376 -0
  74. package/dist/skillMarker.js +23 -0
  75. package/dist/subagents.js +135 -0
  76. package/dist/teamSkillContext.js +10 -0
  77. package/dist/transcriptModels.js +205 -0
  78. package/dist/upgradeNudge.js +0 -30
  79. package/dist/utils.js +502 -828
  80. package/dist/version.js +0 -10
  81. package/dist/versionCheck.js +0 -33
  82. package/package.json +8 -9
  83. package/dist/backup/cache.d.ts +0 -14
  84. package/dist/backup/match.d.ts +0 -2
  85. package/dist/backup/run.d.ts +0 -25
  86. package/dist/captureExclusions.d.ts +0 -30
  87. package/dist/captureLog.d.ts +0 -20
  88. package/dist/captureReadiness.d.ts +0 -65
  89. package/dist/cli.d.ts +0 -16
  90. package/dist/codexHookTrust.d.ts +0 -34
  91. package/dist/codie.d.ts +0 -2
  92. package/dist/codieLauncher.d.ts +0 -53
  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/commands/ask.d.ts +0 -1
  98. package/dist/commands/capture.d.ts +0 -14
  99. package/dist/commands/createTicket.d.ts +0 -27
  100. package/dist/commands/delete.d.ts +0 -1
  101. package/dist/commands/doctor.d.ts +0 -1
  102. package/dist/commands/inbox.d.ts +0 -3
  103. package/dist/commands/library.d.ts +0 -2
  104. package/dist/commands/note.d.ts +0 -1
  105. package/dist/commands/ping.d.ts +0 -1
  106. package/dist/commands/promote.d.ts +0 -1
  107. package/dist/commands/promote.js +0 -53
  108. package/dist/commands/pull.d.ts +0 -2
  109. package/dist/commands/push.d.ts +0 -33
  110. package/dist/commands/react.d.ts +0 -2
  111. package/dist/commands/react.js +0 -40
  112. package/dist/commands/reverseTicket.d.ts +0 -2
  113. package/dist/commands/reverseTicket.js +0 -477
  114. package/dist/commands/search.d.ts +0 -2
  115. package/dist/commands/security.d.ts +0 -1
  116. package/dist/commands/security.js +0 -156
  117. package/dist/commands/send.d.ts +0 -2
  118. package/dist/commands/share.d.ts +0 -2
  119. package/dist/commands/shared.d.ts +0 -64
  120. package/dist/configDir.d.ts +0 -1
  121. package/dist/connect.d.ts +0 -1
  122. package/dist/connectFlow.d.ts +0 -13
  123. package/dist/cursorHooks.d.ts +0 -23
  124. package/dist/detection.d.ts +0 -30
  125. package/dist/hook.d.ts +0 -6
  126. package/dist/inboxFormat.d.ts +0 -38
  127. package/dist/limitEvent.d.ts +0 -16
  128. package/dist/limitEventReporter.d.ts +0 -21
  129. package/dist/mcp.d.ts +0 -12
  130. package/dist/prUrl.d.ts +0 -9
  131. package/dist/prUrl.js +0 -33
  132. package/dist/repoResolver.d.ts +0 -17
  133. package/dist/secret.d.ts +0 -1
  134. package/dist/security.d.ts +0 -102
  135. package/dist/security.js +0 -437
  136. package/dist/securityDeepScan.d.ts +0 -41
  137. package/dist/securityDeepScan.js +0 -248
  138. package/dist/securityDoctor.d.ts +0 -32
  139. package/dist/securityDoctor.js +0 -63
  140. package/dist/securityFeature.d.ts +0 -5
  141. package/dist/securityFeature.js +0 -7
  142. package/dist/securityInstall.d.ts +0 -63
  143. package/dist/securityInstall.js +0 -239
  144. package/dist/securityInventory.d.ts +0 -54
  145. package/dist/securityInventory.js +0 -556
  146. package/dist/securityPilot.d.ts +0 -19
  147. package/dist/securityPilot.js +0 -61
  148. package/dist/securityPolicy.d.ts +0 -33
  149. package/dist/securityPolicy.js +0 -188
  150. package/dist/securitySession.d.ts +0 -6
  151. package/dist/securitySession.js +0 -72
  152. package/dist/upgradeNudge.d.ts +0 -25
  153. package/dist/utils.d.ts +0 -342
  154. package/dist/version.d.ts +0 -1
  155. package/dist/versionCheck.d.ts +0 -68
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MAX_GATED_COMMAND_BYTES = void 0;
37
+ exports.skillsFromPayload = skillsFromPayload;
38
+ exports.encodeGatedCommand = encodeGatedCommand;
39
+ exports.decodeGatedCommand = decodeGatedCommand;
40
+ exports.parseGateArgs = parseGateArgs;
41
+ exports.gateMatches = gateMatches;
42
+ exports.splitShellOverride = splitShellOverride;
43
+ exports.planShellCommand = planShellCommand;
44
+ exports.planGateCommand = planGateCommand;
45
+ exports.runHookGate = runHookGate;
46
+ exports.runHookGateCli = runHookGateCli;
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ const child_process_1 = require("child_process");
50
+ function str(value) {
51
+ return typeof value === "string" && value ? value : undefined;
52
+ }
53
+ function parseMaybeJson(value) {
54
+ if (typeof value !== "string")
55
+ return value;
56
+ try {
57
+ return JSON.parse(value);
58
+ }
59
+ catch {
60
+ return value;
61
+ }
62
+ }
63
+ const SKILL_PATH = /[\\/]skills[\\/]([^\\/\s'"`;|&<>()]+)[\\/]SKILL\.md\b/g;
64
+ function skillsInPath(text) {
65
+ return [...text.matchAll(SKILL_PATH)].map((m) => m[1]);
66
+ }
67
+ function stripPlugin(name) {
68
+ const index = name.lastIndexOf(":");
69
+ return index >= 0 ? name.slice(index + 1) : name;
70
+ }
71
+ function skillsFromPayload(payload) {
72
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
73
+ return [];
74
+ const p = payload;
75
+ const toolName = str(p.tool_name) ?? str(p.toolName) ?? "";
76
+ const rawInput = parseMaybeJson(p.tool_input ?? p.toolInput ?? p.toolArgs ?? p.input);
77
+ const input = rawInput && typeof rawInput === "object" && !Array.isArray(rawInput)
78
+ ? rawInput
79
+ : {};
80
+ const tool = toolName.toLowerCase();
81
+ if (tool === "skill") {
82
+ const name = str(input.skill) ?? str(input.name) ?? str(input.skill_name);
83
+ return name ? [stripPlugin(name.trim())] : [];
84
+ }
85
+ if (tool === "read" || tool === "view" || tool === "read_file") {
86
+ const file = str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? "";
87
+ return skillsInPath(file);
88
+ }
89
+ if (tool === "bash" || tool === "shell" || tool === "exec_command" || tool === "local_shell") {
90
+ const command = Array.isArray(input.command) ? input.command.join(" ") : str(input.command) ?? str(input.cmd) ?? "";
91
+ return skillsInPath(command);
92
+ }
93
+ return [];
94
+ }
95
+ exports.MAX_GATED_COMMAND_BYTES = 16 * 1024;
96
+ function encodeGatedCommand(command) {
97
+ return Buffer.from(command, "utf8").toString("base64url");
98
+ }
99
+ function decodeGatedCommand(value) {
100
+ if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
101
+ throw new Error("--cmd-b64 is not base64url");
102
+ if (value.length > Math.ceil((exports.MAX_GATED_COMMAND_BYTES * 4) / 3) + 4)
103
+ throw new Error("--cmd-b64 command is over 16KB");
104
+ const bytes = Buffer.from(value, "base64url");
105
+ if (bytes.toString("base64url") !== value)
106
+ throw new Error("--cmd-b64 is not canonical base64url");
107
+ if (bytes.length > exports.MAX_GATED_COMMAND_BYTES)
108
+ throw new Error("--cmd-b64 command is over 16KB");
109
+ let text;
110
+ try {
111
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
112
+ }
113
+ catch {
114
+ throw new Error("--cmd-b64 command is not UTF-8");
115
+ }
116
+ if (text.includes("\u0000"))
117
+ throw new Error("--cmd-b64 command contains NUL");
118
+ if (!text.trim())
119
+ throw new Error("--cmd-b64 command is empty");
120
+ return text;
121
+ }
122
+ function parseGateArgs(argv) {
123
+ const sep = argv.indexOf("--");
124
+ const flags = sep >= 0 ? argv.slice(0, sep) : argv;
125
+ const command = sep >= 0 ? argv.slice(sep + 1) : [];
126
+ let skills = [];
127
+ let cmdB64;
128
+ for (let i = 0; i < flags.length; i++) {
129
+ const a = flags[i];
130
+ if (a === "--cmd-b64" || a.startsWith("--cmd-b64=")) {
131
+ cmdB64 = a === "--cmd-b64" ? flags[++i] ?? "" : a.slice("--cmd-b64=".length);
132
+ continue;
133
+ }
134
+ const value = a === "--skills" || a === "--skill" ? flags[++i] : a.startsWith("--skills=") ? a.slice(9) : undefined;
135
+ if (value === undefined)
136
+ throw new Error(`Unknown hook-gate argument: ${a}`);
137
+ skills.push(...value.split(",").map((s) => stripPlugin(s.trim())).filter(Boolean));
138
+ }
139
+ skills = [...new Set(skills)];
140
+ if (skills.length === 0)
141
+ throw new Error("hook-gate needs --skills a,b");
142
+ if (cmdB64 !== undefined && command.length)
143
+ throw new Error("hook-gate takes --cmd-b64 or -- <command>, not both");
144
+ if (cmdB64 === undefined && command.length === 0)
145
+ throw new Error("hook-gate needs --cmd-b64 <base64url> or -- <command>");
146
+ return { skills, command, ...(cmdB64 !== undefined ? { cmdB64 } : {}) };
147
+ }
148
+ function gateMatches(skills, payload) {
149
+ const running = skillsFromPayload(payload);
150
+ return running.some((name) => skills.includes(name));
151
+ }
152
+ function splitShellOverride(value) {
153
+ const out = [];
154
+ for (const m of value.matchAll(/"([^"]*)"|'([^']*)'|(\S+)/g))
155
+ out.push(m[1] ?? m[2] ?? m[3]);
156
+ return out;
157
+ }
158
+ function shellFor(line, platform, env) {
159
+ const override = env.CODIEDEV_HOOK_SHELL?.trim();
160
+ if (override) {
161
+ const [file, ...args] = splitShellOverride(override);
162
+ if (file)
163
+ return { file, args: [...args, line] };
164
+ }
165
+ if (platform === "win32") {
166
+ return { file: env.ComSpec || env.COMSPEC || "cmd.exe", args: ["/d", "/s", "/c", `"${line}"`], verbatim: true };
167
+ }
168
+ return { file: "/bin/sh", args: ["-c", line] };
169
+ }
170
+ function planShellCommand(line, options = {}) {
171
+ return shellFor(line, options.platform ?? process.platform, options.env ?? process.env);
172
+ }
173
+ function planGateCommand(command, options = {}) {
174
+ const platform = options.platform ?? process.platform;
175
+ const env = options.env ?? process.env;
176
+ const legacy = command.length === 3 && /^(?:\/bin\/)?sh(?:\.exe)?$/i.test(command[0]) && command[1] === "-c";
177
+ if (legacy && platform === "win32" && !(options.hasSh ?? (() => onPathSimple("sh", env, platform)))()) {
178
+ return { ...shellFor(command[2], platform, env), note: "codiedev hook-gate: sh isn't available; running the hook with cmd.exe instead\n" };
179
+ }
180
+ const [file, ...args] = command;
181
+ return { file, args };
182
+ }
183
+ function onPathSimple(bin, env, platform) {
184
+ const sep = platform === "win32" ? ";" : ":";
185
+ const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
186
+ for (const dir of (env.PATH ?? env.Path ?? "").split(sep).filter(Boolean)) {
187
+ for (const ext of exts) {
188
+ try {
189
+ if (fs.statSync(path.join(dir, bin + ext)).isFile())
190
+ return true;
191
+ }
192
+ catch {
193
+ }
194
+ }
195
+ }
196
+ return false;
197
+ }
198
+ function runHookGate(argv, stdin, env = process.env, options = {}) {
199
+ let args;
200
+ try {
201
+ args = parseGateArgs(argv);
202
+ }
203
+ catch (error) {
204
+ process.stderr.write(`codiedev hook-gate: ${error.message}\n`);
205
+ return 0;
206
+ }
207
+ let payload;
208
+ try {
209
+ payload = JSON.parse(stdin);
210
+ }
211
+ catch {
212
+ return 0;
213
+ }
214
+ if (!gateMatches(args.skills, payload))
215
+ return 0;
216
+ let plan;
217
+ if (args.cmdB64 !== undefined) {
218
+ let line;
219
+ try {
220
+ line = decodeGatedCommand(args.cmdB64);
221
+ }
222
+ catch (error) {
223
+ process.stderr.write(`codiedev hook-gate: ${error.message}; hook skipped\n`);
224
+ return 0;
225
+ }
226
+ plan = planShellCommand(line, { ...options, env });
227
+ }
228
+ else {
229
+ plan = planGateCommand(args.command, { ...options, env });
230
+ }
231
+ if (plan.note)
232
+ process.stderr.write(plan.note);
233
+ const result = (options.spawn ?? child_process_1.spawnSync)(plan.file, plan.args, {
234
+ input: stdin,
235
+ stdio: ["pipe", "inherit", "inherit"],
236
+ env,
237
+ windowsHide: true,
238
+ ...(plan.verbatim ? { windowsVerbatimArguments: true } : {}),
239
+ });
240
+ const ignoredStdin = result.error?.code === "EPIPE" && result.status !== null;
241
+ if (result.error && !ignoredStdin) {
242
+ process.stderr.write(`codiedev hook-gate: ${result.error.message}\n`);
243
+ return 1;
244
+ }
245
+ return result.status ?? 1;
246
+ }
247
+ function runHookGateCli(argv) {
248
+ let stdin = "";
249
+ try {
250
+ stdin = fs.readFileSync(0, "utf8");
251
+ }
252
+ catch {
253
+ stdin = "";
254
+ }
255
+ process.exitCode = runHookGate(argv, stdin);
256
+ }
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.codexPackHooksPath = codexPackHooksPath;
37
+ exports.codexPackTrustEntries = codexPackTrustEntries;
38
+ exports.installPacks = installPacks;
39
+ exports.uninstallPacks = uninstallPacks;
40
+ exports.formatUninstallLines = formatUninstallLines;
41
+ exports.formatResultLines = formatResultLines;
42
+ const fs = __importStar(require("fs"));
43
+ const os = __importStar(require("os"));
44
+ const path = __importStar(require("path"));
45
+ const harnessDirs_1 = require("../harnessDirs");
46
+ const codexHookTrust_1 = require("../codexHookTrust");
47
+ const harnesses_1 = require("./harnesses");
48
+ const manifest_1 = require("./manifest");
49
+ const paths_1 = require("./paths");
50
+ const shim_1 = require("./shim");
51
+ const store_1 = require("./store");
52
+ function marketplaceEntries(registry) {
53
+ return Object.entries(registry.packs).map(([slug, entry]) => ({
54
+ slug,
55
+ version: entry.version,
56
+ description: entry.description,
57
+ }));
58
+ }
59
+ function codexPackHooksPath(codexDir, slug, version) {
60
+ const base = path.join(codexDir, "plugins", "cache", paths_1.MARKETPLACE_NAME, slug);
61
+ const exact = path.join(base, (0, store_1.pluginVersion)(version), "hooks", "hooks.json");
62
+ if (fs.existsSync(exact))
63
+ return exact;
64
+ let best = null;
65
+ try {
66
+ for (const entry of fs.readdirSync(base)) {
67
+ const file = path.join(base, entry, "hooks", "hooks.json");
68
+ try {
69
+ const mtime = fs.statSync(file).mtimeMs;
70
+ if (!best || mtime > best.mtime)
71
+ best = { file, mtime };
72
+ }
73
+ catch {
74
+ }
75
+ }
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ return best?.file ?? null;
81
+ }
82
+ function codexPackTrustEntries(registry, codexDir) {
83
+ const bySlug = new Map();
84
+ for (const [slug, entry] of Object.entries(registry.packs).sort(([a], [b]) => a.localeCompare(b))) {
85
+ if (!entry.harnesses?.includes("codex"))
86
+ continue;
87
+ const hooksPath = codexPackHooksPath(codexDir, slug, entry.version);
88
+ if (!hooksPath)
89
+ continue;
90
+ try {
91
+ const plugin = { id: `${slug}@${paths_1.MARKETPLACE_NAME}`, root: path.dirname(path.dirname(hooksPath)) };
92
+ bySlug.set(slug, (0, codexHookTrust_1.packCodexHookTrustEntries)(hooksPath, JSON.parse(fs.readFileSync(hooksPath, "utf8")), plugin));
93
+ }
94
+ catch {
95
+ }
96
+ }
97
+ return bySlug;
98
+ }
99
+ function shimInputs(registry) {
100
+ const packs = [];
101
+ for (const [slug, entry] of Object.entries(registry.packs).sort(([a], [b]) => a.localeCompare(b))) {
102
+ if (!entry.harnesses?.includes("codie"))
103
+ continue;
104
+ try {
105
+ const parsed = JSON.parse(fs.readFileSync(path.join(entry.dir, "hooks", "hooks.json"), "utf8"));
106
+ if (parsed?.hooks && typeof parsed.hooks === "object")
107
+ packs.push({ slug, root: entry.dir, hooks: parsed.hooks });
108
+ }
109
+ catch {
110
+ }
111
+ }
112
+ return packs;
113
+ }
114
+ function installPacks(options) {
115
+ const env = options.env ?? process.env;
116
+ const home = options.home ?? os.homedir();
117
+ const run = options.run ?? (0, harnesses_1.defaultRunner)(env);
118
+ const now = options.now ?? Date.now;
119
+ const root = (0, paths_1.packsRoot)(env, home);
120
+ const selected = new Set(options.harnesses ?? harnesses_1.ADAPTERS.map((a) => a.name));
121
+ const adapters = harnesses_1.ADAPTERS.filter((a) => selected.has(a.name));
122
+ const registry = (0, store_1.readRegistry)(root);
123
+ const detected = new Map();
124
+ for (const adapter of adapters)
125
+ detected.set(adapter.name, adapter.detect({ root, env, home, run }));
126
+ const output = [];
127
+ for (const manifest of options.manifests) {
128
+ const dir = (0, paths_1.pluginDir)(root, manifest.slug);
129
+ const previous = registry.packs[manifest.slug];
130
+ const files = Object.keys((0, store_1.pluginFiles)(manifest)).sort();
131
+ const results = [];
132
+ if (options.dryRun) {
133
+ for (const adapter of adapters) {
134
+ const ctx = { root, env, home, run, manifest, pluginDir: dir, portablePluginDir: (0, paths_1.pluginDir)((0, paths_1.portableRoot)(root), manifest.slug), previous };
135
+ results.push(detected.get(adapter.name)
136
+ ? { harness: adapter.name, status: "dry-run", detail: `would run: ${adapter.plan(ctx)}` }
137
+ : { harness: adapter.name, status: "skipped", detail: "not detected" });
138
+ }
139
+ output.push({ slug: manifest.slug, version: manifest.version, contentHash: manifest.contentHash, dir, files, results, harnesses: [] });
140
+ continue;
141
+ }
142
+ (0, store_1.writePluginDir)(root, manifest);
143
+ (0, store_1.writePluginDir)((0, paths_1.portableRoot)(root), manifest, { portable: true });
144
+ const pending = {
145
+ packs: {
146
+ ...registry.packs,
147
+ [manifest.slug]: {
148
+ version: manifest.version,
149
+ contentHash: manifest.contentHash,
150
+ dir,
151
+ installedAt: previous?.installedAt ?? now(),
152
+ harnesses: previous?.harnesses ?? [],
153
+ name: manifest.name,
154
+ description: manifest.description,
155
+ },
156
+ },
157
+ };
158
+ (0, store_1.writeMarketplace)(root, marketplaceEntries(pending));
159
+ (0, store_1.writeMarketplace)((0, paths_1.portableRoot)(root), marketplaceEntries(pending));
160
+ for (const adapter of adapters) {
161
+ if (!detected.get(adapter.name)) {
162
+ results.push({ harness: adapter.name, status: "skipped", detail: "not detected" });
163
+ continue;
164
+ }
165
+ try {
166
+ const detail = adapter.install({ root, env, home, run, manifest, pluginDir: dir, portablePluginDir: (0, paths_1.pluginDir)((0, paths_1.portableRoot)(root), manifest.slug), previous });
167
+ results.push({ harness: adapter.name, status: "ok", detail });
168
+ }
169
+ catch (error) {
170
+ results.push({ harness: adapter.name, status: "failed", detail: error instanceof Error ? error.message : String(error) });
171
+ }
172
+ }
173
+ const kept = (previous?.harnesses ?? []).filter((h) => !selected.has(h));
174
+ const succeeded = results.filter((r) => r.status === "ok").map((r) => r.harness);
175
+ const harnesses = [...new Set([...kept, ...succeeded])].sort();
176
+ registry.packs[manifest.slug] = {
177
+ version: manifest.version,
178
+ contentHash: manifest.contentHash,
179
+ dir,
180
+ installedAt: now(),
181
+ harnesses,
182
+ name: manifest.name,
183
+ description: manifest.description,
184
+ ...(manifest.channel ? { channel: manifest.channel } : {}),
185
+ ...(manifest.icon ? { icon: manifest.icon } : {}),
186
+ };
187
+ (0, store_1.writeRegistry)(root, registry);
188
+ output.push({ slug: manifest.slug, ...(manifest.channel ? { channel: manifest.channel } : {}), version: manifest.version, contentHash: manifest.contentHash, dir, files, results, harnesses });
189
+ }
190
+ if (options.dryRun || options.manifests.length === 0)
191
+ return output;
192
+ if (selected.has("codex") && detected.get("codex")) {
193
+ const bySlug = regenerateCodexTrust(registry, env, home);
194
+ for (const pack of output) {
195
+ const codex = pack.results.find((r) => r.harness === "codex" && r.status === "ok");
196
+ const count = bySlug.get(pack.slug)?.length ?? 0;
197
+ if (codex && count)
198
+ codex.detail += `; ${count} hook${count === 1 ? "" : "s"} trusted`;
199
+ }
200
+ }
201
+ if (selected.has("codie")) {
202
+ (0, shim_1.writeShim)((0, paths_1.shimPath)(root), shimInputs(registry));
203
+ const skipped = (0, shim_1.unsupportedShimEvents)(shimInputs(registry));
204
+ for (const pack of output) {
205
+ const codie = pack.results.find((r) => r.harness === "codie" && r.status === "ok");
206
+ const events = skipped.get(pack.slug);
207
+ if (codie && events?.length)
208
+ codie.notes = [`hooks Codie can't run were skipped: ${events.join(", ")}`];
209
+ }
210
+ }
211
+ return output;
212
+ }
213
+ function regenerateCodexTrust(registry, env, home) {
214
+ const codexDir = (0, harnessDirs_1.codexHome)(env, home);
215
+ const bySlug = codexPackTrustEntries(registry, codexDir);
216
+ (0, codexHookTrust_1.writeCodexPackHookTrust)(path.join(codexDir, "config.toml"), [...bySlug.values()].flat());
217
+ return bySlug;
218
+ }
219
+ function uninstallPacks(options) {
220
+ const env = options.env ?? process.env;
221
+ const home = options.home ?? os.homedir();
222
+ const run = options.run ?? (0, harnesses_1.defaultRunner)(env);
223
+ const root = (0, paths_1.packsRoot)(env, home);
224
+ const registry = (0, store_1.readRegistry)(root);
225
+ const output = [];
226
+ for (const slug of options.slugs) {
227
+ const entry = registry.packs[slug];
228
+ if (!entry || !(0, manifest_1.isSafeSegment)(slug))
229
+ continue;
230
+ const results = [];
231
+ for (const adapter of harnesses_1.ADAPTERS) {
232
+ if (!entry.harnesses?.includes(adapter.name))
233
+ continue;
234
+ if (!adapter.detect({ root, env, home, run })) {
235
+ results.push({ harness: adapter.name, status: "skipped", detail: "not detected" });
236
+ continue;
237
+ }
238
+ try {
239
+ results.push({ harness: adapter.name, status: "ok", detail: adapter.uninstall({ root, env, home, run, slug }) });
240
+ }
241
+ catch (error) {
242
+ results.push({ harness: adapter.name, status: "failed", detail: error instanceof Error ? error.message : String(error) });
243
+ }
244
+ }
245
+ delete registry.packs[slug];
246
+ fs.rmSync((0, paths_1.pluginDir)(root, slug), { recursive: true, force: true });
247
+ fs.rmSync((0, paths_1.pluginDir)((0, paths_1.portableRoot)(root), slug), { recursive: true, force: true });
248
+ output.push({ slug, results });
249
+ }
250
+ if (output.length === 0)
251
+ return output;
252
+ (0, store_1.writeRegistry)(root, registry);
253
+ (0, store_1.writeMarketplace)(root, marketplaceEntries(registry));
254
+ (0, store_1.writeMarketplace)((0, paths_1.portableRoot)(root), marketplaceEntries(registry));
255
+ const codexConfig = path.join((0, harnessDirs_1.codexHome)(env, home), "config.toml");
256
+ if (fs.existsSync(codexConfig))
257
+ regenerateCodexTrust(registry, env, home);
258
+ (0, shim_1.writeShim)((0, paths_1.shimPath)(root), shimInputs(registry));
259
+ return output;
260
+ }
261
+ function formatUninstallLines(results) {
262
+ const lines = [];
263
+ for (const pack of results) {
264
+ lines.push(`${pack.slug} removed (no longer assigned to your team)`);
265
+ for (const r of pack.results) {
266
+ const mark = r.status === "ok" ? "✓" : r.status === "failed" ? "✗" : "-";
267
+ lines.push(` ${mark} ${r.harness}: ${r.status === "failed" ? "failed: " : r.status === "skipped" ? "skipped: " : ""}${r.detail}`);
268
+ }
269
+ }
270
+ return lines;
271
+ }
272
+ function formatResultLines(results) {
273
+ const lines = [];
274
+ for (const pack of results) {
275
+ lines.push(`${pack.slug} v${pack.version}${pack.channel ? ` (${pack.channel})` : ""} → ${pack.dir}`);
276
+ for (const r of pack.results) {
277
+ const mark = r.status === "ok" ? "✓" : r.status === "failed" ? "✗" : r.status === "dry-run" ? "·" : "-";
278
+ const word = r.status === "ok" ? "" : r.status === "failed" ? "failed: " : r.status === "skipped" ? "skipped: " : "";
279
+ lines.push(` ${mark} ${r.harness}: ${word}${r.detail}`);
280
+ if (process.env.CODIEDEV_DEBUG)
281
+ for (const note of r.notes ?? [])
282
+ lines.push(` note: ${note}`);
283
+ }
284
+ }
285
+ return lines;
286
+ }
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ManifestError = void 0;
4
+ exports.isSafeSegment = isSafeSegment;
5
+ exports.isSafeSkillName = isSafeSkillName;
6
+ exports.parseManifest = parseManifest;
7
+ exports.cleanLabel = cleanLabel;
8
+ exports.displayName = displayName;
9
+ exports.parseFrontmatter = parseFrontmatter;
10
+ const SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
11
+ function isSafeSegment(value) {
12
+ return typeof value === "string" && SAFE_SEGMENT.test(value) && !value.includes("..");
13
+ }
14
+ const SAFE_SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._ -]{0,127}$/;
15
+ function isSafeSkillName(value) {
16
+ return typeof value === "string" && SAFE_SKILL_NAME.test(value) && !value.includes("..") && value.trim() === value;
17
+ }
18
+ class ManifestError extends Error {
19
+ }
20
+ exports.ManifestError = ManifestError;
21
+ function fileList(value, field, safe) {
22
+ if (value === undefined || value === null)
23
+ return [];
24
+ if (!Array.isArray(value))
25
+ throw new ManifestError(`manifest.${field} must be an array`);
26
+ const seen = new Set();
27
+ return value.map((item, index) => {
28
+ const entry = item;
29
+ if (!entry || typeof entry !== "object")
30
+ throw new ManifestError(`manifest.${field}[${index}] is not an object`);
31
+ if (!safe(entry.name)) {
32
+ throw new ManifestError(`manifest.${field}[${index}] has an unsafe name: ${JSON.stringify(entry.name)}`);
33
+ }
34
+ if (typeof entry.content !== "string")
35
+ throw new ManifestError(`manifest.${field}[${index}].content must be a string`);
36
+ const key = entry.name.toLowerCase();
37
+ if (seen.has(key))
38
+ throw new ManifestError(`manifest.${field} has a duplicate name: ${entry.name}`);
39
+ seen.add(key);
40
+ const artifactId = typeof entry.artifactId === "string" && /^[a-z0-9]{16,64}$/i.test(entry.artifactId) ? entry.artifactId : undefined;
41
+ return { name: entry.name, content: entry.content, ...(artifactId ? { artifactId } : {}) };
42
+ });
43
+ }
44
+ function parseManifest(input) {
45
+ let raw = input;
46
+ if (typeof raw === "string") {
47
+ try {
48
+ raw = JSON.parse(raw);
49
+ }
50
+ catch {
51
+ throw new ManifestError("manifest is not valid JSON");
52
+ }
53
+ }
54
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
55
+ throw new ManifestError("manifest is not an object");
56
+ const m = raw;
57
+ if (!isSafeSegment(m.slug))
58
+ throw new ManifestError(`manifest has an unsafe slug: ${JSON.stringify(m.slug)}`);
59
+ const version = Number(m.version);
60
+ if (!Number.isInteger(version) || version < 0)
61
+ throw new ManifestError("manifest.version must be a non-negative integer");
62
+ if (typeof m.contentHash !== "string" || !m.contentHash)
63
+ throw new ManifestError("manifest.contentHash is missing");
64
+ let hooksJson = null;
65
+ if (m.hooksJson !== undefined && m.hooksJson !== null) {
66
+ if (typeof m.hooksJson !== "string")
67
+ throw new ManifestError("manifest.hooksJson must be a string or null");
68
+ if (m.hooksJson.trim()) {
69
+ let parsed;
70
+ try {
71
+ parsed = JSON.parse(m.hooksJson);
72
+ }
73
+ catch {
74
+ throw new ManifestError("manifest.hooksJson is not valid JSON");
75
+ }
76
+ const hooks = parsed?.hooks;
77
+ if (!hooks || typeof hooks !== "object" || Array.isArray(hooks)) {
78
+ throw new ManifestError("manifest.hooksJson must look like {\"hooks\":{...}}");
79
+ }
80
+ hooksJson = m.hooksJson;
81
+ }
82
+ }
83
+ return {
84
+ slug: m.slug,
85
+ name: typeof m.name === "string" && m.name ? m.name : m.slug,
86
+ description: typeof m.description === "string" ? m.description : "",
87
+ version,
88
+ contentHash: m.contentHash,
89
+ skills: fileList(m.skills, "skills", isSafeSkillName),
90
+ agents: fileList(m.agents, "agents", isSafeSegment),
91
+ hooksJson,
92
+ ...(cleanLabel(m.channel, 16) ? { channel: cleanLabel(m.channel, 16) } : {}),
93
+ ...(cleanLabel(m.icon, 16) ? { icon: cleanLabel(m.icon, 16) } : {}),
94
+ };
95
+ }
96
+ function cleanLabel(value, max) {
97
+ if (typeof value !== "string")
98
+ return undefined;
99
+ const clean = value
100
+ .replace(/\u001b\[[0-9;?]*[ -\/]*[@-~]/g, "")
101
+ .replace(/[\u0000-\u001f\u007f-\u009f]/g, "")
102
+ .trim();
103
+ return clean ? [...clean].slice(0, max).join("") : undefined;
104
+ }
105
+ function displayName(pack) {
106
+ const icon = cleanLabel(pack.icon, 8);
107
+ const name = pack.name || pack.slug;
108
+ return icon ? `${icon} ${name}` : name;
109
+ }
110
+ function parseFrontmatter(content) {
111
+ const match = content.match(/^?---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/);
112
+ if (!match)
113
+ return { data: {}, body: content };
114
+ const data = {};
115
+ for (const line of match[1].split(/\r?\n/)) {
116
+ const kv = line.match(/^([A-Za-z0-9_-]+)\s*:\s*(.*)$/);
117
+ if (!kv)
118
+ continue;
119
+ let value = kv[2].trim();
120
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
121
+ value = value.slice(1, -1);
122
+ }
123
+ data[kv[1]] = value;
124
+ }
125
+ return { data, body: content.slice(match[0].length) };
126
+ }