@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.
- package/CHANGELOG.md +59 -0
- package/dist/types/cli/args.d.ts +2 -2
- package/dist/types/cli/root-flags.d.ts +4 -2
- package/dist/types/cli.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +1 -1
- package/dist/types/config/autorouting-tier-map.d.ts +3 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +9 -0
- package/dist/types/config/settings-schema.d.ts +29 -1
- package/dist/types/discovery/claude-plugins.d.ts +3 -1
- package/dist/types/discovery/helpers.d.ts +2 -0
- package/dist/types/extensibility/gjc-plugins/mcp-policy.d.ts +16 -0
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +1 -1
- package/dist/types/extensibility/shared-events.d.ts +1 -1
- package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
- package/dist/types/modes/components/assistant-message.d.ts +1 -2
- package/dist/types/modes/components/settings-selector.d.ts +6 -1
- package/dist/types/modes/components/status-line/command.d.ts +35 -0
- package/dist/types/modes/components/status-line/index.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +5 -0
- package/dist/types/modes/components/tool-status-header.d.ts +14 -0
- package/dist/types/modes/controllers/event-controller.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/runtime-mcp/client.d.ts +9 -1
- package/dist/types/runtime-mcp/manager.d.ts +7 -1
- package/dist/types/runtime-mcp/pool.d.ts +22 -3
- package/dist/types/runtime-mcp/transports/stdio.d.ts +0 -4
- package/dist/types/runtime-mcp/types.d.ts +22 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +12 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +6 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +12 -0
- package/dist/types/sdk/host/session-runtime.d.ts +23 -0
- package/dist/types/sdk/session-api-key.d.ts +26 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +9 -0
- package/dist/types/setup/paseo/announce.d.ts +111 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +2 -1
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +2 -1
- package/dist/types/tools/fetch.d.ts +7 -0
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/path-utils.d.ts +2 -0
- package/dist/types/tools/search.d.ts +6 -0
- package/package.json +7 -7
- package/scripts/capture-status-line-custom-editor-showcase.ts +151 -0
- package/scripts/generate-sdk-operation-inventory.ts +9 -0
- package/scripts/verify-status-line-custom-editor-showcase.ts +309 -0
- package/src/cli/args.ts +20 -9
- package/src/cli/root-flags.ts +5 -3
- package/src/config/autorouting-tier-map.ts +1 -0
- package/src/config/file-lock.ts +181 -17
- package/src/config/model-preset-registry.ts +5 -3
- package/src/config/model-profiles.ts +40 -0
- package/src/config/model-registry.ts +57 -11
- package/src/config/model-resolver.ts +48 -0
- package/src/config/settings-schema.ts +33 -1
- package/src/config/settings.ts +1 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +11 -11
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +13 -2
- package/src/discovery/builtin.ts +13 -4
- package/src/discovery/claude-plugins.ts +12 -4
- package/src/discovery/helpers.ts +10 -2
- package/src/extensibility/gjc-plugins/compiler.ts +208 -58
- package/src/extensibility/gjc-plugins/installer.ts +13 -12
- package/src/extensibility/gjc-plugins/mcp-policy.ts +81 -52
- package/src/extensibility/gjc-plugins/paths.ts +13 -0
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +758 -16
- package/src/extensibility/runtime-skill-discovery.ts +77 -151
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/skills.ts +44 -16
- package/src/gjc-runtime/repository-binding.ts +1 -1
- package/src/gjc-runtime/session-state-lock.ts +92 -2
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/main.ts +72 -34
- package/src/modes/DESIGN.md +54 -0
- package/src/modes/components/assistant-message.ts +22 -9
- package/src/modes/components/model-selector.ts +166 -33
- package/src/modes/components/settings-selector.ts +1075 -235
- package/src/modes/components/status-line/command.ts +190 -0
- package/src/modes/components/status-line/index.ts +1 -0
- package/src/modes/components/status-line/segments.ts +32 -5
- package/src/modes/components/status-line/types.ts +5 -0
- package/src/modes/components/tool-status-header.ts +393 -21
- package/src/modes/controllers/command-controller.ts +2 -0
- package/src/modes/controllers/event-controller.ts +148 -5
- package/src/modes/controllers/selector-controller.ts +21 -0
- package/src/modes/interactive-mode.ts +47 -1
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/system/system-prompt.md +8 -0
- package/src/prompts/tools/search.md +2 -0
- package/src/runtime-mcp/client.ts +60 -17
- package/src/runtime-mcp/manager.ts +171 -14
- package/src/runtime-mcp/pool.test.ts +209 -0
- package/src/runtime-mcp/pool.ts +224 -23
- package/src/runtime-mcp/transports/stdio.ts +158 -24
- package/src/runtime-mcp/types.ts +24 -0
- package/src/sdk/broker/broker.ts +5 -4
- package/src/sdk/bus/chat-daemon-control.ts +1 -1
- package/src/sdk/bus/chat-daemon-runtime.ts +37 -1
- package/src/sdk/bus/slack-daemon.ts +92 -2
- package/src/sdk/bus/slack-live-provider.ts +12 -0
- package/src/sdk/bus/slack-provider.ts +5 -0
- package/src/sdk/cli/session-cli.ts +9 -6
- package/src/sdk/host/session-runtime.test.ts +2 -2
- package/src/sdk/host/session-runtime.ts +275 -43
- package/src/sdk/protocol/operation-inventory.generated.json +66 -0
- package/src/sdk/session-api-key.ts +94 -0
- package/src/sdk/session.ts +73 -29
- package/src/sdk/transport/serve-cli.ts +3 -3
- package/src/session/agent-session.ts +123 -38
- package/src/session/contribution-prep.ts +214 -21
- package/src/setup/paseo/announce.ts +450 -0
- package/src/setup/paseo/setup-deps.ts +15 -3
- package/src/slash-commands/builtin-registry.ts +1 -0
- package/src/system-prompt.ts +4 -0
- package/src/task/executor.ts +2 -1
- package/src/task/index.ts +17 -4
- package/src/tools/bash.ts +35 -8
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +29 -1
- package/src/tools/index.ts +8 -0
- package/src/tools/job.ts +8 -2
- package/src/tools/monitor.ts +8 -2
- package/src/tools/path-utils.ts +7 -0
- package/src/tools/search.ts +116 -58
- package/src/tools/skill.ts +22 -2
- package/src/tools/subagent.ts +3 -1
- package/src/tools/tool-catalog.generated.ts +8 -1
- package/src/web/insane/bridge.ts +113 -23
- 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
|
-
|
|
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
|
-
|
|
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
|
|
156
|
-
|
|
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
|
|
186
|
-
`Manifest: ${
|
|
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
|
|
227
|
-
`Working directory: ${
|
|
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
|
-
|
|
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: ${
|
|
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(
|
|
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
|
-
|
|
505
|
+
[command.cmd, ...command.args, "--no-skills", "--", `@${path.basename(workerPromptPath)}`],
|
|
506
|
+
artifactDir,
|
|
314
507
|
command.shell,
|
|
315
508
|
);
|
|
316
509
|
spawned = true;
|