@aeolus-fleet/trierarch 0.22.0 → 0.24.0
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 +3 -3
- package/dist/adapters/capped-log.d.ts +23 -0
- package/dist/adapters/capped-log.js +74 -0
- package/dist/adapters/capped-log.js.map +1 -0
- package/dist/adapters/claude-code-screen.d.ts +1 -5
- package/dist/adapters/claude-code-screen.js +8 -13
- package/dist/adapters/claude-code-screen.js.map +1 -1
- package/dist/adapters/claude-code.d.ts +2 -0
- package/dist/adapters/claude-code.js +22 -4
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex-plugin-data.d.ts +11 -0
- package/dist/adapters/codex-plugin-data.js +44 -0
- package/dist/adapters/codex-plugin-data.js.map +1 -0
- package/dist/adapters/codex-screen.d.ts +1 -7
- package/dist/adapters/codex-screen.js +9 -13
- package/dist/adapters/codex-screen.js.map +1 -1
- package/dist/adapters/codex-session-log.d.ts +8 -0
- package/dist/adapters/codex-session-log.js +45 -0
- package/dist/adapters/codex-session-log.js.map +1 -0
- package/dist/adapters/codex.js +33 -5
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/json-state.js +2 -0
- package/dist/adapters/json-state.js.map +1 -1
- package/dist/adapters/launch-marker.d.ts +33 -0
- package/dist/adapters/launch-marker.js +39 -0
- package/dist/adapters/launch-marker.js.map +1 -0
- package/dist/adapters/launch-screen.d.ts +7 -17
- package/dist/adapters/launch-screen.js +3 -18
- package/dist/adapters/launch-screen.js.map +1 -1
- package/dist/adapters/plugin-identity.d.ts +15 -2
- package/dist/adapters/plugin-identity.js +8 -2
- package/dist/adapters/plugin-identity.js.map +1 -1
- package/dist/adapters/plugin-update.d.ts +41 -0
- package/dist/adapters/plugin-update.js +141 -0
- package/dist/adapters/plugin-update.js.map +1 -0
- package/dist/adapters/plugin.d.ts +8 -1
- package/dist/adapters/plugin.js +14 -6
- package/dist/adapters/plugin.js.map +1 -1
- package/dist/adapters/running-processes.d.ts +10 -0
- package/dist/adapters/running-processes.js +28 -0
- package/dist/adapters/running-processes.js.map +1 -0
- package/dist/adapters/tmux.d.ts +2 -1
- package/dist/adapters/tmux.js +3 -2
- package/dist/adapters/tmux.js.map +1 -1
- package/dist/cli/main.js +27 -9
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/run.js +2 -1
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/upgrade.d.ts +34 -1
- package/dist/cli/upgrade.js +105 -6
- package/dist/cli/upgrade.js.map +1 -1
- package/dist/core/check-settings.d.ts +10 -0
- package/dist/core/check-settings.js +9 -1
- package/dist/core/check-settings.js.map +1 -1
- package/dist/core/entry.d.ts +4 -0
- package/dist/core/entry.js.map +1 -1
- package/dist/core/ports.d.ts +12 -12
- package/dist/core/reconciler.d.ts +8 -7
- package/dist/core/reconciler.js +39 -30
- package/dist/core/reconciler.js.map +1 -1
- package/dist/core/run-pass.d.ts +2 -0
- package/dist/core/run-pass.js +40 -25
- package/dist/core/run-pass.js.map +1 -1
- package/package.json +11 -4
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AeolusPlugin } from './plugin-identity.js';
|
|
2
|
+
/**
|
|
3
|
+
* The launch marker the aeolus plugin's hooks keep for a session the
|
|
4
|
+
* trierarch started with a launch id (#490), read and cleared through the
|
|
5
|
+
* plugin's own `aeolus-identity.sh launch`, never a copy of how the plugin
|
|
6
|
+
* names its files. Its first line is the launch id, then one line per event
|
|
7
|
+
* with when: `started` with the transcript, `active`, and `refused` with the
|
|
8
|
+
* model id the refusal names when it names one.
|
|
9
|
+
*/
|
|
10
|
+
export interface LaunchMarker {
|
|
11
|
+
readonly isStarted: boolean;
|
|
12
|
+
/** The transcript the harness keeps of the session, as its session start named it; for Codex its session log. */
|
|
13
|
+
readonly transcript?: string;
|
|
14
|
+
readonly isActive: boolean;
|
|
15
|
+
/** Set once a turn failed because the model was not found, with the model's id when the refusal named it. */
|
|
16
|
+
readonly refused?: {
|
|
17
|
+
readonly model?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** What the marker text says of the launch given; none when it is of another launch. */
|
|
21
|
+
export declare function launchMarkerOf(text: string, launchId: string): LaunchMarker | undefined;
|
|
22
|
+
export interface LaunchMarks {
|
|
23
|
+
/** Forgets the folder's marker, before a session is started for a new launch. */
|
|
24
|
+
clear(folder: string): Promise<void>;
|
|
25
|
+
/** What the folder's marker says of the launch given; none before the hooks marked anything of it. */
|
|
26
|
+
read(at: {
|
|
27
|
+
folder: string;
|
|
28
|
+
launchId: string;
|
|
29
|
+
}): Promise<LaunchMarker | undefined>;
|
|
30
|
+
/** Whether the plugin keeps launch markers: one older than them answers `launch` with its usage. */
|
|
31
|
+
isMarking(): Promise<boolean>;
|
|
32
|
+
}
|
|
33
|
+
export declare function createLaunchMarks(plugin: AeolusPlugin): LaunchMarks;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { runIdentity } from './plugin-identity.js';
|
|
2
|
+
/** The exit of a plugin script that does not know the command it was given, as an aeolus plugin older than the launch marker answers `launch`. */
|
|
3
|
+
const USAGE_EXIT = 2;
|
|
4
|
+
/** What the marker text says of the launch given; none when it is of another launch. */
|
|
5
|
+
export function launchMarkerOf(text, launchId) {
|
|
6
|
+
const [first, ...events] = text.split('\n');
|
|
7
|
+
if (first !== `launch ${launchId}`) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const event = (name) => events.find((line) => line.startsWith(`${name} `))?.split(' ');
|
|
11
|
+
const started = event('started');
|
|
12
|
+
// Everything after when, as a path may hold spaces.
|
|
13
|
+
const transcript = started?.slice(2).join(' ');
|
|
14
|
+
const refused = event('refused');
|
|
15
|
+
const model = refused?.[2];
|
|
16
|
+
return {
|
|
17
|
+
isStarted: started !== undefined,
|
|
18
|
+
...(transcript !== undefined && transcript !== '' && { transcript }),
|
|
19
|
+
isActive: event('active') !== undefined,
|
|
20
|
+
...(refused !== undefined && { refused: model === undefined || model === '' ? {} : { model } }),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function createLaunchMarks(plugin) {
|
|
24
|
+
return {
|
|
25
|
+
clear: async (folder) => {
|
|
26
|
+
const cleared = await runIdentity(plugin, { folder, args: ['launch', 'clear'] });
|
|
27
|
+
if (cleared.status !== 0) {
|
|
28
|
+
throw new Error(`aeolus-identity.sh launch clear failed: ${cleared.stderr.trim()}`);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
read: async ({ folder, launchId }) => {
|
|
32
|
+
const marker = await runIdentity(plugin, { folder, args: ['launch'] });
|
|
33
|
+
return marker.status === 0 ? launchMarkerOf(marker.stdout, launchId) : undefined;
|
|
34
|
+
},
|
|
35
|
+
// Asked for the crews folder itself, which no session crews, so the answer is only whether the command is known.
|
|
36
|
+
isMarking: async () => (await runIdentity(plugin, { folder: plugin.crews, args: ['launch'] })).status !== USAGE_EXIT,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=launch-marker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch-marker.js","sourceRoot":"","sources":["../../src/adapters/launch-marker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAmBnD,kJAAkJ;AAClJ,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,wFAAwF;AACxF,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,QAAgB;IAC3D,MAAM,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,KAAK,KAAK,UAAU,QAAQ,EAAE,EAAE,CAAC;QACnC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACjC,oDAAoD;IACpD,MAAM,UAAU,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO;QACL,SAAS,EAAE,OAAO,KAAK,SAAS;QAChC,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QACpE,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,SAAS;QACvC,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;KAChG,CAAC;AACJ,CAAC;AAWD,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,OAAO;QACL,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACtB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YACjF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACtF,CAAC;QACH,CAAC;QACD,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;YACnC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACvE,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACnF,CAAC;QACD,iHAAiH;QACjH,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU;KACrH,CAAC;AACJ,CAAC"}
|
|
@@ -1,24 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The texts a harness writes to its screen in a session's launch window, each
|
|
3
|
+
* adapter its own. Since the launch marker (#490), the screen is read only for
|
|
4
|
+
* what no hook sees: a screen that stops the session before its hooks run.
|
|
5
|
+
*/
|
|
3
6
|
export interface LaunchTexts {
|
|
4
|
-
/** A line that shows a tool call, done or under way. */
|
|
5
|
-
readonly activity: RegExp;
|
|
6
|
-
/** The refusal of a model, with the id it refused as its first group; global, so every refusal is seen. */
|
|
7
|
-
readonly refused: RegExp;
|
|
8
7
|
/** The harness's screens a session can stop at before its first prompt runs (#403), each by its name and a text only it shows. */
|
|
9
8
|
readonly screens: readonly {
|
|
10
9
|
readonly name: string;
|
|
11
10
|
readonly text: RegExp;
|
|
12
11
|
}[];
|
|
13
12
|
}
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
* launched with (or any, when it launched with none, so the CLI's own
|
|
17
|
-
* default); else activity when a tool line shows; else none, naming the
|
|
18
|
-
* known screen it stopped at when one shows. A refusal of another id is only
|
|
19
|
-
* text, as when a ship discusses one.
|
|
20
|
-
*/
|
|
21
|
-
export declare function launchSeenWith(texts: LaunchTexts, at: {
|
|
22
|
-
screen: string;
|
|
23
|
-
model?: string;
|
|
24
|
-
}): LaunchSeen;
|
|
13
|
+
/** The known screen the session stopped at, by its name; none when the screen shows none of them. */
|
|
14
|
+
export declare function screenStoppedAt(texts: LaunchTexts, screen: string): string | undefined;
|
|
@@ -1,20 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* default); else activity when a tool line shows; else none, naming the
|
|
5
|
-
* known screen it stopped at when one shows. A refusal of another id is only
|
|
6
|
-
* text, as when a ship discusses one.
|
|
7
|
-
*/
|
|
8
|
-
export function launchSeenWith(texts, at) {
|
|
9
|
-
for (const [, id] of at.screen.matchAll(texts.refused)) {
|
|
10
|
-
if (id !== undefined && (at.model === undefined || id === at.model)) {
|
|
11
|
-
return { kind: 'refused', model: id };
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
if (texts.activity.test(at.screen)) {
|
|
15
|
-
return { kind: 'active' };
|
|
16
|
-
}
|
|
17
|
-
const stopped = texts.screens.find((screen) => screen.text.test(at.screen));
|
|
18
|
-
return stopped === undefined ? { kind: 'none' } : { kind: 'none', screen: stopped.name };
|
|
1
|
+
/** The known screen the session stopped at, by its name; none when the screen shows none of them. */
|
|
2
|
+
export function screenStoppedAt(texts, screen) {
|
|
3
|
+
return texts.screens.find((each) => each.text.test(screen))?.name;
|
|
19
4
|
}
|
|
20
5
|
//# sourceMappingURL=launch-screen.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launch-screen.js","sourceRoot":"","sources":["../../src/adapters/launch-screen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"launch-screen.js","sourceRoot":"","sources":["../../src/adapters/launch-screen.ts"],"names":[],"mappings":"AAUA,qGAAqG;AACrG,MAAM,UAAU,eAAe,CAAC,KAAkB,EAAE,MAAc;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC;AACpE,CAAC"}
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import type { HarnessPort } from '../core/ports.js';
|
|
2
|
-
/** The aeolus plugin as a harness installed it: its scripts and its
|
|
2
|
+
/** The aeolus plugin as a harness installed it: its scripts, its data folder, and where its sessions' identities live. */
|
|
3
3
|
export interface AeolusPlugin {
|
|
4
4
|
readonly root: string;
|
|
5
5
|
readonly data: string;
|
|
6
|
+
/** ~/.aeolus/crews/<harness> (#658). */
|
|
7
|
+
readonly crews: string;
|
|
6
8
|
}
|
|
9
|
+
/** Runs the plugin's own `aeolus-identity.sh` for the folder, with the plugin's data and crews folders. */
|
|
10
|
+
export declare function runIdentity(plugin: AeolusPlugin, at: {
|
|
11
|
+
folder: string;
|
|
12
|
+
args: readonly string[];
|
|
13
|
+
}): Promise<{
|
|
14
|
+
status: number;
|
|
15
|
+
stdout: string;
|
|
16
|
+
stderr: string;
|
|
17
|
+
}>;
|
|
7
18
|
/**
|
|
8
19
|
* A session's identity and turn, through the aeolus plugin's own
|
|
9
20
|
* `aeolus-identity.sh`, never a copy of how the plugin names its files. The
|
|
10
|
-
* same for every harness; each keeps them in
|
|
21
|
+
* same for every harness; each keeps them in a crews folder of its own. The
|
|
22
|
+
* data folder goes along, so the script moves an identity an older plugin
|
|
23
|
+
* kept there.
|
|
11
24
|
*/
|
|
12
25
|
export declare function createPluginIdentity(plugin: AeolusPlugin): Pick<HarnessPort, 'prepareIdentity' | 'crewTokenOf' | 'removeIdentity' | 'turnOf'>;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { runCommand } from './run-command.js';
|
|
3
|
+
/** Runs the plugin's own `aeolus-identity.sh` for the folder, with the plugin's data and crews folders. */
|
|
4
|
+
export function runIdentity(plugin, at) {
|
|
5
|
+
return runCommand('bash', { args: [`${plugin.root}/scripts/aeolus-identity.sh`, ...at.args], env: { AEOLUS_FOLDER: at.folder, AEOLUS_DATA: plugin.data, AEOLUS_CREWS: plugin.crews } });
|
|
6
|
+
}
|
|
3
7
|
/**
|
|
4
8
|
* A session's identity and turn, through the aeolus plugin's own
|
|
5
9
|
* `aeolus-identity.sh`, never a copy of how the plugin names its files. The
|
|
6
|
-
* same for every harness; each keeps them in
|
|
10
|
+
* same for every harness; each keeps them in a crews folder of its own. The
|
|
11
|
+
* data folder goes along, so the script moves an identity an older plugin
|
|
12
|
+
* kept there.
|
|
7
13
|
*/
|
|
8
14
|
export function createPluginIdentity(plugin) {
|
|
9
|
-
const identity =
|
|
15
|
+
const identity = (folder, args) => runIdentity(plugin, { folder, args });
|
|
10
16
|
return {
|
|
11
17
|
prepareIdentity: async ({ folder, identity: crew }) => {
|
|
12
18
|
const written = await identity(folder, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-identity.js","sourceRoot":"","sources":["../../src/adapters/plugin-identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-identity.js","sourceRoot":"","sources":["../../src/adapters/plugin-identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAU9C,2GAA2G;AAC3G,MAAM,UAAU,WAAW,CAAC,MAAoB,EAAE,EAA+C;IAC/F,OAAO,UAAU,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,6BAA6B,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC1L,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAoB;IACvD,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,IAAuB,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpG,OAAO;QACL,eAAe,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;YACpD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE;gBACrC,OAAO;gBACP,WAAW;gBACX,WAAW;gBACX,IAAI,CAAC,QAAQ;gBACb,IAAI,CAAC,MAAM;gBACX,IAAI,CAAC,QAAQ;gBACb,IAAI,CAAC,SAAS;gBACd,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aACxD,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/E,CAAC;QACH,CAAC;QACD,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC5B,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1D,OAAO,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC/B,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrC,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAiB,EAAE;YACtC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACzF,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type PluginHarness } from './plugin.js';
|
|
2
|
+
import { type RunningProcess } from './running-processes.js';
|
|
3
|
+
/**
|
|
4
|
+
* The aeolus plugin updated through each harness's own command (#581), from
|
|
5
|
+
* the release tag it is given, or main without one (#652): each harness's
|
|
6
|
+
* aeolus-fleet marketplace is pointed at it first. Neither harness adds a
|
|
7
|
+
* second source for a marketplace. Codex's is removed and added again, which
|
|
8
|
+
* keeps the plugin and its cache, once a throwaway Codex home proves this
|
|
9
|
+
* Codex keeps the plugin's data, its log and the crew identities not yet
|
|
10
|
+
* moved to ~/.aeolus/crews, when it is removed (#660); the upgrade changes
|
|
11
|
+
* nothing otherwise. Claude Code's is never removed, since that uninstalls the
|
|
12
|
+
* plugin and deletes its data, with its log and those identities: the
|
|
13
|
+
* marketplace its settings declare is dropped from them, and adding it again
|
|
14
|
+
* declares the new source.
|
|
15
|
+
* Codex's plugin upgrade installs the new version and deletes every other
|
|
16
|
+
* version folder, so a Codex session still running on the old version would
|
|
17
|
+
* lose its plugin scripts: the version folders there before are kept aside and
|
|
18
|
+
* put back beside the new one, also when the upgrade fails. After an upgrade
|
|
19
|
+
* that succeeded, a version folder no running session can use is removed
|
|
20
|
+
* (#653): a session uses the newest version there was when it started, so a
|
|
21
|
+
* version is left behind once its next version came before every running
|
|
22
|
+
* Codex process, and the trierarch, started. A version counts from when the
|
|
23
|
+
* upgrade installed it. Claude Code keeps old versions beside the new one
|
|
24
|
+
* itself.
|
|
25
|
+
*/
|
|
26
|
+
export interface PluginUpdate {
|
|
27
|
+
/** `tag`: the release tag to install the plugin from; none installs it from main. */
|
|
28
|
+
update(harness: PluginHarness, tag: string | undefined): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export declare function createPluginUpdate(at: {
|
|
31
|
+
homeDirectory: string;
|
|
32
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
33
|
+
/** The programs to run; `codex` and `claude` unless a test runs others. */
|
|
34
|
+
commands?: Partial<Record<PluginHarness, string>>;
|
|
35
|
+
/** The clock; a test passes its own. */
|
|
36
|
+
now?: () => Date;
|
|
37
|
+
/** The processes running on this machine now; ps unless a test says them. */
|
|
38
|
+
processes?: (now: Date) => Promise<readonly RunningProcess[]>;
|
|
39
|
+
/** The running trierarch's pid, none when none runs: it took its plugin scripts from the newest version when it started. */
|
|
40
|
+
trierarchPid: () => Promise<number | undefined>;
|
|
41
|
+
}): PluginUpdate;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { cp, mkdtemp, readdir, readFile, rename, rm, stat, utimes, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { codexKeepsPluginData } from './codex-plugin-data.js';
|
|
6
|
+
import { byVersion } from './plugin.js';
|
|
7
|
+
import { runCommand } from './run-command.js';
|
|
8
|
+
import { runningProcesses } from './running-processes.js';
|
|
9
|
+
const MARKETPLACE = 'aeolus-fleet';
|
|
10
|
+
const REPOSITORY = 'ThomasHendrickx/aeolus-fleet';
|
|
11
|
+
const PLUGIN = 'aeolus@aeolus-fleet';
|
|
12
|
+
async function run(command, args) {
|
|
13
|
+
const result = await runCommand(command, { args });
|
|
14
|
+
if (result.status !== 0) {
|
|
15
|
+
throw new Error(`${[command, ...args].join(' ')} failed: ${`${result.stdout}${result.stderr}`.trim()}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const settingsSchema = z.record(z.string(), z.unknown());
|
|
19
|
+
const marketplacesSchema = z.record(z.string(), z.unknown());
|
|
20
|
+
/** Drops the aeolus-fleet marketplace from the `extraKnownMarketplaces` of Claude Code's settings, leaving everything else as it is. */
|
|
21
|
+
async function dropDeclaredMarketplace(path) {
|
|
22
|
+
const text = await readFile(path, 'utf8').catch(() => undefined);
|
|
23
|
+
if (text === undefined) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const settings = settingsSchema.parse(JSON.parse(text));
|
|
27
|
+
const declared = marketplacesSchema.safeParse(settings.extraKnownMarketplaces).data;
|
|
28
|
+
if (declared?.[MARKETPLACE] === undefined) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const others = Object.fromEntries(Object.entries(declared).filter(([name]) => name !== MARKETPLACE));
|
|
32
|
+
const temporary = `${path}.aeolus-trierarch.tmp`;
|
|
33
|
+
await writeFile(temporary, `${JSON.stringify({ ...settings, extraKnownMarketplaces: others }, null, 2)}\n`, { mode: (await stat(path)).mode & 0o777 });
|
|
34
|
+
await rename(temporary, path);
|
|
35
|
+
}
|
|
36
|
+
/** The folders under `cache`, none where it does not exist. */
|
|
37
|
+
async function versionFolders(cache) {
|
|
38
|
+
const names = await readdir(cache).catch(() => []);
|
|
39
|
+
const folders = [];
|
|
40
|
+
for (const name of names) {
|
|
41
|
+
if ((await stat(join(cache, name))).isDirectory()) {
|
|
42
|
+
folders.push(name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return folders;
|
|
46
|
+
}
|
|
47
|
+
/** ps says elapsed time in whole seconds, and a session takes a moment to read its plugin: a start this close after a version came may still have found the one before. */
|
|
48
|
+
const START_MARGIN_MS = 60 * 1000;
|
|
49
|
+
const VERSION = /^\d+\.\d+\.\d+$/;
|
|
50
|
+
/** Marks each version folder the upgrade installed with the time it did, whatever times Codex gave its files. */
|
|
51
|
+
async function markInstalled(cache, at) {
|
|
52
|
+
for (const version of await versionFolders(cache)) {
|
|
53
|
+
if (!at.before.includes(version)) {
|
|
54
|
+
await utimes(join(cache, version), at.now, at.now);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Removes each version folder whose next version came before the earliest start, every older one when nothing runs. */
|
|
59
|
+
async function removeUnused(cache, earliestStart) {
|
|
60
|
+
const versions = (await versionFolders(cache)).filter((name) => VERSION.test(name)).sort(byVersion);
|
|
61
|
+
for (const [index, version] of versions.entries()) {
|
|
62
|
+
const next = versions[index + 1];
|
|
63
|
+
if (next === undefined) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const nextCame = (await stat(join(cache, next))).mtime.getTime();
|
|
67
|
+
if (earliestStart === undefined || earliestStart.getTime() >= nextCame + START_MARGIN_MS) {
|
|
68
|
+
await rm(join(cache, version), { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** The earliest start of a process that may use a Codex plugin version: a Codex one, or the trierarch. */
|
|
73
|
+
function earliestStartOf(processes, trierarchPid) {
|
|
74
|
+
const users = processes.filter((process) => basename(process.program) === 'codex' || process.pid === trierarchPid);
|
|
75
|
+
return users.map((process) => process.startedAt).reduce((earliest, startedAt) => (earliest === undefined || startedAt < earliest ? startedAt : earliest), undefined);
|
|
76
|
+
}
|
|
77
|
+
/** Runs `upgrade` with every version folder in `cache` kept aside, and puts back each one it deleted; then removes the unused ones. */
|
|
78
|
+
async function keepingVersions(cache, at) {
|
|
79
|
+
const versions = await versionFolders(cache);
|
|
80
|
+
const times = new Map(await Promise.all(versions.map(async (version) => [version, await stat(join(cache, version))])));
|
|
81
|
+
const aside = await mkdtemp(join(tmpdir(), 'aeolus-plugin-versions-'));
|
|
82
|
+
try {
|
|
83
|
+
for (const version of versions) {
|
|
84
|
+
await cp(join(cache, version), join(aside, version), { recursive: true, preserveTimestamps: true });
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
await at.upgrade();
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
const left = new Set(await versionFolders(cache));
|
|
91
|
+
for (const version of versions.filter((name) => !left.has(name))) {
|
|
92
|
+
await cp(join(aside, version), join(cache, version), { recursive: true, preserveTimestamps: true });
|
|
93
|
+
// cp keeps the times of files, not of folders: the folder's time says when its version came.
|
|
94
|
+
const time = times.get(version);
|
|
95
|
+
if (time !== undefined) {
|
|
96
|
+
await utimes(join(cache, version), time.atime, time.mtime);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
await at.afterUpgrade(versions);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
await rm(aside, { recursive: true, force: true });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function createPluginUpdate(at) {
|
|
107
|
+
const now = at.now ?? (() => new Date());
|
|
108
|
+
const processes = at.processes ?? runningProcesses;
|
|
109
|
+
const codex = at.commands?.codex ?? 'codex';
|
|
110
|
+
const claude = at.commands?.['claude-code'] ?? 'claude';
|
|
111
|
+
const claudeSettings = join(at.env.CLAUDE_CONFIG_DIR ?? join(at.homeDirectory, '.claude'), 'settings.json');
|
|
112
|
+
const codexCache = join(at.env.CODEX_HOME ?? join(at.homeDirectory, '.codex'), 'plugins', 'cache', MARKETPLACE, 'aeolus');
|
|
113
|
+
return {
|
|
114
|
+
update: async (harness, tag) => {
|
|
115
|
+
if (harness === 'codex') {
|
|
116
|
+
if (!(await codexKeepsPluginData(codex))) {
|
|
117
|
+
throw new Error(`Codex would delete the aeolus plugin's data on this machine, its log and the crew identities not yet moved to ~/.aeolus/crews, when its ${MARKETPLACE} marketplace is removed: the upgrade leaves the marketplace as it is`);
|
|
118
|
+
}
|
|
119
|
+
await keepingVersions(codexCache, {
|
|
120
|
+
upgrade: async () => {
|
|
121
|
+
// There may be no marketplace to remove: adding it says what is wrong.
|
|
122
|
+
await runCommand(codex, { args: ['plugin', 'marketplace', 'remove', MARKETPLACE] });
|
|
123
|
+
await run(codex, ['plugin', 'marketplace', 'add', REPOSITORY, ...(tag === undefined ? [] : ['--ref', tag])]);
|
|
124
|
+
await run(codex, ['plugin', 'marketplace', 'upgrade', MARKETPLACE]);
|
|
125
|
+
},
|
|
126
|
+
afterUpgrade: async (before) => {
|
|
127
|
+
const upgradedAt = now();
|
|
128
|
+
await markInstalled(codexCache, { before, now: upgradedAt });
|
|
129
|
+
await removeUnused(codexCache, earliestStartOf(await processes(upgradedAt), await at.trierarchPid()));
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
await dropDeclaredMarketplace(claudeSettings);
|
|
135
|
+
await run(claude, ['plugin', 'marketplace', 'add', tag === undefined ? REPOSITORY : `${REPOSITORY}#${tag}`]);
|
|
136
|
+
await run(claude, ['plugin', 'marketplace', 'update', MARKETPLACE]);
|
|
137
|
+
await run(claude, ['plugin', 'update', PLUGIN]);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=plugin-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-update.js","sourceRoot":"","sources":["../../src/adapters/plugin-update.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { AeolusPlugin } from './plugin-identity.js';
|
|
2
2
|
/** The harnesses that install the aeolus plugin, each in its own plugin folders. */
|
|
3
3
|
export type PluginHarness = 'claude-code' | 'codex';
|
|
4
|
+
export declare const PLUGIN_HARNESSES: readonly PluginHarness[];
|
|
5
|
+
/** The aeolus plugin's data folder in a harness's plugin folders, as both harnesses name it. */
|
|
6
|
+
export declare const PLUGIN_DATA_FOLDER = "aeolus-aeolus-fleet";
|
|
4
7
|
/**
|
|
5
8
|
* Where a harness installed the aeolus plugin: the newest version in its
|
|
6
9
|
* plugin cache and the plugin's data folder, unless variables name others
|
|
7
10
|
* (AEOLUS_PLUGIN_ROOT and AEOLUS_PLUGIN_DATA for Claude Code,
|
|
8
11
|
* AEOLUS_CODEX_PLUGIN_ROOT and AEOLUS_CODEX_PLUGIN_DATA for Codex). The
|
|
9
|
-
* folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do.
|
|
12
|
+
* folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do. The
|
|
13
|
+
* identities of the harness's sessions live in ~/.aeolus/crews/<harness>, as
|
|
14
|
+
* the plugin keeps them (decision 0015).
|
|
10
15
|
*/
|
|
11
16
|
export declare function findAeolusPlugin(at: {
|
|
12
17
|
homeDirectory: string;
|
|
@@ -23,3 +28,5 @@ export declare function aeolusPluginVersion(at: {
|
|
|
23
28
|
env: Readonly<Record<string, string | undefined>>;
|
|
24
29
|
harness: string;
|
|
25
30
|
}): Promise<string | undefined>;
|
|
31
|
+
/** Orders versions such as 0.9.0 and 0.10.0 by their numbers. */
|
|
32
|
+
export declare function byVersion(left: string, right: string): number;
|
package/dist/adapters/plugin.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { readdir, readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
export const PLUGIN_HARNESSES = ['claude-code', 'codex'];
|
|
5
|
+
/** The aeolus plugin's data folder in a harness's plugin folders, as both harnesses name it. */
|
|
6
|
+
export const PLUGIN_DATA_FOLDER = 'aeolus-aeolus-fleet';
|
|
4
7
|
/** Where each harness keeps its plugins, and the variables that point elsewhere. */
|
|
5
8
|
function placesOf(at) {
|
|
6
9
|
const { homeDirectory, env } = at;
|
|
@@ -14,13 +17,17 @@ function placesOf(at) {
|
|
|
14
17
|
* plugin cache and the plugin's data folder, unless variables name others
|
|
15
18
|
* (AEOLUS_PLUGIN_ROOT and AEOLUS_PLUGIN_DATA for Claude Code,
|
|
16
19
|
* AEOLUS_CODEX_PLUGIN_ROOT and AEOLUS_CODEX_PLUGIN_DATA for Codex). The
|
|
17
|
-
* folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do.
|
|
20
|
+
* folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do. The
|
|
21
|
+
* identities of the harness's sessions live in ~/.aeolus/crews/<harness>, as
|
|
22
|
+
* the plugin keeps them (decision 0015).
|
|
18
23
|
*/
|
|
19
24
|
export async function findAeolusPlugin(at) {
|
|
20
|
-
const
|
|
21
|
-
const
|
|
25
|
+
const harness = at.harness ?? 'claude-code';
|
|
26
|
+
const places = placesOf({ ...at, harness });
|
|
27
|
+
const data = places.data ?? join(places.plugins, 'data', PLUGIN_DATA_FOLDER);
|
|
28
|
+
const crews = join(at.homeDirectory, '.aeolus', 'crews', harness);
|
|
22
29
|
if (places.root !== undefined) {
|
|
23
|
-
return { root: places.root, data };
|
|
30
|
+
return { root: places.root, data, crews };
|
|
24
31
|
}
|
|
25
32
|
const cache = join(places.plugins, 'cache', 'aeolus-fleet', 'aeolus');
|
|
26
33
|
const versions = (await readdir(cache).catch(() => [])).filter((name) => /^\d+\.\d+\.\d+$/.test(name)).sort(byVersion);
|
|
@@ -28,7 +35,7 @@ export async function findAeolusPlugin(at) {
|
|
|
28
35
|
if (newest === undefined) {
|
|
29
36
|
throw new Error(`The aeolus plugin is not installed for ${places.name} (nothing in ${cache}): install it, or set ${places.rootVariable}`);
|
|
30
37
|
}
|
|
31
|
-
return { root: join(cache, newest), data };
|
|
38
|
+
return { root: join(cache, newest), data, crews };
|
|
32
39
|
}
|
|
33
40
|
/** The part of a plugin's manifest the version is read from. */
|
|
34
41
|
const manifestSchema = z.object({ version: z.string() });
|
|
@@ -59,7 +66,8 @@ export async function aeolusPluginVersion(at) {
|
|
|
59
66
|
return undefined;
|
|
60
67
|
}
|
|
61
68
|
}
|
|
62
|
-
|
|
69
|
+
/** Orders versions such as 0.9.0 and 0.10.0 by their numbers. */
|
|
70
|
+
export function byVersion(left, right) {
|
|
63
71
|
const [a, b] = [left, right].map((version) => version.split('.').map(Number));
|
|
64
72
|
for (let index = 0; index < 3; index += 1) {
|
|
65
73
|
const difference = (a?.[index] ?? 0) - (b?.[index] ?? 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/adapters/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,oFAAoF;AACpF,SAAS,QAAQ,CAAC,EAAwG;IACxH,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAClC,IAAI,EAAE,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,wBAAwB,EAAE,IAAI,EAAE,GAAG,CAAC,wBAAwB,EAAE,YAAY,EAAE,0BAA0B,EAAE,CAAC;IACxN,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,GAAG,CAAC,kBAAkB,EAAE,YAAY,EAAE,oBAAoB,EAAE,CAAC;AACpN,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/adapters/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A process running on this machine: its pid, its program and when it started. */
|
|
2
|
+
export interface RunningProcess {
|
|
3
|
+
readonly pid: number;
|
|
4
|
+
readonly program: string;
|
|
5
|
+
readonly startedAt: Date;
|
|
6
|
+
}
|
|
7
|
+
/** The processes `ps -A -o pid=,etime=,comm=` says, each started its elapsed time before `now`. */
|
|
8
|
+
export declare function processesOf(text: string, now: Date): RunningProcess[];
|
|
9
|
+
/** Every process running on this machine now, as macOS and Linux ps both say them. */
|
|
10
|
+
export declare function runningProcesses(now: Date): Promise<RunningProcess[]>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { runCommand } from './run-command.js';
|
|
2
|
+
const SECOND = 1000;
|
|
3
|
+
const MINUTE = 60 * SECOND;
|
|
4
|
+
const HOUR = 60 * MINUTE;
|
|
5
|
+
const DAY = 24 * HOUR;
|
|
6
|
+
/** A line of `ps -A -o pid=,etime=,comm=`: the elapsed time is `[[days-]hours:]minutes:seconds`. */
|
|
7
|
+
const LINE = /^\s*(\d+)\s+(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)\s+(.+)$/;
|
|
8
|
+
/** The processes `ps -A -o pid=,etime=,comm=` says, each started its elapsed time before `now`. */
|
|
9
|
+
export function processesOf(text, now) {
|
|
10
|
+
return text.split('\n').flatMap((line) => {
|
|
11
|
+
const match = LINE.exec(line);
|
|
12
|
+
if (match === null) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const [, pid, days, hours, minutes, seconds, program] = match;
|
|
16
|
+
const elapsed = Number(days ?? 0) * DAY + Number(hours ?? 0) * HOUR + Number(minutes) * MINUTE + Number(seconds) * SECOND;
|
|
17
|
+
return [{ pid: Number(pid), program: (program ?? '').trim(), startedAt: new Date(now.getTime() - elapsed) }];
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Every process running on this machine now, as macOS and Linux ps both say them. */
|
|
21
|
+
export async function runningProcesses(now) {
|
|
22
|
+
const listed = await runCommand('ps', { args: ['-A', '-o', 'pid=,etime=,comm='] });
|
|
23
|
+
if (listed.status !== 0) {
|
|
24
|
+
throw new Error(`ps -A -o pid=,etime=,comm= failed: ${listed.stderr.trim()}`);
|
|
25
|
+
}
|
|
26
|
+
return processesOf(listed.stdout, now);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=running-processes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"running-processes.js","sourceRoot":"","sources":["../../src/adapters/running-processes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAS9C,MAAM,MAAM,GAAG,IAAI,CAAC;AACpB,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC;AAC3B,MAAM,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC;AACzB,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtB,oGAAoG;AACpG,MAAM,IAAI,GAAG,uDAAuD,CAAC;AAErE,mGAAmG;AACnG,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,GAAS;IACjD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;QAC1H,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;AACL,CAAC;AAED,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAS;IAC9C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACnF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACzC,CAAC"}
|
package/dist/adapters/tmux.d.ts
CHANGED
|
@@ -12,11 +12,12 @@ import type { ProcessPort } from '../core/ports.js';
|
|
|
12
12
|
* group on a restart (#537), and the unit's stop leaves it alone (#479).
|
|
13
13
|
*/
|
|
14
14
|
export interface Tmux extends ProcessPort {
|
|
15
|
-
/** Starts the command in the folder, in a new session for the ship; an exited one is replaced. */
|
|
15
|
+
/** Starts the command in the folder, with the environment given, in a new session for the ship; an exited one is replaced. */
|
|
16
16
|
start(session: {
|
|
17
17
|
shipId: ShipId;
|
|
18
18
|
folder: string;
|
|
19
19
|
command: readonly string[];
|
|
20
|
+
env?: Readonly<Record<string, string>>;
|
|
20
21
|
}): Promise<void>;
|
|
21
22
|
/** Types the text into the ship's session and presses Enter, after `settleMs` when given. */
|
|
22
23
|
type(at: {
|
package/dist/adapters/tmux.js
CHANGED
|
@@ -41,7 +41,7 @@ export function createTmux(options = {}) {
|
|
|
41
41
|
stop: async (shipId) => {
|
|
42
42
|
await tmux(['kill-session', '-t', `=${sessionName(shipId)}`]);
|
|
43
43
|
},
|
|
44
|
-
start: async ({ shipId, folder, command }) => {
|
|
44
|
+
start: async ({ shipId, folder, command, env = {} }) => {
|
|
45
45
|
const name = sessionName(shipId);
|
|
46
46
|
await tmux(['kill-session', '-t', `=${name}`]);
|
|
47
47
|
// Start with the shell, keep the pane on exit, then run the command: so even a command that ends at once leaves its exit to see.
|
|
@@ -52,7 +52,8 @@ export function createTmux(options = {}) {
|
|
|
52
52
|
throw new Error(`tmux new-session failed: ${started.stderr.trim()}`);
|
|
53
53
|
}
|
|
54
54
|
await must(['set-option', '-w', '-t', `=${name}:`, 'remain-on-exit', 'on']);
|
|
55
|
-
|
|
55
|
+
const environment = Object.entries(env).flatMap(([variable, value]) => ['-e', `${variable}=${value}`]);
|
|
56
|
+
await must(['respawn-pane', '-k', '-t', `=${name}:`, '-c', folder, ...environment, '--', ...command]);
|
|
56
57
|
},
|
|
57
58
|
type: async ({ shipId, text, settleMs }) => {
|
|
58
59
|
const target = `=${sessionName(shipId)}:`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/adapters/tmux.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/adapters/tmux.ts"],"names":[],"mappings":"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"}
|