orquesta-agent 0.2.235 → 0.2.238

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.
Files changed (43) hide show
  1. package/README.md +45 -0
  2. package/dist/cli-auth-detect.d.ts +17 -0
  3. package/dist/cli-auth-detect.d.ts.map +1 -0
  4. package/dist/cli-auth-detect.js +31 -0
  5. package/dist/cli-auth-detect.js.map +1 -0
  6. package/dist/executor.d.ts +12 -4
  7. package/dist/executor.d.ts.map +1 -1
  8. package/dist/executor.js +201 -66
  9. package/dist/executor.js.map +1 -1
  10. package/dist/hook.d.ts +26 -1
  11. package/dist/hook.d.ts.map +1 -1
  12. package/dist/hook.js +170 -21
  13. package/dist/hook.js.map +1 -1
  14. package/dist/index.js +28 -14
  15. package/dist/index.js.map +1 -1
  16. package/dist/init.d.ts +42 -0
  17. package/dist/init.d.ts.map +1 -1
  18. package/dist/init.js +100 -28
  19. package/dist/init.js.map +1 -1
  20. package/dist/sandbox.d.ts.map +1 -1
  21. package/dist/sandbox.js +4 -0
  22. package/dist/sandbox.js.map +1 -1
  23. package/dist/supabase.d.ts +16 -8
  24. package/dist/supabase.d.ts.map +1 -1
  25. package/dist/supabase.js +30 -2
  26. package/dist/supabase.js.map +1 -1
  27. package/dist/types/hook-types.d.ts +49 -1
  28. package/dist/types/hook-types.d.ts.map +1 -1
  29. package/dist/ui/onboarding.js +1 -1
  30. package/dist/ui/onboarding.js.map +1 -1
  31. package/dist/ui/public/app.js +11 -1
  32. package/dist/ui/public/index.html +1 -0
  33. package/dist/ui/public/style.css +1 -0
  34. package/dist/ui/public/welcome.html +2 -0
  35. package/dist/ui/server.d.ts +1 -1
  36. package/dist/ui/server.d.ts.map +1 -1
  37. package/dist/ui/server.js +2 -2
  38. package/dist/ui/server.js.map +1 -1
  39. package/dist/ui/types.d.ts +1 -1
  40. package/dist/ui/types.d.ts.map +1 -1
  41. package/dist/ws-client.d.ts +1 -1
  42. package/dist/ws-client.d.ts.map +1 -1
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -86,6 +86,51 @@ This checks:
86
86
  - Claude authentication (API key or web subscription)
87
87
  - Git installation
88
88
 
89
+ ## IDE Hooks — mirror Claude Code and Cursor sessions
90
+
91
+ Everything above is *dispatch*: Orquesta sends work down to the agent. Hooks are
92
+ the opposite direction — you keep working in your own IDE and Orquesta mirrors
93
+ what happened. No daemon runs, and nothing is ever executed back into your editor.
94
+
95
+ ```bash
96
+ # Wire both tools (default)
97
+ orquesta-agent init --token oat_xxxxx
98
+
99
+ # Or pick one
100
+ orquesta-agent init --token oat_xxxxx --client cursor
101
+ orquesta-agent init --token oat_xxxxx --client claude
102
+ ```
103
+
104
+ `init` writes `.orquesta.json` (project binding — it is added to `.gitignore`
105
+ because it holds the raw token) plus `.claude/settings.json` and/or
106
+ `.cursor/hooks.json`. Hooks you already had are preserved, and re-running `init`
107
+ upgrades Orquesta's entries rather than stacking duplicates.
108
+
109
+ | Moment | Claude Code | Cursor | Recorded as |
110
+ |---|---|---|---|
111
+ | Prompt sent | `UserPromptSubmit` | `beforeSubmitPrompt` | The prompt |
112
+ | Tool ran | `PostToolUse` | `postToolUse`, `afterShellExecution`, `afterFileEdit` | Tool call + result |
113
+ | Answer written | — | `afterAgentResponse` | The assistant's reply |
114
+ | Session done | `Stop` | `stop` | Marks the prompt complete |
115
+
116
+ Cursor surfaces shell runs and file edits as their own events on top of
117
+ `postToolUse`, so all three are wired and the handler de-dupes by content — an
118
+ action reported twice is still logged once.
119
+
120
+ Two behaviours differ per tool, both deliberate:
121
+
122
+ - **stdout.** Claude Code reads `UserPromptSubmit` stdout as extra model context,
123
+ so the hook injects a short Orquesta block there. Cursor parses hook stdout as a
124
+ JSON permission decision, so on that path the hook writes **nothing**.
125
+ - **Failure is always silent.** Every hook exits 0. An unreachable Orquesta, a
126
+ revoked token, a malformed payload or a directory with no `.orquesta.json` all
127
+ leave your session untouched.
128
+
129
+ The tool is detected from the payload, so `--client` is only needed to override
130
+ the guess. Mirrored prompts arrive with `source: terminal` and a `cli_type` of
131
+ `claude-code` or `cursor-cli`, and are excluded from agent dispatch so a hooked
132
+ session is never re-executed.
133
+
89
134
  ## Architecture
