@gajae-code/coding-agent 0.11.10 → 0.12.0
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 +86 -2
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/cli.d.ts +8 -1
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/config/model-profile-activation.d.ts +1 -0
- package/dist/types/config/model-profile-contract.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +86 -3
- package/dist/types/config/settings.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +43 -2
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
- package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/linux-proc.d.ts +22 -14
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +112 -1
- package/dist/types/gjc-runtime/state-runtime.d.ts +3 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +2 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +22 -9
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/queue-pane.d.ts +8 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/welcome.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +7 -1
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/runtime/memory-domain.d.ts +9 -0
- package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
- package/dist/types/runtime/memory-guard.d.ts +39 -0
- package/dist/types/runtime/memory-limit.d.ts +11 -0
- package/dist/types/runtime-mcp/manager.d.ts +8 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/final-text.d.ts +19 -0
- package/dist/types/sdk/acp/mcp.d.ts +23 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +7 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +2 -1
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +18 -2
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +23 -3
- package/dist/types/sdk/host/control/operations.d.ts +2 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/lifecycle-session.d.ts +10 -1
- package/dist/types/sdk/startup-capability.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +51 -19
- package/dist/types/session/fallback-chain-controller.d.ts +18 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +27 -0
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +59 -13
- package/dist/types/session/streaming-output.d.ts +60 -5
- package/dist/types/skill-state/active-state.d.ts +0 -4
- package/dist/types/skill-state/workflow-hud.d.ts +3 -0
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/types.d.ts +36 -0
- package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/output-meta.d.ts +21 -1
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -1
- package/dist/types/tools/resource-gc.d.ts +23 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/package.json +9 -13
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +4 -0
- package/scripts/run-test-manifest.ts +6 -4
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/capability/index.ts +8 -0
- package/src/cli/args.ts +14 -8
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/read-cli.ts +2 -1
- package/src/cli.ts +49 -2
- package/src/commands/deep-interview.ts +29 -9
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/sdk.ts +91 -7
- package/src/commands/team.ts +1 -1
- package/src/config/model-profile-activation.ts +1 -0
- package/src/config/model-profile-contract.ts +13 -0
- package/src/config/model-profiles.ts +24 -0
- package/src/config/model-registry.ts +21 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +84 -3
- package/src/config/settings.ts +254 -108
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +229 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +78 -26
- package/src/defaults/gjc/skills/team/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +26 -16
- package/src/eval/py/executor.ts +7 -2
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +42 -4
- package/src/extensibility/shared-events.ts +5 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -68
- package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
- package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
- package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
- package/src/gjc-runtime/deep-interview-state.ts +12 -921
- package/src/gjc-runtime/gc-render.ts +1 -0
- package/src/gjc-runtime/gc-runtime.ts +11 -1
- package/src/gjc-runtime/linux-proc.ts +70 -36
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +979 -71
- package/src/gjc-runtime/state-runtime.ts +50 -12
- package/src/gjc-runtime/state-writer.ts +70 -222
- package/src/gjc-runtime/team-launch.ts +34 -5
- package/src/gjc-runtime/team-runtime.ts +970 -33
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/gjc-runtime/team-workers.ts +1 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +18 -0
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +13 -7
- package/src/gjc-runtime/workflow-manifest.generated.json +97 -350
- package/src/gjc-runtime/workflow-manifest.ts +34 -179
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/hooks/skill-state.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +10 -11
- package/src/internal-urls/local-protocol.ts +23 -4
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/main.ts +9 -5
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +47 -0
- package/src/modes/acp/acp-agent.ts +597 -67
- package/src/modes/acp/acp-event-mapper.ts +106 -12
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +76 -5
- package/src/modes/components/notifications-settings-editor.ts +1 -1
- package/src/modes/components/oauth-selector.ts +42 -12
- package/src/modes/components/queue-pane.ts +55 -9
- package/src/modes/components/queued-message-selector.ts +53 -10
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +187 -32
- package/src/modes/components/settings-selector.ts +60 -18
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +1 -4
- package/src/modes/components/welcome.ts +18 -3
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +23 -12
- package/src/modes/controllers/input-controller.ts +62 -6
- package/src/modes/controllers/selector-controller.ts +83 -37
- package/src/modes/interactive-mode.ts +127 -29
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +20 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/agents/executor.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -1
- package/src/prompts/tools/read.md +4 -2
- package/src/runtime/memory-domain.ts +66 -0
- package/src/runtime/memory-guard-contract.ts +73 -0
- package/src/runtime/memory-guard.ts +292 -0
- package/src/runtime/memory-limit.ts +50 -0
- package/src/runtime-mcp/manager.ts +26 -6
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/acp/adapter.ts +8 -1
- package/src/sdk/acp/final-text.ts +40 -0
- package/src/sdk/acp/mcp.ts +26 -0
- package/src/sdk/broker/lifecycle.ts +107 -7
- package/src/sdk/bus/chat-daemon-cli.ts +2 -2
- package/src/sdk/bus/chat-daemon-control.ts +4 -3
- package/src/sdk/bus/config.ts +1 -1
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +503 -60
- package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/rate-limit-pool.ts +8 -0
- package/src/sdk/bus/reconciliation-store.ts +224 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +6 -4
- package/src/sdk/bus/telegram-daemon.ts +531 -53
- package/src/sdk/host/control/dispatch.ts +7 -1
- package/src/sdk/host/control/operations.ts +2 -1
- package/src/sdk/host/host.ts +25 -3
- package/src/sdk/host/query/handlers.ts +55 -0
- package/src/sdk/lifecycle-session.ts +19 -3
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/protocol/operation-inventory.generated.json +76 -0
- package/src/sdk/protocol/operation-registry.ts +8 -2
- package/src/sdk/session.ts +25 -2
- package/src/sdk/startup-capability.ts +6 -0
- package/src/session/agent-session.ts +720 -190
- package/src/session/fallback-chain-controller.ts +47 -8
- package/src/session/internal/managed-session-scope.ts +40 -10
- package/src/session/internal/native-publish-outcome.ts +8 -3
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +1372 -42
- package/src/session/streaming-output.ts +262 -43
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +0 -10
- package/src/skill-state/workflow-hud.ts +25 -2
- package/src/skill-state/workflow-mutation-guard.ts +65 -7
- package/src/task/executor.ts +11 -3
- package/src/task/index.ts +2 -0
- package/src/task/types.ts +22 -11
- package/src/task/ultragoal-redteam-activation.ts +75 -0
- package/src/tools/ask.ts +89 -69
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/output-meta.ts +176 -9
- package/src/tools/path-utils.ts +5 -1
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1542 -310
- package/src/tools/resource-gc.ts +665 -125
- package/src/tools/tool-result.ts +14 -1
- package/src/web/search/providers/codex.ts +1 -1
- package/src/workflow/workflow-intent-diff.ts +4 -1
- package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
- package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
- package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
- package/src/gjc-runtime/deep-interview-draft.ts +0 -843
- package/src/gjc-runtime/deep-interview-payload.ts +0 -262
- package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
|
@@ -147,6 +147,17 @@ const MAX_LEGACY_LOCAL_BYTES = 64 * 1024 * 1024;
|
|
|
147
147
|
|
|
148
148
|
type LegacyMigrationState = "complete" | "cleanup_pending";
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Marker values that mean legacy migration has settled for this root and the
|
|
152
|
+
* synchronous resolver may proceed. `cleanup_pending` counts: the entries are
|
|
153
|
+
* installed and content-verified, and only retirement of the legacy source is
|
|
154
|
+
* outstanding. Must stay in sync with {@link readMigrationMarker}, which the
|
|
155
|
+
* async gate uses to decide the same question.
|
|
156
|
+
*/
|
|
157
|
+
function isSettledMigrationMarkerValue(value: string): boolean {
|
|
158
|
+
return value === "verified\n" || value === "absent\n" || value === "cleanup_pending\n";
|
|
159
|
+
}
|
|
160
|
+
|
|
150
161
|
interface LegacyEntrySnapshot {
|
|
151
162
|
readonly relativePath: string;
|
|
152
163
|
readonly dev: bigint;
|
|
@@ -350,7 +361,7 @@ async function migrateManagedLegacyLocal(
|
|
|
350
361
|
throw new Error("Legacy local:// migration destination verification failed");
|
|
351
362
|
}
|
|
352
363
|
}
|
|
353
|
-
for (const entry of await fs.readdir(staging)) {
|
|
364
|
+
for (const entry of (await fs.readdir(staging)).sort()) {
|
|
354
365
|
const destination = path.join(localRoot, entry);
|
|
355
366
|
try {
|
|
356
367
|
await fs.lstat(destination);
|
|
@@ -540,8 +551,13 @@ function initializeLocalRootSyncWhenLegacyAbsent(options: LocalProtocolOptions,
|
|
|
540
551
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) throw new Error("Unsafe local:// root");
|
|
541
552
|
const marker = path.join(localRoot, LEGACY_MIGRATION_MARKER);
|
|
542
553
|
try {
|
|
543
|
-
|
|
544
|
-
|
|
554
|
+
// Accept exactly the marker states the async gate treats as settled. A
|
|
555
|
+
// `cleanup_pending` marker means the entries are fully installed and verified
|
|
556
|
+
// and only retirement of the legacy source is outstanding, so resolution is
|
|
557
|
+
// safe; rejecting it here made the sync resolver fail closed on a root the
|
|
558
|
+
// async gate had already completed.
|
|
559
|
+
if (!isSettledMigrationMarkerValue(fsSync.readFileSync(marker, "utf8")))
|
|
560
|
+
throw new Error("Unsafe local:// migration marker");
|
|
545
561
|
initializedLocalRoots.add(localRoot);
|
|
546
562
|
return;
|
|
547
563
|
} catch (error) {
|
|
@@ -558,7 +574,10 @@ function initializeLocalRootSyncWhenLegacyAbsent(options: LocalProtocolOptions,
|
|
|
558
574
|
fsSync.writeFileSync(marker, "absent\n", { mode: 0o600, flag: "wx" });
|
|
559
575
|
} catch (error) {
|
|
560
576
|
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
561
|
-
|
|
577
|
+
// A concurrent initializer won the exclusive create. Any settled marker state
|
|
578
|
+
// it wrote is authoritative; only an unrecognized value is unsafe.
|
|
579
|
+
if (!isSettledMigrationMarkerValue(fsSync.readFileSync(marker, "utf8")))
|
|
580
|
+
throw new Error("Unsafe local:// migration marker");
|
|
562
581
|
}
|
|
563
582
|
initializedLocalRoots.add(localRoot);
|
|
564
583
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { isEnoent } from "@gajae-code/utils";
|
|
5
|
+
import type { GcCollectResult, GcContext, GcError, GcRecord, GcStoreAdapter } from "../gjc-runtime/gc-runtime";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* GC for `local://` session roots.
|
|
9
|
+
*
|
|
10
|
+
* `resolveLocalRoot` gives every session its own `<tmp>/gjc-local/<session-id>`
|
|
11
|
+
* directory, and the first `local://` resolution seeds it with a migration
|
|
12
|
+
* marker. Nothing ever removes those directories, so a machine accumulates one
|
|
13
|
+
* per session indefinitely — and the overwhelming majority only ever hold the
|
|
14
|
+
* marker, because most sessions never write a `local://` file.
|
|
15
|
+
*
|
|
16
|
+
* Only marker-only directories are eligible, and only after a grace period.
|
|
17
|
+
* That keeps the rule provably safe without needing a session-liveness oracle:
|
|
18
|
+
* a directory holding real content is never touched, and a session that just
|
|
19
|
+
* started is still inside its grace window.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const LOCAL_ROOT_PARENT = "gjc-local";
|
|
23
|
+
const LEGACY_MIGRATION_MARKER = ".gjc-local-legacy-migrated-v1";
|
|
24
|
+
|
|
25
|
+
/** Directories younger than this are left alone so a live session is never raced. */
|
|
26
|
+
const GRACE_MS = 24 * 60 * 60 * 1000;
|
|
27
|
+
|
|
28
|
+
/** Bound the scan so a pathological directory cannot stall `gjc gc`. */
|
|
29
|
+
const MAX_ENTRIES = 20_000;
|
|
30
|
+
|
|
31
|
+
function localRootParent(env: NodeJS.ProcessEnv): string {
|
|
32
|
+
return path.join(env.TMPDIR?.trim() || os.tmpdir(), LOCAL_ROOT_PARENT);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A root is prunable only when the marker is the single thing inside it. */
|
|
36
|
+
async function classify(dir: string, now: number): Promise<{ status: string; stale: boolean; reason: string } | null> {
|
|
37
|
+
let entries: string[];
|
|
38
|
+
try {
|
|
39
|
+
entries = await fs.readdir(dir);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (isEnoent(error)) return null;
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const extra = entries.filter(name => name !== LEGACY_MIGRATION_MARKER);
|
|
46
|
+
if (extra.length > 0)
|
|
47
|
+
return {
|
|
48
|
+
status: "in_use",
|
|
49
|
+
stale: false,
|
|
50
|
+
reason: `Holds ${extra.length} entr${extra.length === 1 ? "y" : "ies"} beyond the marker`,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const stat = await fs.stat(dir);
|
|
54
|
+
if (now - stat.mtimeMs < GRACE_MS) return { status: "recent", stale: false, reason: "Inside the grace window" };
|
|
55
|
+
return { status: "marker_only", stale: true, reason: "Only the migration marker, past the grace window" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const localRootsGcAdapter: GcStoreAdapter = {
|
|
59
|
+
store: "local_roots",
|
|
60
|
+
async collect(ctx: GcContext): Promise<GcCollectResult> {
|
|
61
|
+
const records: GcRecord[] = [];
|
|
62
|
+
const errors: GcError[] = [];
|
|
63
|
+
const parent = localRootParent(ctx.env);
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
|
|
66
|
+
let dirents: string[];
|
|
67
|
+
try {
|
|
68
|
+
dirents = await fs.readdir(parent);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (isEnoent(error)) return { records, errors };
|
|
71
|
+
errors.push({ store: "local_roots", scope: parent, message: (error as Error).message });
|
|
72
|
+
return { records, errors };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const name of dirents.slice(0, MAX_ENTRIES)) {
|
|
76
|
+
const dir = path.join(parent, name);
|
|
77
|
+
try {
|
|
78
|
+
const classified = await classify(dir, now);
|
|
79
|
+
if (!classified) continue;
|
|
80
|
+
records.push({
|
|
81
|
+
store: "local_roots",
|
|
82
|
+
id: name,
|
|
83
|
+
path: dir,
|
|
84
|
+
status: classified.status,
|
|
85
|
+
stale: classified.stale,
|
|
86
|
+
removable: classified.stale,
|
|
87
|
+
action: classified.stale ? "would_remove" : "none",
|
|
88
|
+
reason: classified.reason,
|
|
89
|
+
});
|
|
90
|
+
} catch (error) {
|
|
91
|
+
errors.push({ store: "local_roots", scope: dir, message: (error as Error).message });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (dirents.length > MAX_ENTRIES) {
|
|
96
|
+
errors.push({
|
|
97
|
+
store: "local_roots",
|
|
98
|
+
scope: parent,
|
|
99
|
+
message: `Scan truncated at ${MAX_ENTRIES} entries`,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { records, errors };
|
|
104
|
+
},
|
|
105
|
+
async prune(record: GcRecord) {
|
|
106
|
+
const dir = record.path;
|
|
107
|
+
if (!dir) return { removed: false, error: "Missing local root path" };
|
|
108
|
+
|
|
109
|
+
// Re-validate immediately before removing: the session may have written a
|
|
110
|
+
// file between collect and prune.
|
|
111
|
+
let classified: Awaited<ReturnType<typeof classify>>;
|
|
112
|
+
try {
|
|
113
|
+
classified = await classify(dir, Date.now());
|
|
114
|
+
} catch (error) {
|
|
115
|
+
return { removed: false, error: (error as Error).message };
|
|
116
|
+
}
|
|
117
|
+
if (!classified) return { removed: false, skipped: "Local root disappeared" };
|
|
118
|
+
if (!classified.stale) return { removed: false, skipped: `Local root no longer eligible (${classified.status})` };
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
122
|
+
return { removed: true };
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return { removed: false, error: (error as Error).message };
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
};
|
package/src/main.ts
CHANGED
|
@@ -698,7 +698,7 @@ async function promptForkSession(session: SessionInfo): Promise<boolean> {
|
|
|
698
698
|
}
|
|
699
699
|
}
|
|
700
700
|
|
|
701
|
-
async function getChangelogForDisplay(parsed: Args): Promise<string | undefined> {
|
|
701
|
+
export async function getChangelogForDisplay(parsed: Args): Promise<string | undefined> {
|
|
702
702
|
if (parsed.continue || parsed.resume) {
|
|
703
703
|
return undefined;
|
|
704
704
|
}
|
|
@@ -710,15 +710,19 @@ async function getChangelogForDisplay(parsed: Args): Promise<string | undefined>
|
|
|
710
710
|
|
|
711
711
|
const lastVersion = settings.get("lastChangelogVersion");
|
|
712
712
|
if (!lastVersion) {
|
|
713
|
-
settings.
|
|
714
|
-
|
|
713
|
+
if (settings.canWriteDurableConfig()) {
|
|
714
|
+
settings.set("lastChangelogVersion", VERSION);
|
|
715
|
+
await flushChangelogVersion();
|
|
716
|
+
}
|
|
715
717
|
return getInstalledVersionChangelogEntry(entries, VERSION)?.content;
|
|
716
718
|
}
|
|
717
719
|
|
|
718
720
|
if (lastVersion !== VERSION) {
|
|
719
721
|
const newEntries = getNewEntries(entries, lastVersion);
|
|
720
|
-
settings.
|
|
721
|
-
|
|
722
|
+
if (settings.canWriteDurableConfig()) {
|
|
723
|
+
settings.set("lastChangelogVersion", VERSION);
|
|
724
|
+
await flushChangelogVersion();
|
|
725
|
+
}
|
|
722
726
|
if (newEntries.length > 0) {
|
|
723
727
|
return newEntries.map(e => e.content).join("\n\n");
|
|
724
728
|
}
|
package/src/memories/index.ts
CHANGED
|
@@ -976,6 +976,11 @@ function redactSecrets(input: string): string {
|
|
|
976
976
|
/(?:sk|pk|rk|tok|key|secret|token|password)[-_A-Za-z0-9]{12,}/g,
|
|
977
977
|
/[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g,
|
|
978
978
|
/(?:AKIA|ASIA)[A-Z0-9]{16}/g,
|
|
979
|
+
// GitHub tokens carry no keyword the first pattern recognizes, so without
|
|
980
|
+
// this they reached MEMORY.md and memory_summary.md verbatim — and the
|
|
981
|
+
// summary is injected into every later session. Same shapes the
|
|
982
|
+
// contribution-prep scrubber already covers.
|
|
983
|
+
/\b(?:gh[opsur]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})\b/g,
|
|
979
984
|
];
|
|
980
985
|
for (const pattern of patterns) {
|
|
981
986
|
out = out.replace(pattern, "[REDACTED]");
|
|
@@ -983,6 +988,11 @@ function redactSecrets(input: string): string {
|
|
|
983
988
|
return out;
|
|
984
989
|
}
|
|
985
990
|
|
|
991
|
+
/** Secret scrubbing applied to every phase-2 consolidation output. Test seam. */
|
|
992
|
+
export function redactMemorySecretsForTesting(input: string): string {
|
|
993
|
+
return redactSecrets(input);
|
|
994
|
+
}
|
|
995
|
+
|
|
986
996
|
function sanitizeSkillName(name: string): string {
|
|
987
997
|
return name
|
|
988
998
|
.toLowerCase()
|
package/src/modes/DESIGN.md
CHANGED
|
@@ -261,3 +261,50 @@ record both manifest counts as 108 plus CJK review results.
|
|
|
261
261
|
|
|
262
262
|
No raw third-party design corpus, screenshot, or reference asset is stored by
|
|
263
263
|
this workflow.
|
|
264
|
+
|
|
265
|
+
## Sticky transcript viewport contract
|
|
266
|
+
|
|
267
|
+
Live mode remains in natural terminal flow. Entering manual history makes the
|
|
268
|
+
application-owned transcript lane scrollable while the status line and every
|
|
269
|
+
later direct composer child are a fixed suffix at the bottom. PageUp/PageDown
|
|
270
|
+
move by the transcript capacity; the wheel remains three rows. A focused editor
|
|
271
|
+
keeps focus, and ordinary editor input or paste follows live before processing
|
|
272
|
+
that input.
|
|
273
|
+
|
|
274
|
+
Manual output has one bounded boolean indication, exactly **`New output — type
|
|
275
|
+
to follow`**. It is not a count. New visible agent/tool/extension output may set
|
|
276
|
+
it while manual; reflow, transient chrome, reconciliation, and user input may
|
|
277
|
+
not. Following clears it only after a successful live repaint. Manual-era output
|
|
278
|
+
is authoritative in the application transcript but is never retroactively
|
|
279
|
+
replayed into native host scrollback; subsequent ordinary live output follows
|
|
280
|
+
normal host behavior.
|
|
281
|
+
|
|
282
|
+
The transcript is the only selectable coordinate space. Pinned status/composer
|
|
283
|
+
chrome, notices, blank rows, and overlays never enter selection or copied text;
|
|
284
|
+
CJK selection clamping remains directional and grapheme/cell aware. Under
|
|
285
|
+
constrained height the notice drops first, then decorative pet and low-priority
|
|
286
|
+
hooks. Focused editor/cursor, status, and normal hooks outrank those rows; zero
|
|
287
|
+
transcript capacity is valid and must not corrupt cursor geometry.
|
|
288
|
+
|
|
289
|
+
At narrow widths use ANSI-aware terminal-cell measurement. ASCII/no-color keeps
|
|
290
|
+
textual state without SGR. Korean, Japanese, Chinese, and mixed CJK/Latin prose
|
|
291
|
+
must wrap at semantic phrase boundaries, never through an action/status label or
|
|
292
|
+
short identifier; a semantic CJK break is a visual-QA failure.
|
|
293
|
+
|
|
294
|
+
### Sticky viewport deterministic visual QA
|
|
295
|
+
|
|
296
|
+
`test/fixtures/tui/sticky-viewport-showcase.ts` is a fixed-clock, no-network,
|
|
297
|
+
first-party harness that starts the production `TUI` over a `VirtualTerminal`.
|
|
298
|
+
It constructs transcript, status, hooks, and the real composer as children,
|
|
299
|
+
then drives the live/manual viewport path before capturing the terminal frame.
|
|
300
|
+
Capture with `bun packages/coding-agent/scripts/capture-sticky-viewport-showcase.ts
|
|
301
|
+
--out .gjc/qa/sticky-viewport-<run>` and verify with the paired `--root` script.
|
|
302
|
+
The immutable matrix has exactly 20 keys: `live-overflow`, `manual-history`,
|
|
303
|
+
`manual-new-output`, `multiline-editor-hooks-pet`, `capacity-many`,
|
|
304
|
+
`capacity-one`, `capacity-zero`, and `selection-boundary` at both 80x24 and
|
|
305
|
+
120x36 Unicode/color; plus `manual-new-output/80x24/ascii-no-color`,
|
|
306
|
+
`capacity-zero/48x10/ascii-no-color`,
|
|
307
|
+
`multiline-editor-hooks-pet/48x10/unicode-color`, and
|
|
308
|
+
`narrow-cjk/48x10/unicode-color`. Do not add or replace a manual-follow case.
|
|
309
|
+
|
|
310
|
+
Each key has only `terminal.txt`, ANSI-preserving `terminal-ansi.txt`, `terminal.html`, and `metadata.json`; the manifest records SHA-256 and byte length. Per-key metadata binds immutable font/render assumptions and the ANSI-aware wrapping/truncation policy. `VirtualTerminal` reconstructs ANSI from visible xterm cells, including cell padding, palette/RGB colors, attributes, and inverse video; plain text is always the stripped reconstruction. The verifier owns an independent literal 20-key oracle and fails closed unless stripped ANSI equals text, `terminal.html` equals the exported canonical `ansiToHtml(terminal-ansi.txt)` byte-for-byte (including its complete document envelope and global CSS), HTML independently preserves the ANSI style-run text, every retained row has the exact `Bun.stringWidth` cell width (including trailing spaces), and `ansi_mode` agrees with required Unicode color SGR or ASCII/no-color output. Every metadata entry has exact CJK phrase-boundary metadata: the narrow-CJK key has only the three canonical boundaries in order and every other key has `[]`. Manual captures prove successful production wheel and PageUp paths and retain observable historical transcript-row evidence. It validates exact payload paths (no duplicates or traversal), immutable source/output revisions, state/status/suffix order, notice cardinality, capacity, actual mouse-copied transcript-only selection, composer, CJK, and provenance invariants. `review-input.json` binds the exact manifest digest, capture author/executor identity, acceptance/design versions, required artifacts, narrow-CJK boundaries, and deterministic host matrix. `--require-independent-review` requires an attestation with an exact root key set; exact per-key result and artifact-check key sets; exact defect `{ description, accepted }` keys with a trimmed, nonblank description; canonical trimmed reviewer identity distinct from both bound identities; the independent-terminal-reviewer role; fixture revision; expected and observed counts of 20; exact checked keys; accepted per-key artifact-check/notes results; accepted artifact/CJK/host decisions; bound digest; and final `accept`. Any malformed, incomplete, or extra attestation content fails closed.
|