{"record":{"id":"d882d1c1a8ac302a","repo":"wavetermdev/waveterm","slug":"cannot-get-last-command-data-without-shell-integra","errorCode":null,"errorMessage":"Cannot get last command data without shell integration","messagePattern":"Cannot get last command data without shell integration","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/app/view/term/term-wsh.tsx","lineNumber":127,"sourceCode":"        rh: RpcResponseHelper,\n        data: CommandTermGetScrollbackLinesData\n    ): Promise<CommandTermGetScrollbackLinesRtnData> {\n        const termWrap = this.model.termRef.current;\n        if (!termWrap || !termWrap.terminal) {\n            return {\n                totallines: 0,\n                linestart: data.linestart,\n                lines: [],\n                lastupdated: 0,\n            };\n        }\n\n        const buffer = termWrap.terminal.buffer.active;\n        const totalLines = buffer.length;\n\n        if (data.lastcommand) {\n            if (globalStore.get(termWrap.shellIntegrationStatusAtom) == null) {\n                throw new Error(\"Cannot get last command data without shell integration\");\n            }\n\n            let startBufferIndex = 0;\n            let endBufferIndex = totalLines;\n            if (termWrap.promptMarkers.length > 0) {\n                // The last marker is the current prompt, so we want the second-to-last for the previous command\n                // If there's only one marker, use it (edge case for first command)\n                const markerIndex =\n                    termWrap.promptMarkers.length > 1\n                        ? termWrap.promptMarkers.length - 2\n                        : termWrap.promptMarkers.length - 1;\n                const commandStartMarker = termWrap.promptMarkers[markerIndex];\n                startBufferIndex = commandStartMarker.line;\n\n                // End at the last marker (current prompt) if there are multiple markers\n                if (termWrap.promptMarkers.length > 1) {\n                    const currentPromptMarker = termWrap.promptMarkers[termWrap.promptMarkers.length - 1];\n                    endBufferIndex = currentPromptMarker.line;","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/frontend/app/view/term/term-wsh.tsx#L109-L145","documentation":"When a termgetscrollbacklines request asks for lastcommand metadata, the terminal must have shell integration active (prompt markers/command tracking). If the shell integration status atom is null, no such data can be derived, so the handler throws instead of returning wrong boundaries.","triggerScenarios":"Requesting scrollback with lastcommand:true while the shell lacks integration (plain bash/sh without osc prompt hooks), the integration script failed to load, or the terminal just started and status was never set.","commonSituations":"Using minimal/ exotic shells without Wave's shell-integration hooks, connecting over ssh without the integration being injected, or users disabling shell integration in settings.","solutions":["Enable/install shell integration for the running shell (source the provided integration script in the shell rc).","Retry only after shellIntegrationStatusAtom is non-null; poll or subscribe instead of assuming.","Set lastcommand:false (or omit it) if you only need raw scrollback lines.","Verify the shell/term environment actually reports integration status (check termWrap.shellIntegrationStatusAtom)."],"exampleFix":"// before\nconst lines = await RpcApi.TermGetScrollbackLines(controller, { lastcommand: true });\n// after\nconst hasIntegration = globalStore.get(termWrap.shellIntegrationStatusAtom) != null;\nconst lines = await RpcApi.TermGetScrollbackLines(controller, { lastcommand: hasIntegration });","handlingStrategy":"fallback","validationCode":"const status = globalStore.get(termWrap.shellIntegrationStatusAtom);\nif (data.lastcommand && status == null) {\n  // degrade: request without lastcommand metadata\n  data = { ...data, lastcommand: false };\n}","typeGuard":"function hasShellIntegration(termWrap: TermWrap): boolean {\n  return globalStore.get(termWrap.shellIntegrationStatusAtom) != null;\n}","tryCatchPattern":"try {\n  return await getScrollbackLines(data);\n} catch (e) {\n  if (String(e.message).includes(\"without shell integration\")) {\n    // fall back to plain scrollback without last-command boundaries\n    return await getScrollbackLines({ ...data, lastcommand: false });\n  }\n  throw e;\n}","preventionTips":["Install Wave's shell-integration hooks in all shells you use (including remote/ssh).","Check shellIntegrationStatusAtom before requesting command metadata.","Design callers to degrade gracefully to raw scrollback when integration is absent."],"tags":["terminal","shell-integration","precondition-failed"],"backgroundTag":"shell-integration-required","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}