90
135
 
91
136
  ```
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Reading a coding CLI's own words to decide whether it is logged out.
3
+ *
4
+ * Its own module, with no imports, for one reason: executor.ts pulls in node-pty
5
+ * and the whole execution stack, so nothing there can be unit-tested. The
6
+ * classifier is the part that can actually be wrong, so it lives where a test
7
+ * can reach it.
8
+ *
9
+ * The contract is deliberately one-sided — it answers "did this CLI SAY it is
10
+ * logged out", not "is it logged in". Everything else (an older build with no
11
+ * status subcommand, a timeout, an unfamiliar phrasing) is treated as unknown by
12
+ * the caller and reported as authenticated: a false "not logged in" badge on a
13
+ * working machine sends the user chasing a problem that isn't there, while the
14
+ * badge we had before this existed was simply always green.
15
+ */
16
+ export declare function isLoggedOutMessage(output: string | null | undefined): boolean;
17
+ //# sourceMappingURL=cli-auth-detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-auth-detect.d.ts","sourceRoot":"","sources":["../src/cli-auth-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG7E"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Reading a coding CLI's own words to decide whether it is logged out.
3
+ *
4
+ * Its own module, with no imports, for one reason: executor.ts pulls in node-pty
5
+ * and the whole execution stack, so nothing there can be unit-tested. The
6
+ * classifier is the part that can actually be wrong, so it lives where a test
7
+ * can reach it.
8
+ *
9
+ * The contract is deliberately one-sided — it answers "did this CLI SAY it is
10
+ * logged out", not "is it logged in". Everything else (an older build with no
11
+ * status subcommand, a timeout, an unfamiliar phrasing) is treated as unknown by
12
+ * the caller and reported as authenticated: a false "not logged in" badge on a
13
+ * working machine sends the user chasing a problem that isn't there, while the
14
+ * badge we had before this existed was simply always green.
15
+ */
16
+ const LOGGED_OUT_PATTERNS = [
17
+ // "Not logged in", "not authenticated", "You are not logged in."
18
+ /not\s+(logged\s*in|authenticated|signed\s*in)/i,
19
+ // "Logged out", "Signed out"
20
+ /(logged|signed)\s*out/i,
21
+ // "No active session", "no credentials found"
22
+ /no\s+(active\s+)?(session|credentials)/i,
23
+ // The instruction every one of them prints when unauthenticated.
24
+ /run\s+`?(cursor-agent|claude|kimi)\s+login/i,
25
+ ];
26
+ export function isLoggedOutMessage(output) {
27
+ if (!output)
28
+ return false;
29
+ return LOGGED_OUT_PATTERNS.some(pattern => pattern.test(output));
30
+ }
31
+ //# sourceMappingURL=cli-auth-detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-auth-detect.js","sourceRoot":"","sources":["../src/cli-auth-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,mBAAmB,GAAG;IAC1B,iEAAiE;IACjE,gDAAgD;IAChD,6BAA6B;IAC7B,wBAAwB;IACxB,8CAA8C;IAC9C,yCAAyC;IACzC,iEAAiE;IACjE,6CAA6C;CAC9C,CAAA;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAiC;IAClE,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzB,OAAO,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;AAClE,CAAC"}
@@ -66,7 +66,7 @@ export declare function getEffectiveRuntimeConfig(): {
66
66
  sandboxMode: SandboxMode;
67
67
  sandboxStatus: 'active' | 'unavailable' | 'off';
68
68
  };
