commandmate 0.40.1 → 0.41.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/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +134 -134
- package/.next/app-path-routes-manifest.json +21 -21
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +12 -12
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +21 -21
- package/.next/server/chunks/4443.js +1 -1
- package/.next/server/chunks/5164.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/650.js +1 -1
- package/.next/server/chunks/8581.js +2 -2
- package/.next/server/chunks/8728.js +1 -1
- package/.next/server/chunks/9627.js +30 -24
- package/.next/server/chunks/9882.js +3 -3
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{2407-d750620d0511e94f.js → 2407-99799e3c2ff03bae.js} +1 -1
- package/.next/static/chunks/{4768-979c8a03bed218e7.js → 4768-fc0aa1d0891cac08.js} +1 -1
- package/.next/static/chunks/{8606-9a381b996f9b6834.js → 8606-79c36d4c204bbd38.js} +1 -1
- package/.next/static/chunks/app/{layout-3d3fcc8aac7b3bb5.js → layout-1fb647d6df55c498.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/{page-a91e812ad9d94697.js → page-f24da37453224716.js} +1 -1
- package/.next/trace +13 -13
- package/dist/server/src/lib/auto-yes-poller.js +72 -1
- package/dist/server/src/lib/db/chat-db.js +38 -0
- package/dist/server/src/lib/detection/cli-patterns.js +11 -0
- package/dist/server/src/lib/detection/selection-shape.js +76 -0
- package/dist/server/src/lib/detection/tools/antigravity/detect.js +64 -0
- package/dist/server/src/lib/detection/tools/claude/detect.js +28 -1
- package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +51 -0
- package/dist/server/src/lib/detection/tools/codex/detect.js +21 -2
- package/dist/server/src/lib/detection/tools/command-code/detect.js +14 -3
- package/dist/server/src/lib/polling/antigravity-permission-receipts.js +113 -0
- package/dist/server/src/lib/polling/response-checker.js +73 -4
- package/dist/server/src/lib/session/current-output-builder.js +25 -0
- package/dist/server/src/lib/session/layer-disagreement.js +108 -0
- package/dist/server/src/types/sidebar.js +1 -0
- package/package.json +1 -1
- package/release-notes/0.41.0.json +29 -0
- /package/.next/static/{JfzIPPhL-ikSVcJYOKgfD → UoGuvKnR_kGftU9RHtebq}/_buildManifest.js +0 -0
- /package/.next/static/{JfzIPPhL-ikSVcJYOKgfD → UoGuvKnR_kGftU9RHtebq}/_ssgManifest.js +0 -0
|
@@ -61,6 +61,7 @@ exports.stopAutoYesPollingByWorktree = stopAutoYesPollingByWorktree;
|
|
|
61
61
|
exports.isAnyPollerActiveForWorktree = isAnyPollerActiveForWorktree;
|
|
62
62
|
const cli_session_1 = require("./session/cli-session");
|
|
63
63
|
const response_checker_1 = require("./polling/response-checker");
|
|
64
|
+
const antigravity_permission_receipts_1 = require("./polling/antigravity-permission-receipts");
|
|
64
65
|
const auto_yes_resolver_1 = require("./polling/auto-yes-resolver");
|
|
65
66
|
const auto_yes_policy_1 = require("./polling/auto-yes-policy");
|
|
66
67
|
const auto_yes_suppression_state_1 = require("./polling/auto-yes-suppression-state");
|
|
@@ -82,6 +83,16 @@ const auto_yes_state_1 = require("./auto-yes-state");
|
|
|
82
83
|
/** In-memory storage for poller states (globalThis for hot reload persistence) */
|
|
83
84
|
const autoYesPollerStates = globalThis.__autoYesPollerStates ??
|
|
84
85
|
(globalThis.__autoYesPollerStates = new Map());
|
|
86
|
+
/**
|
|
87
|
+
* When `antigravity-autoyes-withheld-no-hook-receipt` was last logged, per
|
|
88
|
+
* compositeKey (Issue #2857). The poller re-reads a static pane every 2s, so the
|
|
89
|
+
* line is limited to one per {@link WITHHELD_NO_RECEIPT_LOG_INTERVAL_MS} per
|
|
90
|
+
* instance. globalThis for the same reason as the poller states above.
|
|
91
|
+
*/
|
|
92
|
+
const withheldNoReceiptLoggedAt = globalThis.__autoYesWithheldNoReceiptLoggedAt ??
|
|
93
|
+
(globalThis.__autoYesWithheldNoReceiptLoggedAt = new Map());
|
|
94
|
+
/** Least gap between two `antigravity-autoyes-withheld-no-hook-receipt` lines for one instance. */
|
|
95
|
+
const WITHHELD_NO_RECEIPT_LOG_INTERVAL_MS = 60_000;
|
|
85
96
|
// =============================================================================
|
|
86
97
|
// Poller State Accessors (compositeKey-based)
|
|
87
98
|
// =============================================================================
|
|
@@ -108,6 +119,7 @@ function getActivePollerCount() {
|
|
|
108
119
|
function clearAllPollerStates() {
|
|
109
120
|
stopAllAutoYesPolling();
|
|
110
121
|
autoYesPollerStates.clear();
|
|
122
|
+
withheldNoReceiptLoggedAt.clear();
|
|
111
123
|
}
|
|
112
124
|
/**
|
|
113
125
|
* Get the last server response timestamp for a composite key.
|
|
@@ -284,6 +296,50 @@ function processStopConditionDelta(compositeKey, pollerState, cleanOutput) {
|
|
|
284
296
|
}
|
|
285
297
|
return false;
|
|
286
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Say, once a minute, that Auto-Yes left an agy dialog alone for want of a hook
|
|
301
|
+
* receipt (Issue #2857).
|
|
302
|
+
*
|
|
303
|
+
* `detectPromptOnCleanFrame` hands a frame the receipt gate (#2849) withholds
|
|
304
|
+
* back as an ordinary `isPrompt: false`, so the poller cannot tell "no dialog on
|
|
305
|
+
* the pane" from "a dialog agy never asked us about" by looking at the result.
|
|
306
|
+
* The gate is the ONLY thing `receiptScope` changes, so the same frame read
|
|
307
|
+
* without it answering a prompt is exactly the withheld case. That second
|
|
308
|
+
* reading is taken only after the cheap tests: no receipt for this instance in
|
|
309
|
+
* the window (with one, the gate let the frame through and a no-prompt result is
|
|
310
|
+
* a real one) and no line for it in the last minute.
|
|
311
|
+
*
|
|
312
|
+
* Why it is worth a line: a machine whose `~/.gemini/config/hooks.json` points at
|
|
313
|
+
* another server (#2622) never sends us the question, and every real dialog then
|
|
314
|
+
* waits for a human with no sign of why. The line names the file to look at.
|
|
315
|
+
* The response-checker's own `antigravity-dialog-no-recent-receipt` stays at
|
|
316
|
+
* debug — it prints on every tick the same pane is read again.
|
|
317
|
+
*
|
|
318
|
+
* @param compositeKey - The instance's key, for the once-a-minute limit
|
|
319
|
+
* @param readWithoutGate - The same frame read without `receiptScope`
|
|
320
|
+
*/
|
|
321
|
+
function logIfWithheldForWantOfReceipt(worktreeId, instanceId, compositeKey, readWithoutGate) {
|
|
322
|
+
if ((0, antigravity_permission_receipts_1.hasRecentAntigravityPermissionReceipt)(worktreeId, 'antigravity', instanceId))
|
|
323
|
+
return;
|
|
324
|
+
const now = Date.now();
|
|
325
|
+
const lastLoggedAt = withheldNoReceiptLoggedAt.get(compositeKey);
|
|
326
|
+
if (lastLoggedAt !== undefined && now - lastLoggedAt < WITHHELD_NO_RECEIPT_LOG_INTERVAL_MS)
|
|
327
|
+
return;
|
|
328
|
+
const ungated = readWithoutGate();
|
|
329
|
+
if (!ungated.isPrompt || !ungated.promptData)
|
|
330
|
+
return;
|
|
331
|
+
for (const [key, loggedAt] of withheldNoReceiptLoggedAt) {
|
|
332
|
+
if (now - loggedAt >= WITHHELD_NO_RECEIPT_LOG_INTERVAL_MS)
|
|
333
|
+
withheldNoReceiptLoggedAt.delete(key);
|
|
334
|
+
}
|
|
335
|
+
withheldNoReceiptLoggedAt.set(compositeKey, now);
|
|
336
|
+
logger.info('antigravity-autoyes-withheld-no-hook-receipt', {
|
|
337
|
+
worktreeId,
|
|
338
|
+
instanceId: instanceId ?? 'antigravity',
|
|
339
|
+
windowMs: antigravity_permission_receipts_1.ANTIGRAVITY_PERMISSION_RECEIPT_WINDOW_MS,
|
|
340
|
+
hint: 'hook の受信記録が直近に無いため Auto-Yes は答えなかった。~/.gemini/config/hooks.json の向き先(#2622)を確認',
|
|
341
|
+
});
|
|
342
|
+
}
|
|
287
343
|
/**
|
|
288
344
|
* Detect prompt in terminal output, resolve auto-answer, and send response.
|
|
289
345
|
*
|
|
@@ -330,10 +386,25 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
330
386
|
// the same tick's raw capture reached it. `precomputedLines` stays the split
|
|
331
387
|
// of `cleanOutput` — the stop-condition delta and every other tool's reading
|
|
332
388
|
// are measured on that string and must not move.
|
|
333
|
-
|
|
389
|
+
//
|
|
390
|
+
// Issue #2857 adds the fifth, and this is the only caller that passes it: the
|
|
391
|
+
// one that ANSWERS the frame. For agy the frame then reads as a prompt only
|
|
392
|
+
// when agy asked CommandMate about a tool call for this instance in the last
|
|
393
|
+
// few seconds (#2849) — a dialog it never asked about is a reply quoting one
|
|
394
|
+
// (#2845, #2851) or a menu the user opened, and neither is ours to answer.
|
|
395
|
+
// The status API, the response poller's `prompt` row and the notification
|
|
396
|
+
// still call without it, so a real dialog stays visible to a human on a
|
|
397
|
+
// machine whose hook does not reach us. The price is that Auto-Yes leaves
|
|
398
|
+
// such a machine's dialogs alone, which is why `logIfWithheldForWantOfReceipt`
|
|
399
|
+
// says so.
|
|
400
|
+
const receiptScope = { worktreeId, instanceId };
|
|
401
|
+
const promptDetection = (0, response_checker_1.detectPromptOnCleanFrame)(cleanOutput, cliToolId, precomputedLines, rawOutput, receiptScope);
|
|
334
402
|
if (!promptDetection.isPrompt || !promptDetection.promptData) {
|
|
335
403
|
pollerState.lastAnsweredPromptKey = null;
|
|
336
404
|
pollerState.lastAnsweredAt = null;
|
|
405
|
+
if (cliToolId === 'antigravity' && !promptDetection.isPrompt) {
|
|
406
|
+
logIfWithheldForWantOfReceipt(worktreeId, instanceId, compositeKey, () => (0, response_checker_1.detectPromptOnCleanFrame)(cleanOutput, cliToolId, precomputedLines, rawOutput));
|
|
407
|
+
}
|
|
337
408
|
return 'no_prompt';
|
|
338
409
|
}
|
|
339
410
|
// 2. Check for duplicate prompt (Issue #306)
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.RELAY_SYSTEM_REQUEST_ID_PREFIX = exports.RELAY_REQUEST_ID_PREFIX = exports.MODEL_CHANGE_REQUEST_ID_PREFIX = exports.USER_TURN_CANDIDATE_LIMIT = exports.ACTIVE_FILTER = void 0;
|
|
10
10
|
exports.getLastAssistantMessageAt = getLastAssistantMessageAt;
|
|
11
|
+
exports.getLastMessageAtByInstance = getLastMessageAtByInstance;
|
|
11
12
|
exports.createMessage = createMessage;
|
|
12
13
|
exports.updateMessageContent = updateMessageContent;
|
|
13
14
|
exports.getMessages = getMessages;
|
|
@@ -85,6 +86,43 @@ function getLastAssistantMessageAt(db, worktreeId) {
|
|
|
85
86
|
}
|
|
86
87
|
return new Date(row.last_assistant_message_at);
|
|
87
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Latest message time per worktree and agent instance (Issue #2838).
|
|
91
|
+
*
|
|
92
|
+
* The sidebar's session rows need a time of their own: `worktrees.updated_at`
|
|
93
|
+
* moves on a message from ANY instance, so every row of one worktree used to
|
|
94
|
+
* share it. One `GROUP BY` for the whole server — the list polls it, so a
|
|
95
|
+
* query per worktree would multiply every poll.
|
|
96
|
+
*
|
|
97
|
+
* A row belongs to `COALESCE(instance_id, cli_tool_id, 'claude')`, the instance
|
|
98
|
+
* `getMessages` reads it as, so pre-#868 rows (`instance_id IS NULL`) count
|
|
99
|
+
* toward the primary instance. Role and `archived` are not filtered, matching
|
|
100
|
+
* what moves `updated_at` (`createMessage` touches it for every row).
|
|
101
|
+
*
|
|
102
|
+
* @returns worktreeId → (instanceId → latest message time); worktrees without
|
|
103
|
+
* messages are absent
|
|
104
|
+
*/
|
|
105
|
+
function getLastMessageAtByInstance(db) {
|
|
106
|
+
const rows = db.prepare(`
|
|
107
|
+
SELECT worktree_id,
|
|
108
|
+
COALESCE(instance_id, cli_tool_id, 'claude') AS resolved_instance_id,
|
|
109
|
+
MAX(timestamp) AS last_message_at
|
|
110
|
+
FROM chat_messages
|
|
111
|
+
GROUP BY worktree_id, resolved_instance_id
|
|
112
|
+
`).all();
|
|
113
|
+
const result = new Map();
|
|
114
|
+
for (const row of rows) {
|
|
115
|
+
if (row.last_message_at === null)
|
|
116
|
+
continue;
|
|
117
|
+
let byInstance = result.get(row.worktree_id);
|
|
118
|
+
if (!byInstance) {
|
|
119
|
+
byInstance = {};
|
|
120
|
+
result.set(row.worktree_id, byInstance);
|
|
121
|
+
}
|
|
122
|
+
byInstance[row.resolved_instance_id] = new Date(row.last_message_at);
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
88
126
|
/**
|
|
89
127
|
* Create a new chat message
|
|
90
128
|
*/
|
|
@@ -2272,6 +2272,13 @@ exports.ANTIGRAVITY_SURVEY_PATTERN = /^\s*\[1\]\s*Good\s+\[2\]\s*Fine\s+\[3\]\s*
|
|
|
2272
2272
|
* scrollback above a newer one is never the one read. Returns null when the
|
|
2273
2273
|
* frame has no footer at all.
|
|
2274
2274
|
*
|
|
2275
|
+
* Also null when agy's input box is drawn BELOW that footer (Issue #2845): agy
|
|
2276
|
+
* paints no `>` composer while a dialog is open — the dialog takes its place —
|
|
2277
|
+
* so a footer with a composer under it is the model's reply quoting a dialog,
|
|
2278
|
+
* or a dialog left in the scrollback, not a screen waiting for a keypress. It is
|
|
2279
|
+
* the same reading `isAntigravitySurveyOpen` gives the survey row (#2364), and
|
|
2280
|
+
* the composer is recognised by the same {@link ANTIGRAVITY_PROMPT_PATTERN}.
|
|
2281
|
+
*
|
|
2275
2282
|
* @param lines - ANSI-stripped rows, box drawing optional
|
|
2276
2283
|
*/
|
|
2277
2284
|
function locateAntigravityDialogRegion(lines) {
|
|
@@ -2284,6 +2291,10 @@ function locateAntigravityDialogRegion(lines) {
|
|
|
2284
2291
|
}
|
|
2285
2292
|
if (footer < 0)
|
|
2286
2293
|
return null;
|
|
2294
|
+
for (let i = footer + 1; i < lines.length; i++) {
|
|
2295
|
+
if (exports.ANTIGRAVITY_PROMPT_PATTERN.test(lines[i]))
|
|
2296
|
+
return null;
|
|
2297
|
+
}
|
|
2287
2298
|
const floor = Math.max(0, footer - exports.ANTIGRAVITY_DIALOG_MAX_ROWS);
|
|
2288
2299
|
let start = floor;
|
|
2289
2300
|
for (let i = footer - 1; i >= floor; i--) {
|
|
@@ -66,6 +66,9 @@
|
|
|
66
66
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
67
67
|
exports.COMMAND_CODE_PLAN_APPROVE_CHOICE_FOOTER = exports.COMMAND_CODE_PLAN_APPROVE_CHOICE_ROW = exports.COMMAND_CODE_PLAN_REVIEW_FOOTER = exports.DISMISSABLE_PANEL_FOOTER_PATTERN = exports.COMMAND_CODE_SELECTION_LIST_FOOTER = exports.SET_AS_DEFAULT_FOOTER_PATTERN = exports.SESSION_SCOPE_FOOTER_PATTERN = exports.MAX_OPTION_NUMBER = exports.SELECTION_SHAPE_TAIL_LINE_COUNT = void 0;
|
|
68
68
|
exports.isCommandCodePlanApproveChoice = isCommandCodePlanApproveChoice;
|
|
69
|
+
exports.hasCommandCodeSelectionListFooterAtBottom = hasCommandCodeSelectionListFooterAtBottom;
|
|
70
|
+
exports.hasCommandCodeDismissablePanelFooterAtBottom = hasCommandCodeDismissablePanelFooterAtBottom;
|
|
71
|
+
exports.hasCommandCodePlanReviewFooterAtBottom = hasCommandCodePlanReviewFooterAtBottom;
|
|
69
72
|
exports.hasDismissablePanelFooter = hasDismissablePanelFooter;
|
|
70
73
|
exports.readCommandCodeQuestionRegion = readCommandCodeQuestionRegion;
|
|
71
74
|
exports.hasCommandCodeQuestionChrome = hasCommandCodeQuestionChrome;
|
|
@@ -282,6 +285,79 @@ function isCommandCodePlanApproveChoice(tail) {
|
|
|
282
285
|
return (exports.COMMAND_CODE_PLAN_APPROVE_CHOICE_ROW.test(tail) &&
|
|
283
286
|
exports.COMMAND_CODE_PLAN_APPROVE_CHOICE_FOOTER.test(tail));
|
|
284
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* How many content rows the plan review footer's LAST row (`Cancel esc`) may
|
|
290
|
+
* have under it and still be the overlay's own footer (Issue #2846): the footer's
|
|
291
|
+
* two rows plus three.
|
|
292
|
+
*
|
|
293
|
+
* Measured over the sixteen plan review captures that carry the footer
|
|
294
|
+
* (`tests/fixtures/command-code-plan-review-2761/`, `-2763/`): fourteen draw ONE
|
|
295
|
+
* row below it, the hint bar (`type + enter to comment · …`); one draws two, an
|
|
296
|
+
* `Editor exited with code 127` row and then the hint bar; and the garbled
|
|
297
|
+
* `editor-killed-staircase.txt` draws three, because the pane wrapped the hint
|
|
298
|
+
* bar. So the plan review footer is NOT the last row the way the picker's is,
|
|
299
|
+
* and a "last two rows" rule misses every one of them.
|
|
300
|
+
*
|
|
301
|
+
* What bounds it from above is the composer. A transcript is always drawn above
|
|
302
|
+
* one, and its shortest measured form is four rows — rule, `❯ Ask your
|
|
303
|
+
* question...`, rule, status row — so a footer QUOTED in a reply has at least
|
|
304
|
+
* four content rows under it and its `Approve` row falls outside this window.
|
|
305
|
+
* The margin between the widest overlay (3) and the narrowest composer (4) is
|
|
306
|
+
* one row; a capture that narrows it is the reason to re-measure, not to widen
|
|
307
|
+
* this.
|
|
308
|
+
*/
|
|
309
|
+
const COMMAND_CODE_PLAN_REVIEW_TAIL_ROW_COUNT = 5;
|
|
310
|
+
/**
|
|
311
|
+
* The last `count` rows of `text` that carry content, joined with `\n`.
|
|
312
|
+
*
|
|
313
|
+
* Blank rows are dropped rather than counted: the pane is padded with them, and
|
|
314
|
+
* a real footer is set off from its hint bar by one.
|
|
315
|
+
*/
|
|
316
|
+
function lastContentRows(text, count) {
|
|
317
|
+
return text
|
|
318
|
+
.split('\n')
|
|
319
|
+
.filter((row) => row.trim() !== '')
|
|
320
|
+
.slice(-count)
|
|
321
|
+
.join('\n');
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Whether the LAST content row of this tail is Command Code's picker footer
|
|
325
|
+
* (Issue #2846).
|
|
326
|
+
*
|
|
327
|
+
* {@link COMMAND_CODE_SELECTION_LIST_FOOTER} matches the sentence anywhere, and
|
|
328
|
+
* a reply that quotes the `/model` footer is that sentence in the middle of the
|
|
329
|
+
* transcript. The picker draws the footer as the last row of the pane (all four
|
|
330
|
+
* captures that carry it do, `tests/fixtures/chat-dialog-card-2254/`), and a
|
|
331
|
+
* transcript always has the composer under it — the same reasoning
|
|
332
|
+
* {@link COMMAND_CODE_PLAN_APPROVE_CHOICE_FOOTER} anchors with `$`.
|
|
333
|
+
*
|
|
334
|
+
* @param tail - the frame's last rows, ANSI stripped, last content row last
|
|
335
|
+
*/
|
|
336
|
+
function hasCommandCodeSelectionListFooterAtBottom(tail) {
|
|
337
|
+
return exports.COMMAND_CODE_SELECTION_LIST_FOOTER.test(lastContentRows(tail, 1));
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Whether the LAST content row of this tail is the dismiss-only panel's footer
|
|
341
|
+
* (Issue #2846). `Press Esc to close` is the panel's last row
|
|
342
|
+
* ({@link DISMISSABLE_PANEL_FOOTER_PATTERN}); the same row inside a reply has
|
|
343
|
+
* the composer under it.
|
|
344
|
+
*
|
|
345
|
+
* @param tail - the frame's last rows, ANSI stripped, last content row last
|
|
346
|
+
*/
|
|
347
|
+
function hasCommandCodeDismissablePanelFooterAtBottom(tail) {
|
|
348
|
+
return exports.DISMISSABLE_PANEL_FOOTER_PATTERN.test(lastContentRows(tail, 1));
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Whether the plan review footer ({@link COMMAND_CODE_PLAN_REVIEW_FOOTER}) sits
|
|
352
|
+
* at the bottom of this tail (Issue #2846): both of its rows are within the last
|
|
353
|
+
* {@link COMMAND_CODE_PLAN_REVIEW_TAIL_ROW_COUNT} content rows, which is the
|
|
354
|
+
* overlay's own hint bar and nothing as tall as a composer.
|
|
355
|
+
*
|
|
356
|
+
* @param tail - the frame's last rows, ANSI stripped, last content row last
|
|
357
|
+
*/
|
|
358
|
+
function hasCommandCodePlanReviewFooterAtBottom(tail) {
|
|
359
|
+
return exports.COMMAND_CODE_PLAN_REVIEW_FOOTER.test(lastContentRows(tail, COMMAND_CODE_PLAN_REVIEW_TAIL_ROW_COUNT));
|
|
360
|
+
}
|
|
285
361
|
/**
|
|
286
362
|
* How many rows from the end of the content the dismiss footer is looked for.
|
|
287
363
|
*
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.antigravityStatusDetector = exports.VERIFIED_AGAINST = void 0;
|
|
20
|
+
exports.isAntigravityQuotedNumberedList = isAntigravityQuotedNumberedList;
|
|
20
21
|
const cli_patterns_1 = require("../../cli-patterns");
|
|
21
22
|
const status_reason_1 = require("../../status-reason");
|
|
22
23
|
const run_detection_1 = require("../run-detection");
|
|
@@ -61,9 +62,66 @@ function isAntigravitySurveyOpen(contentLines) {
|
|
|
61
62
|
const { promptPattern } = (0, cli_patterns_1.getCliToolPatterns)('antigravity');
|
|
62
63
|
return !tail.slice(surveyAt + 1).some(row => promptPattern.test(row));
|
|
63
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Is the screen the selection-list pattern matched the LIVE one, rather than
|
|
67
|
+
* words the model quoted or a screen left in the scrollback? (Issue #2845)
|
|
68
|
+
*
|
|
69
|
+
* agy paints no `>` composer while a dialog or picker is open — the screen
|
|
70
|
+
* replaces it — so a composer drawn below the last row the pattern matches
|
|
71
|
+
* means that row is not an open screen's. Without this the model quoting
|
|
72
|
+
* `↑/↓ Navigate` in a reply put the whole pane at `waiting` while agy sat at its
|
|
73
|
+
* composer, and Auto-Yes answered a dialog nobody had opened. The same reading
|
|
74
|
+
* `locateAntigravityDialogRegion` gives the numbered dialog's footer, and
|
|
75
|
+
* `isAntigravitySurveyOpen` above gives the survey row, with the same composer
|
|
76
|
+
* pattern.
|
|
77
|
+
*/
|
|
78
|
+
function isAntigravitySelectionScreenOpen(lastLines) {
|
|
79
|
+
const rows = lastLines.split('\n');
|
|
80
|
+
let matchedAt = -1;
|
|
81
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
82
|
+
if (cli_patterns_1.ANTIGRAVITY_SELECTION_LIST_PATTERN.test(rows[i])) {
|
|
83
|
+
matchedAt = i;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (matchedAt < 0)
|
|
88
|
+
return false;
|
|
89
|
+
const { promptPattern } = (0, cli_patterns_1.getCliToolPatterns)('antigravity');
|
|
90
|
+
return !rows.slice(matchedAt + 1).some(row => promptPattern.test(row));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Is the numbered list the shared parser read a quotation, not a dialog?
|
|
94
|
+
* (Issue #2845)
|
|
95
|
+
*
|
|
96
|
+
* The shared pass takes any `> 1. …` run in the last rows for a menu, wherever
|
|
97
|
+
* on the frame it sits. agy draws its numbered screens either IN PLACE OF the
|
|
98
|
+
* composer (the approval dialogs) or BELOW it (`/feedback`'s category menu),
|
|
99
|
+
* never above it — so a numbered list with the composer drawn under its last row
|
|
100
|
+
* is the model's reply, or a dialog left in the scrollback. Branch 0.9 declines
|
|
101
|
+
* such a frame (see {@link isAntigravitySelectionScreenOpen}); without this the
|
|
102
|
+
* shared pass then read the quoted `Do you want to proceed?` menu itself and
|
|
103
|
+
* published the composer-idle pane as `waiting` / `prompt_detected`.
|
|
104
|
+
*/
|
|
105
|
+
function isAntigravityQuotedNumberedList(frame, prompt) {
|
|
106
|
+
if (prompt.promptData?.type !== 'multiple_choice')
|
|
107
|
+
return false;
|
|
108
|
+
const rows = (0, cli_patterns_1.stripBoxDrawing)(frame.contentLines.join('\n')).split('\n');
|
|
109
|
+
const { promptPattern } = (0, cli_patterns_1.getCliToolPatterns)('antigravity');
|
|
110
|
+
let composerAt = -1;
|
|
111
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
112
|
+
if (promptPattern.test(rows[i])) {
|
|
113
|
+
composerAt = i;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (composerAt < 0)
|
|
118
|
+
return false;
|
|
119
|
+
return !rows.slice(composerAt + 1).some(row => cli_patterns_1.ANTIGRAVITY_NUMBERED_OPTION_PATTERN.test(row));
|
|
120
|
+
}
|
|
64
121
|
exports.antigravityStatusDetector = (0, run_detection_1.createToolStatusDetector)({
|
|
65
122
|
tool: 'antigravity',
|
|
66
123
|
verifiedAgainst: exports.VERIFIED_AGAINST,
|
|
124
|
+
isStalePrompt: isAntigravityQuotedNumberedList,
|
|
67
125
|
beforePrompt(frame) {
|
|
68
126
|
// 0.85. Issue #2364: the survey agy draws in place of its composer after a
|
|
69
127
|
// tool decision — `[1] Good [2] Fine [3] Bad [0] Skip` under `How's the
|
|
@@ -88,8 +146,14 @@ exports.antigravityStatusDetector = (0, run_detection_1.createToolStatusDetector
|
|
|
88
146
|
// screen as "generating" and NavigationButtons would never be shown. Detecting the
|
|
89
147
|
// selection list here — ahead of thinking — is the fix. Mirrors the Copilot /
|
|
90
148
|
// Codex early-detection pattern.
|
|
149
|
+
//
|
|
150
|
+
// Issue #2845: only while the screen is the live one. The words alone are
|
|
151
|
+
// not enough — a reply that quotes the `↑/↓ Navigate` footer leaves them in
|
|
152
|
+
// the last rows of a pane whose composer is drawn below them.
|
|
91
153
|
if (!cli_patterns_1.ANTIGRAVITY_SELECTION_LIST_PATTERN.test(frame.lastLines))
|
|
92
154
|
return null;
|
|
155
|
+
if (!isAntigravitySelectionScreenOpen(frame.lastLines))
|
|
156
|
+
return null;
|
|
93
157
|
// Issue #2270 / #2364: except when the frame is a NUMBERED dialog.
|
|
94
158
|
//
|
|
95
159
|
// #997 widened the pattern above to the bare `↑/↓ Navigate` footer so the
|
|
@@ -16,6 +16,7 @@ const composer_text_1 = require("../../composer-text");
|
|
|
16
16
|
const prompt_detect_multiple_choice_1 = require("../../prompt-detect-multiple-choice");
|
|
17
17
|
const status_reason_1 = require("../../status-reason");
|
|
18
18
|
const prompt_1 = require("./prompt");
|
|
19
|
+
const frame_1 = require("../frame");
|
|
19
20
|
const run_detection_1 = require("../run-detection");
|
|
20
21
|
const patterns_1 = require("./patterns");
|
|
21
22
|
/**
|
|
@@ -93,6 +94,30 @@ function readIdleEvidence(frame) {
|
|
|
93
94
|
return 'positive';
|
|
94
95
|
return 'none';
|
|
95
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* The rows a selection-list footer may be read from (Issue #2847).
|
|
99
|
+
*
|
|
100
|
+
* The footer belongs to the picker, and a picker is either the input box's
|
|
101
|
+
* neighbour or its replacement. Above the input box is the conversation, which
|
|
102
|
+
* can quote the footer's wording (a reply explaining the picker, a pasted
|
|
103
|
+
* transcript) without any picker being open — and reading the whole 15-row tail
|
|
104
|
+
* turned that quotation into `waiting` on an idle composer.
|
|
105
|
+
*
|
|
106
|
+
* So when the input box is on screen, only its rows and the status bar under it
|
|
107
|
+
* are read (still inside the 15-row tail, never wider). When there is no input
|
|
108
|
+
* box, a picker has taken its place and the tail is read as before.
|
|
109
|
+
*
|
|
110
|
+
* The box is located by {@link findClaudeInputBox}, the finder
|
|
111
|
+
* {@link findClaudeTranscriptTail} and {@link readIdleEvidence} already use, so
|
|
112
|
+
* this rule cannot disagree with them about where the conversation ends.
|
|
113
|
+
*/
|
|
114
|
+
function selectionFooterRows(frame) {
|
|
115
|
+
const box = (0, composer_text_1.findClaudeInputBox)(frame.contentLines);
|
|
116
|
+
if (!box)
|
|
117
|
+
return frame.lastLines;
|
|
118
|
+
const tailStart = frame.contentLines.length - frame_1.STATUS_CHECK_LINE_COUNT;
|
|
119
|
+
return frame.contentLines.slice(Math.max(box.openingSeparator, tailStart)).join('\n');
|
|
120
|
+
}
|
|
96
121
|
exports.claudeStatusDetector = (0, run_detection_1.createToolStatusDetector)({
|
|
97
122
|
tool: 'claude',
|
|
98
123
|
verifiedAgainst: patterns_1.VERIFIED_AGAINST,
|
|
@@ -102,7 +127,9 @@ exports.claudeStatusDetector = (0, run_detection_1.createToolStatusDetector)({
|
|
|
102
127
|
// use arrow keys + Enter to navigate and toggle, not number input.
|
|
103
128
|
// The 15-line window may miss the question line, causing SEC-001a rejection above.
|
|
104
129
|
// Detect via the footer instruction pattern and show NavigationButtons instead of PromptPanel.
|
|
105
|
-
|
|
130
|
+
// Read only the rows at or below the input box (Issue #2847): a footer quoted in the reply
|
|
131
|
+
// above it is conversation, not a picker.
|
|
132
|
+
if (cli_patterns_1.CLAUDE_SELECTION_LIST_FOOTER.test(selectionFooterRows(frame))) {
|
|
106
133
|
return {
|
|
107
134
|
status: 'waiting',
|
|
108
135
|
confidence: 'high',
|
|
@@ -101,6 +101,7 @@ exports.CODEX_DIALOG_FOOTER_PATTERN = exports.CODEX_DIALOG_RULES_VERIFIED_AGAINS
|
|
|
101
101
|
exports.readCodexGlyphRowKind = readCodexGlyphRowKind;
|
|
102
102
|
exports.findCodexBottomGlyphRow = findCodexBottomGlyphRow;
|
|
103
103
|
exports.readCodexDialogFrame = readCodexDialogFrame;
|
|
104
|
+
exports.isCodexComposerAtBottom = isCodexComposerAtBottom;
|
|
104
105
|
exports.reportCodexDialogFooterDrift = reportCodexDialogFooterDrift;
|
|
105
106
|
exports.resetCodexDialogFooterDriftForTests = resetCodexDialogFooterDriftForTests;
|
|
106
107
|
const logger_1 = require("../../../../lib/logger");
|
|
@@ -384,6 +385,56 @@ function readCodexDialogFrame(raw, contentLines, contentEnd) {
|
|
|
384
385
|
footerRecognised: exports.CODEX_DIALOG_FOOTER_PATTERN.test(footer),
|
|
385
386
|
};
|
|
386
387
|
}
|
|
388
|
+
/** A `›` row that is a numbered option (`› 1. …`), as opposed to the composer. */
|
|
389
|
+
const CODEX_NUMBERED_GLYPH_ROW_PATTERN = /^\s*›\s*\d{1,2}[.)]\s/;
|
|
390
|
+
/**
|
|
391
|
+
* Is the bottom of this codex pane the composer (Issue #2841)?
|
|
392
|
+
*
|
|
393
|
+
* codex draws exactly one thing between the conversation and its status bar:
|
|
394
|
+
* the composer, or a dialog that REPLACES the composer while it is open. Every
|
|
395
|
+
* measured dialog frame (`tests/fixtures/codex-dialogs-0155/`,
|
|
396
|
+
* `tests/fixtures/codex-live-2310/`, `codex-live-1628/`) ends on the dialog's
|
|
397
|
+
* rows with no `›` row below its footer. So when the composer is the pane's
|
|
398
|
+
* bottom, no dialog is open, whatever the conversation above it says — and the
|
|
399
|
+
* conversation is free text: an agent quoting another session's approval dialog
|
|
400
|
+
* (the reported case), a numbered list, a pasted footer.
|
|
401
|
+
*
|
|
402
|
+
* This is the one question every dialog reading in this module asks first, so
|
|
403
|
+
* that no reading can be satisfied by words in the transcript.
|
|
404
|
+
*
|
|
405
|
+
* Two readings, in order:
|
|
406
|
+
*
|
|
407
|
+
* 1. **raw** — the bottom-most `›` row of the RAW capture
|
|
408
|
+
* ({@link findCodexBottomGlyphRow}) is `composer` → true; `option` → false;
|
|
409
|
+
* `transcript-echo` → false (not shown to be the composer).
|
|
410
|
+
* 2. **stripped** (no attributes: Auto-Yes and `prompt-answer-sender` hand the
|
|
411
|
+
* layer a `stripAnsi`'d capture) — the last non-blank row of the content
|
|
412
|
+
* region starts with `›` and is not a numbered option row. A dialog's
|
|
413
|
+
* highlighted row can also be the last row; a numbered one is excluded here,
|
|
414
|
+
* and an unnumbered one keeps the reading it had before (branch 2.7 B
|
|
415
|
+
* already calls that frame `ready` when stripped).
|
|
416
|
+
*
|
|
417
|
+
* False only means "not shown to be the composer": callers must use it as a
|
|
418
|
+
* veto on a dialog reading, never as evidence of one.
|
|
419
|
+
*
|
|
420
|
+
* @param raw - The capture exactly as it arrived (`NormalizedFrame.raw`)
|
|
421
|
+
* @param contentLines - The ANSI-stripped rows (`NormalizedFrame.contentLines`)
|
|
422
|
+
* @param contentEnd - Exclusive end of the conversation region (the row above
|
|
423
|
+
* the status bar with padding walked off, or `contentLines.length`)
|
|
424
|
+
*/
|
|
425
|
+
function isCodexComposerAtBottom(raw, contentLines, contentEnd) {
|
|
426
|
+
const glyphRow = findCodexBottomGlyphRow(raw);
|
|
427
|
+
if (glyphRow !== null)
|
|
428
|
+
return glyphRow.kind === 'composer';
|
|
429
|
+
const end = Math.min(contentEnd, contentLines.length);
|
|
430
|
+
let last = end - 1;
|
|
431
|
+
while (last >= 0 && contentLines[last].trim() === '')
|
|
432
|
+
last--;
|
|
433
|
+
if (last < 0)
|
|
434
|
+
return false;
|
|
435
|
+
const row = contentLines[last];
|
|
436
|
+
return row.trimStart().startsWith(exports.CODEX_GLYPH) && !CODEX_NUMBERED_GLYPH_ROW_PATTERN.test(row);
|
|
437
|
+
}
|
|
387
438
|
/** Index of the bottom-most `›` row within the content region, or -1. */
|
|
388
439
|
function findLastGlyphContentRow(contentLines, endExclusive) {
|
|
389
440
|
for (let i = Math.min(endExclusive, contentLines.length) - 1; i >= 0; i--) {
|
|
@@ -166,6 +166,16 @@ exports.codexStatusDetector = (0, run_detection_1.createToolStatusDetector)({
|
|
|
166
166
|
verifiedAgainst: exports.VERIFIED_AGAINST,
|
|
167
167
|
beforePrompt(frame) {
|
|
168
168
|
const { contentLines } = frame;
|
|
169
|
+
// 0.6. The composer is the pane's bottom → no dialog is open (Issue #2841).
|
|
170
|
+
// Every branch below reads dialog chrome (a pager footer, a lifecycle
|
|
171
|
+
// screen, a "Press enter to confirm" footer, a `›`-selected block) out of
|
|
172
|
+
// rows that can also be conversation text. codex hides the composer while a
|
|
173
|
+
// dialog is up, so a composer at the bottom vetoes all of them at once, and
|
|
174
|
+
// the chain goes on to the prompt / thinking / idle readings it would have
|
|
175
|
+
// reached had the transcript not quoted anything.
|
|
176
|
+
if ((0, cli_patterns_2.isCodexComposerAtBottom)(frame.raw, contentLines, findCodexContentEnd(contentLines))) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
169
179
|
// 0.7. Codex: pager / edit-previous (transcript) mode detection (Issue #1017)
|
|
170
180
|
// Codex's transcript pager renders scroll / edit key-hint footers, e.g.:
|
|
171
181
|
// "↑/↓ to scroll pgup/pgdn to page home/end to jump"
|
|
@@ -321,15 +331,24 @@ exports.codexStatusDetector = (0, run_detection_1.createToolStatusDetector)({
|
|
|
321
331
|
return null;
|
|
322
332
|
},
|
|
323
333
|
isStalePrompt(frame) {
|
|
324
|
-
|
|
334
|
+
// Issue #2841: a prompt above the composer is conversation text, not a
|
|
335
|
+
// dialog — the same veto branch 0.6 applies to the status branches.
|
|
336
|
+
return (isCodexStalePrompt(frame.contentLines) ||
|
|
337
|
+
(0, cli_patterns_2.isCodexComposerAtBottom)(frame.raw, frame.contentLines, findCodexContentEnd(frame.contentLines)));
|
|
325
338
|
},
|
|
326
339
|
// §4 D1 決定 4 (Issue #1928). All three inputs are readings this module
|
|
327
340
|
// already performs for its status branches, passed rather than recomputed:
|
|
328
341
|
// the content boundary (0.8 / 2.7), the #1160 staleness guard and the #1829
|
|
329
342
|
// lifecycle screens. `prompt.ts` therefore needs no import from this file.
|
|
330
343
|
detectDialog(frame) {
|
|
344
|
+
// Issue #2841: Auto-Yes and `respond` act on this answer, so it takes the
|
|
345
|
+
// same veto as the status branches — before the lifecycle screens too, whose
|
|
346
|
+
// wording (`Do you trust …`) can be quoted like any other.
|
|
347
|
+
const contentEnd = findCodexContentEnd(frame.contentLines);
|
|
348
|
+
if ((0, cli_patterns_2.isCodexComposerAtBottom)(frame.raw, frame.contentLines, contentEnd))
|
|
349
|
+
return null;
|
|
331
350
|
return (0, prompt_1.detectCodexDialog)(frame, {
|
|
332
|
-
contentEnd
|
|
351
|
+
contentEnd,
|
|
333
352
|
stalePrompt: isCodexStalePrompt(frame.contentLines),
|
|
334
353
|
lifecycleDialog: (0, cli_patterns_1.getCodexLifecycleDialog)(frame.clean),
|
|
335
354
|
});
|
|
@@ -174,7 +174,13 @@ exports.commandCodeStatusDetector = (0, run_detection_1.createToolStatusDetector
|
|
|
174
174
|
// pending (`←/→ choose · enter confirm · esc back`). The same verdict: it is
|
|
175
175
|
// the same overlay, still waiting on a human's decision about the plan,
|
|
176
176
|
// and the arrow pad (`◀` `▶` `Enter` `Esc`) is exactly what it asks for.
|
|
177
|
-
|
|
177
|
+
//
|
|
178
|
+
// Issue #2846: the footer has to be at the BOTTOM of the frame, not merely
|
|
179
|
+
// somewhere in the 15-row window. A reply that quotes `Approve ctrl+a` /
|
|
180
|
+
// `Cancel esc` sits above the composer, and `frame.lastLines` used to match it
|
|
181
|
+
// there — `waiting` on a pane that was waiting for a message. See
|
|
182
|
+
// `hasCommandCodePlanReviewFooterAtBottom` for how far from the end is "bottom".
|
|
183
|
+
if ((0, selection_shape_1.hasCommandCodePlanReviewFooterAtBottom)(frame.lastLines) ||
|
|
178
184
|
(0, selection_shape_1.isCommandCodePlanApproveChoice)(frame.lastLines)) {
|
|
179
185
|
return {
|
|
180
186
|
status: 'waiting',
|
|
@@ -278,7 +284,10 @@ exports.commandCodeStatusDetector = (0, run_detection_1.createToolStatusDetector
|
|
|
278
284
|
//
|
|
279
285
|
// A human still has to press the key, so `waiting` is also the honest word:
|
|
280
286
|
// nothing on this pane will move until they do.
|
|
281
|
-
|
|
287
|
+
//
|
|
288
|
+
// Issue #2846: only when `Press Esc to close` is the LAST row. The panel draws
|
|
289
|
+
// it last; a reply that quotes it has the composer underneath.
|
|
290
|
+
if ((0, selection_shape_1.hasCommandCodeDismissablePanelFooterAtBottom)(frame.lastLines)) {
|
|
282
291
|
return {
|
|
283
292
|
status: 'waiting',
|
|
284
293
|
confidence: 'high',
|
|
@@ -298,7 +307,9 @@ exports.commandCodeStatusDetector = (0, run_detection_1.createToolStatusDetector
|
|
|
298
307
|
// `waiting` + `positive`, exactly as claude's selection-list branch reports:
|
|
299
308
|
// a human has to move the highlight and press enter, and the frame says so
|
|
300
309
|
// in as many words.
|
|
301
|
-
|
|
310
|
+
//
|
|
311
|
+
// Issue #2846: last row only, for the reason the branch above gives.
|
|
312
|
+
if ((0, selection_shape_1.hasCommandCodeSelectionListFooterAtBottom)(frame.lastLines)) {
|
|
302
313
|
return {
|
|
303
314
|
status: 'waiting',
|
|
304
315
|
confidence: 'high',
|