@aeolus-fleet/trierarch 0.20.0 → 0.20.2
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/README.md +5 -5
- package/dist/adapters/claude-code-detector.d.ts +26 -0
- package/dist/adapters/claude-code-detector.js +97 -0
- package/dist/adapters/claude-code-detector.js.map +1 -0
- package/dist/adapters/codex-detector.d.ts +12 -0
- package/dist/adapters/codex-detector.js +53 -0
- package/dist/adapters/codex-detector.js.map +1 -0
- package/dist/adapters/detected-file.d.ts +2 -0
- package/dist/adapters/detected-file.js +44 -0
- package/dist/adapters/detected-file.js.map +1 -0
- package/dist/adapters/detectors.d.ts +5 -0
- package/dist/adapters/detectors.js +21 -0
- package/dist/adapters/detectors.js.map +1 -0
- package/dist/adapters/paths.d.ts +2 -0
- package/dist/adapters/paths.js +1 -0
- package/dist/adapters/paths.js.map +1 -1
- package/dist/adapters/run-command.d.ts +6 -1
- package/dist/adapters/run-command.js +14 -2
- package/dist/adapters/run-command.js.map +1 -1
- package/dist/cli/config-check.js +4 -1
- package/dist/cli/config-check.js.map +1 -1
- package/dist/cli/detect.d.ts +26 -0
- package/dist/cli/detect.js +30 -0
- package/dist/cli/detect.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +4 -0
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/main.js +17 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/run.js +14 -1
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/upgrade.d.ts +7 -0
- package/dist/cli/upgrade.js +21 -1
- package/dist/cli/upgrade.js.map +1 -1
- package/dist/core/check-settings.d.ts +3 -1
- package/dist/core/check-settings.js +7 -5
- package/dist/core/check-settings.js.map +1 -1
- package/dist/core/detect-harnesses.d.ts +21 -0
- package/dist/core/detect-harnesses.js +43 -0
- package/dist/core/detect-harnesses.js.map +1 -0
- package/dist/core/detected-options.d.ts +9 -0
- package/dist/core/detected-options.js +11 -0
- package/dist/core/detected-options.js.map +1 -0
- package/dist/core/ports.d.ts +34 -0
- package/dist/core/reconciler.js +2 -2
- package/dist/core/reconciler.js.map +1 -1
- package/dist/core/report-detection-problems.d.ts +11 -0
- package/dist/core/report-detection-problems.js +16 -0
- package/dist/core/report-detection-problems.js.map +1 -0
- package/dist/core/report-self.js +10 -6
- package/dist/core/report-self.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -41,8 +41,9 @@ That gives the command `aeolus-trierarch`.
|
|
|
41
41
|
| `aeolus-trierarch list` | The ships it crews: ship, state, harness, workspace, since, restarts |
|
|
42
42
|
| `aeolus-trierarch logs [--lines <n>] [--follow]` | The last lines of `~/.aeolus/trierarch/logs/trierarch.log`, and with `--follow` each new one. The log holds one JSON record per line: each action the loop takes for a ship (crew, launch, wake, report, release, confirm, forget, leave, stop) as `{ time, shipId, shipName, action, outcome, next }`, where `next` says what happens after a failure, or a message as `{ time, level, message }`. `logs` renders them as text, and `--json` gives the records as they are (a line that is no record as `{ line }`). `run` in a terminal writes the text |
|
|
43
43
|
| `aeolus-trierarch config check` | Checks the configuration and gives the flags each harness launches with, and each option value's flags. Then the command each harness launches on a first start and on a restart, with each flag marked `(configuration)` or `(adapter)` when the adapter adds it itself (`--no-daemon` for Codex, `--continue` on a Claude Code restart, the remote-control session name) |
|
|
44
|
+
| `aeolus-trierarch detect` | Detects again what each configured harness offers (its models, and effort where its CLI has a flag for it) and keeps it in `~/.aeolus/trierarch/detected.json`, then gives per harness its version, each option's values and when its models were last confirmed. Restart the trierarch so it reads them ([docs/trierarch.md](../../docs/trierarch.md#detected-options)) |
|
|
44
45
|
| `aeolus-trierarch start`, `stop`, `restart` | The service. `stop` returns once the trierarch has exited; a stopped one starts again at the next login. Restart it after you change the configuration |
|
|
45
|
-
| `aeolus-trierarch upgrade [version]` | Installs the given version, or the latest on npm, globally and pinned to it. Then it stops the old process and starts the new one, and shows `status`. Sessions keep running: the new process takes them over. If the install fails, the old version keeps running. It never upgrades on its own |
|
|
46
|
+
| `aeolus-trierarch upgrade [version]` | Installs the given version, or the latest on npm, globally and pinned to it. Then it stops the old process and starts the new one, waits until the new one says its version (at most 30 seconds), and shows `status`. Sessions keep running: the new process takes them over. If the install fails, the old version keeps running. It never upgrades on its own |
|
|
46
47
|
| `aeolus-trierarch install [--no-load]` | Installs the service; over a running one it waits for the old process to exit, then loads it again. With `--no-load` it only writes its file |
|
|
47
48
|
| `aeolus-trierarch uninstall` | Removes the service and stops every session. It deletes nothing else: it lists the worktrees it leaves, and keeps its own files under `~/.aeolus/trierarch/` |
|
|
48
49
|
| `aeolus-trierarch run` | What the service runs: keeps the ships assigned to it crewed until stopped |
|
|
@@ -66,13 +67,12 @@ To stop the trierarch: `aeolus-trierarch stop`, or `aeolus-trierarch uninstall`
|
|
|
66
67
|
"claude-code": {
|
|
67
68
|
"flags": ["--remote-control"],
|
|
68
69
|
"options": {
|
|
69
|
-
"
|
|
70
|
+
"effort": { "values": { "high": ["--effort", "high"], "max": ["--effort", "max"] }, "default": "high" }
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
73
|
"codex": {
|
|
73
74
|
"flags": ["--dangerously-bypass-approvals-and-sandbox"],
|
|
74
75
|
"options": {
|
|
75
|
-
"model": { "values": { "sol": ["-m", "gpt-5.6-sol"] }, "default": "sol" }
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -84,7 +84,7 @@ To stop the trierarch: `aeolus-trierarch stop`, or `aeolus-trierarch uninstall`
|
|
|
84
84
|
- **folders**: by name, used as they are, one ship per folder, never removed.
|
|
85
85
|
- **harnesses**: `claude-code`, `codex` or both: the flags every launch gets, and named options. A crew request's settings pick option values by name; they never add a flag or carry a path. There is no policy on which flags: put `--dangerously-skip-permissions` in `flags` if you want it. The trierarch never adds a flag by itself. With `--remote-control` and no name after it, each session is named `[<repository or folder>] <ship>`, such as `[aeolus-fleet] trial-1`, so it is easy to find among your remote-control sessions.
|
|
86
86
|
|
|
87
|
-
`aeolus-trierarch init` writes caps, repositories, folders, and Claude Code's and Codex's flags
|
|
87
|
+
`aeolus-trierarch init` writes caps, repositories, folders, and Claude Code's and Codex's flags, and detects each harness's models and effort levels into `detected.json` ([docs/trierarch.md](../../docs/trierarch.md#detected-options)). Options you write here replace the detected option of the same name whole: the example above narrows Claude Code's effort to two levels with a default, and takes the detected models as they are. Edit the file for options and `worktreeRoot`, then `aeolus-trierarch config check` and `aeolus-trierarch restart`.
|
|
88
88
|
|
|
89
89
|
The trierarch finds the aeolus plugin in each offered harness's plugin cache (the newest version): Claude Code's under `~/.claude/plugins`, Codex's under `~/.codex/plugins` (or `$CODEX_HOME/plugins`). Set `AEOLUS_PLUGIN_ROOT` and `AEOLUS_PLUGIN_DATA` (Claude Code), or `AEOLUS_CODEX_PLUGIN_ROOT` and `AEOLUS_CODEX_PLUGIN_DATA` (Codex), to point it elsewhere. `aeolus-trierarch install` carries these, `CODEX_HOME`, `AEOLUS_TRIERARCH_CONFIG` and `PATH` into the service as they are set where it runs.
|
|
90
90
|
|
|
@@ -101,5 +101,5 @@ The trierarch finds the aeolus plugin in each offered harness's plugin cache (th
|
|
|
101
101
|
- git worktrees and folders;
|
|
102
102
|
- Claude Code and Codex, through the aeolus plugin's `aeolus-identity.sh`. Each passes its prompt last, after `--`, so a prompt never reads as a flag. A Codex session starts with `codex ... -- <prompt>`, always with `--no-daemon`, comes back with `codex resume --last`, and is woken by typing `$aeolus-wake`;
|
|
103
103
|
- the JSON state store.
|
|
104
|
-
- **The command** (`src/cli`): `init`, `status`, `list`, `logs`, `config check`, `start`, `stop`, `restart`, `install`, `uninstall`, `run`.
|
|
104
|
+
- **The command** (`src/cli`): `init`, `status`, `list`, `logs`, `config check`, `detect`, `start`, `stop`, `restart`, `install`, `uninstall`, `run`.
|
|
105
105
|
- **Adapters for the setup**: the service (launchd or systemd), Claude Code's own files and Codex's app server for their one-time questions.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HarnessDetector } from '../core/ports.js';
|
|
2
|
+
import type { CommandResult } from './run-command.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detecting Claude Code (#365; docs/trierarch.md, "Detected options"). Its
|
|
5
|
+
* CLI lists no models, but its --help names the aliases it takes, each for
|
|
6
|
+
* the latest of a family: each is probed once with a short print-mode turn,
|
|
7
|
+
* from a neutral folder and never as a ship, and the exact id it resolves to
|
|
8
|
+
* is read from the answer's modelUsage. Those ids are declared, so they follow
|
|
9
|
+
* the installed CLI with no list to keep. An alias the CLI refuses is left
|
|
10
|
+
* out; one whose probe neither confirms nor refuses it (offline, not logged
|
|
11
|
+
* in) keeps the id it resolved to before at the same version. The effort
|
|
12
|
+
* levels come from --help. Neither has a default: the CLI keeps its own.
|
|
13
|
+
*/
|
|
14
|
+
/** The longest a probe may take: a CLI that hangs is ended, its id neither confirmed nor refused. */
|
|
15
|
+
export declare const CLAUDE_CODE_PROBE_TIMEOUT_MS = 60000;
|
|
16
|
+
export declare function createClaudeCodeDetector(deps: {
|
|
17
|
+
run: (command: string, options: {
|
|
18
|
+
args: readonly string[];
|
|
19
|
+
cwd?: string;
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
}) => Promise<CommandResult>;
|
|
22
|
+
/** An empty folder to probe from, so no project's hooks or settings run. */
|
|
23
|
+
neutralFolder: () => Promise<string>;
|
|
24
|
+
/** The program to run; `claude` unless a test runs another. */
|
|
25
|
+
program?: string;
|
|
26
|
+
}): HarnessDetector;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { trierarchNameSchema } from '@aeolus-fleet/common';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Detecting Claude Code (#365; docs/trierarch.md, "Detected options"). Its
|
|
5
|
+
* CLI lists no models, but its --help names the aliases it takes, each for
|
|
6
|
+
* the latest of a family: each is probed once with a short print-mode turn,
|
|
7
|
+
* from a neutral folder and never as a ship, and the exact id it resolves to
|
|
8
|
+
* is read from the answer's modelUsage. Those ids are declared, so they follow
|
|
9
|
+
* the installed CLI with no list to keep. An alias the CLI refuses is left
|
|
10
|
+
* out; one whose probe neither confirms nor refuses it (offline, not logged
|
|
11
|
+
* in) keeps the id it resolved to before at the same version. The effort
|
|
12
|
+
* levels come from --help. Neither has a default: the CLI keeps its own.
|
|
13
|
+
*/
|
|
14
|
+
/** The longest a probe may take: a CLI that hangs is ended, its id neither confirmed nor refused. */
|
|
15
|
+
export const CLAUDE_CODE_PROBE_TIMEOUT_MS = 60_000;
|
|
16
|
+
/** The longest --version and --help may take. */
|
|
17
|
+
const QUICK_TIMEOUT_MS = 10_000;
|
|
18
|
+
/** How Claude Code says it does not know a model. */
|
|
19
|
+
const UNRECOGNIZED_MODEL = 'unrecognized_model';
|
|
20
|
+
const PROBE_PROMPT = 'Reply OK';
|
|
21
|
+
const probeAnswerSchema = z.object({ modelUsage: z.record(z.string(), z.unknown()) });
|
|
22
|
+
/** The id the probe ran: the one in modelUsage that names the alias, or the only one. */
|
|
23
|
+
function resolvedIdOf(alias, modelUsage) {
|
|
24
|
+
const ids = Object.keys(modelUsage).filter((id) => trierarchNameSchema.safeParse(id).success);
|
|
25
|
+
return ids.find((id) => id.includes(alias)) ?? (ids.length === 1 ? ids[0] : undefined);
|
|
26
|
+
}
|
|
27
|
+
function outcomeOf(alias, result) {
|
|
28
|
+
if (`${result.stdout}\n${result.stderr}`.includes(UNRECOGNIZED_MODEL)) {
|
|
29
|
+
return { kind: 'refused' };
|
|
30
|
+
}
|
|
31
|
+
if (result.status !== 0) {
|
|
32
|
+
return { kind: 'unknown' };
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const answer = probeAnswerSchema.safeParse(JSON.parse(result.stdout));
|
|
36
|
+
const id = answer.success ? resolvedIdOf(alias, answer.data.modelUsage) : undefined;
|
|
37
|
+
return id === undefined ? { kind: 'unknown' } : { kind: 'resolved', id };
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return { kind: 'unknown' };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** The aliases --help names for --model, quoted, such as 'opus'. */
|
|
44
|
+
function aliasesOf(help) {
|
|
45
|
+
const line = /--model <model>[^\n]*/.exec(help)?.[0] ?? '';
|
|
46
|
+
return [...line.matchAll(/'([a-z0-9][a-z0-9._-]*)'/g)].flatMap((match) => (match[1] === undefined ? [] : [match[1]]));
|
|
47
|
+
}
|
|
48
|
+
/** The levels `--effort <level> ... (low, medium, high)` names in --help, each a value name. */
|
|
49
|
+
function effortLevelsOf(help) {
|
|
50
|
+
const listed = /--effort <level>[^\n(]*\(([^)]*)\)/.exec(help)?.[1];
|
|
51
|
+
return (listed ?? '')
|
|
52
|
+
.split(',')
|
|
53
|
+
.map((level) => level.trim())
|
|
54
|
+
.filter((level) => trierarchNameSchema.safeParse(level).success);
|
|
55
|
+
}
|
|
56
|
+
function optionOf(names, flag) {
|
|
57
|
+
return { values: Object.fromEntries(names.map((name) => [name, [flag, name]])) };
|
|
58
|
+
}
|
|
59
|
+
export function createClaudeCodeDetector(deps) {
|
|
60
|
+
const program = deps.program ?? 'claude';
|
|
61
|
+
return {
|
|
62
|
+
version: async () => {
|
|
63
|
+
const result = await deps.run(program, { args: ['--version'], timeoutMs: QUICK_TIMEOUT_MS }).catch(() => undefined);
|
|
64
|
+
return result?.status === 0 ? /^\S+/.exec(result.stdout.trim())?.[0] : undefined;
|
|
65
|
+
},
|
|
66
|
+
detect: async ({ version, previous, now }) => {
|
|
67
|
+
const help = await deps.run(program, { args: ['--help'], timeoutMs: QUICK_TIMEOUT_MS });
|
|
68
|
+
const text = help.status === 0 ? help.stdout : '';
|
|
69
|
+
const levels = effortLevelsOf(text);
|
|
70
|
+
const aliases = aliasesOf(text);
|
|
71
|
+
const before = previous?.version === version ? previous : undefined;
|
|
72
|
+
const resolvedBefore = Object.keys(before?.options.model?.values ?? {});
|
|
73
|
+
const folder = aliases.length === 0 ? undefined : await deps.neutralFolder();
|
|
74
|
+
const ids = [];
|
|
75
|
+
let isAnyResolved = false;
|
|
76
|
+
for (const alias of aliases) {
|
|
77
|
+
const outcome = outcomeOf(alias, await deps.run(program, { args: ['-p', '--model', alias, '--max-turns', '1', '--output-format', 'json', PROBE_PROMPT], cwd: folder, timeoutMs: CLAUDE_CODE_PROBE_TIMEOUT_MS }));
|
|
78
|
+
isAnyResolved ||= outcome.kind === 'resolved';
|
|
79
|
+
const kept = outcome.kind === 'resolved' ? [outcome.id] : outcome.kind === 'unknown' ? resolvedBefore.filter((id) => id.includes(alias)) : [];
|
|
80
|
+
ids.push(...kept.filter((id) => !ids.includes(id)));
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
version,
|
|
84
|
+
detectedAt: now,
|
|
85
|
+
confirmedAt: isAnyResolved ? now : (before?.confirmedAt ?? null),
|
|
86
|
+
options: {
|
|
87
|
+
...(ids.length > 0 && { model: optionOf(ids, '--model') }),
|
|
88
|
+
...(levels.length > 0 && { effort: optionOf(levels, '--effort') }),
|
|
89
|
+
},
|
|
90
|
+
...(aliases.length === 0 && {
|
|
91
|
+
problem: `Claude Code ${version}'s --help names no model alias, so this machine declares no Claude Code model: add the ones you want to its configuration`,
|
|
92
|
+
}),
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=claude-code-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-detector.js","sourceRoot":"","sources":["../../src/adapters/claude-code-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HarnessDetector } from '../core/ports.js';
|
|
2
|
+
import type { CommandResult } from './run-command.js';
|
|
3
|
+
export declare function createCodexDetector(deps: {
|
|
4
|
+
run: (command: string, options: {
|
|
5
|
+
args: readonly string[];
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
}) => Promise<CommandResult>;
|
|
8
|
+
/** The user's Codex configuration, `~/.codex/config.toml`; undefined when there is none. */
|
|
9
|
+
readConfig: () => Promise<string | undefined>;
|
|
10
|
+
/** The program to run; `codex` unless a test runs another. */
|
|
11
|
+
program?: string;
|
|
12
|
+
}): HarnessDetector;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { trierarchNameSchema } from '@aeolus-fleet/common';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Detecting Codex (#365; docs/trierarch.md, "Detected options"): its own
|
|
5
|
+
* catalog, offline (`codex debug models --bundled`), gives its models. The
|
|
6
|
+
* visible ones are declared, each with `-m`; the default is the model the
|
|
7
|
+
* user's `~/.codex/config.toml` sets at its top level when it is one of them,
|
|
8
|
+
* else the catalog's first. Codex has no effort flag, so no effort is
|
|
9
|
+
* declared.
|
|
10
|
+
*/
|
|
11
|
+
const catalogSchema = z.object({ models: z.array(z.object({ slug: z.string(), visibility: z.string() })) });
|
|
12
|
+
/** The longest --version and the catalog may take: both are read offline. */
|
|
13
|
+
const QUICK_TIMEOUT_MS = 10_000;
|
|
14
|
+
/** The catalog's way of marking a model the picker shows. */
|
|
15
|
+
const VISIBLE = 'list';
|
|
16
|
+
/** The `model = "..."` of the configuration's top level, before its first table. */
|
|
17
|
+
function configuredModelOf(config) {
|
|
18
|
+
const topLevel = (config ?? '').split(/^\s*\[/m)[0] ?? '';
|
|
19
|
+
return /^\s*model\s*=\s*"([^"]+)"/m.exec(topLevel)?.[1];
|
|
20
|
+
}
|
|
21
|
+
function catalogOf(result) {
|
|
22
|
+
if (result.status !== 0) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const parsed = catalogSchema.safeParse(JSON.parse(result.stdout));
|
|
27
|
+
return parsed.success ? parsed.data : undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function createCodexDetector(deps) {
|
|
34
|
+
const program = deps.program ?? 'codex';
|
|
35
|
+
return {
|
|
36
|
+
version: async () => {
|
|
37
|
+
const result = await deps.run(program, { args: ['--version'], timeoutMs: QUICK_TIMEOUT_MS }).catch(() => undefined);
|
|
38
|
+
return result?.status === 0 ? /\S+$/.exec(result.stdout.trim())?.[0] : undefined;
|
|
39
|
+
},
|
|
40
|
+
detect: async ({ version, now }) => {
|
|
41
|
+
const catalog = catalogOf(await deps.run(program, { args: ['debug', 'models', '--bundled'], timeoutMs: QUICK_TIMEOUT_MS }));
|
|
42
|
+
const slugs = (catalog?.models ?? []).filter((model) => model.visibility === VISIBLE && trierarchNameSchema.safeParse(model.slug).success).map((model) => model.slug);
|
|
43
|
+
const [first] = slugs;
|
|
44
|
+
if (first === undefined) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const configured = configuredModelOf(await deps.readConfig());
|
|
48
|
+
const values = Object.fromEntries(slugs.map((slug) => [slug, ['-m', slug]]));
|
|
49
|
+
return { version, detectedAt: now, confirmedAt: now, options: { model: { values, default: configured !== undefined && slugs.includes(configured) ? configured : first } } };
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=codex-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-detector.js","sourceRoot":"","sources":["../../src/adapters/codex-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { trierarchNameSchema } from '@aeolus-fleet/common';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* The detected file, `~/.aeolus/trierarch/detected.json` (#365): what
|
|
7
|
+
* detection found per harness, apart from the operator's configuration, which
|
|
8
|
+
* the trierarch never writes. A file that is missing or does not fit holds
|
|
9
|
+
* nothing, so detection runs again.
|
|
10
|
+
*/
|
|
11
|
+
const optionSchema = z.strictObject({ values: z.record(trierarchNameSchema, z.array(z.string())), default: trierarchNameSchema.optional() });
|
|
12
|
+
const detectedSchema = z.record(z.string(), z.strictObject({
|
|
13
|
+
version: z.string().min(1),
|
|
14
|
+
detectedAt: z.iso.datetime(),
|
|
15
|
+
confirmedAt: z.iso.datetime().nullable(),
|
|
16
|
+
options: z.record(trierarchNameSchema, optionSchema),
|
|
17
|
+
problem: z.string().optional(),
|
|
18
|
+
}));
|
|
19
|
+
export function createDetectedFile(path) {
|
|
20
|
+
return {
|
|
21
|
+
load: async () => {
|
|
22
|
+
let json;
|
|
23
|
+
try {
|
|
24
|
+
json = JSON.parse(await readFile(path, 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
const parsed = detectedSchema.safeParse(json);
|
|
30
|
+
if (!parsed.success) {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
return Object.fromEntries(Object.entries(parsed.data).map(([harness, found]) => [
|
|
34
|
+
harness,
|
|
35
|
+
{ ...found, detectedAt: new Date(found.detectedAt), confirmedAt: found.confirmedAt === null ? null : new Date(found.confirmedAt) },
|
|
36
|
+
]));
|
|
37
|
+
},
|
|
38
|
+
save: async (detected) => {
|
|
39
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
40
|
+
await writeFile(path, `${JSON.stringify(detected, null, 2)}\n`);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=detected-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detected-file.js","sourceRoot":"","sources":["../../src/adapters/detected-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;GAKG;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAE7I,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAC7B,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,YAAY,CAAC;IACb,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;IAC5B,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,YAAY,CAAC;IACpD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CACH,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO;QACL,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,IAAI,IAAa,CAAC;YAClB,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;gBACpD,OAAO;gBACP,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;aACnI,CAAC,CACH,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,KAAK,EAAE,QAAkB,EAAE,EAAE;YACjC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7D,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAClE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { mkdtemp, readFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { createClaudeCodeDetector } from './claude-code-detector.js';
|
|
5
|
+
import { createCodexDetector } from './codex-detector.js';
|
|
6
|
+
import { runCommand } from './run-command.js';
|
|
7
|
+
/** The detector of each harness this trierarch has an adapter for (#365), running the real CLIs. */
|
|
8
|
+
export function createDetectors(at) {
|
|
9
|
+
return {
|
|
10
|
+
'claude-code': createClaudeCodeDetector({
|
|
11
|
+
run: runCommand,
|
|
12
|
+
// A new empty folder per detection: no project's hooks, settings or identity apply, so a probe is never a ship.
|
|
13
|
+
neutralFolder: () => mkdtemp(join(tmpdir(), 'aeolus-trierarch-probe-')),
|
|
14
|
+
}),
|
|
15
|
+
codex: createCodexDetector({
|
|
16
|
+
run: runCommand,
|
|
17
|
+
readConfig: () => readFile(join(at.homeDirectory, '.codex', 'config.toml'), 'utf8').catch(() => undefined),
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=detectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectors.js","sourceRoot":"","sources":["../../src/adapters/detectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,oGAAoG;AACpG,MAAM,UAAU,eAAe,CAAC,EAA6B;IAC3D,OAAO;QACL,aAAa,EAAE,wBAAwB,CAAC;YACtC,GAAG,EAAE,UAAU;YACf,gHAAgH;YAChH,aAAa,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC;SACxE,CAAC;QACF,KAAK,EAAE,mBAAmB,CAAC;YACzB,GAAG,EAAE,UAAU;YACf,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;SAC3G,CAAC;KACH,CAAC;AACJ,CAAC"}
|
package/dist/adapters/paths.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface TrierarchPaths {
|
|
|
10
10
|
readonly configSchema: string;
|
|
11
11
|
readonly crewToken: string;
|
|
12
12
|
readonly state: string;
|
|
13
|
+
/** What detection found per harness (#365), apart from the configuration. */
|
|
14
|
+
readonly detected: string;
|
|
13
15
|
readonly running: string;
|
|
14
16
|
readonly logs: string;
|
|
15
17
|
readonly worktrees: string;
|
package/dist/adapters/paths.js
CHANGED
|
@@ -7,6 +7,7 @@ export function trierarchPaths(at) {
|
|
|
7
7
|
configSchema: join(home, 'config.schema.json'),
|
|
8
8
|
crewToken: join(home, 'crew-token'),
|
|
9
9
|
state: join(home, 'state.json'),
|
|
10
|
+
detected: join(home, 'detected.json'),
|
|
10
11
|
running: join(home, 'running.json'),
|
|
11
12
|
logs: join(home, 'logs'),
|
|
12
13
|
worktrees: join(home, 'worktrees'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/adapters/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/adapters/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqBjC,MAAM,UAAU,cAAc,CAAC,EAA8C;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QAC9C,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC;QAC9C,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QACnC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC;QACrC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -4,10 +4,15 @@ export interface CommandResult {
|
|
|
4
4
|
readonly stdout: string;
|
|
5
5
|
readonly stderr: string;
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Runs a program with its arguments and optional input, no shell, and answers
|
|
9
|
+
* how it ended rather than throwing on a non-zero exit. One that runs past
|
|
10
|
+
* `timeoutMs` is ended and answers as failed.
|
|
11
|
+
*/
|
|
8
12
|
export declare function runCommand(command: string, options: {
|
|
9
13
|
args: readonly string[];
|
|
10
14
|
env?: Readonly<Record<string, string>>;
|
|
11
15
|
cwd?: string;
|
|
12
16
|
input?: string;
|
|
17
|
+
timeoutMs?: number;
|
|
13
18
|
}): Promise<CommandResult>;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Runs a program with its arguments and optional input, no shell, and answers
|
|
4
|
+
* how it ended rather than throwing on a non-zero exit. One that runs past
|
|
5
|
+
* `timeoutMs` is ended and answers as failed.
|
|
6
|
+
*/
|
|
3
7
|
export function runCommand(command, options) {
|
|
4
8
|
return new Promise((resolve, reject) => {
|
|
5
9
|
const { input } = options;
|
|
6
10
|
// Stdin only when there is input: a program that exits without reading it would otherwise race the write (EPIPE).
|
|
7
|
-
const child = spawn(command, [...options.args], { env: { ...process.env, ...options.env }, cwd: options.cwd, stdio: [input === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe'] });
|
|
11
|
+
const child = spawn(command, [...options.args], { env: { ...process.env, ...options.env }, cwd: options.cwd, stdio: [input === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe'], ...(options.timeoutMs !== undefined && { timeout: options.timeoutMs }) });
|
|
8
12
|
if (input !== undefined) {
|
|
9
13
|
// A program may exit before it reads all its input; how it ended is the answer either way.
|
|
10
14
|
child.stdin?.on('error', () => undefined);
|
|
@@ -19,6 +23,14 @@ export function runCommand(command, options) {
|
|
|
19
23
|
stderr += chunk.toString('utf8');
|
|
20
24
|
});
|
|
21
25
|
child.on('error', reject);
|
|
26
|
+
// Ended at its time limit: answer now, as a child it forked may hold its output open long after.
|
|
27
|
+
child.on('exit', (code, signal) => {
|
|
28
|
+
if (signal !== null) {
|
|
29
|
+
child.stdout?.destroy();
|
|
30
|
+
child.stderr?.destroy();
|
|
31
|
+
resolve({ status: code ?? 1, stdout, stderr });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
22
34
|
child.on('close', (code) => {
|
|
23
35
|
resolve({ status: code ?? 1, stdout, stderr });
|
|
24
36
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../src/adapters/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAS3C
|
|
1
|
+
{"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../src/adapters/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAS3C;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,OAA8H;IACxK,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;QAC1B,kHAAkH;QAClH,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QACzP,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,2FAA2F;YAC3F,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC1C,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,iGAAiG;QACjG,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAChC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;gBACxB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;gBACxB,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/cli/config-check.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { describeCommandLine } from '../adapters/command-line.js';
|
|
2
|
+
import { createDetectedFile } from '../adapters/detected-file.js';
|
|
2
3
|
import { loadConfiguration } from '../adapters/files.js';
|
|
3
4
|
import { describeFlags, effectiveFlags } from '../adapters/flags.js';
|
|
4
5
|
import { adapterFlagsOf, commandLinesOf } from '../adapters/harnesses.js';
|
|
6
|
+
import { withDetectedOptions } from '../core/detected-options.js';
|
|
5
7
|
export async function configCheck(paths) {
|
|
6
|
-
|
|
8
|
+
// The detected options too (#365), as the running trierarch has them.
|
|
9
|
+
const configuration = withDetectedOptions(await loadConfiguration(paths.config), await createDetectedFile(paths.detected).load());
|
|
7
10
|
const adapterFlags = adapterFlagsOf(configuration);
|
|
8
11
|
const harnesses = Object.fromEntries(Object.entries(configuration.harnesses).map(([name, harness]) => {
|
|
9
12
|
const flags = effectiveFlags(harness, {});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-check.js","sourceRoot":"","sources":["../../src/cli/config-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAoB,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"config-check.js","sourceRoot":"","sources":["../../src/cli/config-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAoB,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AA2BlE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAqB;IACrD,sEAAsE;IACtE,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAClI,MAAM,YAAY,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAClC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE;QAC9D,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1C,OAAO;YACL,IAAI;YACJ;gBACE,KAAK;gBACL,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;gBACnH,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;gBACtC,GAAG,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC;aAC/B;SACF,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CACjE,OAAO,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAC/D,CAAC,CAAC,GAAG,IAAI,wCAAwC;QACjD,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,cAAc,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC/I,CAAC;IACF,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,MAAM;QAClB,SAAS;QACT,IAAI,EAAE;YACJ,wBAAwB,KAAK,CAAC,MAAM,QAAQ;YAC5C,0DAA0D;YAC1D,aAAa,CAAC,aAAa,CAAC;YAC5B,EAAE;YACF,uDAAuD;YACvD,GAAG,QAAQ;SACZ,CAAC,IAAI,CAAC,IAAI,CAAC;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TrierarchConfiguration } from '@aeolus-fleet/common';
|
|
2
|
+
import type { DetectHarnesses } from '../core/detect-harnesses.js';
|
|
3
|
+
import type { Detected } from '../core/ports.js';
|
|
4
|
+
/** What `aeolus-trierarch detect` found, per harness: its version, when its models were last confirmed, and each option's value names. */
|
|
5
|
+
export interface DetectReport {
|
|
6
|
+
readonly harnesses: Readonly<Record<string, {
|
|
7
|
+
version: string;
|
|
8
|
+
confirmedAt: string | null;
|
|
9
|
+
options: Readonly<Record<string, readonly string[]>>;
|
|
10
|
+
}>>;
|
|
11
|
+
readonly text: string;
|
|
12
|
+
}
|
|
13
|
+
/** Per harness, one line: its version, each option with its values and default, and when its models were last confirmed. */
|
|
14
|
+
export declare function describeDetected(at: {
|
|
15
|
+
harnesses: readonly string[];
|
|
16
|
+
detected: Detected;
|
|
17
|
+
}): string;
|
|
18
|
+
/**
|
|
19
|
+
* `aeolus-trierarch detect` (#365): detects every configured harness again,
|
|
20
|
+
* though its version is the one detected, and gives what it found. A running
|
|
21
|
+
* trierarch reads it at its next start.
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectOptions(at: {
|
|
24
|
+
configuration: TrierarchConfiguration;
|
|
25
|
+
detect: DetectHarnesses;
|
|
26
|
+
}): Promise<DetectReport>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Per harness, one line: its version, each option with its values and default, and when its models were last confirmed. */
|
|
2
|
+
export function describeDetected(at) {
|
|
3
|
+
return at.harnesses
|
|
4
|
+
.map((name) => {
|
|
5
|
+
const found = at.detected[name];
|
|
6
|
+
if (found === undefined) {
|
|
7
|
+
return `${name}: nothing detected`;
|
|
8
|
+
}
|
|
9
|
+
const options = Object.entries(found.options).map(([option, settings]) => `${option} ${Object.keys(settings.values).map((value) => (value === settings.default ? `${value} (default)` : value)).join(', ')}`);
|
|
10
|
+
const confirmed = found.confirmedAt === null ? 'no model confirmed' : `models confirmed ${found.confirmedAt.toISOString()}`;
|
|
11
|
+
return `${name} ${found.version}: ${options.length === 0 ? 'no options detected' : options.join('; ')}; ${confirmed}`;
|
|
12
|
+
})
|
|
13
|
+
.join('\n');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `aeolus-trierarch detect` (#365): detects every configured harness again,
|
|
17
|
+
* though its version is the one detected, and gives what it found. A running
|
|
18
|
+
* trierarch reads it at its next start.
|
|
19
|
+
*/
|
|
20
|
+
export async function detectOptions(at) {
|
|
21
|
+
const harnesses = Object.keys(at.configuration.harnesses);
|
|
22
|
+
const detected = await at.detect({ harnesses, isForced: true });
|
|
23
|
+
return {
|
|
24
|
+
harnesses: Object.fromEntries(Object.entries(detected).flatMap(([name, found]) => found === undefined
|
|
25
|
+
? []
|
|
26
|
+
: [[name, { version: found.version, confirmedAt: found.confirmedAt?.toISOString() ?? null, options: Object.fromEntries(Object.entries(found.options).map(([option, settings]) => [option, Object.keys(settings.values)])) }]])),
|
|
27
|
+
text: describeDetected({ harnesses, detected }),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/cli/detect.ts"],"names":[],"mappings":"AAWA,4HAA4H;AAC5H,MAAM,UAAU,gBAAgB,CAAC,EAAwD;IACvF,OAAO,EAAE,CAAC,SAAS;SAChB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,GAAG,IAAI,oBAAoB,CAAC;QACrC,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAC/C,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3J,CAAC;QACF,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,oBAAoB,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC;QAC5H,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;IACxH,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAsE;IACxG,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,WAAW,CAC3B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CACjD,KAAK,KAAK,SAAS;YACjB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAChO,CACF;QACD,IAAI,EAAE,gBAAgB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
package/dist/cli/init.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { CodexSetup } from '../adapters/codex-setup.js';
|
|
|
4
4
|
import type { TrierarchPaths } from '../adapters/paths.js';
|
|
5
5
|
import type { RestFleet } from '../adapters/rest-fleet.js';
|
|
6
6
|
import type { Service } from '../adapters/service.js';
|
|
7
|
+
import type { DetectHarnesses } from '../core/detect-harnesses.js';
|
|
7
8
|
import type { Prompter } from './prompter.js';
|
|
8
9
|
/**
|
|
9
10
|
* `aeolus-trierarch init`: the whole setup of a machine, asking for what is
|
|
@@ -47,5 +48,7 @@ export declare function initTrierarch(input: {
|
|
|
47
48
|
codex: CodexSetup;
|
|
48
49
|
/** Whether `codex` runs on this machine: only then, or when Codex is configured, does init ask about it. */
|
|
49
50
|
isCodexInstalled: boolean;
|
|
51
|
+
/** Detects the configured harnesses' options (#365), once per harness version. */
|
|
52
|
+
detect: DetectHarnesses;
|
|
50
53
|
service: Pick<Service, 'install' | 'restart' | 'status'>;
|
|
51
54
|
}): Promise<InitReport>;
|
package/dist/cli/init.js
CHANGED
|
@@ -2,6 +2,7 @@ import { mkdir, stat, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
3
3
|
import { idSchema, trierarchNameSchema } from '@aeolus-fleet/common';
|
|
4
4
|
import { configurationJsonSchema, initialConfiguration, loadConfiguration, readCrewFile, TrierarchFileError, writeCrewFile } from '../adapters/files.js';
|
|
5
|
+
import { describeDetected } from './detect.js';
|
|
5
6
|
const CLAUDE_CODE = 'claude-code';
|
|
6
7
|
const SKIP_PERMISSIONS = '--dangerously-skip-permissions';
|
|
7
8
|
const REMOTE_CONTROL = '--remote-control';
|
|
@@ -245,6 +246,9 @@ export async function initTrierarch(input) {
|
|
|
245
246
|
}
|
|
246
247
|
const codex = await setUpCodex({ configuration, codex: input.codex, root });
|
|
247
248
|
said.push(...codex.said);
|
|
249
|
+
// What each harness offers, detected on this machine and kept apart from the configuration (#365).
|
|
250
|
+
const harnesses = Object.keys(configuration.harnesses);
|
|
251
|
+
said.push(...describeDetected({ harnesses, detected: await input.detect({ harnesses, isForced: false }) }).split('\n'));
|
|
248
252
|
// The service: offered when it is not installed, restarted when it should read a new configuration.
|
|
249
253
|
prompter.step('The service');
|
|
250
254
|
let serviced = 'unchanged';
|