@gajae-code/coding-agent 0.16.1 → 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 +70 -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/cli/rows.d.ts +7 -0
- package/dist/types/sdk/host/events.d.ts +1 -0
- package/dist/types/sdk/host/host.d.ts +2 -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 -2
- package/dist/types/tools/path-utils.d.ts +2 -0
- package/dist/types/tools/search.d.ts +6 -0
- package/dist/types/utils/external-editor.d.ts +5 -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 +94 -6
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/main.ts +72 -34
- package/src/modes/DESIGN.md +54 -0
- package/src/modes/acp/acp-agent.ts +29 -14
- 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/bash.md +1 -1
- package/src/prompts/tools/job.md +1 -1
- 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/acp/adapter.ts +1 -1
- 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 +44 -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/rows.ts +47 -2
- package/src/sdk/cli/session-cli.ts +47 -23
- package/src/sdk/host/events.ts +25 -2
- package/src/sdk/host/host.ts +4 -1
- package/src/sdk/host/session-runtime.test.ts +36 -25
- package/src/sdk/host/session-runtime.ts +279 -43
- package/src/sdk/protocol/operation-inventory.generated.json +66 -0
- package/src/sdk/router/session-router.ts +60 -37
- package/src/sdk/session-api-key.ts +94 -0
- package/src/sdk/session.ts +73 -30
- 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 +50 -21
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +29 -1
- package/src/tools/index.ts +8 -2
- 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 +9 -2
- package/src/utils/external-editor.ts +16 -2
- package/src/web/insane/bridge.ts +113 -23
- package/src/web/search/providers/perplexity.ts +102 -41
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
canContinuePersistedHistory,
|
|
37
37
|
dispatchedToolIdentity,
|
|
38
38
|
getAgentTerminalOwnerContext,
|
|
39
|
+
isContinuingMidRunMaintenanceOutcome,
|
|
39
40
|
isNonDispatchedToolEvent,
|
|
40
41
|
type ManagedAttemptContinuationOwnership,
|
|
41
42
|
type ManagedAttemptDecision,
|
|
@@ -882,6 +883,10 @@ export interface AgentSessionConfig {
|
|
|
882
883
|
skills?: Skill[];
|
|
883
884
|
/** Skill loading warnings (already captured by SDK) */
|
|
884
885
|
skillWarnings?: SkillWarning[];
|
|
886
|
+
/** Re-enumerate filesystem and marketplace skills after plugin lifecycle changes. */
|
|
887
|
+
reloadSkills?: (cwd: string) => Promise<{ skills: Skill[]; warnings: SkillWarning[] }>;
|
|
888
|
+
/** Publish a successfully committed skill catalog to SDK/process snapshots. */
|
|
889
|
+
onSkillsReloaded?: (skills: Skill[], warnings: SkillWarning[]) => void;
|
|
885
890
|
/** Custom commands (TypeScript slash commands) */
|
|
886
891
|
customCommands?: LoadedCustomCommand[];
|
|
887
892
|
skillsSettings?: SkillsSettings;
|
|
@@ -1044,7 +1049,7 @@ type AutoCompactionTerminalStatus =
|
|
|
1044
1049
|
| { kind: "compacted"; continuationScheduled?: boolean }
|
|
1045
1050
|
| { kind: "aborted"; source: "signal" | "hook" }
|
|
1046
1051
|
| { kind: "skipped"; continuationScheduled?: boolean }
|
|
1047
|
-
| { kind: "failed" };
|
|
1052
|
+
| { kind: "failed"; errorMessage: string };
|
|
1048
1053
|
|
|
1049
1054
|
type ToolOutputPruneResult = {
|
|
1050
1055
|
prunedCount: number;
|
|
@@ -3124,6 +3129,8 @@ export class AgentSession {
|
|
|
3124
3129
|
|
|
3125
3130
|
#skills: Skill[];
|
|
3126
3131
|
#skillWarnings: SkillWarning[];
|
|
3132
|
+
#reloadSkills: AgentSessionConfig["reloadSkills"];
|
|
3133
|
+
#onSkillsReloaded: AgentSessionConfig["onSkillsReloaded"];
|
|
3127
3134
|
|
|
3128
3135
|
// Custom commands (TypeScript slash commands)
|
|
3129
3136
|
#customCommands: LoadedCustomCommand[] = [];
|
|
@@ -4556,6 +4563,8 @@ export class AgentSession {
|
|
|
4556
4563
|
this.agent.setMainAttemptScopeObserver(scope => this.#bindAttemptScope(scope));
|
|
4557
4564
|
this.#skills = config.skills ?? [];
|
|
4558
4565
|
this.#skillWarnings = config.skillWarnings ?? [];
|
|
4566
|
+
this.#reloadSkills = config.reloadSkills;
|
|
4567
|
+
this.#onSkillsReloaded = config.onSkillsReloaded;
|
|
4559
4568
|
this.#customCommands = config.customCommands ?? [];
|
|
4560
4569
|
this.#skillsSettings = config.skillsSettings;
|
|
4561
4570
|
this.#modelRegistry = config.modelRegistry;
|
|
@@ -5638,6 +5647,27 @@ export class AgentSession {
|
|
|
5638
5647
|
if (failures.length > 0) throw new AggregateError(failures, "Tool session cleanup failed.");
|
|
5639
5648
|
}
|
|
5640
5649
|
|
|
5650
|
+
#claimToolSessionTransitionCleanups(): Promise<void> {
|
|
5651
|
+
const cleanups = Array.from(this.#toolSessionTransitionCleanups);
|
|
5652
|
+
this.#toolSessionTransitionCleanups.clear();
|
|
5653
|
+
return this.#settleClaimedToolSessionCleanups(cleanups, "Tool session transition cleanup failed.");
|
|
5654
|
+
}
|
|
5655
|
+
|
|
5656
|
+
#claimToolSessionCleanups(): Promise<void> {
|
|
5657
|
+
const cleanups = Array.from(this.#toolSessionCleanups);
|
|
5658
|
+
this.#toolSessionCleanups.clear();
|
|
5659
|
+
return this.#settleClaimedToolSessionCleanups(cleanups, "Tool session cleanup failed.");
|
|
5660
|
+
}
|
|
5661
|
+
|
|
5662
|
+
async #settleClaimedToolSessionCleanups(
|
|
5663
|
+
cleanups: readonly (() => Promise<void> | void)[],
|
|
5664
|
+
message: string,
|
|
5665
|
+
): Promise<void> {
|
|
5666
|
+
const results = await Promise.allSettled(cleanups.map(async cleanup => await cleanup()));
|
|
5667
|
+
const failures = results.flatMap(result => (result.status === "rejected" ? [result.reason] : []));
|
|
5668
|
+
if (failures.length > 0) throw new AggregateError(failures, message);
|
|
5669
|
+
}
|
|
5670
|
+
|
|
5641
5671
|
getAsyncJobSnapshot(options?: { recentLimit?: number }): AsyncJobSnapshot | null {
|
|
5642
5672
|
// The session's OWNED manager first: /jobs, the status header, and the
|
|
5643
5673
|
// active-background count must reflect THIS session's jobs — with
|
|
@@ -5918,7 +5948,9 @@ export class AgentSession {
|
|
|
5918
5948
|
const canonicalAdmission = this.#reserveCanonicalMessageAdmission(event);
|
|
5919
5949
|
const terminalOwner = event.type === "agent_end" ? getAgentTerminalOwnerContext(event) : undefined;
|
|
5920
5950
|
const maintenanceCheckpoint =
|
|
5921
|
-
event.type === "agent_end" &&
|
|
5951
|
+
event.type === "agent_end" &&
|
|
5952
|
+
event.stopReason === "maintenance" &&
|
|
5953
|
+
isContinuingMidRunMaintenanceOutcome(event.maintenanceOutcome);
|
|
5922
5954
|
const terminalClaim =
|
|
5923
5955
|
maintenanceCheckpoint || !terminalOwner
|
|
5924
5956
|
? undefined
|
|
@@ -6196,9 +6228,13 @@ export class AgentSession {
|
|
|
6196
6228
|
this.#requestWorkerIntegrationAttempt();
|
|
6197
6229
|
}
|
|
6198
6230
|
// A maintenance agent_end is an internal checkpoint only while another
|
|
6199
|
-
// continuation will follow.
|
|
6200
|
-
//
|
|
6201
|
-
if (
|
|
6231
|
+
// continuation will follow. Failed or aborted maintenance is terminal and
|
|
6232
|
+
// must reach public subscribers.
|
|
6233
|
+
if (
|
|
6234
|
+
event.type === "agent_end" &&
|
|
6235
|
+
event.stopReason === "maintenance" &&
|
|
6236
|
+
isContinuingMidRunMaintenanceOutcome(event.maintenanceOutcome)
|
|
6237
|
+
)
|
|
6202
6238
|
return;
|
|
6203
6239
|
|
|
6204
6240
|
// Hold agent_end until the prompt's finally and all earlier async event work
|
|
@@ -6983,7 +7019,7 @@ export class AgentSession {
|
|
|
6983
7019
|
|
|
6984
7020
|
if (
|
|
6985
7021
|
event.type === "agent_end" &&
|
|
6986
|
-
!(event.stopReason === "maintenance" && event.maintenanceOutcome
|
|
7022
|
+
!(event.stopReason === "maintenance" && isContinuingMidRunMaintenanceOutcome(event.maintenanceOutcome))
|
|
6987
7023
|
) {
|
|
6988
7024
|
this.#releaseDeferredSdkFollowUps();
|
|
6989
7025
|
}
|
|
@@ -6996,28 +7032,33 @@ export class AgentSession {
|
|
|
6996
7032
|
// the same run on the rewritten context (no synthetic prompt), skipping
|
|
6997
7033
|
// the goal-runtime / skill-state / retry / compaction finalization a
|
|
6998
7034
|
// normal agent_end runs — none of that applies to an in-progress run.
|
|
6999
|
-
//
|
|
7000
|
-
// continuation if a newer prompt/abort
|
|
7035
|
+
// Failed and aborted outcomes fall through to terminal handling. The
|
|
7036
|
+
// generation guard drops a successful continuation if a newer prompt/abort
|
|
7037
|
+
// has moved the run on.
|
|
7001
7038
|
if (event.stopReason === "maintenance") {
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7039
|
+
if (isContinuingMidRunMaintenanceOutcome(event.maintenanceOutcome)) {
|
|
7040
|
+
this.#lastAssistantMessage = undefined;
|
|
7041
|
+
if (
|
|
7042
|
+
!maintenanceWasDisposed &&
|
|
7043
|
+
!this.#isDisposed &&
|
|
7044
|
+
maintenanceGeneration !== undefined &&
|
|
7045
|
+
this.#promptGeneration === maintenanceGeneration
|
|
7046
|
+
) {
|
|
7047
|
+
this.#scheduleAgentContinue({
|
|
7048
|
+
generation: maintenanceGeneration,
|
|
7049
|
+
skipCompactionCheck: true,
|
|
7050
|
+
resourceRunId: activePromptHandle,
|
|
7051
|
+
maintenanceContinuation: true,
|
|
7052
|
+
sdkRunToken: attemptScope ? this.#sdkRunTokensByAttemptScope.get(attemptScope) : undefined,
|
|
7053
|
+
});
|
|
7054
|
+
}
|
|
7055
|
+
return;
|
|
7019
7056
|
}
|
|
7020
|
-
|
|
7057
|
+
// Cancellation already owns teardown and terminal publication. Running
|
|
7058
|
+
// normal post-turn finalization here can deadlock abort/dispose while the
|
|
7059
|
+
// maintenance barrier is unwinding. Failed maintenance alone carries the
|
|
7060
|
+
// synthetic assistant error that must flow through terminal handling.
|
|
7061
|
+
if (event.maintenanceOutcome === "aborted") return;
|
|
7021
7062
|
}
|
|
7022
7063
|
const usage = this.getSessionStats().tokens;
|
|
7023
7064
|
await this.#goalRuntime.onAgentEnd({
|
|
@@ -7083,6 +7124,13 @@ export class AgentSession {
|
|
|
7083
7124
|
return;
|
|
7084
7125
|
}
|
|
7085
7126
|
this.#lastSuccessfulYieldToolCallId = undefined;
|
|
7127
|
+
if (event.stopReason === "maintenance" && event.maintenanceOutcome === "failed") {
|
|
7128
|
+
// The maintenance error already terminalized the run. Retrying this
|
|
7129
|
+
// synthetic assistant failure would resubmit the unchanged context that
|
|
7130
|
+
// maintenance failed to rewrite.
|
|
7131
|
+
this.#resolveRetry();
|
|
7132
|
+
return;
|
|
7133
|
+
}
|
|
7086
7134
|
|
|
7087
7135
|
// Check for retryable errors first (overloaded, rate limit, server errors)
|
|
7088
7136
|
if (this.#isRetryableError(msg)) {
|
|
@@ -8580,7 +8628,8 @@ export class AgentSession {
|
|
|
8580
8628
|
? this.#sdkRunTokensByAttemptScope.get(deliveryScope as AttemptScope)
|
|
8581
8629
|
: undefined;
|
|
8582
8630
|
const isTerminalAgentEnd =
|
|
8583
|
-
event.type === "agent_end" &&
|
|
8631
|
+
event.type === "agent_end" &&
|
|
8632
|
+
!(event.stopReason === "maintenance" && isContinuingMidRunMaintenanceOutcome(event.maintenanceOutcome));
|
|
8584
8633
|
const finishAttempt = () => {
|
|
8585
8634
|
if (!isTerminalAgentEnd) return;
|
|
8586
8635
|
// A merged wake batch whose flush fired while still streaming cleared its
|
|
@@ -9371,10 +9420,10 @@ export class AgentSession {
|
|
|
9371
9420
|
// one here left signal exit orphaning the subprocess. Each runner clears
|
|
9372
9421
|
// its set, so a graceful dispose running first makes this a no-op rather
|
|
9373
9422
|
// than a double free.
|
|
9374
|
-
this.#
|
|
9423
|
+
this.#claimToolSessionCleanups().catch((error: unknown) =>
|
|
9375
9424
|
logger.warn("signal teardown: tool session cleanups failed", { error }),
|
|
9376
9425
|
),
|
|
9377
|
-
this.#
|
|
9426
|
+
this.#claimToolSessionTransitionCleanups().catch((error: unknown) =>
|
|
9378
9427
|
logger.warn("signal teardown: tool session transition cleanups failed", { error }),
|
|
9379
9428
|
),
|
|
9380
9429
|
]);
|
|
@@ -14200,6 +14249,25 @@ export class AgentSession {
|
|
|
14200
14249
|
await this.refreshBaseSystemPrompt();
|
|
14201
14250
|
}
|
|
14202
14251
|
|
|
14252
|
+
/** Refresh the live registered-skill catalog after install/remove/reload. */
|
|
14253
|
+
async reloadSkills(cwd = this.sessionManager.getCwd()): Promise<void> {
|
|
14254
|
+
if (!this.#reloadSkills) return;
|
|
14255
|
+
const reloaded = await this.#reloadSkills(cwd);
|
|
14256
|
+
const previousSkills = this.#skills;
|
|
14257
|
+
const previousWarnings = this.#skillWarnings;
|
|
14258
|
+
this.#skills = reloaded.skills;
|
|
14259
|
+
this.#skillWarnings = reloaded.warnings;
|
|
14260
|
+
try {
|
|
14261
|
+
await this.refreshBaseSystemPrompt();
|
|
14262
|
+
} catch (error) {
|
|
14263
|
+
this.#skills = previousSkills;
|
|
14264
|
+
this.#skillWarnings = previousWarnings;
|
|
14265
|
+
await this.refreshBaseSystemPrompt().catch(() => {});
|
|
14266
|
+
throw error;
|
|
14267
|
+
}
|
|
14268
|
+
this.#onSkillsReloaded?.(reloaded.skills, reloaded.warnings);
|
|
14269
|
+
}
|
|
14270
|
+
|
|
14203
14271
|
/**
|
|
14204
14272
|
* Retire the cached workspace tree after a rescope so the next turn re-scans
|
|
14205
14273
|
* at the new cwd instead of re-presenting the abandoned launcher root.
|
|
@@ -18407,18 +18475,23 @@ export class AgentSession {
|
|
|
18407
18475
|
* prune → promote → compact machinery and returns an explicit outcome.
|
|
18408
18476
|
*
|
|
18409
18477
|
* A non-"not-needed" outcome ends the current run losslessly
|
|
18410
|
-
* (`agent_end.stopReason === "maintenance"`)
|
|
18411
|
-
*
|
|
18412
|
-
* This method never self-continues, runs goal-runtime
|
|
18413
|
-
* state, or emits a user-facing pause.
|
|
18478
|
+
* (`agent_end.stopReason === "maintenance"`). The `agent_end` handler resumes
|
|
18479
|
+
* committed maintenance with no synthetic prompt and terminalizes failed or
|
|
18480
|
+
* aborted maintenance. This method never self-continues, runs goal-runtime
|
|
18481
|
+
* hooks, clears skill state, or emits a user-facing pause.
|
|
18414
18482
|
*/
|
|
18415
18483
|
async #runMidRunMaintenance(
|
|
18416
18484
|
context: AgentContext,
|
|
18417
18485
|
lifecycle: MidRunMaintenanceLifecycle,
|
|
18418
18486
|
): Promise<ContextMaintenanceResult> {
|
|
18419
|
-
const result = (
|
|
18487
|
+
const result = (
|
|
18488
|
+
outcome: MidRunMaintenanceOutcome,
|
|
18489
|
+
releaseCurrentContext = false,
|
|
18490
|
+
errorMessage?: string,
|
|
18491
|
+
): ContextMaintenanceResult => ({
|
|
18420
18492
|
outcome,
|
|
18421
18493
|
...(releaseCurrentContext ? { releaseCurrentContext: true } : {}),
|
|
18494
|
+
...(errorMessage ? { errorMessage } : {}),
|
|
18422
18495
|
});
|
|
18423
18496
|
if (this.#isDisposed) return { outcome: "aborted" };
|
|
18424
18497
|
const invocationController = new AbortController();
|
|
@@ -18529,7 +18602,13 @@ export class AgentSession {
|
|
|
18529
18602
|
if (compactionStatus.kind === "aborted") {
|
|
18530
18603
|
return compactionStatus.source === "hook" ? result("not-needed") : result("aborted");
|
|
18531
18604
|
}
|
|
18532
|
-
return result(
|
|
18605
|
+
return result(
|
|
18606
|
+
"failed",
|
|
18607
|
+
false,
|
|
18608
|
+
compactionStatus.kind === "failed"
|
|
18609
|
+
? compactionStatus.errorMessage
|
|
18610
|
+
: "Context maintenance could not commit a compaction before the next model request.",
|
|
18611
|
+
);
|
|
18533
18612
|
} finally {
|
|
18534
18613
|
this.#activeMidRunBarrierControllers.delete(invocationController);
|
|
18535
18614
|
}
|
|
@@ -19643,12 +19722,15 @@ export class AgentSession {
|
|
|
19643
19722
|
*/
|
|
19644
19723
|
#maintenanceProviderTransport(): {
|
|
19645
19724
|
sessionId: string | undefined;
|
|
19725
|
+
providerSessionId: string | undefined;
|
|
19646
19726
|
providerSessionState: Map<string, ProviderSessionState>;
|
|
19647
19727
|
preferWebsockets: boolean | undefined;
|
|
19648
19728
|
remoteCompactionFallbackHealth: RemoteCompactionFallbackHealthHooks;
|
|
19649
19729
|
} {
|
|
19730
|
+
const providerSessionId = this.agent.providerSessionId ?? this.agent.sessionId;
|
|
19650
19731
|
return {
|
|
19651
|
-
sessionId:
|
|
19732
|
+
sessionId: providerSessionId,
|
|
19733
|
+
providerSessionId,
|
|
19652
19734
|
providerSessionState: this.#providerSessionState,
|
|
19653
19735
|
preferWebsockets: this.agent.preferWebsockets,
|
|
19654
19736
|
remoteCompactionFallbackHealth: this.#remoteCompactionFallbackHealth,
|
|
@@ -20286,7 +20368,7 @@ export class AgentSession {
|
|
|
20286
20368
|
? `Context overflow recovery failed: ${errorMessage}`
|
|
20287
20369
|
: `Auto-compaction failed: ${errorMessage}`,
|
|
20288
20370
|
});
|
|
20289
|
-
return { kind: "failed" };
|
|
20371
|
+
return { kind: "failed", errorMessage };
|
|
20290
20372
|
} finally {
|
|
20291
20373
|
if (this.#autoCompactionAbortController === autoCompactionAbortController) {
|
|
20292
20374
|
this.#autoCompactionAbortController = undefined;
|
|
@@ -22350,7 +22432,10 @@ export class AgentSession {
|
|
|
22350
22432
|
onChunk,
|
|
22351
22433
|
signal: abortController.signal,
|
|
22352
22434
|
});
|
|
22353
|
-
|
|
22435
|
+
// A retained kernel can finish after strict session close has fenced
|
|
22436
|
+
// persistence. The caller still receives its completed result, but it
|
|
22437
|
+
// must not reopen a closing session to append history.
|
|
22438
|
+
if (!this.#evalExecutionDisposing) this.recordPythonResult(code, result, options);
|
|
22354
22439
|
return result;
|
|
22355
22440
|
})();
|
|
22356
22441
|
return await this.trackEvalExecution(execution, abortController);
|
|
@@ -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;
|