{"record":{"id":"35aad8c3c9b974ee","repo":"jackwener/OpenCLI","slug":"composer-type-failed-35aad8","errorCode":null,"errorMessage":"composer type failed","messagePattern":"composer type failed","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/qoder/quest.js","lineNumber":67,"sourceCode":"cli({\n    site: 'qoder',\n    name: 'send',\n    access: 'write',\n    description: 'Type text into the Qoder composer and click \"Send message\" (fire-and-forget).',\n    domain: 'localhost',\n    strategy: Strategy.UI,\n    browser: true,\n    args: [\n        { name: 'text', positional: true, required: true, help: 'Text to send' },\n    ],\n    columns: ['Status', 'Length'],\n    func: async (page, kwargs) => {\n        const text = String(kwargs?.text || '').trim();\n        if (!text) throw new ArgumentError('text is required');\n\n        const beforeCount = await evaluateQoder(page, QODER_MESSAGE_COUNT_JS);\n        const typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text));\n        if (!typeRes?.ok) throw new CommandExecutionError(typeRes?.reason || 'composer type failed', '');\n        await page.wait(0.3);\n\n        // Click Send message\n        const sendRes = await evaluateQoder(page, clickFirstScript([\n            'button[aria-label=\"Send message\"]',\n            'button[title=\"Send message\"]',\n        ]));\n        if (!sendRes?.ok) {\n            // Fallback: try clickByText.\n            const textRes = await evaluateQoder(page, clickByTextScript(['Send message', 'Send', '发送']));\n            if (!textRes?.ok) throw new CommandExecutionError('Send button not found', '');\n        }\n        const afterCount = await waitForMessageCountGrowth(page, beforeCount);\n        if (Number(afterCount) <= Number(beforeCount)) {\n            throw new CommandExecutionError('Qoder send did not create a new visible message row');\n        }\n        return [{ Status: 'sent', Length: String(text.length) }];\n    },","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/qoder/quest.js#L49-L85","documentation":"A CommandExecutionError thrown by the qoder send command when the text-injection script (buildQoderInjectTextScript) fails to type the prompt into the composer. The message prefers the script's own reason (typeRes?.reason) and falls back to this literal string. It means DOM evaluation to fill the composer textarea returned ok:false — the send step is never reached.","triggerScenarios":"Running `qoder send <text>` when: the composer textarea/input does not exist yet (UI still loading or wrong panel active); the injection script targeted a selector Qoder changed in an update; the webview is in a state where execCommand/insertText or setting .value + dispatching input events is blocked (React controlled components resetting value); or evaluateQoder could not attach to the page.","commonSituations":"Qoder updates switching the composer from a plain textarea to a contenteditable/ProseMirror editor, breaking value-based injection; sending before the chat view finishes mounting; multiple Qoder windows causing evaluateQoder to target a stale frame.","solutions":["Confirm the Qoder chat view is open and the composer is visible before running send; retry after a short wait.","If the reason indicates a selector miss, inspect the composer DOM and update buildQoderInjectTextScript's selector to match the current markup.","If the value set is reverted (React controlled input), switch the injection to input-event-based methods: document.execCommand('insertText') or native setter + dispatched InputEvent.","Re-attach to the correct webview/window (close extra Qoder windows) and rerun."],"exampleFix":"// before\nconst typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text));\nif (!typeRes?.ok) throw new CommandExecutionError(typeRes?.reason || 'composer type failed', '');\n// after\nawait page.wait(1); // ensure composer mounted\nlet typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text));\nif (!typeRes?.ok) typeRes = await evaluateQoder(page, insertTextViaExecCommandScript(text)); // contenteditable fallback","handlingStrategy":"retry","validationCode":"// Confirm the composer exists and is editable before invoking send\nconst composerReady = await page.evaluate(() => {\n  const el = document.querySelector('textarea, [contenteditable=\"true\"]');\n  return !!el && !el.disabled && !el.readOnly;\n});\nif (!composerReady) throw new Error('Qoder composer not ready — wait for the chat view to mount');","typeGuard":"function injectionSucceeded(res) {\n  return typeof res === 'object' && res !== null && res.ok === true;\n}","tryCatchPattern":"try {\n  await runCli('qoder send', [text]);\n} catch (e) {\n  if (String(e.message).includes('composer type failed')) {\n    await sleep(1000);\n    await runCli('qoder send', [text]); // retry after composer mounts\n  } else throw e;\n}","preventionTips":["Wait for the chat view/composer to be visible before sending.","After Qoder updates, re-test text injection — editor internals may change.","Keep only one Qoder window open so evaluate targets the right frame.","Prefer event-based injection (execCommand/insertText) for contenteditable composers."],"tags":["ui-automation","dom-injection","browser","qoder"],"backgroundTag":"dom-injection-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}