69
- export type CliPreference = 'auto' | 'orquesta' | 'claude' | 'kimi';
69
+ export type CliPreference = 'auto' | 'orquesta' | 'claude' | 'kimi' | 'cursor';
70
70
  export declare function setCliPreference(preference: CliPreference): void;
71
71
  export declare function setCliEndpoint(endpoint: string): void;
72
72
  export declare function getCliEndpoint(): string;
@@ -77,8 +77,16 @@ export declare function resolveClaudeBinary(): string | null;
77
77
  export declare function isClaudeCliAvailable(): boolean;
78
78
  export declare function resolveKimiBinary(): string | null;
79
79
  export declare function isKimiCliAvailable(): boolean;
80
+ export declare function resolveCursorBinary(): string | null;
81
+ export declare function isCursorCliAvailable(): boolean;
82
+ export declare function checkCursorAuth(): {
83
+ available: boolean;
84
+ authenticated: boolean;
85
+ method: string | null;
86
+ };
87
+ export type CliName = 'orquesta' | 'claude' | 'kimi' | 'cursor';
80
88
  export declare function selectCli(): {
81
- cli: 'orquesta' | 'claude' | 'kimi' | null;
89
+ cli: CliName | null;
82
90
  reason: string;
83
91
  };
84
92
  export declare function checkClaudeAuth(): {
@@ -237,7 +245,7 @@ export interface SessionInfo {
237
245
  subAgentName: string | null;
238
246
  workingDirectory: string;
239
247
  uptime: number;
240
- cliType?: 'claude' | 'orquesta' | 'kimi';
248
+ cliType?: 'claude' | 'orquesta' | 'kimi' | 'cursor';
241
249
  }
242
250
  /**
243
251
  * List every active interactive session — the dashboard renders these so each
@@ -254,7 +262,7 @@ export declare function getSessionStatus(): {
254
262
  sessionId: string | null;
255
263
  workingDirectory: string | null;
256
264
  uptime: number | null;
257
- cliType?: 'claude' | 'orquesta' | 'kimi';
265
+ cliType?: 'claude' | 'orquesta' | 'kimi' | 'cursor';
258
266
  sessions: SessionInfo[];
259
267
  };
260
268
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
package/dist/executor.js CHANGED
@@ -122,6 +122,7 @@ import * as logger from './logger.js';
122
122
  // interactive-session spawn — node-pty can't launch the `.cmd` shim).
123
123
  const nodeRequire = createRequire(import.meta.url);
124
124
  import { isSandboxAvailable, buildBwrapArgs, shQuote, ensureStrictProjectDirs, encodeClaudeProjectDir } from './sandbox.js';
125
+ import { isLoggedOutMessage } from './cli-auth-detect.js';
125
126
  import { parseCoordSpec, runCoordination } from './coordination.js';
126
127
  import { parseSudosudoInstallSpec, runSudosudoInstall } from './sudosudo.js';
127
128
  import { sendOutput, sendComplete, sendError, sendSupervisionRequest, sendExecutionResumed, updatePromptStatus, persistOutputLogs, clearOutputBuffer, sendRequirement, persistRequirement, sendQAInstructions, persistQAInstructions, sendPlanItemsGenerated, sendSessionOutput, sendSessionStarted, sendSessionEnded, sendSessionError, sendSessionLog, reportAgentError } from './supabase.js';
@@ -874,6 +875,101 @@ export function resolveKimiBinary() {
874
875
  export function isKimiCliAvailable() {
875
876
  return resolveKimiBinary() !== null;
876
877
  }
878
+ // Resolve Cursor's headless CLI (`cursor-agent`). Its installer
879
+ // (`curl https://cursor.com/install -fsS | bash`) drops the binary in
880
+ // ~/.local/bin and only PRINTS a reminder to add that to PATH — so on a machine
881
+ // where the user never edited their shell profile, a bare `cursor-agent` lookup
882
+ // fails while the CLI is in fact installed. Same trap as kimi.
883
+ // Order: CURSOR_AGENT_PATH → on PATH → ~/.local/bin/cursor-agent.
884
+ // On Windows the PowerShell installer does put it on PATH, so the PATH probe is
885
+ // the working path there.
886
+ let cursorBinaryCache = null;
887
+ export function resolveCursorBinary() {
888
+ const now = Date.now();
889
+ if (cursorBinaryCache && now - cursorBinaryCache.at < CLI_DETECTION_TTL_MS)
890
+ return cursorBinaryCache.path;
891
+ let resolved = null;
892
+ const envPath = process.env.CURSOR_AGENT_PATH;
893
+ if (envPath) {
894
+ try {
895
+ fs.accessSync(envPath, fs.constants.X_OK);
896
+ resolved = envPath;
897
+ }
898
+ catch { /* bad override */ }
899
+ }
900
+ if (!resolved) {
901
+ try {
902
+ execSync('cursor-agent --version', { stdio: 'pipe', timeout: 15000 });
903
+ resolved = 'cursor-agent';
904
+ }
905
+ catch { /* not on PATH */ }
906
+ }
907
+ if (!resolved) {
908
+ const candidate = path.join(os.homedir(), '.local', 'bin', 'cursor-agent');
909
+ try {
910
+ fs.accessSync(candidate, fs.constants.X_OK);
911
+ resolved = candidate;
912
+ }
913
+ catch { /* not installed there */ }
914
+ }
915
+ cursorBinaryCache = { path: resolved, at: now };
916
+ return resolved;
917
+ }
918
+ // Cursor CLI (the `cursor-agent` binary). Authenticated separately with
919
+ // `cursor-agent login` against the user's own Cursor subscription — Orquesta
920
+ // never sees that credential.
921
+ export function isCursorCliAvailable() {
922
+ return resolveCursorBinary() !== null;
923
+ }
924
+ // Is cursor-agent actually LOGGED IN, not just installed?
925
+ //
926
+ // Installed-but-logged-out is a real state and used to be invisible: the agent
927
+ // reported `authenticated: available`, so the dashboard showed a green tick, the
928
+ // user pinned Cursor, and every prompt failed at execution with cursor's own
929
+ // auth error. `cursor-agent status` is the documented way to ask.
930
+ //
931
+ // Deliberately conservative: it reports NOT authenticated only when cursor says
932
+ // so in words. Any other outcome (an older build with no `status` subcommand, a
933
+ // timeout, an unparseable answer) reports authenticated with a null method —
934
+ // crying wolf on a working machine is worse than the tick we had before, and
935
+ // nothing about EXECUTION depends on this flag; selectCli() still keys purely on
936
+ // the binary existing.
937
+ let cursorAuthCache = null;
938
+ export function checkCursorAuth() {
939
+ const now = Date.now();
940
+ if (cursorAuthCache && now - cursorAuthCache.at < CLI_DETECTION_TTL_MS)
941
+ return cursorAuthCache.result;
942
+ const cache = (result) => {
943
+ cursorAuthCache = { result, at: now };
944
+ return result;
945
+ };
946
+ const binary = resolveCursorBinary();
947
+ if (!binary)
948
+ return cache({ available: false, authenticated: false, method: null });
949
+ // An API key in the environment authenticates cursor-agent on its own, and is
950
+ // what CI machines use — no point spawning a process to confirm it.
951
+ if (process.env.CURSOR_API_KEY)
952
+ return cache({ available: true, authenticated: true, method: 'api_key' });
953
+ try {
954
+ const out = execSync(`"${binary}" status`, {
955
+ stdio: ['ignore', 'pipe', 'pipe'],
956
+ timeout: 15000,
957
+ encoding: 'utf-8',
958
+ });
959
+ if (isLoggedOutMessage(out))
960
+ return cache({ available: true, authenticated: false, method: null });
961
+ return cache({ available: true, authenticated: true, method: 'subscription' });
962
+ }
963
+ catch (error) {
964
+ // Non-zero exit covers both "logged out" and "this build has no `status`",
965
+ // so the OUTPUT decides, not the exit code.
966
+ const err = error;
967
+ const combined = `${err.stdout ?? ''}${err.stderr ?? ''}`;
968
+ if (isLoggedOutMessage(combined))
969
+ return cache({ available: true, authenticated: false, method: null });
970
+ return cache({ available: true, authenticated: true, method: null });
971
+ }
972
+ }
877
973
  // Dedupe the fallback warning: selectCli() runs on every heartbeat (the agent
