talos-code 0.1.0 → 0.2.1
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/CHANGELOG.md +112 -0
- package/README.md +9 -4
- package/dist/args.js +4 -1
- package/dist/commands/provider-cli.js +146 -87
- package/dist/config/types.js +1 -1
- package/dist/i18n/en/approval.js +3 -0
- package/dist/i18n/en/credentials.js +10 -0
- package/dist/i18n/en/errors.js +21 -0
- package/dist/i18n/en/firstrun.js +12 -0
- package/dist/i18n/en/screen.js +38 -0
- package/dist/i18n/error-view.js +1 -1
- package/dist/main.js +2 -1
- package/dist/provider/openrouter-login.js +172 -0
- package/dist/runtime/context-archive.js +69 -0
- package/dist/runtime/repo.js +11 -0
- package/dist/runtime/supervisor.js +5 -2
- package/dist/runtime/talos-composition.js +9 -3
- package/dist/tui/agent-view.js +51 -0
- package/dist/tui/app.js +364 -27
- package/dist/tui/catalog-service.js +2 -1
- package/dist/tui/components/status-indicator.js +10 -4
- package/dist/tui/components/terminal-shell.js +10 -1
- package/dist/tui/descendant-approvals.js +104 -0
- package/dist/tui/launch-state.js +9 -0
- package/dist/tui/live-activity.js +13 -2
- package/dist/tui/overlays/agent-tree.js +7 -3
- package/dist/tui/overlays/approval-dialog.js +3 -1
- package/dist/tui/overlays/model-picker.js +5 -0
- package/dist/tui/overlays/provider-picker.js +26 -0
- package/dist/tui/project-trust-prompt.js +5 -3
- package/dist/tui/session-controller.js +25 -12
- package/dist/tui/setup-wizard.js +46 -0
- package/dist/tui/slash-commands.js +3 -1
- package/dist/tui/theme-catalog.js +3 -1
- package/dist/version.js +1 -1
- package/dist/workspace/checkpoint-store.js +32 -1
- package/dist/workspace/checkpoint.js +40 -12
- package/package.json +3 -1
- package/vendor/harness-ui/src/kernel/talosHarness.mjs +149 -2
- package/vendor/manifest.json +2 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# TALOS CLI changelog
|
|
2
|
+
|
|
3
|
+
Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/). Versions follow
|
|
4
|
+
[SemVer](https://semver.org/): in 0.y.z anything may still change. The version lives in `package.json` and
|
|
5
|
+
`src/version.ts`, and in the `talos-cli-vX.Y.Z` tag. The package is published on npm as
|
|
6
|
+
[`talos-code`](https://www.npmjs.com/package/talos-code); the command is `talos`.
|
|
7
|
+
|
|
8
|
+
## talos-cli-v0.2.1 — 2026-09-26
|
|
9
|
+
|
|
10
|
+
`npm i -g talos-code@0.2.1`, or `talos update` to see it.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Faster turns in large folders. The workspace snapshot that makes `/undo` possible no longer reads, rewrites and syncs
|
|
14
|
+
every file at every turn: a file that has not changed since the last turn reuses what was stored. A turn in a plain
|
|
15
|
+
folder of 6,000 files went from 39 s to 1.8 s, and from 2.6 s to 1.4 s in a git repository of the same size. What
|
|
16
|
+
`/undo` covers is unchanged.
|
|
17
|
+
- Faster and complete project search. `cerca` runs ripgrep, shipped inside the package for your platform (no download),
|
|
18
|
+
and each match now comes with its line: `path:line:text`. Four searches over 6,000 files took 9.3 s; now about 0.2 s.
|
|
19
|
+
Before, a search stopped after reading 5,000 files and could miss matches in a bigger project. Several searches asked
|
|
20
|
+
in the same answer run together. Without ripgrep, the previous search still works.
|
|
21
|
+
|
|
22
|
+
### Known limits
|
|
23
|
+
- Tested on Windows 11 x64 only; Node.js 24 (24.18 or later in the 24 line).
|
|
24
|
+
- Shell commands still run one at a time, each in its sandbox; a start of about one second remains.
|
|
25
|
+
|
|
26
|
+
### Verification
|
|
27
|
+
- Measured on a hermetic bench (`scripts/bench-harness.ts`): a local fake provider, no network, TALOS against Pi, Codex
|
|
28
|
+
and OpenCode on the same turns.
|
|
29
|
+
- CLI unit suite: 1876 tests, 1872 pass, 4 skip, 0 fail. Acceptance on the built CLI in a synthetic terminal: 263/263.
|
|
30
|
+
- The package proof (`scripts/prove-standalone.ts`), 16/16 on `talos-code-0.2.1.tgz` (1.76 MB); the installed package
|
|
31
|
+
resolves its own ripgrep.
|
|
32
|
+
|
|
33
|
+
## talos-cli-v0.2.0 — 2026-09-26
|
|
34
|
+
|
|
35
|
+
`npm i -g talos-code@0.2.0`, or `talos update` to see it from 0.1.0.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- Watch a sub-agent live: Alt+A, then Enter on an agent, and its own transcript takes the main view as it streams,
|
|
39
|
+
read-only. Esc goes back to your session without stopping the turn; an agent that finishes stays on screen as done.
|
|
40
|
+
While agents work, the status line says "Alt+A to watch".
|
|
41
|
+
- A guided setup on the first launch: trust this folder, then a provider (a local engine that runs comes
|
|
42
|
+
first), its key or local engine, and a model, one window at a time with "Step N of 4"; Esc skips, and only what is
|
|
43
|
+
missing is asked. It ends with "Ready" and the model. `/setup` or `talos setup` runs it again.
|
|
44
|
+
- Sign in to OpenRouter without pasting a key: choose OpenRouter, then "Sign in with OpenRouter (browser)". TALOS
|
|
45
|
+
opens the browser and waits on 127.0.0.1; on another machine, paste the code OpenRouter shows. Also
|
|
46
|
+
`talos provider login openrouter` (`--paste` for the code). The key that comes back is tested and saved like a pasted one.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
- Forge is the default theme. A theme you chose stays yours.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- A sub-agent that needed your approval (a command, a write) used to wait forever with nothing on screen. Its
|
|
53
|
+
approval now opens like any other and says it comes from the agent and its task; the answer goes to that agent.
|
|
54
|
+
- While delegated sub-agents work, the status line says how many agents are working instead of "thinking" with a
|
|
55
|
+
running clock; any tool that runs silently without asking is shown as running.
|
|
56
|
+
- Changing the theme with `/theme` no longer throws the conversation away. Crossing the colourless `mono` theme used to
|
|
57
|
+
restart the whole screen and lose the session.
|
|
58
|
+
- A turn interrupted while a tool was about to run no longer breaks the session: resuming it used to fail at every turn
|
|
59
|
+
with `CTX_HISTORY_DIVERGED`. A session already broken that way now says so in plain words and offers `/fork`, which
|
|
60
|
+
continues the conversation in a new session.
|
|
61
|
+
|
|
62
|
+
### Known limits
|
|
63
|
+
- Tested on Windows 11 x64 only; Node.js 24 (24.18 or later in the 24 line).
|
|
64
|
+
- Context compaction with a local Ollama model is not yet verified end to end.
|
|
65
|
+
- A local provider that answers 401/403 without needing a key can be set aside as if its key were wrong.
|
|
66
|
+
- The OpenRouter sign-in is tested against a stand-in for OpenRouter; the exchange with the real service follows its
|
|
67
|
+
published contract.
|
|
68
|
+
|
|
69
|
+
### Verification
|
|
70
|
+
- CLI unit suite on the release tree: 1870 tests, 1866 pass, 4 skip, 0 fail. Acceptance on the built CLI in a synthetic
|
|
71
|
+
terminal: 263/263.
|
|
72
|
+
- The package proof (`scripts/prove-standalone.ts`), 16/16 on `talos-code-0.2.0.tgz` (1.76 MB, 407 files): installed
|
|
73
|
+
into an empty prefix outside the repository, hermetic profile, fake provider on 127.0.0.1; every loaded module
|
|
74
|
+
resolved inside the package; nothing written inside the package; no stale build output; no outbound request.
|
|
75
|
+
|
|
76
|
+
## talos-cli-v0.1.0 — 2026-09-25
|
|
77
|
+
|
|
78
|
+
The first public release: `npm i -g talos-code`, then `talos`.
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
- An interactive terminal screen and a headless mode (`talos -p`, `--json`, `--output-format stream-json`) on the
|
|
82
|
+
TALOS kernel, the same one the desktop runs, carried inside the package: it reads no file of a TALOS checkout.
|
|
83
|
+
- Providers from the TALOS registry (OpenAI, Anthropic, Google Gemini, DeepSeek, OpenRouter, Mistral, Groq, xAI and
|
|
84
|
+
more) and local engines with no key (Ollama, LM Studio, llama.cpp). Keys are typed in hidden input and kept in the
|
|
85
|
+
operating system's credential store; a key already in the environment is used only after you agree once.
|
|
86
|
+
- Per-tool permissions (allow, ask, deny) with six modes, project trust for hooks, MCP servers, plugins and commands.
|
|
87
|
+
- `/undo` restores the files a turn changed, from checkpoints kept outside the repository and outside Git.
|
|
88
|
+
- Sessions: `/resume`, `/fork`, export and import (an imported session never runs anything by itself), prompt history.
|
|
89
|
+
- Context: with a known window of 64k tokens or more, compaction at half of it, said on screen; after a summary the
|
|
90
|
+
model did not write properly, automatic compaction pauses (60 s, 5 min, 15 min) and says so, while `/compact` runs
|
|
91
|
+
at once.
|
|
92
|
+
- `/theme` with ten accents, `/help` by group, `/status`, `/retry`, `/copy`, `@` file completion that respects
|
|
93
|
+
`.gitignore`, `Ctrl+R` history search.
|
|
94
|
+
- `talos update` asks the npm registry whether a newer version exists and prints the npm command; it changes nothing.
|
|
95
|
+
- `talos doctor` and a redacted `talos diagnostic bundle`. No telemetry.
|
|
96
|
+
|
|
97
|
+
### Known limits
|
|
98
|
+
- Tested on Windows 11 x64 only; Node.js 24 (24.18 or later in the 24 line).
|
|
99
|
+
- Context compaction with a local Ollama model is not yet verified end to end.
|
|
100
|
+
- A local provider that answers 401/403 without needing a key can be set aside as if its key were wrong.
|
|
101
|
+
- Reported by the owner after the release, to fix in 0.1.x: changing the theme can crash the process; resuming a
|
|
102
|
+
session can end with `CTX_HISTORY_DIVERGED`; sub-agents cannot yet be opened to watch their conversation live, and
|
|
103
|
+
the thinking counter keeps running while they work.
|
|
104
|
+
|
|
105
|
+
### Verification
|
|
106
|
+
- CLI unit suite on the released tree: 1839 tests, 1835 pass, 4 skip, 0 fail. Acceptance on the built CLI in a
|
|
107
|
+
synthetic terminal: 246/247 on the aligned kernel (the one red is a known idle-frame flake).
|
|
108
|
+
- The package proof (`scripts/prove-standalone.ts`), 16/16 on the tarball itself: installed into an empty prefix
|
|
109
|
+
outside the repository, hermetic profile, fake provider on 127.0.0.1; every loaded module resolved inside the
|
|
110
|
+
package; nothing written inside the package; no stale build output.
|
|
111
|
+
- Installed from the registry after publication: `talos --version` answered `0.1.0`, `talos update --check` answered
|
|
112
|
+
up to date.
|
package/README.md
CHANGED
|
@@ -26,9 +26,11 @@ Open a terminal in a project and run:
|
|
|
26
26
|
talos
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
The first time,
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
The first time, a short guided setup asks only what is missing: whether to trust the folder, then a provider (a local
|
|
30
|
+
engine that is running comes first), its key, and a model, one step at a time; Esc skips a step. `/setup` or
|
|
31
|
+
`talos setup` runs it again. A key already in your environment (for example `OPENAI_API_KEY`) is used only after you
|
|
32
|
+
agree once; otherwise you type it in hidden input and it is kept in the operating system's credential store, never in a
|
|
33
|
+
file. For OpenRouter you can also sign in in the browser instead of pasting a key (`talos provider login openrouter`).
|
|
32
34
|
|
|
33
35
|
For a one-shot task, without the interactive screen:
|
|
34
36
|
|
|
@@ -52,6 +54,7 @@ Vertex AI. Local engines: Ollama, LM Studio and llama.cpp, with no key. TALOS ne
|
|
|
52
54
|
one on its own.
|
|
53
55
|
|
|
54
56
|
`/provider` sets up a provider, `/model` (or `Alt+P`) picks the model, and `talos doctor` says what is ready.
|
|
57
|
+
While sub-agents work, `Alt+A` lists them and Enter shows one agent's conversation live, read-only.
|
|
55
58
|
|
|
56
59
|
## What you can rely on
|
|
57
60
|
|
|
@@ -94,7 +97,7 @@ talos update --check
|
|
|
94
97
|
With an npm install, `talos update` tells you if a newer version exists and the command to run
|
|
95
98
|
(`npm i -g talos-code@latest`). It does not change anything by itself.
|
|
96
99
|
|
|
97
|
-
## Known limits in 0.
|
|
100
|
+
## Known limits in 0.2.0
|
|
98
101
|
|
|
99
102
|
- Only Windows 11 x64 is tested.
|
|
100
103
|
- Context compaction with a local Ollama model is not yet verified end to end.
|
|
@@ -106,6 +109,8 @@ With an npm install, `talos update` tells you if a newer version exists and the
|
|
|
106
109
|
missing when something does not work. `talos diagnostic bundle --out talos-diagnostic.zip` makes a redacted report for a
|
|
107
110
|
bug; it contains no prompt or file content.
|
|
108
111
|
|
|
112
|
+
What changed in each version is in `CHANGELOG.md`.
|
|
113
|
+
|
|
109
114
|
## License
|
|
110
115
|
|
|
111
116
|
AGPL-3.0-only. See `LICENSE` and `THIRD_PARTY_NOTICES.md` in this package.
|
package/dist/args.js
CHANGED
|
@@ -82,12 +82,15 @@ export function parseCliArgs(argv) {
|
|
|
82
82
|
positionals: argv.slice(subcommandIndex),
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
/* P17 (owner decision 4): `talos setup` alone is the guided setup, not a prompt that says "setup". */
|
|
86
|
+
const setup = values.print === undefined && outputFormat === 'text' && positionals.length === 1 && positionals[0] === 'setup';
|
|
87
|
+
const promptParts = values.print !== undefined ? [values.print] : setup ? [] : positionals;
|
|
86
88
|
const prompt = promptParts.length ? promptParts.join(' ') : undefined;
|
|
87
89
|
const interactive = values.print === undefined && outputFormat === 'text';
|
|
88
90
|
const timeoutSeconds = positiveInt(values.timeout, '--timeout');
|
|
89
91
|
return {
|
|
90
92
|
command: 'run', interactive, outputFormat, protocolVersion,
|
|
93
|
+
...(setup ? { setup: true } : {}),
|
|
91
94
|
...(prompt !== undefined ? { prompt } : {}), ...(rawMode !== undefined ? { permissionMode: rawMode } : {}),
|
|
92
95
|
...(values.project !== undefined ? { project: values.project } : {}), ...(values.model !== undefined ? { model: values.model } : {}),
|
|
93
96
|
...(values.resume !== undefined ? { resume: values.resume } : {}), ...(values.fork !== undefined ? { fork: values.fork } : {}),
|
|
@@ -11,101 +11,160 @@ import { t } from "../i18n/index.js";
|
|
|
11
11
|
*/
|
|
12
12
|
async function runtimeContext(ctx) { return ctx.createRuntimeContext({ projectRoot: ctx.projectRoot, paths: ctx.paths, repoRoot: ctx.repoRoot, model: ctx.invocation.model ?? 'openai:gpt-5-mini', environmentKeys: 'consent' }); }
|
|
13
13
|
function environmentKeyOf(row) { return row && row.environmentVariable ? { variable: String(row.environmentVariable), state: row.keySource === 'environment' ? 'approved' : row.keySource === 'environment-declined' ? 'declined' : 'unanswered' } : null; }
|
|
14
|
-
export async function runProviderCommand(ctx, args0) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
export async function runProviderCommand(ctx, args0) {
|
|
15
|
+
const args = [...args0];
|
|
16
|
+
const op = args.shift() ?? 'list';
|
|
17
|
+
const rc = await runtimeContext(ctx);
|
|
18
|
+
const store = rc.providerStore;
|
|
19
|
+
const catalog = rc.tuiCatalog;
|
|
20
|
+
if (op === 'list') {
|
|
21
|
+
assertNoUnknownOptions(args);
|
|
22
|
+
if (typeof rc.providerControlPlane?.list === 'function') {
|
|
23
|
+
writeValue(ctx, rc.providerControlPlane.list());
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
const rows = store.listPublic();
|
|
27
|
+
let providers = [];
|
|
28
|
+
try {
|
|
29
|
+
providers = await catalog?.listProviders?.() ?? [];
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
providers = [];
|
|
33
|
+
}
|
|
34
|
+
writeValue(ctx, rows.map((row) => ({ ...row, environmentKey: environmentKeyOf(providers.find((p) => p.id === row?.id)) })));
|
|
18
35
|
return 0;
|
|
19
36
|
}
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
const id = args.shift();
|
|
38
|
+
if (!id)
|
|
39
|
+
throw new Error('PROVIDER_REQUIRED');
|
|
40
|
+
/* P21 (owner decisions 2026-09-26): `talos provider login openrouter` signs in in the browser (the loopback waits for it);
|
|
41
|
+
`--paste`, or a remote session, uses the code OpenRouter shows. Interactive only (clig.dev: never require a prompt in a
|
|
42
|
+
script). The key that comes back is tested and saved like `set-key`'s; it is never printed. */
|
|
43
|
+
if (op === 'login') {
|
|
44
|
+
const paste = takeFlag(args, '--paste');
|
|
45
|
+
assertNoUnknownOptions(args);
|
|
46
|
+
if (id !== 'openrouter')
|
|
47
|
+
throw Object.assign(new Error('PROVIDER_LOGIN_UNSUPPORTED'), { code: 'PROVIDER_LOGIN_UNSUPPORTED' });
|
|
48
|
+
if (typeof catalog?.startOpenRouterLogin !== 'function' || typeof catalog?.setProviderKey !== 'function')
|
|
49
|
+
throw Object.assign(new Error('PROVIDER_LOGIN_UNAVAILABLE'), { code: 'PROVIDER_LOGIN_UNAVAILABLE' });
|
|
50
|
+
if (!ctx.io.stdinIsTTY || !ctx.io.stdoutIsTTY)
|
|
51
|
+
throw Object.assign(new Error('LOGIN_REQUIRES_TTY'), { code: 'LOGIN_REQUIRES_TTY' });
|
|
52
|
+
const login = await catalog.startOpenRouterLogin(paste ? { paste: true } : {});
|
|
53
|
+
if (login.mode === 'paste')
|
|
54
|
+
ctx.io.writeErr(`${t('key.login.paste')}\n${login.url}\n`);
|
|
55
|
+
else
|
|
56
|
+
ctx.io.writeErr(`${t(login.opened ? 'key.login.opened' : 'key.login.open')}\n${login.url}\n${t('key.login.waiting')}\n`);
|
|
57
|
+
let key = '';
|
|
58
|
+
try {
|
|
59
|
+
if (login.mode === 'paste') {
|
|
60
|
+
if (!ctx.io.readSecret)
|
|
61
|
+
throw Object.assign(new Error('SECRET_INPUT_REQUIRES_TTY'), { code: 'SECRET_INPUT_REQUIRES_TTY' });
|
|
62
|
+
key = await login.submit(await ctx.io.readSecret(t('key.login.codePrompt')));
|
|
63
|
+
}
|
|
64
|
+
else
|
|
65
|
+
key = await login.key;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
login.cancel();
|
|
69
|
+
const code = String(error?.code ?? 'OAUTH_FAILED');
|
|
70
|
+
writeValue(ctx, { ok: false, provider: id, code, ...(error?.status ? { httpStatus: error.status } : {}) }, `${t('key.login.failed', { code })}\n`);
|
|
71
|
+
return 11;
|
|
72
|
+
}
|
|
73
|
+
let result;
|
|
74
|
+
try {
|
|
75
|
+
result = await catalog.setProviderKey(id, key);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
key = '';
|
|
79
|
+
}
|
|
80
|
+
const saved = result.saved === true;
|
|
81
|
+
writeValue(ctx, { ok: saved, provider: id, outcome: result.outcome, httpStatus: result.httpStatus, saved }, `${t('key.login.signedIn', { message: result.message, saved: t(saved ? 'key.login.saved' : 'key.login.notSaved') })}\n`);
|
|
82
|
+
return saved ? 0 : 11;
|
|
24
83
|
}
|
|
25
|
-
|
|
26
|
-
|
|
84
|
+
if (op === 'set-key') {
|
|
85
|
+
assertNoUnknownOptions(args);
|
|
86
|
+
if (!ctx.io.readSecret)
|
|
87
|
+
throw new Error('SECRET_INPUT_REQUIRES_TTY');
|
|
88
|
+
if (typeof catalog?.setProviderKey !== 'function')
|
|
89
|
+
throw Object.assign(new Error('PROVIDER_KEY_TEST_UNAVAILABLE'), { code: 'PROVIDER_KEY_TEST_UNAVAILABLE' }); /* a one-token key test is stated before the key is read, so before anything is sent; nothing further is asked */
|
|
90
|
+
const notice = typeof catalog.keyTestNotice === 'function' ? catalog.keyTestNotice(id) : null;
|
|
91
|
+
if (notice)
|
|
92
|
+
ctx.io.writeErr(`${notice}\n`);
|
|
93
|
+
let secret = await ctx.io.readSecret(`Key for ${id}: `);
|
|
94
|
+
let result;
|
|
95
|
+
try {
|
|
96
|
+
result = await catalog.setProviderKey(id, secret);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
secret = '';
|
|
100
|
+
}
|
|
101
|
+
const saved = result.saved === true;
|
|
102
|
+
writeValue(ctx, { ok: saved, provider: id, outcome: result.outcome, httpStatus: result.httpStatus, saved }, `${result.message} ${saved ? 'Saved.' : 'The key was not saved.'}\n`);
|
|
103
|
+
return saved ? 0 : 11;
|
|
27
104
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
105
|
+
if (op === 'env-key') {
|
|
106
|
+
const use = takeFlag(args, '--use');
|
|
107
|
+
const decline = takeFlag(args, '--decline');
|
|
108
|
+
assertNoUnknownOptions(args);
|
|
109
|
+
if (use && decline)
|
|
110
|
+
throw new Error('Use either --use or --decline');
|
|
111
|
+
const row = (await catalog.listProviders()).find((p) => p.id === id);
|
|
112
|
+
if (!row)
|
|
113
|
+
throw Object.assign(new Error('PROVIDER_INVALID'), { code: 'PROVIDER_INVALID' });
|
|
114
|
+
const answering = use || decline;
|
|
115
|
+
if (answering && row.environmentVariable)
|
|
116
|
+
await catalog.answerEnvironmentKey(id, use ? 'yes' : 'no');
|
|
117
|
+
const after = answering ? (await catalog.listProviders()).find((p) => p.id === id) : row;
|
|
118
|
+
const state = environmentKeyOf(after);
|
|
119
|
+
if (!state) {
|
|
120
|
+
writeValue(ctx, { ok: !answering, provider: id, environmentKey: null }, `No key for ${after?.label ?? id} was found in the environment.\n`);
|
|
121
|
+
return answering ? 2 : 0;
|
|
122
|
+
}
|
|
123
|
+
writeValue(ctx, { ok: true, provider: id, environmentKey: state }, `${state.variable}: ${state.state === 'approved' ? 'used for ' + after.label : state.state === 'declined' ? 'declined, not used' : 'not used until approved (talos provider env-key ' + id + ' --use)'}\n`);
|
|
124
|
+
return 0;
|
|
44
125
|
}
|
|
45
|
-
|
|
46
|
-
|
|
126
|
+
if (op === 'remove-key') {
|
|
127
|
+
assertNoUnknownOptions(args);
|
|
128
|
+
store.clearKey(id);
|
|
129
|
+
rc.providerControlPlane?.invalidate?.(id);
|
|
130
|
+
writeValue(ctx, { ok: true, provider: id }, `Removed key for ${id}\n`);
|
|
131
|
+
return 0;
|
|
47
132
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
await catalog.answerEnvironmentKey(id, use ? 'yes' : 'no');
|
|
63
|
-
const after = answering ? (await catalog.listProviders()).find((p) => p.id === id) : row;
|
|
64
|
-
const state = environmentKeyOf(after);
|
|
65
|
-
if (!state) {
|
|
66
|
-
writeValue(ctx, { ok: !answering, provider: id, environmentKey: null }, `No key for ${after?.label ?? id} was found in the environment.\n`);
|
|
67
|
-
return answering ? 2 : 0;
|
|
133
|
+
if (op === 'configure') {
|
|
134
|
+
const endpoint = takeOption(args, '--endpoint');
|
|
135
|
+
const timeoutRaw = takeOption(args, '--timeout');
|
|
136
|
+
assertNoUnknownOptions(args);
|
|
137
|
+
const current = store.getRuntime(id) ?? {};
|
|
138
|
+
const timeoutSeconds = timeoutRaw === undefined ? current.timeoutSeconds : Number(timeoutRaw);
|
|
139
|
+
if (timeoutRaw !== undefined && (!Number.isInteger(timeoutSeconds) || timeoutSeconds < 5 || timeoutSeconds > 300))
|
|
140
|
+
throw new Error('PROVIDER_TIMEOUT_INVALID');
|
|
141
|
+
if (endpoint === undefined && timeoutRaw === undefined)
|
|
142
|
+
throw new Error('PROVIDER_CONFIG_REQUIRED');
|
|
143
|
+
store.setRuntime(id, { ...current, ...(endpoint !== undefined ? { endpoint } : {}), ...(timeoutSeconds !== undefined ? { timeoutSeconds } : {}) });
|
|
144
|
+
rc.providerControlPlane?.invalidate?.(id);
|
|
145
|
+
writeValue(ctx, { ok: true, provider: id, runtime: store.getRuntime(id) }, `Configured ${id}\n`);
|
|
146
|
+
return 0;
|
|
68
147
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
throw new Error('PROVIDER_CONFIG_REQUIRED');
|
|
87
|
-
store.setRuntime(id, { ...current, ...(endpoint !== undefined ? { endpoint } : {}), ...(timeoutSeconds !== undefined ? { timeoutSeconds } : {}) });
|
|
88
|
-
rc.providerControlPlane?.invalidate?.(id);
|
|
89
|
-
writeValue(ctx, { ok: true, provider: id, runtime: store.getRuntime(id) }, `Configured ${id}\n`);
|
|
90
|
-
return 0;
|
|
91
|
-
} if (op === 'test') {
|
|
92
|
-
assertNoUnknownOptions(args); /* M5-A/M5-C: ordinary health testing never opts into token generation, and remediation is the control-plane decision. */
|
|
93
|
-
if (typeof rc.providerControlPlane?.probe === 'function') {
|
|
94
|
-
const profile = await rc.providerControlPlane.probe(id);
|
|
95
|
-
const health = profile.lastHealth ?? {};
|
|
96
|
-
const latency = Number.isFinite(health.latencyMs) ? ` · ${health.latencyMs} ms` : ''; /* R2 (E8 / Q-R2-7): a missing key is the one sentence, as a line of its own; the probe's free-text reason (the kernel's, Italian) is mapped by the remediation code and not printed. */
|
|
97
|
-
const missingKey = profile.remediation?.code === 'add-key';
|
|
98
|
-
const remedy = missingKey ? `${profile.remediation.message}\n` : profile.remediation?.code && profile.remediation.code !== 'none' ? `Remedy: ${profile.remediation.message}\n` : ''; /* R4 Q-R4-16 (a): the kernel's sentence in English by a pinned template, or not printed. */
|
|
99
|
-
const mapped = health.detail && !missingKey ? kernelProbeDetail(String(health.detail), { label: String(profile.label ?? id) }) : null;
|
|
100
|
-
const detail = mapped ? `${mapped}\n` : '';
|
|
101
|
-
writeValue(ctx, missingKey ? { ...profile, code: 'PROVIDER_KEY_MISSING' } : profile, `${profile.label ?? id}: ${health.state ?? 'unknown'}${latency}\n${detail}${remedy}`);
|
|
102
|
-
return health.state === 'available' ? 0 : 11;
|
|
148
|
+
if (op === 'test') {
|
|
149
|
+
assertNoUnknownOptions(args); /* M5-A/M5-C: ordinary health testing never opts into token generation, and remediation is the control-plane decision. */
|
|
150
|
+
if (typeof rc.providerControlPlane?.probe === 'function') {
|
|
151
|
+
const profile = await rc.providerControlPlane.probe(id);
|
|
152
|
+
const health = profile.lastHealth ?? {};
|
|
153
|
+
const latency = Number.isFinite(health.latencyMs) ? ` · ${health.latencyMs} ms` : ''; /* R2 (E8 / Q-R2-7): a missing key is the one sentence, as a line of its own; the probe's free-text reason (the kernel's, Italian) is mapped by the remediation code and not printed. */
|
|
154
|
+
const missingKey = profile.remediation?.code === 'add-key';
|
|
155
|
+
const remedy = missingKey ? `${profile.remediation.message}\n` : profile.remediation?.code && profile.remediation.code !== 'none' ? `Remedy: ${profile.remediation.message}\n` : ''; /* R4 Q-R4-16 (a): the kernel's sentence in English by a pinned template, or not printed. */
|
|
156
|
+
const mapped = health.detail && !missingKey ? kernelProbeDetail(String(health.detail), { label: String(profile.label ?? id) }) : null;
|
|
157
|
+
const detail = mapped ? `${mapped}\n` : '';
|
|
158
|
+
writeValue(ctx, missingKey ? { ...profile, code: 'PROVIDER_KEY_MISSING' } : profile, `${profile.label ?? id}: ${health.state ?? 'unknown'}${latency}\n${detail}${remedy}`);
|
|
159
|
+
return health.state === 'available' ? 0 : 11;
|
|
160
|
+
}
|
|
161
|
+
const probe = typeof rc.providerProbe === 'function' ? rc.providerProbe() : (await importTalosModule(ctx.repoRoot, 'provider-probe.mjs')).createProviderProbe({ leggiChiave: (p) => store.getKey(p), leggiRuntime: (p) => store.getRuntime(p) });
|
|
162
|
+
const result = await probe.prova(id);
|
|
163
|
+
writeValue(ctx, result);
|
|
164
|
+
return result?.esito === 'collegato' ? 0 : 11;
|
|
103
165
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
writeValue(ctx, result);
|
|
107
|
-
return result?.esito === 'collegato' ? 0 : 11;
|
|
108
|
-
} throw new Error(`Unsupported provider operation: ${op}`); }
|
|
166
|
+
throw new Error(`Unsupported provider operation: ${op}`);
|
|
167
|
+
}
|
|
109
168
|
/*
|
|
110
169
|
* R2 (gate E14, E-03): `talos model list` for a person — one row per model under English columns, never the raw JSON array; the
|
|
111
170
|
* MODEL column is exactly what `talos model use` takes (OpenCode `opencode models` prints one id per line and JSON only with
|
package/dist/config/types.js
CHANGED
|
@@ -8,4 +8,4 @@ export const UI_REASONING_MODES = Object.freeze(['collapsed', 'visible']);
|
|
|
8
8
|
export const MODEL_WINDOW_MIN = 1_024;
|
|
9
9
|
export const MODEL_WINDOW_MAX = 10_000_000;
|
|
10
10
|
export const REASONING_EFFORTS = Object.freeze(['low', 'medium', 'high', 'xhigh', 'max']);
|
|
11
|
-
export const DEFAULT_CONFIG = { version: 2, permissionMode: 'default', outputFormat: 'text', updateChannel: 'stable', permissions: { allow: [], ask: [], deny: [] }, ui: { theme: '
|
|
11
|
+
export const DEFAULT_CONFIG = { version: 2, permissionMode: 'default', outputFormat: 'text', updateChannel: 'stable', permissions: { allow: [], ask: [], deny: [] }, ui: { theme: 'forge', markdown: true, exitOutput: 'transcript', busyInput: 'queue', reasoning: 'collapsed' }, extensions: { enabled: [] } };
|
package/dist/i18n/en/approval.js
CHANGED
|
@@ -13,6 +13,9 @@ export const approval = {
|
|
|
13
13
|
'approval.question.TalosService': 'Allow this?',
|
|
14
14
|
/* Q-R3-13 (R0 decision 4): the title of a command approval on a host with no verified sandbox. */
|
|
15
15
|
'approval.unsandboxed': '(unsandboxed)',
|
|
16
|
+
/* P13 (owner decision 8): who asks, when a sub-agent does. */
|
|
17
|
+
'approval.origin.agent': '· from agent · {task}',
|
|
18
|
+
'approval.origin.agentUnnamed': '· from an agent',
|
|
16
19
|
/* Q-R3-6: four choices, Deny highlighted; "deny always" only in the full review (or /permissions). */
|
|
17
20
|
'approval.choice.once': 'Allow once',
|
|
18
21
|
'approval.choice.session': 'Allow for this session',
|
|
@@ -79,4 +79,14 @@ export const credentials = {
|
|
|
79
79
|
'key.models.source.unknown': 'not verified',
|
|
80
80
|
'key.models.none': 'No models are known for this provider.',
|
|
81
81
|
'key.models.use': 'Use one with: talos model use <MODEL>',
|
|
82
|
+
/* P21: `talos provider login openrouter`. */
|
|
83
|
+
'key.login.paste': 'Open this address in a browser on any machine, sign in to OpenRouter, then paste the code it shows:',
|
|
84
|
+
'key.login.opened': 'Opening OpenRouter in your browser. If it did not open, use this address:',
|
|
85
|
+
'key.login.open': 'Open this address in your browser and sign in to OpenRouter:',
|
|
86
|
+
'key.login.waiting': 'Waiting for the browser (10 min). Ctrl+C cancels; on another machine, run it again with --paste.',
|
|
87
|
+
'key.login.codePrompt': 'Code: ',
|
|
88
|
+
'key.login.failed': 'OpenRouter sign-in did not complete ({code}).',
|
|
89
|
+
'key.login.signedIn': 'Signed in to OpenRouter. {message} {saved}',
|
|
90
|
+
'key.login.saved': 'Saved.',
|
|
91
|
+
'key.login.notSaved': 'The key was not saved.',
|
|
82
92
|
};
|
package/dist/i18n/en/errors.js
CHANGED
|
@@ -240,6 +240,27 @@ export const errors = {
|
|
|
240
240
|
'error.code.CTX_COMPACTION_FAILED.todo': 'Try /compact again; if it keeps happening, start a new conversation with /clear.',
|
|
241
241
|
'error.code.CTX_JOB_INTERRUPTED.what': 'A compaction was interrupted because the TALOS process running it stopped; nothing was changed.',
|
|
242
242
|
'error.code.CTX_JOB_INTERRUPTED.todo': 'Nothing to fix: the next request or /compact starts it again.',
|
|
243
|
+
/* P12: a session whose context archive no longer matches its history (before 0.2.0 an interrupted tool turn could
|
|
244
|
+
cause it). Nothing is lost; the way on is a new session that carries the conversation. */
|
|
245
|
+
/* P21: OpenRouter sign-in. */
|
|
246
|
+
'error.code.LOGIN_REQUIRES_TTY.what': 'Signing in needs an interactive terminal.',
|
|
247
|
+
'error.code.LOGIN_REQUIRES_TTY.todo': 'Run talos provider login openrouter in a terminal, or save a key with talos provider set-key openrouter.',
|
|
248
|
+
'error.code.PROVIDER_LOGIN_UNSUPPORTED.what': 'Only OpenRouter offers a sign-in; other providers use a key.',
|
|
249
|
+
'error.code.PROVIDER_LOGIN_UNSUPPORTED.todo': 'Save a key with talos provider set-key <provider>.',
|
|
250
|
+
'error.code.PROVIDER_LOGIN_UNAVAILABLE.what': 'The OpenRouter sign-in is not available in this installation.',
|
|
251
|
+
'error.code.PROVIDER_LOGIN_UNAVAILABLE.todo': 'Save a key with talos provider set-key openrouter.',
|
|
252
|
+
'error.code.OAUTH_CALLBACK_UNAVAILABLE.what': 'TALOS could not listen for OpenRouter on this machine.',
|
|
253
|
+
'error.code.OAUTH_CALLBACK_UNAVAILABLE.todo': 'Sign in with the code instead: talos provider login openrouter --paste.',
|
|
254
|
+
'error.code.OAUTH_CANCELLED.what': 'The sign-in was cancelled.',
|
|
255
|
+
'error.code.OAUTH_CANCELLED.todo': 'Start it again when you are ready.',
|
|
256
|
+
'error.code.OAUTH_CODE_MISSING.what': 'That is not a code from OpenRouter.',
|
|
257
|
+
'error.code.OAUTH_CODE_MISSING.todo': 'Paste the code OpenRouter shows, or the whole address the browser landed on.',
|
|
258
|
+
'error.code.OAUTH_DENIED.what': 'The sign-in was cancelled in the browser.',
|
|
259
|
+
'error.code.OAUTH_DENIED.todo': 'Start it again and allow access on the OpenRouter page.',
|
|
260
|
+
'error.code.OAUTH_TIMEOUT.what': 'The sign-in took longer than 10 minutes.',
|
|
261
|
+
'error.code.OAUTH_TIMEOUT.todo': 'Start it again; the code OpenRouter gives lasts 10 minutes.',
|
|
262
|
+
'error.code.CTX_HISTORY_DIVERGED.what': 'This conversation no longer matches its saved context, so TALOS stopped before sending anything. Nothing was lost.',
|
|
263
|
+
'error.code.CTX_HISTORY_DIVERGED.todo': 'Continue it in a new session with /fork (it keeps the whole conversation), or start fresh with /clear.',
|
|
243
264
|
'error.where.context': '/context shows the window TALOS measured and how compaction is set.',
|
|
244
265
|
'error.code.MODELS_DEV_TOO_LARGE.what': 'The models.dev catalogue answered with more data than TALOS accepts, so it was not used.',
|
|
245
266
|
'error.code.MODELS_DEV_TOO_LARGE.todo': 'Nothing to do: model windows come from the other sources until the next try.',
|
package/dist/i18n/en/firstrun.js
CHANGED
|
@@ -44,6 +44,18 @@ export const firstrun = {
|
|
|
44
44
|
'firstrun.setup.model': 'Choose the model TALOS should use for this project.',
|
|
45
45
|
'firstrun.setup.key': 'The chosen provider has no usable key; add one.',
|
|
46
46
|
'firstrun.setup.loaded': 'Loaded {files}',
|
|
47
|
+
/* P17 (owner decisions 2026-09-26): the guided setup of the first launch, and /setup. */
|
|
48
|
+
'firstrun.setup.stepLine': 'Setup · Step {index} of {total} · {name} · Esc skips this step',
|
|
49
|
+
'firstrun.setup.stepLineOnly': 'Setup · Step {index} of {total} · {name}',
|
|
50
|
+
'firstrun.setup.stepName.trust': 'Trust',
|
|
51
|
+
'firstrun.setup.stepName.provider': 'Provider',
|
|
52
|
+
'firstrun.setup.stepName.key': 'Key or local engine',
|
|
53
|
+
'firstrun.setup.stepName.model': 'Model',
|
|
54
|
+
'firstrun.setup.trustHeading': 'TALOS · Setup · Step 1 of 4 · {title}',
|
|
55
|
+
'firstrun.setup.retryHint': 'R retries · Esc back to the providers',
|
|
56
|
+
'firstrun.setup.skipped': 'Setup skipped. /setup starts it again; /provider and /model change one thing.',
|
|
57
|
+
'firstrun.setup.ready': '✓ Ready · {model} · type your first message',
|
|
58
|
+
'firstrun.setup.readyHints': '/help commands · Shift+Tab permissions · /setup to change this',
|
|
47
59
|
/* Q-R4-11: the provider list marks the chosen provider and says whether a local engine is running. */
|
|
48
60
|
'firstrun.providers.chosen': 'chosen',
|
|
49
61
|
'firstrun.providers.running': 'running',
|
package/dist/i18n/en/screen.js
CHANGED
|
@@ -266,6 +266,11 @@ export const screen = {
|
|
|
266
266
|
/* R3 Q-R3-7 (gate E7): the status words while a turn runs and after it. */
|
|
267
267
|
'screen.busy.tool': 'running',
|
|
268
268
|
'screen.busy.toolNamed': 'running {tool}',
|
|
269
|
+
/* P14: the parent waits on delegated sub-agents. */
|
|
270
|
+
'screen.busy.agents': 'agents working',
|
|
271
|
+
'screen.busy.agentsCount.one': '{count} agent working',
|
|
272
|
+
'screen.busy.agentsCount.other': '{count} agents working',
|
|
273
|
+
'screen.busy.agentsWatch': 'Alt+A to watch',
|
|
269
274
|
'screen.busy.writing': 'writing',
|
|
270
275
|
'screen.busy.waiting': 'waiting for you',
|
|
271
276
|
'screen.busy.done': 'done',
|
|
@@ -304,6 +309,28 @@ export const screen = {
|
|
|
304
309
|
'screen.help.close': 'Esc / Enter / ? closes help',
|
|
305
310
|
'screen.slash.help': 'Show commands',
|
|
306
311
|
'screen.slash.provider': 'Choose the AI provider',
|
|
312
|
+
/* P21 (owner decisions 2026-09-26): OpenRouter sign-in. */
|
|
313
|
+
'screen.provider.loginBrowser': 'Sign in with {provider} (browser)',
|
|
314
|
+
'screen.provider.loginPasteKey': 'Paste an API key',
|
|
315
|
+
'screen.provider.loginChoiceKeys': '↑↓ choose · Enter confirms · Esc cancels',
|
|
316
|
+
'screen.provider.oauthOpened': 'Opening {provider} in your browser. If it did not open, use this address:',
|
|
317
|
+
'screen.provider.oauthNotOpened': 'Open this address in your browser and sign in to {provider}:',
|
|
318
|
+
'screen.provider.oauthRemote': 'Remote session: open this address in a browser on any machine, sign in to {provider}, then paste the code it shows.',
|
|
319
|
+
'screen.provider.oauthPaste': 'Code: {masked}',
|
|
320
|
+
'screen.provider.oauthWaiting': 'Waiting for the browser (10 min) · C paste a code instead · Esc cancels',
|
|
321
|
+
'screen.provider.oauthPasteKeys': 'Paste the code (or the whole address) · Enter signs in · Esc cancels',
|
|
322
|
+
'screen.provider.oauthExchanging': 'Signing in…',
|
|
323
|
+
'screen.provider.oauthFailedKeys': 'Enter starts it again · Esc cancels',
|
|
324
|
+
'screen.provider.oauthAddress': 'Sign in to {provider} at this address (it is also in the window below): {url}',
|
|
325
|
+
'screen.provider.oauthSaved': '✓ Signed in to {provider} · key saved',
|
|
326
|
+
'screen.provider.oauthError.OAUTH_TIMEOUT': 'The sign-in took longer than 10 minutes.',
|
|
327
|
+
'screen.provider.oauthError.OAUTH_SCAMBIO_RIFIUTATO': '{provider} refused this sign-in (HTTP {status}): the code may be expired or already used.',
|
|
328
|
+
'screen.provider.oauthError.OAUTH_RETE': '{provider} could not be reached.',
|
|
329
|
+
'screen.provider.oauthError.OAUTH_RISPOSTA_INATTESA': '{provider} answered without a key.',
|
|
330
|
+
'screen.provider.oauthError.OAUTH_DENIED': 'The sign-in was cancelled in the browser.',
|
|
331
|
+
'screen.provider.oauthError.OAUTH_CODE_MISSING': 'That is not a code from {provider}; paste the code, or the whole address the browser landed on.',
|
|
332
|
+
'screen.provider.oauthError.other': 'The sign-in did not complete.',
|
|
333
|
+
'screen.slash.setup': 'Set up provider, key and model, step by step',
|
|
307
334
|
'screen.slash.model': 'Choose a model from the chosen provider',
|
|
308
335
|
'screen.slash.queue': 'Show or manage queued follow-ups',
|
|
309
336
|
'screen.slash.permissions': 'Show permission mode',
|
|
@@ -472,6 +499,17 @@ export const screen = {
|
|
|
472
499
|
'screen.agents.empty': 'No native agent rows. · Esc close',
|
|
473
500
|
'screen.agents.steerHint': 'Alt+S steer active session from composer · Esc close',
|
|
474
501
|
'screen.agents.inspectOnly': 'inspection only · steering unavailable for selected session · Esc close',
|
|
502
|
+
/* P13 (owner decisions 2026-09-26): Enter watches an agent live, read-only; Esc goes back without stopping the turn. */
|
|
503
|
+
'screen.agents.watchHint': 'Enter watch live · Esc close',
|
|
504
|
+
'screen.agents.backHint': 'Enter back to main · Esc close',
|
|
505
|
+
'screen.agents.watchingHint': 'watching now · Esc close',
|
|
506
|
+
'screen.agentView.watching': 'viewing agent · {task} · Esc back to main',
|
|
507
|
+
'screen.agentView.done': 'agent · {task} · done · Esc back to main',
|
|
508
|
+
'screen.agentView.unnamed': 'unnamed task',
|
|
509
|
+
'screen.agentView.readOnly': 'read-only while viewing an agent · Esc back to main',
|
|
510
|
+
'screen.agentView.task': 'Task from main',
|
|
511
|
+
'screen.agentView.agent': 'Agent',
|
|
512
|
+
'screen.agentView.shortcuts': 'Esc back to main · Alt+A agents · Ctrl+C stops the turn · PageUp/PageDown transcript',
|
|
475
513
|
'screen.automation.title': 'Automation Center',
|
|
476
514
|
'screen.automation.empty': '(no automations)',
|
|
477
515
|
'screen.automation.keys': '↑/↓ select · d dry-run/detail · u refresh · Esc/q close',
|
package/dist/i18n/error-view.js
CHANGED
|
@@ -160,7 +160,7 @@ const CODE_WHERE = {
|
|
|
160
160
|
/* R5b (R5a open 4): the Context Engine's failures point at /context. */
|
|
161
161
|
CTX_CONTEXT_OVERFLOW: 'error.where.context', CTX_TRUNCATED_SUMMARY: 'error.where.context', CTX_SUMMARY_RESPONSE_INVALID: 'error.where.context', CTX_SEGMENT_TOO_LARGE: 'error.where.context',
|
|
162
162
|
CTX_INVALID_SUMMARY: 'error.where.context', CTX_EMPTY_SUMMARY: 'error.where.context', CTX_NO_REDUCTION: 'error.where.context', CTX_NOTHING_TO_COMPACT: 'error.where.context',
|
|
163
|
-
CTX_CONTEXT_TOO_SMALL: 'error.where.context', CTX_COMPACTION_FAILED: 'error.where.context', CTX_JOB_INTERRUPTED: 'error.where.context',
|
|
163
|
+
CTX_CONTEXT_TOO_SMALL: 'error.where.context', CTX_COMPACTION_FAILED: 'error.where.context', CTX_JOB_INTERRUPTED: 'error.where.context', CTX_HISTORY_DIVERGED: 'error.where.context',
|
|
164
164
|
};
|
|
165
165
|
function familyTodo(fam) { return fam === 'interrupted' ? null : `error.family.${fam}.todo`; }
|
|
166
166
|
const RULE_CODES = new Set(['RULE_COMMAND_UNSUPPORTED', 'RULE_COMPOUND_COMMAND', 'RULE_UNREADABLE', 'RULE_MATCHES_NOTHING']);
|
package/dist/main.js
CHANGED
|
@@ -14,6 +14,7 @@ import { createLocalAutoClassifier } from "./security/auto-classifier.js";
|
|
|
14
14
|
import { abortIsolationChecks, cliShellIsolation } from "./security/execution-backends.js";
|
|
15
15
|
import { inertTerminalText, renderSafeTalosFailure } from "./errors.js";
|
|
16
16
|
import { registerActiveRun } from "./runtime/active-run.js";
|
|
17
|
+
import { isFirstLaunch } from "./tui/launch-state.js"; /* P17: the first launch's trust question is step 1 of the setup */
|
|
17
18
|
import { initializeDevelopmentLogging, developmentLog, developmentLogError, closeDevelopmentLogging, developmentTextEvidence } from "./diagnostics/development-log.js";
|
|
18
19
|
import { assessProjectTrust, assertProjectTrusted, needsTrustQuestion, nestedRepositoriesForProjectTrust, projectTrustFailure, trustProjectAssessment } from "./security/project-trust-gate.js";
|
|
19
20
|
import { findTalosRepoRoot, importTalosModule } from "./runtime/repo.js";
|
|
@@ -181,7 +182,7 @@ export async function main(argv, deps = {}) {
|
|
|
181
182
|
const assessment = await (deps.assessProjectTrust ?? assessProjectTrust)(trustInput); /* R4 Q-R4-1: every folder with no saved decision is asked, with or without project files; headless keeps its rule (E3). */
|
|
182
183
|
if (needsTrustQuestion(assessment)) {
|
|
183
184
|
const nestedRepositories = await nestedRepositoriesForProjectTrust(assessment);
|
|
184
|
-
const choice = await (deps.promptProjectTrust ?? defaultPromptProjectTrust)({ assessment, nestedRepositories, color: inv.color !== false, ...await userThemeForTrust(paths, projectRoot) });
|
|
185
|
+
const choice = await (deps.promptProjectTrust ?? defaultPromptProjectTrust)({ assessment, nestedRepositories, color: inv.color !== false, ...await userThemeForTrust(paths, projectRoot), ...(isFirstLaunch(paths.dataRoot) ? { setupStep: true } : {}) });
|
|
185
186
|
if (choice !== 'trust' && choice !== 'trust-parent')
|
|
186
187
|
throw projectTrustFailure(assessment);
|
|
187
188
|
const folder = folderTargetFor(choice, assessment); /* Session only with nothing to trust: nothing is written. */
|