mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 08:59:40 +02:00
fix(omp): complete omp wiring in UI files, skill docs, and tests after rebase
This commit is contained in:
@@ -237,7 +237,7 @@ minutes, never retry the credential.
|
|||||||
flushed slightly *after* the `stop` hook fires, so a read taken the instant the wait
|
flushed slightly *after* the `stop` hook fires, so a read taken the instant the wait
|
||||||
returns is too early (verified live: empty on the first call, full prose seconds later).
|
returns is too early (verified live: empty on the first call, full prose seconds later).
|
||||||
It is also `""` before the worker's first completed turn, and permanently `""` for
|
It is also `""` before the worker's first completed turn, and permanently `""` for
|
||||||
`shell`, `opencode`, `gemini`, `antigravity`, `pi` and `grok`, which write no transcript at
|
`shell`, `opencode`, `gemini`, `antigravity`, `pi`, `grok` and `omp`, which write no transcript at
|
||||||
all. `deepseek` is NOT one of those — it is read from `$DSH_HOME/sessions/**` and lags
|
all. `deepseek` is NOT one of those — it is read from `$DSH_HOME/sessions/**` and lags
|
||||||
for the same reason claude does (the harness finalizes the assistant message just after
|
for the same reason claude does (the harness finalizes the assistant message just after
|
||||||
it reports `idle`), so poll it the same way.
|
it reports `idle`), so poll it the same way.
|
||||||
@@ -339,20 +339,20 @@ ESC=$(printf '\033')
|
|||||||
|
|
||||||
`POST /api/v1/quick-start` body (all optional):
|
`POST /api/v1/quick-start` body (all optional):
|
||||||
`{"caseName":"worker-1","mode":"claude","sessionName":"w9-worker","effort":"high"}`
|
`{"caseName":"worker-1","mode":"claude","sessionName":"w9-worker","effort":"high"}`
|
||||||
, `mode` ∈ `claude|shell|opencode|codex|gemini|antigravity|pi|grok|deepseek`; response is
|
, `mode` ∈ `claude|shell|opencode|codex|gemini|antigravity|pi|grok|deepseek|omp`; response is
|
||||||
`.data.{sessionId, caseName, casePath}`. Creates the case directory (a real directory
|
`.data.{sessionId, caseName, casePath}`. Creates the case directory (a real directory
|
||||||
on the user's disk) if missing, do not retry it in a loop, and remember the name.
|
on the user's disk) if missing, do not retry it in a loop, and remember the name.
|
||||||
|
|
||||||
⚠️ A `mode` whose CLI is **not installed on the server** fails the spawn with
|
⚠️ A `mode` whose CLI is **not installed on the server** fails the spawn with
|
||||||
`OPERATION_FAILED`; it never falls back to claude. Probe first whenever you did not pick
|
`OPERATION_FAILED`; it never falls back to claude. Probe first whenever you did not pick
|
||||||
the mode yourself: `GET /api/v1/claude/status`, `GET /api/v1/opencode/status`,
|
the mode yourself: `GET /api/v1/claude/status`, `GET /api/v1/opencode/status`,
|
||||||
`GET /api/v1/codex/status`, `GET /api/v1/gemini/status`, `GET /api/v1/antigravity/status`, `GET /api/v1/grok/status`, `GET /api/v1/deepseek/status`
|
`GET /api/v1/codex/status`, `GET /api/v1/gemini/status`, `GET /api/v1/antigravity/status`, `GET /api/v1/grok/status`, `GET /api/v1/deepseek/status`,
|
||||||
and `GET /api/v1/pi/status` each return `.data.{available, path}` (no session needed).
|
`GET /api/v1/pi/status` and `GET /api/v1/omp/status` each return `.data.{available, path}` (no session needed).
|
||||||
Pi's and grok's also carry `.data.version`, because `pi` is a short generic name and
|
Pi's, grok's and OMP's also carry `.data.version`, because `pi` is a short generic name,
|
||||||
`grok` is a name with npm squatters, so an unrelated binary on `$PATH` can shadow either:
|
`grok` is a name with npm squatters, and `omp` is a similarly short name, so an unrelated
|
||||||
the resolver rejects one whose `--version` is not version-shaped, so `available:false`
|
binary on `$PATH` can shadow any of them: the resolver rejects one whose `--version` is
|
||||||
there can mean "a different `pi`/`grok` is in front" rather than "nothing is installed".
|
not version-shaped, so `available:false` there can mean "a different `pi`/`grok`/`omp` is
|
||||||
`shell` has no CLI to probe.
|
in front" rather than "nothing is installed". `shell` has no CLI to probe.
|
||||||
|
|
||||||
⚠️ **Branch on `.success` before reading `.data.sessionId`.** On any failure the field
|
⚠️ **Branch on `.success` before reading `.data.sessionId`.** On any failure the field
|
||||||
is absent, `jq -r` prints the literal string `null`, and every later call then targets
|
is absent, `jq -r` prints the literal string `null`, and every later call then targets
|
||||||
@@ -466,9 +466,9 @@ Quirks that will bite you:
|
|||||||
session answers with an empty timeline rather than a 404.
|
session answers with an empty timeline rather than a 404.
|
||||||
- ⚠️ **`active-tools` proves presence, never absence.** It is fed by the BashToolParser,
|
- ⚠️ **`active-tools` proves presence, never absence.** It is fed by the BashToolParser,
|
||||||
which reads Claude's rendered `● Bash(…)` lines, and `_processExpensiveParsers`
|
which reads Claude's rendered `● Bash(…)` lines, and `_processExpensiveParsers`
|
||||||
returns early for every external CLI mode (`session.ts:2261`), so it is permanently
|
returns early for every external CLI mode (`session.ts:~2225`), so it is permanently
|
||||||
`[]` on `opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`deepseek`. ⚠️ **`shell` is NOT one of those**
|
`[]` on `opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`deepseek`/`omp`. ⚠️ **`shell` is NOT one of those**
|
||||||
(`isExternalCliMode`, `session.ts:174-183`, lists only those six), so the parser does
|
(`isExternalCliMode`, `session.ts:176-187`, lists only those seven), so the parser does
|
||||||
run on a shell worker, and `TEXT_COMMAND_PATTERN` (`bash-tool-parser.ts:89`) matches
|
run on a shell worker, and `TEXT_COMMAND_PATTERN` (`bash-tool-parser.ts:89`) matches
|
||||||
bare `tail|cat|head|less|grep|watch|multitail <path>` lines with no `● Bash(` wrapper:
|
bare `tail|cat|head|less|grep|watch|multitail <path>` lines with no `● Bash(` wrapper:
|
||||||
a shell worker running `cat build.log` really does populate this. In practice it stays
|
a shell worker running `cat build.log` really does populate this. In practice it stays
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ own head: the worker enforcing the cap is the one who has to be told about it.
|
|||||||
| synchronize on end of turn | HTTP `wait until=stop` (fires for message-initiated turns too, verified live) |
|
| synchronize on end of turn | HTTP `wait until=stop` (fires for message-initiated turns too, verified live) |
|
||||||
| liveness / death check | HTTP `wait?until=exit` |
|
| liveness / death check | HTTP `wait?until=exit` |
|
||||||
| interrupt a running turn (break-glass) | HTTP input, a bare `\x1b` with no `\r` |
|
| interrupt a running turn (break-glass) | HTTP input, a bare `\x1b` with no `\r` |
|
||||||
| non-claude modes (`shell`/`opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`deepseek`) | HTTP only (no other CLI has messaging) |
|
| non-claude modes (`shell`/`opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`deepseek`/`omp`) | HTTP only (no other CLI has messaging) |
|
||||||
| delete | HTTP, via SKILL.md's `delete_session` guard |
|
| delete | HTTP, via SKILL.md's `delete_session` guard |
|
||||||
|
|
||||||
## Availability: probe, never assume
|
## Availability: probe, never assume
|
||||||
@@ -347,7 +347,7 @@ Without a break-glass, a pair with a bad brief is a token bonfire with no off sw
|
|||||||
|
|
||||||
### Mixed fleets: the pairing matrix
|
### Mixed fleets: the pairing matrix
|
||||||
|
|
||||||
Non-claude workers (`shell`, `opencode`, `codex`, `gemini`, `antigravity`, `pi`, `grok`, `deepseek`) cannot be peers
|
Non-claude workers (`shell`, `opencode`, `codex`, `gemini`, `antigravity`, `pi`, `grok`, `deepseek`, `omp`) cannot be peers
|
||||||
at all; no other CLI has this feature. Their tasks route over HTTP, and you never mention
|
at all; no other CLI has this feature. Their tasks route over HTTP, and you never mention
|
||||||
messaging in their briefs. The claude half of the fleet can use messaging among itself,
|
messaging in their briefs. The claude half of the fleet can use messaging among itself,
|
||||||
subject to the namespace rule: **messaging works between two sessions that share one
|
subject to the namespace rule: **messaging works between two sessions that share one
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ for _ in $(seq 1 10); do
|
|||||||
done
|
done
|
||||||
printf '%s\n' "$TXT"
|
printf '%s\n' "$TXT"
|
||||||
# (.data is {text,timestamp}; text is also "" before the first completed turn and
|
# (.data is {text,timestamp}; text is also "" before the first completed turn and
|
||||||
# always "" for shell/opencode/gemini/antigravity/pi/grok, which have no transcript, use
|
# always "" for shell/opencode/gemini/antigravity/pi/grok/omp, which have no transcript, use
|
||||||
# the terminal tail there, and here only to diagnose an unsubmitted prompt.)
|
# the terminal tail there, and here only to diagnose an unsubmitted prompt.)
|
||||||
|
|
||||||
# 6. clean up: exact id, own list only, through the fail-closed preamble helper
|
# 6. clean up: exact id, own list only, through the fail-closed preamble helper
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ recovered by submitting it with `{"input":"\r"}`.
|
|||||||
only when the workspace actually has them, see [§5.1](#51-where-to-spawn)) **and for
|
only when the workspace actually has them, see [§5.1](#51-where-to-spawn)) **and for
|
||||||
`deepseek`** — the one external CLI that reports its own lifecycle, so its `stop` is a
|
`deepseek`** — the one external CLI that reports its own lifecycle, so its `stop` is a
|
||||||
real end-of-turn signal rather than a guess. On
|
real end-of-turn signal rather than a guess. On
|
||||||
`shell`/`opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`, requesting them explicitly is a
|
`shell`/`opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`omp`, requesting them explicitly is a
|
||||||
400, and lifecycle transitions there are coarse (a short shell command may emit **no**
|
400, and lifecycle transitions there are coarse (a short shell command may emit **no**
|
||||||
`idle` transition at all, verified live), so synchronize those with markers.
|
`idle` transition at all, verified live), so synchronize those with markers.
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ from the transcript file, which is flushed slightly *after* the `stop` hook fire
|
|||||||
single read taken the instant send-and-wait returns comes back `""` even though the
|
single read taken the instant send-and-wait returns comes back `""` even though the
|
||||||
turn finished (verified live: empty on the first call, full text seconds later). `text`
|
turn finished (verified live: empty on the first call, full text seconds later). `text`
|
||||||
is also `""` before the worker's first completed turn, and always `""` for modes with
|
is also `""` before the worker's first completed turn, and always `""` for modes with
|
||||||
no transcript (`shell`, `opencode`, `gemini`, `antigravity`, `pi`, `grok`; the first four
|
no transcript (`shell`, `opencode`, `gemini`, `antigravity`, `pi`, `grok`, `omp`; the first four
|
||||||
verified live, pi from the same source path), which is
|
verified live, pi from the same source path), which is
|
||||||
why the loop above is bounded rather than open-ended. A dsh worker lags too, for its own
|
why the loop above is bounded rather than open-ended. A dsh worker lags too, for its own
|
||||||
reason: the harness finalizes the assistant message just after it reports `idle`. Fall back to the terminal buffer
|
reason: the harness finalizes the assistant message just after it reports `idle`. Fall back to the terminal buffer
|
||||||
@@ -485,7 +485,7 @@ turn), and both better than diffing terminal samples:
|
|||||||
```
|
```
|
||||||
|
|
||||||
⚠️ `active-tools` is parsed out of Claude's own output format, so it is **empty for
|
⚠️ `active-tools` is parsed out of Claude's own output format, so it is **empty for
|
||||||
`opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`deepseek`** (those parsers are skipped wholesale) and
|
`opencode`/`codex`/`gemini`/`antigravity`/`pi`/`grok`/`deepseek`/`omp`** (those parsers are skipped wholesale) and
|
||||||
in practice empty for `shell`. Source-verified, not measured live.
|
in practice empty for `shell`. Source-verified, not measured live.
|
||||||
|
|
||||||
Only if neither helps: sample `terminal?tail=` twice a few seconds apart. A changing
|
Only if neither helps: sample `terminal?tail=` twice a few seconds apart. A changing
|
||||||
|
|||||||
@@ -3097,9 +3097,13 @@ html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="cat
|
|||||||
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is(.btn-toolbar.btn-run.mode-pi, .btn-toolbar.btn-run-gear.mode-pi) {
|
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is(.btn-toolbar.btn-run.mode-pi, .btn-toolbar.btn-run-gear.mode-pi) {
|
||||||
background: linear-gradient(135deg, #be185d, #db2777);
|
background: linear-gradient(135deg, #be185d, #db2777);
|
||||||
border-color: #9d174d;
|
border-color: #9d174d;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is(.btn-toolbar.btn-run.mode-omp, .btn-toolbar.btn-run-gear.mode-omp) {
|
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is(.btn-toolbar.btn-run.mode-omp, .btn-toolbar.btn-run-gear.mode-omp) {
|
||||||
background: linear-gradient(135deg, #4f46e5, #6366f1);
|
background: linear-gradient(135deg, #4f46e5, #6366f1);
|
||||||
border-color: #4338ca; color: #ffffff;
|
border-color: #4338ca;
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is(.btn-toolbar.btn-run.mode-grok, .btn-toolbar.btn-run-gear.mode-grok) {
|
html:is([data-skin="paper-gray"], [data-skin="solarized-light"], [data-skin="catppuccin-latte"], [data-skin="rose-pine-dawn"]) :is(.btn-toolbar.btn-run.mode-grok, .btn-toolbar.btn-run-gear.mode-grok) {
|
||||||
|
|||||||
@@ -400,6 +400,9 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
if (mode === 'antigravity') {
|
if (mode === 'antigravity') {
|
||||||
return await this.runAntigravity();
|
return await this.runAntigravity();
|
||||||
}
|
}
|
||||||
|
if (mode === 'omp') {
|
||||||
|
return await this.runOmp();
|
||||||
|
}
|
||||||
if (mode === 'pi') {
|
if (mode === 'pi') {
|
||||||
return await this.runPi();
|
return await this.runPi();
|
||||||
}
|
}
|
||||||
@@ -409,9 +412,6 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
if (mode === 'deepseek') {
|
if (mode === 'deepseek') {
|
||||||
return await this.runDeepSeek();
|
return await this.runDeepSeek();
|
||||||
}
|
}
|
||||||
if (mode === 'omp') {
|
|
||||||
return await this.runOmp();
|
|
||||||
}
|
|
||||||
if (mode === 'shell') {
|
if (mode === 'shell') {
|
||||||
return await this.runShell();
|
return await this.runShell();
|
||||||
}
|
}
|
||||||
@@ -709,6 +709,9 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
if (runBtn) {
|
if (runBtn) {
|
||||||
runBtn.className = `btn-toolbar btn-run mode-${mode}`;
|
runBtn.className = `btn-toolbar btn-run mode-${mode}`;
|
||||||
}
|
}
|
||||||
|
if (gearBtn) {
|
||||||
|
gearBtn.className = `btn-toolbar btn-run-gear mode-${mode}`;
|
||||||
|
}
|
||||||
if (label) {
|
if (label) {
|
||||||
label.textContent = mode === 'opencode' ? 'Run OC' : mode === 'codex' ? 'Run CX' : mode === 'gemini' ? 'Run GM' : mode === 'antigravity' ? 'Run AG' : mode === 'pi' ? 'Run PI' : mode === 'grok' ? 'Run GK' : mode === 'deepseek' ? 'Run DS' : mode === 'omp' ? 'Run OMP' : mode === 'shell' ? 'Run SH' : 'Run';
|
label.textContent = mode === 'opencode' ? 'Run OC' : mode === 'codex' ? 'Run CX' : mode === 'gemini' ? 'Run GM' : mode === 'antigravity' ? 'Run AG' : mode === 'pi' ? 'Run PI' : mode === 'grok' ? 'Run GK' : mode === 'deepseek' ? 'Run DS' : mode === 'omp' ? 'Run OMP' : mode === 'shell' ? 'Run SH' : 'Run';
|
||||||
}
|
}
|
||||||
@@ -1383,24 +1386,17 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
const isRemote = _runLoc === 'remote' || _runLoc === 'docker';
|
const isRemote = _runLoc === 'remote' || _runLoc === 'docker';
|
||||||
|
|
||||||
const ownsLaunchTerminal = this._beginSessionLaunchStatus(`Starting Pi session in ${caseName}...`);
|
const ownsLaunchTerminal = this._beginSessionLaunchStatus(`Starting Pi session in ${caseName}...`);
|
||||||
async runOmp() {
|
this.terminal.focus();
|
||||||
const caseName = document.getElementById('quickStartCase').value || 'testcase';
|
|
||||||
// Remote/docker cases run omp on the OTHER side — skip the local status probe
|
|
||||||
// and the local-only config below (quick-start rejects them for remote cases).
|
|
||||||
const _runLoc = (this.cases || []).find(c => c.name === caseName)?.location;
|
|
||||||
const isRemote = _runLoc === 'remote' || _runLoc === 'docker';
|
|
||||||
|
|
||||||
const ownsLaunchTerminal = this._beginSessionLaunchStatus(`Starting OMP session in ${caseName}...`); this.terminal.focus();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isRemote) {
|
if (!isRemote) {
|
||||||
const statusRes = await fetch('/api/pi/status');
|
const statusRes = await fetch('/api/pi/status');
|
||||||
const statusRes = await fetch('/api/omp/status'); const status = (await statusRes.json()).data;
|
const status = (await statusRes.json()).data;
|
||||||
if (!status.available) {
|
if (!status.available) {
|
||||||
this._reportSessionLaunchError(
|
this._reportSessionLaunchError(
|
||||||
ownsLaunchTerminal,
|
ownsLaunchTerminal,
|
||||||
'Pi CLI not found. Install with: npm install -g --ignore-scripts @earendil-works/pi-coding-agent'
|
'Pi CLI not found. Install with: npm install -g --ignore-scripts @earendil-works/pi-coding-agent'
|
||||||
'OMP CLI not found. Install with: curl -fsSL https://omp.sh/install | sh' );
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1418,6 +1414,47 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.success) throw new Error(data.error || 'Failed to start Pi');
|
if (!data.success) throw new Error(data.error || 'Failed to start Pi');
|
||||||
|
await this._ensureCreatedSessionVisible(data.data.sessionId, data.data.session);
|
||||||
|
|
||||||
|
if (data.data.sessionId) {
|
||||||
|
await this.selectSession(data.data.sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.terminal.focus();
|
||||||
|
} catch (err) {
|
||||||
|
this._reportSessionLaunchError(ownsLaunchTerminal, err.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async runOmp() {
|
||||||
|
const caseName = document.getElementById('quickStartCase').value || 'testcase';
|
||||||
|
// Remote/docker cases run omp on the OTHER side — skip the local status probe
|
||||||
|
// and the local-only config below (quick-start rejects them for remote cases).
|
||||||
|
const _runLoc = (this.cases || []).find(c => c.name === caseName)?.location;
|
||||||
|
const isRemote = _runLoc === 'remote' || _runLoc === 'docker';
|
||||||
|
|
||||||
|
const ownsLaunchTerminal = this._beginSessionLaunchStatus(`Starting OMP session in ${caseName}...`);
|
||||||
|
this.terminal.focus();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!isRemote) {
|
||||||
|
const statusRes = await fetch('/api/omp/status');
|
||||||
|
const status = (await statusRes.json()).data;
|
||||||
|
if (!status.available) {
|
||||||
|
this._reportSessionLaunchError(
|
||||||
|
ownsLaunchTerminal,
|
||||||
|
'OMP CLI not found. Install with: curl -fsSL https://omp.sh/install | sh'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const envOverrides = this.buildEnvOverrides(this.getCaseSettings(caseName), this.loadAppSettingsFromStorage());
|
||||||
|
const res = await fetch('/api/quick-start', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
caseName,
|
||||||
mode: 'omp',
|
mode: 'omp',
|
||||||
sessionName: `w${this._nextCaseSessionStartNumber(caseName)}-${caseName}`,
|
sessionName: `w${this._nextCaseSessionStartNumber(caseName)}-${caseName}`,
|
||||||
...(isRemote ? {} : {
|
...(isRemote ? {} : {
|
||||||
@@ -1426,7 +1463,8 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.success) throw new Error(data.error || 'Failed to start OMP'); await this._ensureCreatedSessionVisible(data.data.sessionId, data.data.session);
|
if (!data.success) throw new Error(data.error || 'Failed to start OMP');
|
||||||
|
await this._ensureCreatedSessionVisible(data.data.sessionId, data.data.session);
|
||||||
|
|
||||||
if (data.data.sessionId) {
|
if (data.data.sessionId) {
|
||||||
await this.selectSession(data.data.sessionId);
|
await this.selectSession(data.data.sessionId);
|
||||||
@@ -1644,6 +1682,7 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
const isAltMode = session.mode === 'opencode' || session.mode === 'codex' || session.mode === 'gemini' || session.mode === 'antigravity' || session.mode === 'pi' || session.mode === 'grok' || session.mode === 'deepseek' || session.mode === 'omp';
|
const isAltMode = session.mode === 'opencode' || session.mode === 'codex' || session.mode === 'gemini' || session.mode === 'antigravity' || session.mode === 'pi' || session.mode === 'grok' || session.mode === 'deepseek' || session.mode === 'omp';
|
||||||
this.switchOptionsTab(isAltMode ? 'summary' : 'respawn');
|
this.switchOptionsTab(isAltMode ? 'summary' : 'respawn');
|
||||||
|
|
||||||
|
// Update respawn status display and buttons
|
||||||
const respawnStatus = document.getElementById('sessionRespawnStatus');
|
const respawnStatus = document.getElementById('sessionRespawnStatus');
|
||||||
const enableBtn = document.getElementById('modalEnableRespawnBtn');
|
const enableBtn = document.getElementById('modalEnableRespawnBtn');
|
||||||
const stopBtn = document.getElementById('modalStopRespawnBtn');
|
const stopBtn = document.getElementById('modalStopRespawnBtn');
|
||||||
@@ -1673,6 +1712,7 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
const isExternalCli = session.mode === 'opencode' || session.mode === 'codex' || session.mode === 'gemini' || session.mode === 'antigravity' || session.mode === 'pi' || session.mode === 'grok' || session.mode === 'deepseek' || session.mode === 'omp';
|
const isExternalCli = session.mode === 'opencode' || session.mode === 'codex' || session.mode === 'gemini' || session.mode === 'antigravity' || session.mode === 'pi' || session.mode === 'grok' || session.mode === 'deepseek' || session.mode === 'omp';
|
||||||
const claudeOnlyEls = document.querySelectorAll('[data-claude-only]');
|
const claudeOnlyEls = document.querySelectorAll('[data-claude-only]');
|
||||||
claudeOnlyEls.forEach(el => { el.style.display = isExternalCli ? 'none' : ''; });
|
claudeOnlyEls.forEach(el => { el.style.display = isExternalCli ? 'none' : ''; });
|
||||||
|
|
||||||
// Reset duration presets to default (unlimited)
|
// Reset duration presets to default (unlimited)
|
||||||
this.selectDurationPreset('');
|
this.selectDurationPreset('');
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { isAntigravityAvailable } from '../src/utils/antigravity-cli-resolver.js
|
|||||||
import { isPiAvailable } from '../src/utils/pi-cli-resolver.js';
|
import { isPiAvailable } from '../src/utils/pi-cli-resolver.js';
|
||||||
import { isGrokAvailable } from '../src/utils/grok-cli-resolver.js';
|
import { isGrokAvailable } from '../src/utils/grok-cli-resolver.js';
|
||||||
import { isDeepSeekAvailable, isDeepSeekRunnable } from '../src/utils/deepseek-cli-resolver.js';
|
import { isDeepSeekAvailable, isDeepSeekRunnable } from '../src/utils/deepseek-cli-resolver.js';
|
||||||
|
import { isOmpAvailable } from '../src/utils/omp-cli-resolver.js';
|
||||||
import { isCloudflaredAvailable } from '../src/utils/cloudflared-resolver.js';
|
import { isCloudflaredAvailable } from '../src/utils/cloudflared-resolver.js';
|
||||||
import { isGitAvailable } from '../src/git-clone.js';
|
import { isGitAvailable } from '../src/git-clone.js';
|
||||||
|
|
||||||
@@ -66,6 +67,10 @@ vi.mock('../src/utils/deepseek-cli-resolver.js', () => ({
|
|||||||
listDeepSeekProfiles: vi.fn(() => []),
|
listDeepSeekProfiles: vi.fn(() => []),
|
||||||
resolveDefaultDeepSeekProfile: vi.fn(() => null),
|
resolveDefaultDeepSeekProfile: vi.fn(() => null),
|
||||||
}));
|
}));
|
||||||
|
vi.mock('../src/utils/omp-cli-resolver.js', () => ({
|
||||||
|
isOmpAvailable: vi.fn(() => false),
|
||||||
|
resolveOmpDir: vi.fn(() => null),
|
||||||
|
}));
|
||||||
vi.mock('../src/utils/cloudflared-resolver.js', () => ({
|
vi.mock('../src/utils/cloudflared-resolver.js', () => ({
|
||||||
isCloudflaredAvailable: vi.fn(() => false),
|
isCloudflaredAvailable: vi.fn(() => false),
|
||||||
resolveCloudflaredPath: vi.fn(() => null),
|
resolveCloudflaredPath: vi.fn(() => null),
|
||||||
@@ -156,6 +161,9 @@ describe('WebServer.renderIndexHtml', () => {
|
|||||||
vi.mocked(isAntigravityAvailable).mockReturnValue(false);
|
vi.mocked(isAntigravityAvailable).mockReturnValue(false);
|
||||||
vi.mocked(isPiAvailable).mockReturnValue(true);
|
vi.mocked(isPiAvailable).mockReturnValue(true);
|
||||||
vi.mocked(isGrokAvailable).mockReturnValue(false);
|
vi.mocked(isGrokAvailable).mockReturnValue(false);
|
||||||
|
vi.mocked(isDeepSeekAvailable).mockReturnValue(false);
|
||||||
|
vi.mocked(isDeepSeekRunnable).mockReturnValue(false);
|
||||||
|
vi.mocked(isOmpAvailable).mockReturnValue(true);
|
||||||
vi.mocked(isCloudflaredAvailable).mockReturnValue(true);
|
vi.mocked(isCloudflaredAvailable).mockReturnValue(true);
|
||||||
vi.mocked(isGitAvailable).mockReturnValue(true);
|
vi.mocked(isGitAvailable).mockReturnValue(true);
|
||||||
const { server } = makeServer({});
|
const { server } = makeServer({});
|
||||||
@@ -173,6 +181,7 @@ describe('WebServer.renderIndexHtml', () => {
|
|||||||
grok: false,
|
grok: false,
|
||||||
deepseek: false,
|
deepseek: false,
|
||||||
deepseekBinary: false,
|
deepseekBinary: false,
|
||||||
|
omp: true,
|
||||||
cloudflared: true,
|
cloudflared: true,
|
||||||
git: true,
|
git: true,
|
||||||
});
|
});
|
||||||
@@ -191,6 +200,7 @@ describe('WebServer.renderIndexHtml', () => {
|
|||||||
isGrokAvailable,
|
isGrokAvailable,
|
||||||
isDeepSeekAvailable,
|
isDeepSeekAvailable,
|
||||||
isDeepSeekRunnable,
|
isDeepSeekRunnable,
|
||||||
|
isOmpAvailable,
|
||||||
isCloudflaredAvailable,
|
isCloudflaredAvailable,
|
||||||
isGitAvailable,
|
isGitAvailable,
|
||||||
]) {
|
]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user