878
974
  // reports activeCli), so logging unconditionally spammed thousands of identical
879
975
  // WARN lines. Only log when the message actually changes.
@@ -884,53 +980,48 @@ function warnCliOnce(msg) {
884
980
  lastCliWarn = msg;
885
981
  logger.warn(msg);
886
982
  }
983
+ // Preference order when nothing is pinned, and the order a fallback walks when
984
+ // the pinned CLI turns out not to be installed. Table-driven rather than a nest
985
+ // of pairwise ifs: every CLI added here otherwise costs another N branches, and
986
+ // the pair that got missed is exactly how a preference silently no-ops.
987
+ const CLI_AUTO_ORDER = ['orquesta', 'claude', 'kimi', 'cursor'];
988
+ const CLI_AUTO_REASON = {
989
+ orquesta: 'Auto: orquesta available (local LLM)',
990
+ claude: 'Auto: claude available (Anthropic API)',
991
+ kimi: 'Auto: kimi available',
992
+ cursor: 'Auto: cursor-agent available',
993
+ };
887
994
  // Select which CLI to use based on availability and preference
888
995
  export function selectCli() {
889
- const hasOrquesta = isOrquestaCliAvailable();
890
- const hasClaude = isClaudeCliAvailable();
891
- const hasKimi = isKimiCliAvailable();
892
- // If none available, return null
893
- if (!hasOrquesta && !hasClaude && !hasKimi) {
894
- return { cli: null, reason: 'No CLI found (orquesta, claude, kimi)' };
996
+ const available = {
997
+ orquesta: isOrquestaCliAvailable(),
998
+ claude: isClaudeCliAvailable(),
999
+ kimi: isKimiCliAvailable(),
1000
+ cursor: isCursorCliAvailable(),
1001
+ };
1002
+ if (!CLI_AUTO_ORDER.some(cli => available[cli])) {
1003
+ return { cli: null, reason: `No CLI found (${CLI_AUTO_ORDER.join(', ')})` };
895
1004
  }
1005
+ const preferred = globalCliPreference;
896
1006
  // Explicit preference, available → use it.
897
- if (globalCliPreference === 'orquesta' && hasOrquesta)
898
- return { cli: 'orquesta', reason: 'User preference: orquesta' };
899
- if (globalCliPreference === 'claude' && hasClaude)
900
- return { cli: 'claude', reason: 'User preference: claude' };
901
- if (globalCliPreference === 'kimi' && hasKimi)
902
- return { cli: 'kimi', reason: 'User preference: kimi' };
903
- // Explicit preference, NOT available → warn once + fall back (orquesta claude → kimi).
904
- if (globalCliPreference === 'kimi' && !hasKimi) {
905
- warnCliOnce('Kimi CLI preferred but not available, falling back');
906
- if (hasOrquesta)
907
- return { cli: 'orquesta', reason: 'Fallback: kimi not available' };
908
- if (hasClaude)
909
- return { cli: 'claude', reason: 'Fallback: kimi not available' };
910
- }
911
- if (globalCliPreference === 'orquesta' && !hasOrquesta) {
912
- warnCliOnce('Orquesta CLI preferred but not available, falling back');
913
- if (hasClaude)
914
- return { cli: 'claude', reason: 'Fallback: orquesta not available' };
915
- if (hasKimi)
916
- return { cli: 'kimi', reason: 'Fallback: orquesta not available' };
917
- }
918
- if (globalCliPreference === 'claude' && !hasClaude) {
919
- warnCliOnce('Claude CLI preferred but not available, falling back');
920
- if (hasOrquesta)
921
- return { cli: 'orquesta', reason: 'Fallback: claude not available' };
922
- if (hasKimi)
923
- return { cli: 'kimi', reason: 'Fallback: claude not available' };
924
- }
925
- // Auto mode: prefer orquesta → claude → kimi.
926
- if (hasOrquesta) {
1007
+ if (preferred !== 'auto' && available[preferred]) {
1008
+ lastCliWarn = null;
1009
+ return { cli: preferred, reason: `User preference: ${preferred}` };
1010
+ }
1011
+ // Explicit preference, NOT available → warn once, then fall through to the
1012
+ // auto order skipping the one that isn't there.
1013
+ if (preferred !== 'auto') {
1014
+ warnCliOnce(`${preferred} CLI preferred but not available, falling back`);
1015
+ const fallback = CLI_AUTO_ORDER.find(cli => cli !== preferred && available[cli]);
1016
+ if (fallback)
1017
+ return { cli: fallback, reason: `Fallback: ${preferred} not available` };
1018
+ return { cli: null, reason: 'No CLI found' };
1019
+ }
1020
+ const auto = CLI_AUTO_ORDER.find(cli => available[cli]);
1021
+ if (auto) {
927
1022
  lastCliWarn = null;
928
- return { cli: 'orquesta', reason: 'Auto: orquesta available (local LLM)' };
1023
+ return { cli: auto, reason: CLI_AUTO_REASON[auto] };
929
1024
  }
930
- if (hasClaude)
931
- return { cli: 'claude', reason: 'Auto: claude available (Anthropic API)' };
932
- if (hasKimi)
933
- return { cli: 'kimi', reason: 'Auto: kimi available' };
934
1025
  return { cli: null, reason: 'No CLI found' };
935
1026
  }
936
1027
  // Check if Claude CLI is authenticated
@@ -1989,9 +2080,11 @@ ${userRequestBody}`;
1989
2080
  // (cliCommand stays the TYPE for flag decisions.)
1990
2081
  const cliBinary = cliCommand === 'kimi'
1991
2082
  ? (resolveKimiBinary() || 'kimi')
1992
- : cliCommand === 'claude'
1993
- ? (resolveClaudeBinary() || 'claude')
1994
- : (cliCommand || 'claude');
2083
+ : cliCommand === 'cursor'
2084
+ ? (resolveCursorBinary() || 'cursor-agent')
2085
+ : cliCommand === 'claude'
2086
+ ? (resolveClaudeBinary() || 'claude')
2087
+ : (cliCommand || 'claude');
1995
2088
  const cwd = workingDirectory || process.cwd();
1996
2089
  // Which branch this prompt runs on — captured up front so it's persisted even
1997
2090
  // if the run fails, and broadcast live below once sendSpecialEvent exists.
@@ -2010,7 +2103,9 @@ ${userRequestBody}`;
2010
2103
  // can never regress to a worse state than before.
2011
2104
  let promptContent = fullContent;
2012
2105
  let sysPromptFilePath = null;
2013
- if (cliCommand !== 'kimi') {
2106
+ // kimi and cursor-agent have no --append-system-prompt-file, so their static
2107
+ // context stays inline in the prompt.
2108
+ if (cliCommand !== 'kimi' && cliCommand !== 'cursor') {
2014
2109
  try {
2015
2110
  const promptDir = process.platform === 'win32'
2016
2111
  ? os.tmpdir()
@@ -2037,15 +2132,28 @@ ${userRequestBody}`;
2037
2132
  // Orquesta CLI doesn't need special format flags - it outputs directly
2038
2133
  const baseFlags = cliCommand === 'orquesta'
2039
2134
  ? '--verbose' // Orquesta: simple verbose output
2040
- : cliCommand === 'kimi'
2041
- ? '--output-format text' // Kimi: plain text. NOTE: -p (one-shot) CANNOT be
2042
- // combined with -y ("Cannot combine --prompt with
2043
- // --yolo"), so dispatched kimi prompts respond as
2044
- // chat (no autonomous tool use). Interactive kimi
2045
- // sessions DO get -y (see ptyArgs below).
2046
- : '--verbose --output-format stream-json'; // Claude: stream-json format
2047
- // Kimi has no --dangerously-skip-permissions, and -p forbids -y.
2048
- const permFlags = cliCommand === 'kimi' ? '' : (mode === 'auto' ? '--dangerously-skip-permissions' : '');
2135
+ : cliCommand === 'cursor'
2136
+ ? '--output-format text' // Cursor: plain text. Its stream-json events are a
2137
+ // different shape from Claude's, and parseStreamJson
2138
+ // below only understands Claude's and orquesta-cli's,
2139
+ // so asking for it would give us an unparseable
2140
+ // stream instead of an answer.
2141
+ : cliCommand === 'kimi'
2142
+ ? '--output-format text' // Kimi: plain text. NOTE: -p (one-shot) CANNOT be
2143
+ // combined with -y ("Cannot combine --prompt with
2144
+ // --yolo"), so dispatched kimi prompts respond as
2145
+ // chat (no autonomous tool use). Interactive kimi
2146
+ // sessions DO get -y (see ptyArgs below).
2147
+ : '--verbose --output-format stream-json'; // Claude: stream-json format
2148
+ // Kimi has no --dangerously-skip-permissions, and -p forbids -y. Cursor spells
2149
+ // the same thing --force (alias --yolo).
2150
+ const permFlags = cliCommand === 'kimi'
2151
+ ? ''
2152
+ : mode !== 'auto'
2153
+ ? ''
2154
+ : cliCommand === 'cursor'
2155
+ ? '--force'
2156
+ : '--dangerously-skip-permissions';
2049
2157
  // Per-project endpoint override (orquesta CLI only). Single-quoted for the
2050
2158
  // shell-wrapped (Linux) path; pushed as a separate arg on Win/macOS below.
2051
2159
  const useEndpoint = cliCommand === 'orquesta' && !!globalCliEndpoint;
@@ -2682,10 +2790,20 @@ ${userRequestBody}`;
2682
2790
  // Record WHICH CLI + model executed it (timeline/history). Model is
2683
2791
  // best-effort — the CLI/proxy pick the true upstream model internally
2684
2792
  // (batuta-auto fans out per prompt), so we report the CLI's MODEL CONFIG:
2685
- const cliTypeForDb = cliCommand === 'orquesta' ? 'orquesta-cli' : cliCommand === 'kimi' ? 'kimi-cli' : 'claude-cli';
2793
+ const cliTypeForDb = cliCommand === 'orquesta'
2794
+ ? 'orquesta-cli'
2795
+ : cliCommand === 'kimi'
2796
+ ? 'kimi-cli'
2797
+ : cliCommand === 'cursor'
2798
+ ? 'cursor-cli'
2799
+ : 'claude-cli';
2686
2800
  let modelForDb;
2687
2801
  if (cliCommand === 'kimi')
2688
2802
  modelForDb = 'kimi-for-coding';
2803
+ // cursor-agent picks the model from the user's own Cursor settings and does
2804
+ // not report it in text mode, so leave it unset rather than guess.
2805
+ else if (cliCommand === 'cursor')
2806
+ modelForDb = undefined;
2689
2807
  else if (cliCommand === 'orquesta')
2690
2808
  modelForDb = (globalCliEndpoint === 'batuta' || !globalCliEndpoint) ? 'batuta-auto' : globalCliEndpoint;
2691
2809
  else if (cliCommand === 'claude')
@@ -3544,20 +3662,30 @@ export async function startSession(options) {
3544
3662
  // inside bwrap (/ is ro-bound). cliCommand stays the TYPE.
3545
3663
  const cliBinary = cliCommand === 'kimi'
3546
3664
  ? (resolveKimiBinary() || 'kimi')
3547
- : cliCommand === 'claude'
3548
- ? (resolveClaudeBinary() || 'claude')
3549
- : cliCommand;
3550
- logger.info(`Interactive session CLI: ${cliCommand}${cliCommand === 'kimi' ? ` (${cliBinary})` : ''}`);
3665
+ : cliCommand === 'cursor'
3666
+ ? (resolveCursorBinary() || 'cursor-agent')
3667
+ : cliCommand === 'claude'
3668
+ ? (resolveClaudeBinary() || 'claude')
3669
+ : cliCommand;
3670
+ const resolvedByPath = cliCommand === 'kimi' || cliCommand === 'cursor';
3671
+ logger.info(`Interactive session CLI: ${cliCommand}${resolvedByPath ? ` (${cliBinary})` : ''}`);
3551
3672
  // Best-effort model + cli label reported in session:started so the dashboard
3552
3673
  // can tag the interactive prompt (same mapping dispatched prompts use on
3553
3674
  // completion). claude's exact model isn't knowable from a raw PTY, so it falls
3554
3675
  // back to ANTHROPIC_MODEL when set, else undefined.
3555
3676
  const sessionModel = cliCommand === 'kimi'
3556
3677
  ? 'kimi-for-coding'
3557
- : cliCommand === 'orquesta'
3558
- ? ((globalCliEndpoint === 'batuta' || !globalCliEndpoint) ? 'batuta-auto' : globalCliEndpoint)
3559
- : (process.env.ANTHROPIC_MODEL || undefined);
3560
- const sessionCliType = cliCommand === 'orquesta' ? 'orquesta' : cliCommand === 'kimi' ? 'kimi' : 'claude';
3678
+ : cliCommand === 'cursor'
3679
+ // cursor-agent uses whatever model the user selected in their own Cursor
3680
+ // account; it isn't knowable from the PTY, so report nothing rather than lie.
3681
+ ? undefined
3682
+ : cliCommand === 'orquesta'
3683
+ ? ((globalCliEndpoint === 'batuta' || !globalCliEndpoint) ? 'batuta-auto' : globalCliEndpoint)
3684
+ : (process.env.ANTHROPIC_MODEL || undefined);
3685
+ const sessionCliType = cliCommand === 'orquesta' ? 'orquesta'
3686
+ : cliCommand === 'kimi' ? 'kimi'
3687
+ : cliCommand === 'cursor' ? 'cursor'
3688
+ : 'claude';
3561
3689
  // Filter undefined env values — node-pty requires Record<string, string>.
3562
3690
  // In strict sandbox mode, sandboxEnv() first reduces to the allowlist so the
3563
3691
  // interactive CLI can't read unrelated host secrets from its own env.
@@ -3637,7 +3765,7 @@ export async function startSession(options) {
3637
3765
  // `ps aux`. Default-off because a file unreadable inside bwrap would silently
3638
3766
  // strip the system prompt (degraded session, not a crash) — flip the default
3639
3767
  // only after E2E confirms the sandbox reads it. Rollback = unset the var.
3640
- const wantSysPromptFile = cliCommand !== 'kimi' && ((process.platform === 'win32' && cliCommand === 'orquesta') ||
3768
+ const wantSysPromptFile = cliCommand !== 'kimi' && cliCommand !== 'cursor' && ((process.platform === 'win32' && cliCommand === 'orquesta') ||
3641
3769
  /^(1|true|yes|on)$/i.test(process.env.ORQUESTA_SYSPROMPT_FILE || ''));
3642
3770
  if (wantSysPromptFile) {
3643
3771
  try {
@@ -3656,7 +3784,13 @@ export async function startSession(options) {
3656
3784
  }
3657
3785
  }
3658
3786
  let ptyArgs;
3659
- if (cliCommand === 'kimi') {
3787
+ if (cliCommand === 'cursor') {
3788
+ // cursor-agent has no --append-system-prompt; it reads AGENTS.md / CLAUDE.md
3789
+ // from the working dir (which the agent already syncs), so the capabilities
3790
+ // block isn't injected. `--force` is its --dangerously-skip-permissions.
3791
+ ptyArgs = ['--force'];
3792
+ }
3793
+ else if (cliCommand === 'kimi') {
3660
3794
  // Kimi has neither --dangerously-skip-permissions nor --append-system-prompt.
3661
3795
  // `-y` auto-approves the interactive session; it reads project conventions from
3662
3796
  // CLAUDE.md / AGENTS.md in the working dir (which the agent already syncs), so
@@ -3674,10 +3808,11 @@ export async function startSession(options) {
3674
3808
  // resume flag, so the option is silently ignored there. Prepended so it's an
3675
3809
  // unambiguous standalone flag, separate from --append-system-prompt's value.
3676
3810
  if ((resume || resumeSessionId) && cliCommand !== 'kimi') {
3811
+ // cursor-agent spells these the same way claude does (--continue / --resume <id>).
3677
3812
  // claude can target a SPECIFIC past conversation by id (--resume <id>);
3678
3813
  // orquesta-cli only reattaches the latest (--continue). So when a specific
3679
3814
  // id is requested and we're on claude, use --resume; otherwise --continue.
3680
- if (resumeSessionId && cliCommand === 'claude') {
3815
+ if (resumeSessionId && (cliCommand === 'claude' || cliCommand === 'cursor')) {
3681
3816
  ptyArgs.unshift('--resume', resumeSessionId);
3682
3817
  logger.info(`[Session] Resuming conversation ${resumeSessionId} (--resume) for ${cliCommand}`);
3683
3818
  }