@gajae-code/coding-agent 0.16.3 → 0.16.4

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 (133) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/types/cli/args.d.ts +2 -2
  3. package/dist/types/cli/root-flags.d.ts +4 -2
  4. package/dist/types/cli.d.ts +1 -1
  5. package/dist/types/commands/launch.d.ts +1 -1
  6. package/dist/types/config/autorouting-tier-map.d.ts +3 -0
  7. package/dist/types/config/model-registry.d.ts +4 -0
  8. package/dist/types/config/model-resolver.d.ts +9 -0
  9. package/dist/types/config/settings-schema.d.ts +29 -1
  10. package/dist/types/discovery/claude-plugins.d.ts +3 -1
  11. package/dist/types/discovery/helpers.d.ts +2 -0
  12. package/dist/types/extensibility/gjc-plugins/mcp-policy.d.ts +16 -0
  13. package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -0
  14. package/dist/types/extensibility/runtime-skill-discovery.d.ts +1 -1
  15. package/dist/types/extensibility/shared-events.d.ts +1 -1
  16. package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
  17. package/dist/types/modes/components/assistant-message.d.ts +1 -2
  18. package/dist/types/modes/components/settings-selector.d.ts +6 -1
  19. package/dist/types/modes/components/status-line/command.d.ts +35 -0
  20. package/dist/types/modes/components/status-line/index.d.ts +1 -0
  21. package/dist/types/modes/components/status-line/types.d.ts +5 -0
  22. package/dist/types/modes/components/tool-status-header.d.ts +14 -0
  23. package/dist/types/modes/controllers/event-controller.d.ts +6 -0
  24. package/dist/types/modes/interactive-mode.d.ts +1 -0
  25. package/dist/types/modes/types.d.ts +1 -0
  26. package/dist/types/runtime-mcp/client.d.ts +9 -1
  27. package/dist/types/runtime-mcp/manager.d.ts +7 -1
  28. package/dist/types/runtime-mcp/pool.d.ts +22 -3
  29. package/dist/types/runtime-mcp/transports/stdio.d.ts +0 -4
  30. package/dist/types/runtime-mcp/types.d.ts +22 -0
  31. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +12 -0
  32. package/dist/types/sdk/bus/slack-live-provider.d.ts +6 -0
  33. package/dist/types/sdk/bus/slack-provider.d.ts +12 -0
  34. package/dist/types/sdk/host/session-runtime.d.ts +23 -0
  35. package/dist/types/sdk/session-api-key.d.ts +26 -0
  36. package/dist/types/sdk/transport/serve-cli.d.ts +1 -1
  37. package/dist/types/session/agent-session.d.ts +9 -0
  38. package/dist/types/setup/paseo/announce.d.ts +111 -0
  39. package/dist/types/setup/paseo/setup-deps.d.ts +2 -1
  40. package/dist/types/system-prompt.d.ts +2 -0
  41. package/dist/types/task/executor.d.ts +2 -1
  42. package/dist/types/tools/fetch.d.ts +7 -0
  43. package/dist/types/tools/index.d.ts +8 -0
  44. package/dist/types/tools/path-utils.d.ts +2 -0
  45. package/dist/types/tools/search.d.ts +6 -0
  46. package/package.json +7 -7
  47. package/scripts/capture-status-line-custom-editor-showcase.ts +151 -0
  48. package/scripts/generate-sdk-operation-inventory.ts +9 -0
  49. package/scripts/verify-status-line-custom-editor-showcase.ts +309 -0
  50. package/src/cli/args.ts +20 -9
  51. package/src/cli/root-flags.ts +5 -3
  52. package/src/config/autorouting-tier-map.ts +1 -0
  53. package/src/config/file-lock.ts +181 -17
  54. package/src/config/model-preset-registry.ts +5 -3
  55. package/src/config/model-profiles.ts +40 -0
  56. package/src/config/model-registry.ts +57 -11
  57. package/src/config/model-resolver.ts +48 -0
  58. package/src/config/settings-schema.ts +33 -1
  59. package/src/config/settings.ts +1 -0
  60. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +11 -11
  61. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +13 -2
  62. package/src/discovery/builtin.ts +13 -4
  63. package/src/discovery/claude-plugins.ts +12 -4
  64. package/src/discovery/helpers.ts +10 -2
  65. package/src/extensibility/gjc-plugins/compiler.ts +208 -58
  66. package/src/extensibility/gjc-plugins/installer.ts +13 -12
  67. package/src/extensibility/gjc-plugins/mcp-policy.ts +81 -52
  68. package/src/extensibility/gjc-plugins/paths.ts +13 -0
  69. package/src/extensibility/gjc-plugins/runtime-adapters.ts +758 -16
  70. package/src/extensibility/runtime-skill-discovery.ts +77 -151
  71. package/src/extensibility/shared-events.ts +1 -1
  72. package/src/extensibility/skills.ts +44 -16
  73. package/src/gjc-runtime/repository-binding.ts +1 -1
  74. package/src/gjc-runtime/session-state-lock.ts +92 -2
  75. package/src/internal-urls/docs-index.generated.ts +7 -7
  76. package/src/main.ts +72 -34
  77. package/src/modes/DESIGN.md +54 -0
  78. package/src/modes/components/assistant-message.ts +22 -9
  79. package/src/modes/components/model-selector.ts +166 -33
  80. package/src/modes/components/settings-selector.ts +1075 -235
  81. package/src/modes/components/status-line/command.ts +190 -0
  82. package/src/modes/components/status-line/index.ts +1 -0
  83. package/src/modes/components/status-line/segments.ts +32 -5
  84. package/src/modes/components/status-line/types.ts +5 -0
  85. package/src/modes/components/tool-status-header.ts +393 -21
  86. package/src/modes/controllers/command-controller.ts +2 -0
  87. package/src/modes/controllers/event-controller.ts +148 -5
  88. package/src/modes/controllers/selector-controller.ts +21 -0
  89. package/src/modes/interactive-mode.ts +47 -1
  90. package/src/modes/types.ts +1 -0
  91. package/src/modes/utils/ui-helpers.ts +1 -0
  92. package/src/prompts/system/system-prompt.md +8 -0
  93. package/src/prompts/tools/search.md +2 -0
  94. package/src/runtime-mcp/client.ts +60 -17
  95. package/src/runtime-mcp/manager.ts +171 -14
  96. package/src/runtime-mcp/pool.test.ts +209 -0
  97. package/src/runtime-mcp/pool.ts +224 -23
  98. package/src/runtime-mcp/transports/stdio.ts +158 -24
  99. package/src/runtime-mcp/types.ts +24 -0
  100. package/src/sdk/broker/broker.ts +5 -4
  101. package/src/sdk/bus/chat-daemon-control.ts +1 -1
  102. package/src/sdk/bus/chat-daemon-runtime.ts +37 -1
  103. package/src/sdk/bus/slack-daemon.ts +92 -2
  104. package/src/sdk/bus/slack-live-provider.ts +12 -0
  105. package/src/sdk/bus/slack-provider.ts +5 -0
  106. package/src/sdk/cli/session-cli.ts +9 -6
  107. package/src/sdk/host/session-runtime.test.ts +2 -2
  108. package/src/sdk/host/session-runtime.ts +275 -43
  109. package/src/sdk/protocol/operation-inventory.generated.json +66 -0
  110. package/src/sdk/session-api-key.ts +94 -0
  111. package/src/sdk/session.ts +73 -29
  112. package/src/sdk/transport/serve-cli.ts +3 -3
  113. package/src/session/agent-session.ts +123 -38
  114. package/src/session/contribution-prep.ts +214 -21
  115. package/src/setup/paseo/announce.ts +450 -0
  116. package/src/setup/paseo/setup-deps.ts +15 -3
  117. package/src/slash-commands/builtin-registry.ts +1 -0
  118. package/src/system-prompt.ts +4 -0
  119. package/src/task/executor.ts +2 -1
  120. package/src/task/index.ts +17 -4
  121. package/src/tools/bash.ts +35 -8
  122. package/src/tools/cron.ts +1 -1
  123. package/src/tools/fetch.ts +29 -1
  124. package/src/tools/index.ts +8 -0
  125. package/src/tools/job.ts +8 -2
  126. package/src/tools/monitor.ts +8 -2
  127. package/src/tools/path-utils.ts +7 -0
  128. package/src/tools/search.ts +116 -58
  129. package/src/tools/skill.ts +22 -2
  130. package/src/tools/subagent.ts +3 -1
  131. package/src/tools/tool-catalog.generated.ts +8 -1
  132. package/src/web/insane/bridge.ts +113 -23
  133. package/src/web/search/providers/perplexity.ts +102 -41
