@gajae-code/coding-agent 0.12.0 → 0.12.2
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 +111 -0
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/config/settings-schema.d.ts +56 -2
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +16 -2
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/ralplan-review-conflicts.d.ts +114 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +23 -3
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +25 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +37 -80
- package/dist/types/modes/acp/acp-agent.d.ts +2 -19
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +16 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +18 -0
- package/dist/types/modes/components/settings-selector.d.ts +9 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +1 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +9 -0
- package/dist/types/modes/theme/theme.d.ts +3 -1
- package/dist/types/modes/types.d.ts +32 -0
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +5 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/index.d.ts +29 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +8 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +7 -3
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +40 -2
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +30 -4
- package/dist/types/session/session-manager.d.ts +23 -6
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +36 -7
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -0
- package/dist/types/skill-state/workflow-hud.d.ts +6 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +7 -1
- package/dist/types/task/output-manager.d.ts +1 -0
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +9 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +6 -0
- package/dist/types/tools/output-meta.d.ts +23 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +0 -6
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +10 -8
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/dogfood-ralplan-review-conflicts.ts +272 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +290 -0
- package/src/async/job-manager.ts +99 -39
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/commands/team.ts +19 -1
- package/src/config/file-lock.ts +11 -2
- package/src/config/settings-schema.ts +53 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/debug/index.ts +42 -17
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ralplan/SKILL.md +25 -20
- package/src/defaults/gjc/skills/team/SKILL.md +2 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +39 -26
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +18 -1
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- package/src/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/launch-worktree.ts +103 -1
- package/src/gjc-runtime/ledger-event-renderer.ts +1 -0
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/ralplan-review-conflicts.ts +472 -0
- package/src/gjc-runtime/ralplan-runtime.ts +491 -27
- package/src/gjc-runtime/team-launch.ts +8 -0
- package/src/gjc-runtime/team-runtime.ts +140 -32
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +10 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-evidence.ts +6 -74
- package/src/gjc-runtime/ultragoal-runtime.ts +635 -612
- package/src/gjc-runtime/workflow-manifest.generated.json +37 -99
- package/src/gjc-runtime/workflow-manifest.ts +21 -70
- package/src/internal-urls/docs-index.generated.ts +16 -16
- package/src/modes/DESIGN.md +104 -0
- package/src/modes/acp/acp-agent.ts +298 -186
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +30 -1
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +68 -30
- package/src/modes/components/session-observer-overlay.ts +305 -86
- package/src/modes/components/settings-selector.ts +56 -5
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-status-header.ts +3 -15
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +42 -34
- package/src/modes/controllers/event-controller.ts +27 -16
- package/src/modes/controllers/extension-ui-controller.ts +193 -34
- package/src/modes/controllers/selector-controller.ts +160 -22
- package/src/modes/interactive-mode.ts +189 -62
- package/src/modes/jobs-observer.ts +1 -1
- package/src/modes/runtime-init.ts +3 -0
- package/src/modes/theme/theme.ts +11 -9
- package/src/modes/types.ts +88 -0
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -4
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +18 -13
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +7 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/index.ts +661 -126
- package/src/sdk/bus/kind-aware-reconciliation.ts +148 -73
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/reconciliation-store.ts +95 -16
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +12 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -0
- package/src/sdk/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +33 -0
- package/src/sdk/session.ts +89 -9
- package/src/session/agent-session.ts +844 -173
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +200 -111
- package/src/session/internal/managed-session-storage.ts +492 -62
- package/src/session/session-manager.ts +1614 -435
- package/src/session/session-storage.ts +38 -45
- package/src/session/streaming-output.ts +238 -68
- package/src/setup/credential-import.ts +75 -13
- package/src/skill-state/active-state.ts +32 -0
- package/src/skill-state/workflow-hud.ts +17 -0
- package/src/skill-state/workflow-mutation-guard.ts +496 -2
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +280 -45
- package/src/task/output-manager.ts +24 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +34 -8
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +86 -55
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +6 -0
- package/src/tools/output-meta.ts +108 -14
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +18 -0
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
package/src/cli/plugin-cli.ts
CHANGED
|
@@ -7,7 +7,19 @@
|
|
|
7
7
|
import { APP_NAME, getProjectDir } from "@gajae-code/utils";
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import { resolveOrDefaultProjectRegistryPath } from "../discovery/helpers";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
applyGjcBundleUpdate,
|
|
12
|
+
bundleIdentity,
|
|
13
|
+
type GjcBundleIdentity,
|
|
14
|
+
type GjcBundleSummary,
|
|
15
|
+
GjcPluginLoadError,
|
|
16
|
+
getGjcBundle,
|
|
17
|
+
installGjcBundle,
|
|
18
|
+
isGjcPluginBundleSource,
|
|
19
|
+
isGjcPluginSourceShape,
|
|
20
|
+
listGjcBundles,
|
|
21
|
+
previewGjcBundleUpdate,
|
|
22
|
+
} from "../extensibility/gjc-plugins";
|
|
11
23
|
import { PluginManager, parseSettingValue, validateSetting } from "../extensibility/plugins";
|
|
12
24
|
import {
|
|
13
25
|
getInstalledPluginsRegistryPath,
|
|
@@ -312,9 +324,118 @@ async function handleDiscover(args: string[], _flags: PluginCommandArgs["flags"]
|
|
|
312
324
|
}
|
|
313
325
|
}
|
|
314
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Scope-qualified GJC bundle upgrade: re-resolve the stored source, review the
|
|
329
|
+
* candidate, then apply it as a compare-and-swap. `--dry-run` stops after the
|
|
330
|
+
* preview. Requires exactly one of `--user` / `--project` because (scope, name)
|
|
331
|
+
* is the canonical target.
|
|
332
|
+
*/
|
|
333
|
+
async function handleGjcUpgrade(name: string, flags: PluginCommandArgs["flags"]): Promise<void> {
|
|
334
|
+
if (flags.user === flags.project) {
|
|
335
|
+
console.error(chalk.red(`GJC bundle upgrade requires exactly one of --user or --project for "${name}".`));
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
const scope: "user" | "project" = flags.user ? "user" : "project";
|
|
339
|
+
const ctx = { cwd: getProjectDir() };
|
|
340
|
+
const identity = bundleIdentity(scope, name);
|
|
341
|
+
|
|
342
|
+
const emitError = (error: { code: string; message: string; recovery?: string }): never => {
|
|
343
|
+
if (flags.json) console.log(JSON.stringify({ error }, null, 2));
|
|
344
|
+
else {
|
|
345
|
+
console.error(chalk.red(`${theme.status.error} ${error.message}`));
|
|
346
|
+
if (error.recovery) console.error(chalk.dim(` Try: ${error.recovery}`));
|
|
347
|
+
}
|
|
348
|
+
process.exit(3);
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// Source re-resolution can throw with a cause carrying the raw locator, so
|
|
352
|
+
// the whole flow reports a stable code instead of the underlying error.
|
|
353
|
+
try {
|
|
354
|
+
await runGjcUpgrade(ctx, identity, name, scope, flags, emitError);
|
|
355
|
+
} catch (err) {
|
|
356
|
+
const reason = err instanceof GjcPluginLoadError ? err.code : "upgrade_failed";
|
|
357
|
+
console.error(chalk.red(`${theme.status.error} Failed to upgrade GJC bundle ${name} (${reason})`));
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function runGjcUpgrade(
|
|
363
|
+
ctx: { cwd: string },
|
|
364
|
+
identity: GjcBundleIdentity,
|
|
365
|
+
name: string,
|
|
366
|
+
scope: "user" | "project",
|
|
367
|
+
flags: PluginCommandArgs["flags"],
|
|
368
|
+
emitError: (error: { code: string; message: string; recovery?: string }) => never,
|
|
369
|
+
): Promise<void> {
|
|
370
|
+
const preview = await previewGjcBundleUpdate(ctx, identity);
|
|
371
|
+
if (!preview.ok) emitError(preview.error);
|
|
372
|
+
else if (flags.dryRun || !preview.value.changed) {
|
|
373
|
+
const { changed, candidateVersion, addedSurfaceIds, removedSurfaceIds } = preview.value;
|
|
374
|
+
if (flags.json) {
|
|
375
|
+
console.log(
|
|
376
|
+
JSON.stringify(
|
|
377
|
+
{
|
|
378
|
+
status: changed ? "update-available" : "up-to-date",
|
|
379
|
+
identity,
|
|
380
|
+
currentVersion: preview.value.current.version,
|
|
381
|
+
candidateVersion,
|
|
382
|
+
addedSurfaceIds,
|
|
383
|
+
removedSurfaceIds,
|
|
384
|
+
},
|
|
385
|
+
null,
|
|
386
|
+
2,
|
|
387
|
+
),
|
|
388
|
+
);
|
|
389
|
+
} else if (!changed) {
|
|
390
|
+
console.log(chalk.dim(`GJC bundle ${name} (${scope}) is up to date at ${preview.value.current.version}`));
|
|
391
|
+
} else {
|
|
392
|
+
console.log(
|
|
393
|
+
chalk.cyan(`[dry-run] ${name} (${scope}): ${preview.value.current.version} -> ${candidateVersion}`),
|
|
394
|
+
);
|
|
395
|
+
if (addedSurfaceIds.length > 0) console.log(chalk.dim(` + ${addedSurfaceIds.join(", ")}`));
|
|
396
|
+
if (removedSurfaceIds.length > 0) console.log(chalk.dim(` - ${removedSurfaceIds.join(", ")}`));
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
const applied = await applyGjcBundleUpdate(ctx, preview.value.token);
|
|
400
|
+
if (!applied.ok) emitError(applied.error);
|
|
401
|
+
else if (flags.json) {
|
|
402
|
+
console.log(
|
|
403
|
+
JSON.stringify(
|
|
404
|
+
{
|
|
405
|
+
status: applied.value.status,
|
|
406
|
+
bundle: applied.value.summary,
|
|
407
|
+
remnantCount: applied.value.remnantCount,
|
|
408
|
+
},
|
|
409
|
+
null,
|
|
410
|
+
2,
|
|
411
|
+
),
|
|
412
|
+
);
|
|
413
|
+
} else {
|
|
414
|
+
console.log(
|
|
415
|
+
chalk.green(
|
|
416
|
+
`${theme.status.success} ${applied.value.status} GJC bundle ${name}@${applied.value.summary.version} (${scope})`,
|
|
417
|
+
),
|
|
418
|
+
);
|
|
419
|
+
if (applied.value.remnantCount > 0) {
|
|
420
|
+
console.error(chalk.yellow(` ${applied.value.remnantCount} leftover directory could not be removed`));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
315
426
|
async function handleUpgrade(args: string[], flags: PluginCommandArgs["flags"]): Promise<void> {
|
|
316
|
-
const manager = await makeMarketplaceManager();
|
|
317
427
|
const pluginId = args[0];
|
|
428
|
+
// Scope-qualified GJC bundles upgrade through the lifecycle service, never
|
|
429
|
+
// through the marketplace manager.
|
|
430
|
+
if (pluginId && (flags.user || flags.project)) {
|
|
431
|
+
const scope: "user" | "project" = flags.user ? "user" : "project";
|
|
432
|
+
const existing = await getGjcBundle({ cwd: getProjectDir() }, bundleIdentity(scope, pluginId));
|
|
433
|
+
if (existing.ok) {
|
|
434
|
+
await handleGjcUpgrade(pluginId, flags);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const manager = await makeMarketplaceManager();
|
|
318
439
|
try {
|
|
319
440
|
if (pluginId) {
|
|
320
441
|
if (flags.scope) {
|
|
@@ -349,6 +470,15 @@ async function handleUpgrade(args: string[], flags: PluginCommandArgs["flags"]):
|
|
|
349
470
|
}
|
|
350
471
|
}
|
|
351
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Stable, non-identifying reason for an install failure. The raw spec and the
|
|
475
|
+
* underlying cause can both carry credentials, a query string, or an absolute
|
|
476
|
+
* home path, so neither is ever printed.
|
|
477
|
+
*/
|
|
478
|
+
function describeInstallFailure(error: unknown): string {
|
|
479
|
+
return error instanceof GjcPluginLoadError ? error.code : "install_failed";
|
|
480
|
+
}
|
|
481
|
+
|
|
352
482
|
async function handleInstall(
|
|
353
483
|
manager: PluginManager,
|
|
354
484
|
packages: string[],
|
|
@@ -374,27 +504,52 @@ async function handleInstall(
|
|
|
374
504
|
const knownMarketplaces = new Set((await mktMgr.listMarketplaces()).map(m => m.name));
|
|
375
505
|
|
|
376
506
|
for (const spec of packages) {
|
|
377
|
-
// GJC
|
|
378
|
-
// git
|
|
379
|
-
|
|
507
|
+
// A GJC bundle is identified by the SHAPE of its source: a filesystem path,
|
|
508
|
+
// a git locator, or a tarball. npm and marketplace specs are never any of
|
|
509
|
+
// those, so shape alone separates the two worlds without resolving.
|
|
510
|
+
//
|
|
511
|
+
// Shape is checked BEFORE `isGjcPluginBundleSource`, which resolves the
|
|
512
|
+
// source: a deleted or unreachable GJC source fails that probe and would
|
|
513
|
+
// otherwise fall through to npm, losing the create-only refusal the
|
|
514
|
+
// lifecycle owes for an already-installed target.
|
|
515
|
+
if (isGjcPluginSourceShape(spec) || (await isGjcPluginBundleSource(spec))) {
|
|
380
516
|
if (flags.user === flags.project) {
|
|
381
517
|
console.error(
|
|
382
|
-
|
|
518
|
+
// The spec can carry credentials or an absolute home path, so name
|
|
519
|
+
// the missing flag instead of echoing it back.
|
|
520
|
+
chalk.red("GJC plugin bundle install requires exactly one of --user or --project."),
|
|
383
521
|
);
|
|
384
522
|
process.exit(1);
|
|
385
523
|
}
|
|
386
524
|
const scope: "user" | "project" = flags.user ? "user" : "project";
|
|
387
525
|
try {
|
|
388
|
-
const res = await
|
|
526
|
+
const res = await installGjcBundle({ cwd: getProjectDir() }, scope, spec);
|
|
527
|
+
if (!res.ok) {
|
|
528
|
+
const doc = {
|
|
529
|
+
error: { code: res.error.code, message: res.error.message, recovery: res.error.recovery },
|
|
530
|
+
};
|
|
531
|
+
if (flags.json) console.log(JSON.stringify(doc, null, 2));
|
|
532
|
+
else {
|
|
533
|
+
console.error(chalk.red(`${theme.status.error} ${res.error.message}`));
|
|
534
|
+
if (res.error.recovery) console.error(chalk.dim(` Try: ${res.error.recovery}`));
|
|
535
|
+
}
|
|
536
|
+
process.exit(3);
|
|
537
|
+
}
|
|
538
|
+
const { summary } = res.value;
|
|
389
539
|
if (flags.json) {
|
|
390
|
-
console.log(JSON.stringify({
|
|
540
|
+
console.log(JSON.stringify({ status: res.value.status, bundle: summary }, null, 2));
|
|
391
541
|
} else {
|
|
392
542
|
console.log(
|
|
393
|
-
chalk.green(
|
|
543
|
+
chalk.green(
|
|
544
|
+
`${theme.status.success} installed GJC plugin ${summary.identity.name}@${summary.version} (${scope})`,
|
|
545
|
+
),
|
|
394
546
|
);
|
|
395
547
|
}
|
|
396
548
|
} catch (err) {
|
|
397
|
-
|
|
549
|
+
// Never echo the raw spec or the underlying cause: either can carry
|
|
550
|
+
// credentials, a query string, or an absolute home path.
|
|
551
|
+
const reason = err instanceof GjcPluginLoadError ? err.code : "install_failed";
|
|
552
|
+
console.error(chalk.red(`${theme.status.error} Failed to install GJC bundle (${reason})`));
|
|
398
553
|
process.exit(1);
|
|
399
554
|
}
|
|
400
555
|
continue;
|
|
@@ -414,7 +569,9 @@ async function handleInstall(
|
|
|
414
569
|
),
|
|
415
570
|
);
|
|
416
571
|
} catch (err) {
|
|
417
|
-
|
|
572
|
+
// The spec can carry credentials, a query string, or an absolute home
|
|
573
|
+
// path, so report the failure without echoing it or the raw cause.
|
|
574
|
+
console.error(chalk.red(`${theme.status.error} Failed to install plugin (${describeInstallFailure(err)})`));
|
|
418
575
|
process.exit(1);
|
|
419
576
|
}
|
|
420
577
|
continue;
|
|
@@ -449,7 +606,9 @@ async function handleInstall(
|
|
|
449
606
|
}
|
|
450
607
|
}
|
|
451
608
|
} catch (err) {
|
|
452
|
-
|
|
609
|
+
// The spec can carry credentials, a query string, or an absolute home
|
|
610
|
+
// path, so report the failure without echoing it or the raw cause.
|
|
611
|
+
console.error(chalk.red(`${theme.status.error} Failed to install plugin (${describeInstallFailure(err)})`));
|
|
453
612
|
process.exit(1);
|
|
454
613
|
}
|
|
455
614
|
}
|
|
@@ -503,8 +662,7 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
|
|
|
503
662
|
const mktMgr = await makeMarketplaceManager();
|
|
504
663
|
const mktPlugins = await mktMgr.listInstalledPlugins();
|
|
505
664
|
const cwd = getProjectDir();
|
|
506
|
-
const [
|
|
507
|
-
const gjcBundles = [...gjcUser.plugins, ...gjcProject.plugins];
|
|
665
|
+
const gjcBundles: GjcBundleSummary[] = await listGjcBundles({ cwd });
|
|
508
666
|
|
|
509
667
|
if (flags.json) {
|
|
510
668
|
console.log(JSON.stringify({ npm: npmPlugins, marketplace: mktPlugins, gjc: gjcBundles }, null, 2));
|
|
@@ -559,9 +717,9 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
|
|
|
559
717
|
console.log(chalk.bold("GJC Plugin Bundles:\n"));
|
|
560
718
|
for (const plugin of gjcBundles) {
|
|
561
719
|
const status = plugin.enabled ? chalk.green(theme.status.enabled) : chalk.dim(theme.status.disabled);
|
|
562
|
-
const scopeLabel = chalk.dim(` (${plugin.scope})`);
|
|
563
|
-
const disabledCount = plugin.
|
|
564
|
-
const quarantineCount = plugin.
|
|
720
|
+
const scopeLabel = chalk.dim(` (${plugin.identity.scope})`);
|
|
721
|
+
const disabledCount = plugin.surfaces.filter(s => !s.enabled).length;
|
|
722
|
+
const quarantineCount = plugin.surfaces.filter(s => s.quarantined).length;
|
|
565
723
|
const detail = [
|
|
566
724
|
disabledCount > 0 ? `${disabledCount} disabled` : null,
|
|
567
725
|
quarantineCount > 0 ? `${quarantineCount} quarantined` : null,
|
|
@@ -569,7 +727,7 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
|
|
|
569
727
|
.filter((v): v is string => Boolean(v))
|
|
570
728
|
.join(", ");
|
|
571
729
|
console.log(
|
|
572
|
-
`${status} ${plugin.name}@${plugin.version}${scopeLabel}${detail ? chalk.dim(` — ${detail}`) : ""}`,
|
|
730
|
+
`${status} ${plugin.identity.name}@${plugin.version}${scopeLabel}${detail ? chalk.dim(` — ${detail}`) : ""}`,
|
|
573
731
|
);
|
|
574
732
|
}
|
|
575
733
|
}
|
package/src/commands/team.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
readGjcTeamSnapshot,
|
|
14
14
|
shutdownGjcTeam,
|
|
15
15
|
startGjcTeam,
|
|
16
|
+
UnknownGjcTeamApiOperationError,
|
|
16
17
|
} from "../gjc-runtime/team-runtime";
|
|
17
18
|
import { syncSkillActiveState } from "../skill-state/active-state";
|
|
18
19
|
|
|
@@ -183,7 +184,24 @@ export default class Team extends Command {
|
|
|
183
184
|
return;
|
|
184
185
|
}
|
|
185
186
|
const input = parseInputFlag(rest);
|
|
186
|
-
|
|
187
|
+
let result: unknown;
|
|
188
|
+
try {
|
|
189
|
+
result = await executeGjcTeamApiOperation(operation, input);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if (!(error instanceof UnknownGjcTeamApiOperationError)) throw error;
|
|
192
|
+
process.exitCode = 1;
|
|
193
|
+
if (json) {
|
|
194
|
+
writeReceipt({
|
|
195
|
+
ok: false,
|
|
196
|
+
error: error.code,
|
|
197
|
+
operation: error.operation,
|
|
198
|
+
suggestions: error.suggestions,
|
|
199
|
+
});
|
|
200
|
+
} else {
|
|
201
|
+
process.stderr.write(`${error.message}\n`);
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
187
205
|
const teamName = String(input.team_name ?? input.teamName ?? "").trim();
|
|
188
206
|
if (teamName) {
|
|
189
207
|
try {
|
package/src/config/file-lock.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Stats } from "node:fs";
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { isEnoent } from "@gajae-code/utils/fs-error";
|
|
4
|
+
import { hasFsCode, isEnoent } from "@gajae-code/utils/fs-error";
|
|
5
5
|
|
|
6
6
|
export interface FileLockOptions {
|
|
7
7
|
staleMs?: number;
|
|
@@ -185,7 +185,16 @@ async function staleLockSnapshot(
|
|
|
185
185
|
staleMs: number,
|
|
186
186
|
startTimeCache?: Map<string, string | null>,
|
|
187
187
|
): Promise<LockStaleSnapshot> {
|
|
188
|
-
|
|
188
|
+
let info: LockInfo | null;
|
|
189
|
+
try {
|
|
190
|
+
info = await readLockInfo(lockPath);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
// Windows can transiently deny reads of a just-created lock metadata file
|
|
193
|
+
// while another contender is publishing it. Treat that as active
|
|
194
|
+
// contention and retry rather than failing the caller or reaping by path.
|
|
195
|
+
if (hasFsCode(error, "EPERM")) return { stale: false };
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
189
198
|
if (!info) {
|
|
190
199
|
try {
|
|
191
200
|
const stats = await fs.stat(lockPath);
|
|
@@ -275,6 +275,13 @@ export const SETTINGS_SCHEMA = {
|
|
|
275
275
|
values: ["copy-retain", "disabled"] as const,
|
|
276
276
|
default: "copy-retain",
|
|
277
277
|
},
|
|
278
|
+
// SDK-owned prompt deadline. Hidden from the UI; ACP has no separate timeout.
|
|
279
|
+
"sdk.promptDeadlineMs": {
|
|
280
|
+
type: "number",
|
|
281
|
+
default: 1_800_000,
|
|
282
|
+
description: "SDK-owned prompt deadline; ACP has no separate timeout.",
|
|
283
|
+
validate: (value: number) => Number.isSafeInteger(value) && value >= 60_000 && value <= 86_400_000,
|
|
284
|
+
},
|
|
278
285
|
|
|
279
286
|
// Notifications (shared daemon with Telegram/Discord/Slack presentation adapters)
|
|
280
287
|
"notifications.enabled": { type: "boolean", default: false },
|
|
@@ -287,6 +294,17 @@ export const SETTINGS_SCHEMA = {
|
|
|
287
294
|
"notifications.telegram.activation": { type: "record", default: {} as Record<string, unknown> },
|
|
288
295
|
"notifications.telegram.btw.enabled": { type: "boolean", default: true },
|
|
289
296
|
"notifications.telegram.streaming.enabled": { type: "boolean", default: true },
|
|
297
|
+
"notifications.telegram.sound": {
|
|
298
|
+
type: "enum",
|
|
299
|
+
values: ["all", "important", "none"] as const,
|
|
300
|
+
default: "all",
|
|
301
|
+
ui: {
|
|
302
|
+
tab: "notifications",
|
|
303
|
+
label: "Telegram Notification Sounds",
|
|
304
|
+
description: "Choose which Telegram notifications play a sound.",
|
|
305
|
+
editing: "notification-atomic",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
290
308
|
"notifications.telegram.rich.enabled": {
|
|
291
309
|
type: "boolean",
|
|
292
310
|
default: true,
|
|
@@ -489,6 +507,22 @@ export const SETTINGS_SCHEMA = {
|
|
|
489
507
|
options: "runtime",
|
|
490
508
|
},
|
|
491
509
|
},
|
|
510
|
+
"session.resumeModelBehavior": {
|
|
511
|
+
type: "enum",
|
|
512
|
+
values: ["keepSessionModel", "useCurrentDefault", "ask"] as const,
|
|
513
|
+
default: "keepSessionModel",
|
|
514
|
+
ui: {
|
|
515
|
+
tab: "model",
|
|
516
|
+
label: "Resume Model Behavior",
|
|
517
|
+
description:
|
|
518
|
+
"When resuming a session: keep the model that session last used, switch to the currently configured default model, or ask (TUI only; falls back to keeping the session's model in headless/CLI resume).",
|
|
519
|
+
options: [
|
|
520
|
+
{ value: "keepSessionModel", label: "Keep session's saved model" },
|
|
521
|
+
{ value: "useCurrentDefault", label: "Use current default model" },
|
|
522
|
+
{ value: "ask", label: "Ask on resume (TUI only)" },
|
|
523
|
+
],
|
|
524
|
+
},
|
|
525
|
+
},
|
|
492
526
|
|
|
493
527
|
modelTags: { type: "record", default: EMPTY_MODEL_TAGS_RECORD },
|
|
494
528
|
|
|
@@ -501,6 +535,11 @@ export const SETTINGS_SCHEMA = {
|
|
|
501
535
|
default: 0.05,
|
|
502
536
|
validate: (value: number) => Number.isFinite(value) && value > 0 && value <= 1,
|
|
503
537
|
},
|
|
538
|
+
"gjc.ralplan.autoHandoff": {
|
|
539
|
+
type: "enum",
|
|
540
|
+
values: ["off", "ultragoal", "team"],
|
|
541
|
+
default: "off",
|
|
542
|
+
},
|
|
504
543
|
"gjc.ralplan.maxIterations": {
|
|
505
544
|
type: "number",
|
|
506
545
|
default: 5,
|
|
@@ -834,8 +873,8 @@ export const SETTINGS_SCHEMA = {
|
|
|
834
873
|
default: true,
|
|
835
874
|
ui: {
|
|
836
875
|
tab: "appearance",
|
|
837
|
-
label: "
|
|
838
|
-
description: "Show contextual keyboard shortcuts in the
|
|
876
|
+
label: "Composer Shortcut Hints",
|
|
877
|
+
description: "Show contextual keyboard shortcuts in the composer placeholder",
|
|
839
878
|
},
|
|
840
879
|
},
|
|
841
880
|
|
|
@@ -1224,6 +1263,16 @@ export const SETTINGS_SCHEMA = {
|
|
|
1224
1263
|
"Maximum provider stream replay retries for replay-safe transient stream failures. Counts retries, not the first attempt. Set to 0 to disable provider stream retries.",
|
|
1225
1264
|
},
|
|
1226
1265
|
},
|
|
1266
|
+
"retry.streamFirstEventTimeoutMs": {
|
|
1267
|
+
type: "number",
|
|
1268
|
+
default: 100_000,
|
|
1269
|
+
validate: (value: number) => Number.isFinite(value) && value >= 0,
|
|
1270
|
+
ui: {
|
|
1271
|
+
tab: "model",
|
|
1272
|
+
label: "First Event Timeout",
|
|
1273
|
+
description: "Maximum wait for the first provider stream event, in ms. Set to 0 to disable the watchdog.",
|
|
1274
|
+
},
|
|
1275
|
+
},
|
|
1227
1276
|
"retry.fallbackChains": { type: "record", default: {} as Record<string, string[]> },
|
|
1228
1277
|
"retry.fallbackRevertPolicy": {
|
|
1229
1278
|
type: "enum",
|
|
@@ -3810,6 +3859,7 @@ export interface RetrySettings {
|
|
|
3810
3859
|
maxDelayMs: number;
|
|
3811
3860
|
requestMaxRetries: number;
|
|
3812
3861
|
streamMaxRetries: number;
|
|
3862
|
+
streamFirstEventTimeoutMs: number;
|
|
3813
3863
|
}
|
|
3814
3864
|
|
|
3815
3865
|
export interface MemoriesSettings {
|
|
@@ -3929,6 +3979,7 @@ export interface NotificationsSettings {
|
|
|
3929
3979
|
telegram: {
|
|
3930
3980
|
botToken: string | undefined;
|
|
3931
3981
|
chatId: string | undefined;
|
|
3982
|
+
sound: "all" | "important" | "none";
|
|
3932
3983
|
btw: {
|
|
3933
3984
|
enabled: boolean;
|
|
3934
3985
|
};
|
|
@@ -147,7 +147,7 @@ function askSchema(labels: string[], multi: boolean, allowEmpty: boolean): JsonS
|
|
|
147
147
|
}
|
|
148
148
|
export function decodeAskGateV1(gate: WorkflowGate): PrivateAskGateCodecV1 | null {
|
|
149
149
|
if (
|
|
150
|
-
gate.stage !== "deep-interview" ||
|
|
150
|
+
(gate.stage !== "deep-interview" && gate.stage !== "ralplan" && gate.stage !== "ultragoal") ||
|
|
151
151
|
gate.kind !== "question" ||
|
|
152
152
|
!isRecord(gate.context) ||
|
|
153
153
|
!boundedText(gate.context.prompt, MAX_TEXT) ||
|
|
@@ -859,7 +859,7 @@ interface RuntimePromptAcknowledgement {
|
|
|
859
859
|
turn_id: string;
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
-
function
|
|
862
|
+
function sdkResultPayload(result: unknown): Record<string, unknown> | null {
|
|
863
863
|
const response = asRecord(result);
|
|
864
864
|
if (!response) return null;
|
|
865
865
|
const envelope = ["ok", "result", "error"].some(key => Object.hasOwn(response, key));
|
|
@@ -887,7 +887,7 @@ function runtimeAcknowledgementIdentity(
|
|
|
887
887
|
}
|
|
888
888
|
|
|
889
889
|
function normalizeRuntimePromptAcknowledgement(result: unknown): RuntimePromptAcknowledgement {
|
|
890
|
-
const acknowledgement =
|
|
890
|
+
const acknowledgement = sdkResultPayload(result);
|
|
891
891
|
if (acknowledgement?.accepted !== true)
|
|
892
892
|
throw new SdkClientError("unavailable", "SDK did not acknowledge prompt delivery.");
|
|
893
893
|
return {
|
|
@@ -2458,15 +2458,8 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
2458
2458
|
items.push(...pageItems);
|
|
2459
2459
|
if (complete) {
|
|
2460
2460
|
const valid = items.every(item => {
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
const gate = item as WorkflowGateQueryRecord & WorkflowGate;
|
|
2464
|
-
return (
|
|
2465
|
-
gate.tag === "pending" &&
|
|
2466
|
-
typeof gate.gate_id === "string" &&
|
|
2467
|
-
gate.gate_id.length > 0 &&
|
|
2468
|
-
!!decodeAskGateV1(gate)
|
|
2469
|
-
);
|
|
2461
|
+
const encoded = JSON.stringify(item);
|
|
2462
|
+
return typeof encoded === "string" && Buffer.byteLength(encoded) <= 16 * 1024;
|
|
2470
2463
|
});
|
|
2471
2464
|
return valid
|
|
2472
2465
|
? { items, revision, complete: true, reason: null }
|
|
@@ -4492,7 +4485,7 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
|
|
|
4492
4485
|
{ id: gateId, response: translated, expectedSessionId: sessionId },
|
|
4493
4486
|
(claimed as { requestId: string }).requestId,
|
|
4494
4487
|
);
|
|
4495
|
-
const resolution =
|
|
4488
|
+
const resolution = sdkResultPayload(result);
|
|
4496
4489
|
const status = resolution?.status;
|
|
4497
4490
|
if (status === "rejected") {
|
|
4498
4491
|
await withAdmittedSessionTransaction(questionPaths, sessionId, async transaction => {
|
package/src/debug/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { getSessionsDir } from "@gajae-code/utils";
|
|
|
11
11
|
import { DynamicBorder } from "../modes/components/dynamic-border";
|
|
12
12
|
import { getSelectListTheme, getSymbolTheme, theme } from "../modes/theme/theme";
|
|
13
13
|
import type { InteractiveModeContext } from "../modes/types";
|
|
14
|
+
import { suspendInteractiveActivityIndicator } from "../modes/types";
|
|
14
15
|
import { formatBytes } from "../tools/render-utils";
|
|
15
16
|
import { openPath } from "../utils/open";
|
|
16
17
|
import { DebugLogViewerComponent } from "./log-viewer";
|
|
@@ -77,10 +78,12 @@ export class DebugSelectorComponent extends Container {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
handleInput(keyData: string): void {
|
|
81
|
+
if (this.ctx.isStopped?.()) return;
|
|
80
82
|
this.#selectList.handleInput(keyData);
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
async #handleSelection(value: string): Promise<void> {
|
|
86
|
+
if (this.ctx.isStopped?.()) return;
|
|
84
87
|
switch (value) {
|
|
85
88
|
case "open-artifacts":
|
|
86
89
|
await this.#handleOpenArtifacts();
|
|
@@ -115,12 +118,23 @@ export class DebugSelectorComponent extends Container {
|
|
|
115
118
|
}
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
#finishStatusLoader(loader: Loader, releaseActivityIndicator: () => void): void {
|
|
122
|
+
loader.stop();
|
|
123
|
+
if (!this.ctx.isStopped?.()) this.ctx.statusContainer.clear();
|
|
124
|
+
releaseActivityIndicator();
|
|
125
|
+
}
|
|
126
|
+
|
|
118
127
|
async #handlePerformanceReport(): Promise<void> {
|
|
119
128
|
// Start profiling
|
|
120
129
|
let session: ProfilerSession;
|
|
121
130
|
try {
|
|
122
131
|
session = await startCpuProfile();
|
|
132
|
+
if (this.ctx.isStopped?.()) {
|
|
133
|
+
await session.stop().catch(() => {});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
123
136
|
} catch (err) {
|
|
137
|
+
if (this.ctx.isStopped?.()) return;
|
|
124
138
|
this.ctx.showError(`Failed to start profiler: ${err instanceof Error ? err.message : String(err)}`);
|
|
125
139
|
return;
|
|
126
140
|
}
|
|
@@ -151,9 +165,17 @@ export class DebugSelectorComponent extends Container {
|
|
|
151
165
|
resolve();
|
|
152
166
|
};
|
|
153
167
|
|
|
154
|
-
|
|
168
|
+
const stopped = Promise.withResolvers<void>();
|
|
169
|
+
const unsubscribeStop = this.ctx.onStop?.(() => stopped.resolve());
|
|
170
|
+
const stopWon = await Promise.race([promise.then(() => false), stopped.promise.then(() => true)]);
|
|
171
|
+
unsubscribeStop?.();
|
|
172
|
+
if (stopWon || this.ctx.isStopped?.()) {
|
|
173
|
+
await session.stop().catch(() => {});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
155
176
|
|
|
156
177
|
// Stop profiling and create report
|
|
178
|
+
const releaseActivityIndicator = suspendInteractiveActivityIndicator(this.ctx);
|
|
157
179
|
const loader = new Loader(
|
|
158
180
|
this.ctx.ui,
|
|
159
181
|
spinner => theme.fg("accent", spinner),
|
|
@@ -174,8 +196,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
174
196
|
workProfile,
|
|
175
197
|
});
|
|
176
198
|
|
|
177
|
-
loader
|
|
178
|
-
this.ctx.
|
|
199
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
200
|
+
if (this.ctx.isStopped?.()) return;
|
|
179
201
|
|
|
180
202
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
181
203
|
this.ctx.chatContainer.addChild(
|
|
@@ -184,8 +206,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
184
206
|
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", formatFileHyperlink(result.path)), 1, 0));
|
|
185
207
|
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
186
208
|
} catch (err) {
|
|
187
|
-
loader
|
|
188
|
-
this.ctx.
|
|
209
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
210
|
+
if (this.ctx.isStopped?.()) return;
|
|
189
211
|
this.ctx.showError(`Failed to create report: ${err instanceof Error ? err.message : String(err)}`);
|
|
190
212
|
}
|
|
191
213
|
|
|
@@ -219,6 +241,7 @@ export class DebugSelectorComponent extends Container {
|
|
|
219
241
|
}
|
|
220
242
|
|
|
221
243
|
async #handleDumpReport(): Promise<void> {
|
|
244
|
+
const releaseActivityIndicator = suspendInteractiveActivityIndicator(this.ctx);
|
|
222
245
|
const loader = new Loader(
|
|
223
246
|
this.ctx.ui,
|
|
224
247
|
spinner => theme.fg("accent", spinner),
|
|
@@ -235,8 +258,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
235
258
|
settings: this.#getResolvedSettings(),
|
|
236
259
|
});
|
|
237
260
|
|
|
238
|
-
loader
|
|
239
|
-
this.ctx.
|
|
261
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
262
|
+
if (this.ctx.isStopped?.()) return;
|
|
240
263
|
|
|
241
264
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
242
265
|
this.ctx.chatContainer.addChild(
|
|
@@ -245,8 +268,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
245
268
|
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", formatFileHyperlink(result.path)), 1, 0));
|
|
246
269
|
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
247
270
|
} catch (err) {
|
|
248
|
-
loader
|
|
249
|
-
this.ctx.
|
|
271
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
272
|
+
if (this.ctx.isStopped?.()) return;
|
|
250
273
|
this.ctx.showError(`Failed to create report: ${err instanceof Error ? err.message : String(err)}`);
|
|
251
274
|
}
|
|
252
275
|
|
|
@@ -254,6 +277,7 @@ export class DebugSelectorComponent extends Container {
|
|
|
254
277
|
}
|
|
255
278
|
|
|
256
279
|
async #handleMemoryReport(): Promise<void> {
|
|
280
|
+
const releaseActivityIndicator = suspendInteractiveActivityIndicator(this.ctx);
|
|
257
281
|
const loader = new Loader(
|
|
258
282
|
this.ctx.ui,
|
|
259
283
|
spinner => theme.fg("accent", spinner),
|
|
@@ -274,8 +298,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
274
298
|
heapSnapshot,
|
|
275
299
|
});
|
|
276
300
|
|
|
277
|
-
loader
|
|
278
|
-
this.ctx.
|
|
301
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
302
|
+
if (this.ctx.isStopped?.()) return;
|
|
279
303
|
|
|
280
304
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
281
305
|
this.ctx.chatContainer.addChild(
|
|
@@ -284,8 +308,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
284
308
|
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", formatFileHyperlink(result.path)), 1, 0));
|
|
285
309
|
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
286
310
|
} catch (err) {
|
|
287
|
-
loader
|
|
288
|
-
this.ctx.
|
|
311
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
312
|
+
if (this.ctx.isStopped?.()) return;
|
|
289
313
|
this.ctx.showError(`Failed to create report: ${err instanceof Error ? err.message : String(err)}`);
|
|
290
314
|
}
|
|
291
315
|
|
|
@@ -405,6 +429,7 @@ export class DebugSelectorComponent extends Container {
|
|
|
405
429
|
}
|
|
406
430
|
|
|
407
431
|
// Clear cache
|
|
432
|
+
const releaseActivityIndicator = suspendInteractiveActivityIndicator(this.ctx);
|
|
408
433
|
const loader = new Loader(
|
|
409
434
|
this.ctx.ui,
|
|
410
435
|
spinner => theme.fg("accent", spinner),
|
|
@@ -418,8 +443,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
418
443
|
try {
|
|
419
444
|
const result = await clearArtifactCache(sessionsDir, 30);
|
|
420
445
|
|
|
421
|
-
loader
|
|
422
|
-
this.ctx.
|
|
446
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
447
|
+
if (this.ctx.isStopped?.()) return;
|
|
423
448
|
|
|
424
449
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
425
450
|
this.ctx.chatContainer.addChild(
|
|
@@ -430,8 +455,8 @@ export class DebugSelectorComponent extends Container {
|
|
|
430
455
|
),
|
|
431
456
|
);
|
|
432
457
|
} catch (err) {
|
|
433
|
-
loader
|
|
434
|
-
this.ctx.
|
|
458
|
+
this.#finishStatusLoader(loader, releaseActivityIndicator);
|
|
459
|
+
if (this.ctx.isStopped?.()) return;
|
|
435
460
|
this.ctx.showError(`Failed to clear cache: ${err instanceof Error ? err.message : String(err)}`);
|
|
436
461
|
}
|
|
437
462
|
|
|
@@ -180,6 +180,7 @@ Run this phase only when the active deep-interview state or invocation indicates
|
|
|
180
180
|
- Direct `.gjc/` file edits are forbidden unless an explicit force override is active; do not use `write`, `edit`, or `ast_edit` against `.gjc/_session-{sessionid}/specs`, `.gjc/_session-{sessionid}/plans`, `.gjc/_session-{sessionid}/state`, or other `.gjc/` paths during normal workflow operation.
|
|
181
181
|
- Preferred: pass the spec markdown **inline** to the native deep-interview write command (`--write … --spec "<markdown>"`) — no scratch file is needed. The CLI is the only sanctioned writer for `.gjc/_session-{sessionid}/specs`.
|
|
182
182
|
- Only if a spec is too large to pass inline, stage it with the `write` tool to a system temp directory (`os.tmpdir()`/`$TMPDIR`, `/tmp`, `/var/tmp`) outside the project tree, then pass that path to `--spec`. The planning phase-boundary block tolerates these neutral temp writes; never stage interview artifacts inside the repo or under `.gjc/`, and do not improvise repo-relative scratch files.
|
|
183
|
+
- When staging via bash instead of the `write` tool, a heredoc into a neutral temp path (`cat > /tmp/spec.md <<'EOF' … EOF`) is also tolerated; quote the heredoc delimiter (`<<'EOF'`) so the document body stays inert. Never stage into the repo or `.gjc/`, and prefer the `write` tool over bash for large bodies.
|
|
183
184
|
|
|
184
185
|
4. **Initialize state** via `gjc deep-interview write --input '<json>'`:
|
|
185
186
|
|