create-walle 0.9.30 → 0.9.32
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/package.json +1 -1
- package/template/claude-task-manager/api-prompts.js +410 -5
- package/template/claude-task-manager/api-reviews.js +251 -3
- package/template/claude-task-manager/approval-agent.js +322 -24
- package/template/claude-task-manager/db.js +77 -13
- package/template/claude-task-manager/docs/codex-app-server-approvals.md +35 -1
- package/template/claude-task-manager/docs/postgres-concurrency-dgx-spark.html +407 -0
- package/template/claude-task-manager/docs/prompt-manager-redesign-proposal.html +667 -0
- package/template/claude-task-manager/docs/resume-ux-redesign.html +493 -0
- package/template/claude-task-manager/docs/review-redesign-proposal.html +892 -0
- package/template/claude-task-manager/docs/unified-auto-approver-proposal.html +520 -0
- package/template/claude-task-manager/git-utils.js +164 -26
- package/template/claude-task-manager/lib/agent-capabilities.js +26 -5
- package/template/claude-task-manager/lib/agent-cli-cache.js +1 -1
- package/template/claude-task-manager/lib/agent-presets.js +12 -0
- package/template/claude-task-manager/lib/agent-version-service.js +650 -0
- package/template/claude-task-manager/lib/approval-drift.js +57 -0
- package/template/claude-task-manager/lib/approval-hook.js +13 -0
- package/template/claude-task-manager/lib/auth-rules.js +6 -0
- package/template/claude-task-manager/lib/broadcast-payload-memo.js +109 -0
- package/template/claude-task-manager/lib/coding-agent-models.js +89 -8
- package/template/claude-task-manager/lib/db-owner-cooperative-scheduler.js +10 -1
- package/template/claude-task-manager/lib/document-review.js +75 -1
- package/template/claude-task-manager/lib/escalation-review.js +33 -3
- package/template/claude-task-manager/lib/headless-term-service.js +54 -9
- package/template/claude-task-manager/lib/mcp-risk.js +128 -0
- package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +51 -2
- package/template/claude-task-manager/lib/native-agent-model-args.js +149 -0
- package/template/claude-task-manager/lib/opencode-conversation-store.js +269 -0
- package/template/claude-task-manager/lib/permission-match.js +77 -5
- package/template/claude-task-manager/lib/read-pool-client.js +15 -6
- package/template/claude-task-manager/lib/restore-backoff.js +82 -0
- package/template/claude-task-manager/lib/runtime-registry.js +1 -0
- package/template/claude-task-manager/lib/scheduled-wake.js +42 -0
- package/template/claude-task-manager/lib/session-capture.js +33 -6
- package/template/claude-task-manager/lib/session-history.js +60 -3
- package/template/claude-task-manager/lib/session-jobs.js +19 -0
- package/template/claude-task-manager/lib/session-restore.js +5 -4
- package/template/claude-task-manager/lib/session-standup.js +2 -0
- package/template/claude-task-manager/lib/session-stream.js +9 -0
- package/template/claude-task-manager/lib/state-sync/cell-diff.js +31 -4
- package/template/claude-task-manager/lib/state-sync/restore-frame-hold.js +39 -0
- package/template/claude-task-manager/lib/tui-input-modes.js +40 -0
- package/template/claude-task-manager/lib/walle-ctm-history.js +103 -36
- package/template/claude-task-manager/lib/walle-session-model-catalog.js +7 -1
- package/template/claude-task-manager/lib/walle-token-chip.js +65 -0
- package/template/claude-task-manager/package.json +1 -1
- package/template/claude-task-manager/providers/claude-code.js +20 -1
- package/template/claude-task-manager/providers/codex-mcp-extract.js +33 -0
- package/template/claude-task-manager/providers/codex-mcp.js +23 -20
- package/template/claude-task-manager/providers/codex.js +65 -1
- package/template/claude-task-manager/public/css/prompts.css +345 -0
- package/template/claude-task-manager/public/css/reviews.css +248 -40
- package/template/claude-task-manager/public/css/walle-session.css +90 -26
- package/template/claude-task-manager/public/index.html +2031 -428
- package/template/claude-task-manager/public/js/document-review-links.js +255 -13
- package/template/claude-task-manager/public/js/file-context-menu.js +185 -0
- package/template/claude-task-manager/public/js/message-renderer.js +46 -1
- package/template/claude-task-manager/public/js/mobile-review-core.js +54 -0
- package/template/claude-task-manager/public/js/prompt-diff.js +55 -0
- package/template/claude-task-manager/public/js/prompt-editor-chrome.js +108 -0
- package/template/claude-task-manager/public/js/prompt-editor-modes.js +87 -0
- package/template/claude-task-manager/public/js/prompt-organize.js +179 -0
- package/template/claude-task-manager/public/js/prompt-reuse.js +77 -0
- package/template/claude-task-manager/public/js/prompts.js +683 -215
- package/template/claude-task-manager/public/js/resume-state.js +186 -0
- package/template/claude-task-manager/public/js/reviews.js +402 -121
- package/template/claude-task-manager/public/js/screenshot-router.js +91 -0
- package/template/claude-task-manager/public/js/session-search-utils.js +81 -0
- package/template/claude-task-manager/public/js/state-sync-client.js +134 -17
- package/template/claude-task-manager/public/js/stream-view.js +93 -20
- package/template/claude-task-manager/public/js/walle-session.js +183 -32
- package/template/claude-task-manager/public/js/walle.js +21 -9
- package/template/claude-task-manager/public/m/app.css +117 -0
- package/template/claude-task-manager/public/m/app.js +309 -3
- package/template/claude-task-manager/public/m/index.html +56 -1
- package/template/claude-task-manager/server.js +724 -305
- package/template/claude-task-manager/workers/db-owner-worker.js +8 -0
- package/template/claude-task-manager/workers/read-pool-worker.js +4 -0
- package/template/claude-task-manager/workers/state-detectors/claude-code.js +10 -1
- package/template/docs/proposals/2026-06-23-local-model-right-path.html +340 -0
- package/template/docs/proposals/2026-06-24-qlora-done-right.md +255 -0
- package/template/package.json +1 -1
- package/template/wall-e/api-walle.js +21 -3
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +27 -4
- package/template/wall-e/brain.js +50 -5
- package/template/wall-e/chat/force-compact.js +73 -0
- package/template/wall-e/chat.js +137 -9
- package/template/wall-e/coding/action-memory-policy.js +120 -1
- package/template/wall-e/coding/compaction-service.js +10 -3
- package/template/wall-e/coding/model-router.js +116 -0
- package/template/wall-e/coding-orchestrator.js +303 -11
- package/template/wall-e/coding-prompts.js +1 -1
- package/template/wall-e/docs/skill-self-heal-design.html +429 -0
- package/template/wall-e/llm/client.js +115 -6
- package/template/wall-e/llm/codex-cli.js +71 -23
- package/template/wall-e/llm/codex-cli.plugin.json +1 -0
- package/template/wall-e/llm/default-fallback.js +71 -11
- package/template/wall-e/llm/mlx-worker.js +0 -0
- package/template/wall-e/llm/mlx.js +46 -12
- package/template/wall-e/llm/provider-error.js +9 -3
- package/template/wall-e/llm/provider-health-state.js +561 -11
- package/template/wall-e/llm/registry.js +6 -0
- package/template/wall-e/llm/routing-policy.js +255 -25
- package/template/wall-e/llm/tool-call-validator.js +156 -0
- package/template/wall-e/skills/skill-dispatch-decision.js +82 -2
- package/template/wall-e/skills/skill-planner.js +72 -5
- package/template/wall-e/tools/command-registry.js +34 -0
- package/template/wall-e/training/gemma-e4b-qlora.js +197 -1
- package/template/wall-e/training/mlx_lora_launch.py +196 -0
- package/template/wall-e/training/training-coexistence.sh +87 -0
- package/template/wall-e/training/training-mem-guard.sh +76 -0
|
@@ -1814,6 +1814,13 @@ function runMigrations() {
|
|
|
1814
1814
|
if (!scCols2.find(c => c.name === 'extracted_source_len')) {
|
|
1815
1815
|
getDb().prepare("ALTER TABLE session_conversations ADD COLUMN extracted_source_len INTEGER DEFAULT -1").run();
|
|
1816
1816
|
}
|
|
1817
|
+
// Byte size of the .jsonl.bak at last full compact-pair stitch. The .bak is byte-stable between
|
|
1818
|
+
// compactions, so a later .jsonl-only growth can append just the new tail (priorJsonlSize =
|
|
1819
|
+
// file_size - compact_bak_size) instead of re-reading+re-stitching the whole (100MB+) pair — the
|
|
1820
|
+
// giant compacted-session import freeze. 0 = not a compact-pair / unknown → take the full path.
|
|
1821
|
+
if (!scCols2.find(c => c.name === 'compact_bak_size')) {
|
|
1822
|
+
getDb().prepare("ALTER TABLE session_conversations ADD COLUMN compact_bak_size INTEGER DEFAULT 0").run();
|
|
1823
|
+
}
|
|
1817
1824
|
if (!scCols2.find(c => c.name === 'last_message_at')) {
|
|
1818
1825
|
getDb().prepare("ALTER TABLE session_conversations ADD COLUMN last_message_at TEXT").run();
|
|
1819
1826
|
try {
|
|
@@ -4164,7 +4171,7 @@ function getPrompt(id) {
|
|
|
4164
4171
|
}
|
|
4165
4172
|
|
|
4166
4173
|
function listPrompts({ folder_id, context_type, search, starred, limit, offset, include_children, lifecycle_status } = {}) {
|
|
4167
|
-
let sql = `SELECT p.*, (SELECT COUNT(*) FROM prompts c WHERE c.parent_id = p.id) as child_count FROM prompts p WHERE 1=1`;
|
|
4174
|
+
let sql = `SELECT p.*, (SELECT COUNT(*) FROM prompts c WHERE c.parent_id = p.id) as child_count, (SELECT COUNT(*) FROM prompt_usage u WHERE u.prompt_id = p.id) as use_count, (SELECT MAX(v.version) FROM prompt_versions v WHERE v.prompt_id = p.id) as version FROM prompts p WHERE 1=1`;
|
|
4168
4175
|
const params = [];
|
|
4169
4176
|
|
|
4170
4177
|
// By default, only show top-level prompts (parent_id IS NULL)
|
|
@@ -5030,6 +5037,19 @@ const _importTokenEstimateLen = new Map();
|
|
|
5030
5037
|
function _blobRetirementActive() {
|
|
5031
5038
|
return process.env.CTM_DUAL_WRITE_BLOB !== '1' && process.env.CTM_SESSION_ROWS !== '0';
|
|
5032
5039
|
}
|
|
5040
|
+
// Belt-and-suspenders: the over-cap guard above should already skip the whole-array stringify for a
|
|
5041
|
+
// multi-GB conversation, but if any caller ever under-reports the size again, a >512MB JSON.stringify
|
|
5042
|
+
// would throw a RangeError and abort the import (and the loop). Degrade to an empty blob instead — the
|
|
5043
|
+
// session then renders from rows / the streaming transcript-store, exactly like the over-cap path.
|
|
5044
|
+
function _safeBlobStringify(messages) {
|
|
5045
|
+
try {
|
|
5046
|
+
return JSON.stringify(messages || []);
|
|
5047
|
+
} catch (e) {
|
|
5048
|
+
console.error(`[db] blob stringify failed (${e.message}) — storing empty blob, reads fall back to rows.`);
|
|
5049
|
+
return '[]';
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
|
|
5033
5053
|
function importSessionConversation({
|
|
5034
5054
|
session_id, project_path, messages, user_msg_count, assistant_msg_count,
|
|
5035
5055
|
search_messages,
|
|
@@ -5047,6 +5067,16 @@ function importSessionConversation({
|
|
|
5047
5067
|
// while content-rows-backfill fills rows across slices (chunked/cold-import route). Over-cap still
|
|
5048
5068
|
// wins — a multi-GB stringify is never safe regardless of this flag.
|
|
5049
5069
|
forceBlobWrite,
|
|
5070
|
+
// Byte size of the .jsonl.bak at this compact-pair stitch (0 / omitted for non-compact imports).
|
|
5071
|
+
// Persisted so a later .jsonl-only growth can append just the new tail instead of re-stitching the
|
|
5072
|
+
// whole pair. Always written so a session that stops being a compact-pair resets to 0.
|
|
5073
|
+
compact_bak_size,
|
|
5074
|
+
// Truthful on-disk transcript size, used ONLY for the over-cap decision below. Some callers pass a
|
|
5075
|
+
// `file_size` that under-reports the real conversation size (codex `importedFileSize` is a
|
|
5076
|
+
// consumed-bytes high-water-mark), which would let a multi-GB rollout slip under the parse cap and
|
|
5077
|
+
// then throw at JSON.stringify (>512MB). Decision-only: the stored `file_size` column is unchanged.
|
|
5078
|
+
// Defaults to `file_size` when omitted (back-compat for every existing caller).
|
|
5079
|
+
parse_size_bytes,
|
|
5050
5080
|
}) {
|
|
5051
5081
|
// Attribution: the whole import is one synchronous span — a JSON.stringify of
|
|
5052
5082
|
// the full message array (multi-MB for 2000+ prompt sessions) + an upsert + a
|
|
@@ -5064,7 +5094,12 @@ function importSessionConversation({
|
|
|
5064
5094
|
// heavy work; the streaming transcript-store rows remain the source of truth.
|
|
5065
5095
|
let _isOverParseCap = null;
|
|
5066
5096
|
try { _isOverParseCap = require('./lib/size-cap').isOverParseCap; } catch { /* optional */ }
|
|
5067
|
-
|
|
5097
|
+
// Prefer the truthful on-disk size when the caller provides it; fall back to file_size. isOverParseCap
|
|
5098
|
+
// already fails open on a non-finite/zero value, so the fallback is robust.
|
|
5099
|
+
const _parseSizeBytes = Number.isFinite(Number(parse_size_bytes)) && Number(parse_size_bytes) > 0
|
|
5100
|
+
? Number(parse_size_bytes)
|
|
5101
|
+
: file_size;
|
|
5102
|
+
const _overParseCap = typeof _isOverParseCap === 'function' ? _isOverParseCap(_parseSizeBytes) : false;
|
|
5068
5103
|
// Phase 7 (blob retirement): reads are served from session_message_rows (the
|
|
5069
5104
|
// faithful per-message store), so the monolithic `messages` blob is dead weight
|
|
5070
5105
|
// and its full-array JSON.stringify on every append is the O(N²) write cost we
|
|
@@ -5080,7 +5115,7 @@ function importSessionConversation({
|
|
|
5080
5115
|
const _skipBlobWrite = _overParseCap || (_retireBlob && !forceBlobWrite);
|
|
5081
5116
|
if (_overParseCap && !_overCapImportLogged.has(session_id)) {
|
|
5082
5117
|
_overCapImportLogged.add(session_id);
|
|
5083
|
-
console.warn(`[db] session_conversations import over parse cap (file_size=${file_size}) for ${String(session_id || '').slice(0, 8)} — storing empty blob, skipping full stringify/row-rewrite.`);
|
|
5118
|
+
console.warn(`[db] session_conversations import over parse cap (parse_size=${_parseSizeBytes}, file_size=${file_size}) for ${String(session_id || '').slice(0, 8)} — storing empty blob, skipping full stringify/row-rewrite.`);
|
|
5084
5119
|
}
|
|
5085
5120
|
// Estimate-tier token fallback, FOLDED INTO the upsert below (no extra write /
|
|
5086
5121
|
// WAL flush). Stored so providers without an authoritative transcript
|
|
@@ -5115,8 +5150,8 @@ function importSessionConversation({
|
|
|
5115
5150
|
|
|
5116
5151
|
const _doImport = () => {
|
|
5117
5152
|
getDb().prepare(
|
|
5118
|
-
`INSERT INTO session_conversations (ctm_session_id, project_path, messages, user_msg_count, assistant_msg_count, title, first_message, git_branch, file_size, session_created_at, last_message_at, hostname, model_provider, model_id, import_parser_version, last_user_content, first_assistant_text, rename_name, tokens_total, tokens_ctx, tokens_window, tokens_exact, tokens_breakdown, tokens_updated_at)
|
|
5119
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
5153
|
+
`INSERT INTO session_conversations (ctm_session_id, project_path, messages, user_msg_count, assistant_msg_count, title, first_message, git_branch, file_size, session_created_at, last_message_at, hostname, model_provider, model_id, import_parser_version, last_user_content, first_assistant_text, rename_name, tokens_total, tokens_ctx, tokens_window, tokens_exact, tokens_breakdown, compact_bak_size, tokens_updated_at)
|
|
5154
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
5120
5155
|
ON CONFLICT(ctm_session_id) DO UPDATE SET
|
|
5121
5156
|
project_path=excluded.project_path,
|
|
5122
5157
|
messages=excluded.messages, user_msg_count=excluded.user_msg_count,
|
|
@@ -5143,16 +5178,18 @@ function importSessionConversation({
|
|
|
5143
5178
|
tokens_exact=CASE WHEN excluded.tokens_total IS NOT NULL THEN excluded.tokens_exact ELSE session_conversations.tokens_exact END,
|
|
5144
5179
|
tokens_breakdown=COALESCE(excluded.tokens_breakdown, session_conversations.tokens_breakdown),
|
|
5145
5180
|
tokens_updated_at=CASE WHEN excluded.tokens_total IS NOT NULL THEN excluded.tokens_updated_at ELSE session_conversations.tokens_updated_at END,
|
|
5181
|
+
compact_bak_size=excluded.compact_bak_size,
|
|
5146
5182
|
imported_at=datetime('now')`
|
|
5147
5183
|
).run(
|
|
5148
|
-
session_id, project_path || '', _skipBlobWrite ? '[]' :
|
|
5184
|
+
session_id, project_path || '', _skipBlobWrite ? '[]' : _safeBlobStringify(messages),
|
|
5149
5185
|
user_msg_count || 0, assistant_msg_count || 0, title || '',
|
|
5150
5186
|
first_message || '', git_branch || '', file_size || 0, session_created_at || '',
|
|
5151
5187
|
_lastMessageAt,
|
|
5152
5188
|
hostname || require('os').hostname(), model_provider || '', model_id || '',
|
|
5153
5189
|
Number(import_parser_version || 0),
|
|
5154
5190
|
last_user_content || '', first_assistant_text || '', rename_name || '',
|
|
5155
|
-
_tokTotal, _tokCtx, _tokWindow, _tokExact, _tokBreakdown
|
|
5191
|
+
_tokTotal, _tokCtx, _tokWindow, _tokExact, _tokBreakdown,
|
|
5192
|
+
Number(compact_bak_size) || 0
|
|
5156
5193
|
);
|
|
5157
5194
|
|
|
5158
5195
|
// Chunked-import route: rows are written later by content-rows-backfill (in windows). Stamp the
|
|
@@ -8190,9 +8227,16 @@ function appendSessionMessageRows(sessionId, newMessages, expectedBaseCount) {
|
|
|
8190
8227
|
const count = Number(d.prepare('SELECT COUNT(*) AS n FROM session_message_rows WHERE ctm_session_id = ?').get(sessionId).n);
|
|
8191
8228
|
// Dense 0..count-1 block — no gaps, starts at 0 — else appending would misorder.
|
|
8192
8229
|
if (count === 0 || minRow == null || minRow.idx !== 0 || count !== Number(maxRow.idx) + 1) return null;
|
|
8193
|
-
// The row
|
|
8194
|
-
//
|
|
8195
|
-
|
|
8230
|
+
// The dense row base must COVER the base length the delta was parsed against (count >= HWM).
|
|
8231
|
+
// A base SHORTER than the HWM (count < expectedBaseCount) is still backfilling / incomplete →
|
|
8232
|
+
// refuse so the full path re-establishes the invariant. A base AHEAD of the HWM (count > HWM) is
|
|
8233
|
+
// the giant compact-pair drift: a chunked full re-stitch stamps extracted_source_len = parseCount
|
|
8234
|
+
// but never rewrites the rows, so a piecewise-append row count sits a few ahead of the HWM. The
|
|
8235
|
+
// delta's byte boundary (file_size - bakSize) is independent of this count drift, so the delta is
|
|
8236
|
+
// still strictly-new bytes — appending onto the (dense, gap-free, 0-based) base at `count` is
|
|
8237
|
+
// correct and re-aligns the HWM (newLen = count + add.length). Refusing here instead forced a
|
|
8238
|
+
// perpetual full re-stitch of the 100MB+ pair every growth = the multi-second main-loop freeze.
|
|
8239
|
+
if (!Number.isFinite(expectedBaseCount) || expectedBaseCount < 0 || count < expectedBaseCount) return null;
|
|
8196
8240
|
const insertRow = d.prepare(
|
|
8197
8241
|
'INSERT OR IGNORE INTO session_message_rows (ctm_session_id, message_index, role, text, timestamp, meta) VALUES (?, ?, ?, ?, ?, ?)'
|
|
8198
8242
|
);
|
|
@@ -8354,6 +8398,22 @@ function sessionContentRowsAvailable(sessionId) {
|
|
|
8354
8398
|
} catch { return false; }
|
|
8355
8399
|
}
|
|
8356
8400
|
|
|
8401
|
+
// True when a chunked-route import deferred this session's per-message rows (extracted_source_len
|
|
8402
|
+
// stamped as the HWM) but the windowed content-rows-backfill hasn't filled them yet. This is the
|
|
8403
|
+
// exact window where the O(Δ) appendSessionConversation fast-path can't prove its row base and
|
|
8404
|
+
// refuses ('rows-not-appendable') — without this signal the caller falls through to a multi-second
|
|
8405
|
+
// full-rebuild blob re-parse (the giant-session restart freeze). A session with no deferred-rows HWM
|
|
8406
|
+
// (expected <= 0) is NOT pending: it's either a normal inline import or simply has no rows to wait on.
|
|
8407
|
+
function sessionRowsBackfillPending(sessionId) {
|
|
8408
|
+
try {
|
|
8409
|
+
const d = getDb();
|
|
8410
|
+
const conv = d.prepare('SELECT extracted_source_len FROM session_conversations WHERE ctm_session_id = ?').get(sessionId);
|
|
8411
|
+
const expected = conv ? Number(conv.extracted_source_len) : 0;
|
|
8412
|
+
if (!(expected > 0)) return false; // no deferred-rows HWM → nothing to wait on
|
|
8413
|
+
return !sessionContentRowsAvailable(sessionId); // HWM set but rows < HWM → backfill still pending
|
|
8414
|
+
} catch { return false; }
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8357
8417
|
// Newest-first offset page (matches lib/message-pagination.js semantics), O(limit) rows.
|
|
8358
8418
|
// Delegates to the shared lib/session-messages-page module so the SAME logic runs on the main
|
|
8359
8419
|
// thread (here) and on the read-pool worker (off-thread, read-only handle) — parity by construction.
|
|
@@ -8473,8 +8533,12 @@ function runContentRowsBackfillSweep(options = {}) {
|
|
|
8473
8533
|
const budgetMs = Math.max(0, Number(o.budgetMs ?? process.env.CTM_ROWS_BACKFILL_BUDGET_MS ?? 250));
|
|
8474
8534
|
const maxRows = Math.max(0, Number(o.maxRows ?? process.env.CTM_ROWS_BACKFILL_MAX_ROWS ?? 3000));
|
|
8475
8535
|
// Per-session row cap: migrate a giant session in bounded slices across ticks (resumable) so one
|
|
8476
|
-
// session can't hold the write lock for its whole length. 0 = whole-session (legacy/tests).
|
|
8477
|
-
|
|
8536
|
+
// session can't hold the write lock for its whole length. 0 = whole-session (legacy/tests). Default
|
|
8537
|
+
// 500: appendChunk holds the cross-process write lock for the whole row batch, and at the measured
|
|
8538
|
+
// ~6-7ms/row under Dropbox-WAL contention a 2000-row batch ran ~13.6s — over the coop 5s ceiling,
|
|
8539
|
+
// starving interactive writers during a giant session's first backfill. 500 keeps each batch's
|
|
8540
|
+
// lock-hold ~3-4s (under the ceiling, with margin); tune via CTM_ROWS_BACKFILL_MAX_ROWS_PER_SESSION.
|
|
8541
|
+
const maxRowsPerSession = Math.max(0, Number(o.maxRowsPerSession ?? process.env.CTM_ROWS_BACKFILL_MAX_ROWS_PER_SESSION ?? 500));
|
|
8478
8542
|
const bf = require('./lib/session-content-backfill');
|
|
8479
8543
|
return bf.runContentRowsBackfillSweep(getDb(), replaceSessionMessageRows, {
|
|
8480
8544
|
limit, budgetMs, maxRows, maxRowsPerSession,
|
|
@@ -10421,7 +10485,7 @@ module.exports = {
|
|
|
10421
10485
|
listPermissionLog, addPermissionLog,
|
|
10422
10486
|
getAlwaysAskTools, setAlwaysAsk,
|
|
10423
10487
|
importSessionConversation, appendSessionConversation, appendSessionMessageRows, listSessionConversations, getSessionConversation, getSessionConversationMeta, getSessionConversationMessages, updateSessionModel,
|
|
10424
|
-
replaceSessionMessageRows, appendSessionMessageRowsChunk, getSessionMessagesArray, sessionContentRowsAvailable, getSessionMessagesPage, getSessionMessagesTurnPage, countSessionMessageRows,
|
|
10488
|
+
replaceSessionMessageRows, appendSessionMessageRowsChunk, getSessionMessagesArray, sessionContentRowsAvailable, sessionRowsBackfillPending, getSessionMessagesPage, getSessionMessagesTurnPage, countSessionMessageRows,
|
|
10425
10489
|
runContentRowsBackfillSweep, getSessionRowsStatus, retireLegacyStores, runVacuum, _blobRetirementActive,
|
|
10426
10490
|
updateSessionTokens, getSessionTokens,
|
|
10427
10491
|
pickDisplayTitle,
|
|
@@ -64,9 +64,43 @@ The engine is also the right substrate for any **programmatic** Codex consumer (
|
|
|
64
64
|
Wall-E coding backend), where there is no TUI and driven mode is the *only* mode — there
|
|
65
65
|
the remaining UI item (1) does not even apply.
|
|
66
66
|
|
|
67
|
+
## Spike re-validation — codex-cli 0.142.3 (2026-06-27)
|
|
68
|
+
|
|
69
|
+
Triggered by the live `search_graph` strand: the scrape approver missed Codex's new MCP
|
|
70
|
+
approval UI (fixed separately — verb-anchored detection + a drift alarm). That prompted a
|
|
71
|
+
re-validation of the structured channel against the current binary. Findings:
|
|
72
|
+
|
|
73
|
+
1. **`--remote` removes the old blocker.** 0.142.3 ships `codex --remote <ws://|unix://>`,
|
|
74
|
+
`codex remote-control`, and `codex app-server proxy` — **a TUI can attach to a running
|
|
75
|
+
app-server**. So structured approvals no longer cost the interactive terminal, which was
|
|
76
|
+
the entire "larger product decision" above. The follow-on plan's **step 1** is to stand
|
|
77
|
+
up an app-server (or `app-server daemon`) and confirm the `--remote` attach UX end to end
|
|
78
|
+
(CTM hosts; the user's terminal attaches).
|
|
79
|
+
2. **Protocol method names held.** The v2 `item/commandExecution|fileChange|permissions/
|
|
80
|
+
requestApproval` + legacy `execCommandApproval`/`applyPatchApproval` the bridge maps are
|
|
81
|
+
still present in the 0.142.3 schema. The existing bridge mapping does not need to change
|
|
82
|
+
for those.
|
|
83
|
+
3. **GAP — the MCP path the screenshot represents is unhandled.** The schema now has
|
|
84
|
+
`McpServerElicitationRequest` (params + response) — the `Allow the <server> MCP server to
|
|
85
|
+
run tool …?` form *is* an MCP elicitation (`mode: form|openai/form|url`, `message` +
|
|
86
|
+
`requestedSchema` = the rendered `file_pattern`/`limit` fields). The bridge has **no
|
|
87
|
+
elicitation handler**, and its response is a **form accept**, not a yes/no. Also new and
|
|
88
|
+
unhandled: `item/tool/requestUserInput` (`ToolRequestUserInputParams`). These are the
|
|
89
|
+
concrete adds for driven-mode MCP auto-approval.
|
|
90
|
+
4. **Codex now self-reviews.** It emits `item/autoApprovalReview/started|completed`
|
|
91
|
+
notifications and exposes `approval_policy` / per-server `codex mcp` trust. The follow-on
|
|
92
|
+
must define how CTM's `decideApproval` **composes** with Codex's native auto-approval
|
|
93
|
+
(don't double-decide), or push the safe class into Codex config so it never asks.
|
|
94
|
+
|
|
95
|
+
Net: the structured channel is now the clearly-preferred durable fix (no TUI sacrifice), and
|
|
96
|
+
the remaining work is bounded — wire the driven/remote session type, add the elicitation +
|
|
97
|
+
requestUserInput handlers, and settle the autoApprovalReview composition. This stays a spike
|
|
98
|
+
branch until its own plan is approved.
|
|
99
|
+
|
|
67
100
|
## Reference
|
|
68
101
|
|
|
69
102
|
Exact wire contract (regenerate from the installed binary):
|
|
70
103
|
`codex app-server generate-json-schema --out <dir>` → `ServerRequest.json`,
|
|
71
|
-
`v2/ThreadStartParams.json`, `CommandExecutionRequestApprovalParams.json`,
|
|
104
|
+
`v2/ThreadStartParams.json`, `CommandExecutionRequestApprovalParams.json`,
|
|
105
|
+
`McpServerElicitationRequestParams.json`, etc.
|
|
72
106
|
See memory `ctm-approver-protocol-hook-prototype-validated` for the full protocol notes.
|