@@ -3,7 +3,6 @@ import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import type { AgentMessage } from "@gajae-code/agent-core";
5
5
  import type { AssistantMessage, ToolResultMessage, UserMessage } from "@gajae-code/ai/core";
6
- import { $ } from "bun";
7
6
  import { resolveGjcCommand } from "../task/gjc-command";
8
7
  import { shortenPath } from "../tools/render-utils";
9
8
 
@@ -12,6 +11,12 @@ export const CONTRIBUTION_PREP_SCHEMA_VERSION = 1;
12
11
  const MAX_TRANSCRIPT_MESSAGES = 20;
13
12
  const MAX_TEXT_CHARS = 12000;
14
13
  const MAX_GIT_OUTPUT_CHARS = 60000;
14
+ const MAX_REDACTION_INPUT_CHARS = 1_000_000;
15
+ // Keep whole Git captures within the redactor's input budget; discard an overrun
16
+ // instead of emitting a prefix.
17
+ const MAX_GIT_RAW_OUTPUT_BYTES = MAX_REDACTION_INPUT_CHARS;
18
+ const MAX_JSON_TOKENS = 20_000;
19
+ const MAX_JSON_REPLACEMENTS = 10_000;
15
20
 
16
21
  export interface ContributionPrepArtifact {
17
22
  path: string;
@@ -72,12 +77,133 @@ function replaceRegex(text: string, regex: RegExp, replacement: string, state: R
72
77
  return text.replace(regex, replacement);
73
78
  }
74
79
 
80
+ function redactAwsAccessKeyIds(text: string, state: RedactionState): string {
81
+ return replaceRegex(
82
+ text,
83
+ /(^|[^0-9A-Za-z])(?:AKIA|ASIA)[0-9A-Z]{16}(?![0-9A-Za-z])/g,
84
+ "$1[REDACTED_AWS_KEY_ID]",
85
+ state,
86
+ "aws_keys",
87
+ );
88
+ }
89
+
90
+ function isAwsSecretField(value: string): boolean {
91
+ const normalized = value.toLowerCase().replaceAll(/[_-]/g, "");
92
+ return (
93
+ normalized === "secretaccesskey" ||
94
+ normalized === "sessiontoken" ||
95
+ normalized === "awssecretaccesskey" ||
96
+ normalized === "awssessiontoken" ||
97
+ normalized === "xamzsecuritytoken"
98
+ );
99
+ }
100
+
101
+ function redactAwsLabeledValues(text: string, state: RedactionState): string {
102
+ let redacted = redactAwsAccessKeyIds(text, state);
103
+ redacted = replaceRegex(
104
+ redacted,
105
+ // STS XML responses are commonly pretty-printed, so the value sits on its own
106
+ // line between the tags. `[^<]` still refuses to cross into another element,
107
+ // while the call-wide input bound caps work without imposing a credential-size
108
+ // assumption. The lower bound leaves empty or whitespace-only bodies alone.
109
+ /(<((?:[A-Za-z_][\w.-]*:)?(?:SecretAccessKey|SessionToken))>)[^<]{8,1000000}(<\/\2>)/gi,
110
+ "$1[REDACTED_SECRET]$3",
111
+ state,
112
+ "aws_keys",
113
+ );
114
+ redacted = replaceRegex(
115
+ redacted,
116
+ /(^|[^A-Za-z0-9_-])(["']?(?:(?:aws[_-]?)?secret[_-]?access[_-]?key|(?:aws[_-]?)?session[_-]?token|x[_-]?amz[_-]?security[_-]?token)["']?\s*[=:]\s*)(\$?)(["'`])([^"'`\r\n]{8,})\4/gi,
117
+ "$1$2$3$4[REDACTED_SECRET]$4",
118
+ state,
119
+ "aws_keys",
120
+ );
121
+ return replaceRegex(
122
+ redacted,
123
+ /(^|[^A-Za-z0-9_-])(["']?(?:(?:aws[_-]?)?secret[_-]?access[_-]?key|(?:aws[_-]?)?session[_-]?token|x[_-]?amz[_-]?security[_-]?token)["']?\s*[=:]\s*)[^\s"'`,;{}[\]()&<>#]{8,}/gi,
124
+ "$1$2[REDACTED_SECRET]",
125
+ state,
126
+ "aws_keys",
127
+ );
128
+ }
129
+
130
+ function redactAwsJsonStrings(text: string, state: RedactionState, depth = 0): string {
131
+ const tokens = [...text.matchAll(/"(?:\\(?:["\\/bfnrt]|u[0-9A-Fa-f]{4})|[^"\\\r\n])*"/g)].map(match => ({
132
+ start: match.index,
133
+ end: match.index + match[0].length,
134
+ raw: match[0],
135
+ }));
136
+ if (tokens.length > MAX_JSON_TOKENS) {
137
+ state.labels.add("oversized_content");
138
+ return "[REDACTED_OVERSIZED_CONTENT]";
139
+ }
140
+ const replacements = new Map<number, { end: number; value: string }>();
141
+
142
+ for (const [index, token] of tokens.entries()) {
143
+ let decoded: string;
144
+ try {
145
+ decoded = JSON.parse(token.raw) as string;
146
+ } catch {
147
+ continue;
148
+ }
149
+
150
+ if (isAwsSecretField(decoded)) {
151
+ const separator = /^\s*:\s*/.exec(text.slice(token.end));
152
+ const valueToken = tokens[index + 1];
153
+ if (separator && valueToken?.start === token.end + separator[0].length) {
154
+ let value: string;
155
+ try {
156
+ value = JSON.parse(valueToken.raw) as string;
157
+ } catch {
158
+ value = "";
159
+ }
160
+ if (value.length >= 8)
161
+ replacements.set(valueToken.start, { end: valueToken.end, value: JSON.stringify("[REDACTED_SECRET]") });
162
+ }
163
+ }
164
+
165
+ const nestedRedacted = depth >= 3 ? "[REDACTED_NESTED_CONTENT]" : redactAwsJsonStrings(decoded, state, depth + 1);
166
+ const redacted = redactAwsLabeledValues(nestedRedacted, state);
167
+ if (redacted !== decoded && !replacements.has(token.start)) {
168
+ replacements.set(token.start, { end: token.end, value: JSON.stringify(redacted) });
169
+ }
170
+ }
171
+
172
+ if (replacements.size === 0) return text;
173
+ if (replacements.size > MAX_JSON_REPLACEMENTS) {
174
+ state.labels.add("oversized_content");
175
+ return "[REDACTED_OVERSIZED_CONTENT]";
176
+ }
177
+ state.labels.add("aws_keys");
178
+ const chunks: string[] = [];
179
+ let cursor = 0;
180
+ for (const [start, replacement] of [...replacements.entries()].sort(([left], [right]) => left - right)) {
181
+ chunks.push(text.slice(cursor, start), replacement.value);
182
+ cursor = replacement.end;
183
+ }
184
+ chunks.push(text.slice(cursor));
185
+ return chunks.join("");
186
+ }
187
+
188
+ function assertSafeArtifactPath(artifactDir: string): void {
189
+ const state: RedactionState = { labels: new Set() };
190
+ redactContributionPrepText(artifactDir, path.join(artifactDir, "__gjc_path_probe__"), state);
191
+ if (["tokens", "aws_keys", "provider_keys", "auth_headers", "cookies"].some(label => state.labels.has(label))) {
192
+ throw new Error("Contribution prep artifact path contains credential-like material.");
193
+ }
194
+ }
195
+
75
196
  export function redactContributionPrepText(
76
197
  text: string,
77
198
  cwd: string,
78
199
  state: RedactionState = { labels: new Set() },
79
200
  ): string {
80
- let redacted = text;
201
+ if (text.length > MAX_REDACTION_INPUT_CHARS) {
202
+ state.labels.add("oversized_content");
203
+ return "[REDACTED_OVERSIZED_CONTENT]";
204
+ }
205
+ let redacted = redactAwsJsonStrings(text, state);
206
+ redacted = redactAwsLabeledValues(redacted, state);
81
207
  redacted = replaceRegex(
82
208
  redacted,
83
209
  /\b(?:sk|pk|rk|xox[baprs])-[-_A-Za-z0-9]{12,}\b/g,
@@ -150,17 +276,73 @@ function formatMessage(message: AgentMessage): string {
150
276
  return `## ${message.role}\n\n${JSON.stringify(message)}\n`;
151
277
  }
152
278
 
153
- async function gitOutput(cwd: string, args: string[], maxChars = MAX_GIT_OUTPUT_CHARS): Promise<string> {
279
+ interface BoundedGitOutput {
280
+ text: string;
281
+ oversized: boolean;
282
+ }
283
+
284
+ async function readBoundedGitOutput(stream: ReadableStream<Uint8Array>, maxBytes: number): Promise<BoundedGitOutput> {
285
+ const reader = stream.getReader();
286
+ const chunks: Uint8Array[] = [];
287
+ let totalBytes = 0;
288
+ try {
289
+ for (;;) {
290
+ const { done, value } = await reader.read();
291
+ if (done) break;
292
+ totalBytes += value.byteLength;
293
+ if (totalBytes > maxBytes) return { text: "", oversized: true };
294
+ chunks.push(value);
295
+ }
296
+ } finally {
297
+ reader.releaseLock();
298
+ }
299
+
300
+ const bytes = new Uint8Array(totalBytes);
301
+ let offset = 0;
302
+ for (const chunk of chunks) {
303
+ bytes.set(chunk, offset);
304
+ offset += chunk.byteLength;
305
+ }
306
+ return { text: new TextDecoder().decode(bytes), oversized: false };
307
+ }
308
+
309
+ async function gitOutput(
310
+ cwd: string,
311
+ args: string[],
312
+ state: RedactionState,
313
+ maxChars = MAX_GIT_OUTPUT_CHARS,
314
+ ): Promise<string> {
154
315
  try {
155
- const output = await $`git ${args}`.cwd(cwd).quiet().text();
156
- return limitText(output.trim(), maxChars);
316
+ const proc = Bun.spawn(["git", ...args], { cwd, stdin: "ignore", stdout: "pipe", stderr: "ignore" });
317
+ const stop = (): void => {
318
+ try {
319
+ proc.kill();
320
+ } catch {
321
+ // The process already exited.
322
+ }
323
+ };
324
+ try {
325
+ const output = await readBoundedGitOutput(proc.stdout, MAX_GIT_RAW_OUTPUT_BYTES);
326
+ if (output.oversized) {
327
+ stop();
328
+ await proc.exited;
329
+ state.labels.add("oversized_content");
330
+ return "[REDACTED_OVERSIZED_CONTENT]";
331
+ }
332
+ if ((await proc.exited) !== 0) return "";
333
+ return limitText(redactContributionPrepText(output.text.trim(), cwd, state), maxChars);
334
+ } catch {
335
+ stop();
336
+ await proc.exited;
337
+ return "";
338
+ }
157
339
  } catch {
158
340
  return "";
159
341
  }
160
342
  }
161
343
 
162
- async function changedFiles(cwd: string): Promise<string[]> {
163
- const output = await gitOutput(cwd, ["status", "--short"]);
344
+ async function changedFiles(cwd: string, state: RedactionState): Promise<string[]> {
345
+ const output = await gitOutput(cwd, ["status", "--short"], state);
164
346
  return output
165
347
  .split("\n")
166
348
  .map(line => line.trim())
@@ -180,15 +362,23 @@ async function writeArtifact(
180
362
  }
181
363
 
182
364
  export function buildContributionPrepWorkerPrompt(manifestPath: string): string {
365
+ const manifestName = path.basename(manifestPath);
183
366
  return [
184
367
  "Prepare a maintainer-friendly contribution draft from the redacted context dump.",
185
- "Read the manifest and referenced artifact file pointers. Do not assume transcript context was inlined here.",
186
- `Manifest: ${manifestPath}`,
368
+ "Read the manifest beside this worker prompt and its relative artifact file pointers. Do not assume transcript context was inlined here.",
369
+ `Manifest: ${manifestName}`,
187
370
  "Produce structured markdown with: title, problem summary, reproduction/context, proposed fix or implementation plan, affected files, tests to run, and uncertainty/remaining risks.",
188
371
  "Do not create GitHub issues, open PRs, push branches, or perform remote writes unless the user explicitly confirms that action in this fresh session.",
189
372
  ].join("\n");
190
373
  }
191
374
 
375
+ function safeWorkspaceLabel(cwd: string): string {
376
+ const resolved = path.resolve(cwd);
377
+ const home = os.homedir();
378
+ if (home && (resolved === home || resolved.startsWith(`${home}${path.sep}`))) return shortenPath(resolved);
379
+ return path.basename(resolved) || ".";
380
+ }
381
+
192
382
  export async function prepareContributionPrep(
193
383
  context: ContributionPrepContext,
194
384
  options: ContributionPrepOptions = {},
@@ -199,12 +389,14 @@ export async function prepareContributionPrep(
199
389
  options.artifactRoot ?? path.join(context.cwd, ".gjc", "contribution-prep"),
200
390
  safeTimestamp,
201
391
  );
392
+ assertSafeArtifactPath(artifactDir);
202
393
  await fs.mkdir(artifactDir, { recursive: true });
203
394
 
204
395
  const redactions: RedactionState = { labels: new Set() };
205
396
  const recentMessages = context.messages.slice(-MAX_TRANSCRIPT_MESSAGES);
206
397
  const artifacts: ContributionPrepArtifact[] = [];
207
398
  const redact = (text: string) => redactContributionPrepText(text, context.cwd, redactions);
399
+ const workspaceLabel = safeWorkspaceLabel(context.cwd);
208
400
 
209
401
  artifacts.push(
210
402
  await writeArtifact(
@@ -223,8 +415,8 @@ export async function prepareContributionPrep(
223
415
  [
224
416
  `# Contribution prep context`,
225
417
  `Source session: ${context.sessionId}`,
226
- `Session file: ${context.sessionFile ?? "(none)"}`,
227
- `Working directory: ${context.cwd}`,
418
+ `Session file: ${context.sessionFile ? path.basename(context.sessionFile) : "(none)"}`,
419
+ `Working directory: ${workspaceLabel}`,
228
420
  options.customInstructions || context.customInstructions
229
421
  ? `Custom instructions: ${options.customInstructions ?? context.customInstructions}`
230
422
  : "Custom instructions: (none)",
@@ -233,8 +425,8 @@ export async function prepareContributionPrep(
233
425
  ),
234
426
  );
235
427
 
236
- const gitHead = (await gitOutput(context.cwd, ["rev-parse", "HEAD"])) || null;
237
- const files = await changedFiles(context.cwd);
428
+ const gitHead = (await gitOutput(context.cwd, ["rev-parse", "HEAD"], redactions)) || null;
429
+ const files = await changedFiles(context.cwd, redactions);
238
430
  artifacts.push(
239
431
  await writeArtifact(artifactDir, "changed-files.txt", "Changed files from git status", redact(files.join("\n"))),
240
432
  );
@@ -243,7 +435,7 @@ export async function prepareContributionPrep(
243
435
  artifactDir,
244
436
  "git-diff.patch",
245
437
  "Bounded redacted git diff",
246
- redact(await gitOutput(context.cwd, ["diff", "--no-ext-diff"])),
438
+ await gitOutput(context.cwd, ["diff", "--no-ext-diff"], redactions),
247
439
  ),
248
440
  );
249
441
  artifacts.push(
@@ -253,7 +445,7 @@ export async function prepareContributionPrep(
253
445
  "Redacted environment and reproduction metadata",
254
446
  redact(
255
447
  [
256
- `cwd: ${context.cwd}`,
448
+ `cwd: ${workspaceLabel}`,
257
449
  `git_head: ${gitHead ?? "unknown"}`,
258
450
  `platform: ${process.platform}`,
259
451
  `arch: ${process.arch}`,
@@ -266,15 +458,16 @@ export async function prepareContributionPrep(
266
458
  const manifestPath = path.join(artifactDir, "manifest.json");
267
459
  const workerPromptPath = path.join(artifactDir, "worker-prompt.md");
268
460
  await Bun.write(workerPromptPath, `${buildContributionPrepWorkerPrompt(manifestPath)}\n`);
461
+ const manifestArtifacts = artifacts.map(artifact => ({ ...artifact, path: path.basename(artifact.path) }));
269
462
 
270
463
  const manifest: ContributionPrepManifest = {
271
464
  schema_version: CONTRIBUTION_PREP_SCHEMA_VERSION,
272
- source_session_id: context.sessionId,
465
+ source_session_id: redact(context.sessionId),
273
466
  created_at: createdAt,
274
- cwd: redact(context.cwd),
467
+ cwd: redact(workspaceLabel),
275
468
  git_head: gitHead,
276
469
  changed_files: files.map(redact),
277
- artifacts,
470
+ artifacts: manifestArtifacts,
278
471
  redactions: [...redactions.labels].sort(),
279
472
  recommended_output: [
280
473
  "title",
@@ -285,7 +478,7 @@ export async function prepareContributionPrep(
285
478
  "tests to run",
286
479
  "uncertainty / remaining risks",
287
480
  ],
288
- worker_prompt_path: workerPromptPath,
481
+ worker_prompt_path: path.basename(workerPromptPath),
289
482
  };
290
483
  await Bun.write(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
291
484
 
@@ -309,8 +502,8 @@ export async function prepareContributionPrep(
309
502
  });
310
503
  const command = resolveGjcCommand();
311
504
  await spawn(
312
- [command.cmd, ...command.args, "--no-skills", "--", `@${workerPromptPath}`],
313
- context.cwd,
505
+ [command.cmd, ...command.args, "--no-skills", "--", `@${path.basename(workerPromptPath)}`],
506
+ artifactDir,
314
507
  command.shell,
315
508
  );
316
509
  spawned = true;