@ccmsg/cli 0.9.1 → 0.11.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/package.json +1 -1
- package/src/auth/admin.ts +32 -6
- package/src/cli.ts +377 -57
- package/src/daemon/control.ts +61 -9
- package/src/daemon/registry.ts +398 -70
- package/src/daemon/supervise.ts +27 -3
- package/src/instance/ccmsg-config.d.ts +112 -0
- package/src/instance/config.ts +513 -131
- package/src/instance/identity.ts +11 -2
- package/src/instance/instance.ts +71 -26
- package/src/instance/paths.ts +37 -6
- package/src/mesh/index.ts +0 -1
- package/src/mesh/mesh.ts +47 -62
- package/src/mesh/wire.ts +1 -29
- package/src/mesh/probe.ts +0 -105
package/src/daemon/supervise.ts
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
type Child,
|
|
9
9
|
configHome,
|
|
10
10
|
harnessFor,
|
|
11
|
+
reload,
|
|
11
12
|
prepareFor,
|
|
12
|
-
registered,
|
|
13
13
|
rowFor,
|
|
14
14
|
type SpawnInstance,
|
|
15
15
|
spawnInstance,
|
|
@@ -118,7 +118,30 @@ export class Supervisor {
|
|
|
118
118
|
this.#startTimeoutMs = options.startTimeoutMs ?? START_TIMEOUT_MS;
|
|
119
119
|
this.#stopTimeoutMs = options.stopTimeoutMs ?? STOP_TIMEOUT_MS;
|
|
120
120
|
this.#log = options.log ?? ((line) => process.stderr.write(`${JSON.stringify(line)}\n`));
|
|
121
|
-
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Read the edited files, check them, write down what held, and look after
|
|
124
|
+
* what it names (§8.2).
|
|
125
|
+
*
|
|
126
|
+
* This is the one thing that writes the applied settings: the children read
|
|
127
|
+
* them and write nothing, so nothing races over the file and there is one
|
|
128
|
+
* answer to "what is running". A config that does not check out leaves the
|
|
129
|
+
* applied one standing and is written to this supervisor's log — the
|
|
130
|
+
* children of a host are not something a typo in one file should take down.
|
|
131
|
+
*
|
|
132
|
+
* In `run` rather than in the constructor because the files are TypeScript
|
|
133
|
+
* and reading one is an import: a caller holding a supervisor that has not
|
|
134
|
+
* run yet is holding one that has not read the files yet, which is the same
|
|
135
|
+
* moment it was already true that nothing had been started. */
|
|
136
|
+
async #adopt(): Promise<void> {
|
|
137
|
+
const settled = await reload(this.#env);
|
|
138
|
+
for (const problem of settled.problems) {
|
|
139
|
+
this.#log({ event: "config refused", file: problem.file, problem: problem.msg });
|
|
140
|
+
}
|
|
141
|
+
for (const one of settled.satisfied.instances) {
|
|
142
|
+
const target = targetFor(this.#env, one.dir, one.name, one.id);
|
|
143
|
+
this.#units.set(target.dir, new Supervised(target));
|
|
144
|
+
}
|
|
122
145
|
}
|
|
123
146
|
|
|
124
147
|
/** The config homes this supervisor is looking after right now. */
|
|
@@ -138,6 +161,7 @@ export class Supervisor {
|
|
|
138
161
|
}
|
|
139
162
|
|
|
140
163
|
async #serve(): Promise<void> {
|
|
164
|
+
await this.#adopt();
|
|
141
165
|
await this.#listen();
|
|
142
166
|
for (const unit of this.#units.values()) this.#keep(unit);
|
|
143
167
|
// What ends the run is being asked to, not the children ending: a
|
|
@@ -307,7 +331,7 @@ export class Supervisor {
|
|
|
307
331
|
* behind it is the state `add` exists to leave behind only when there is no
|
|
308
332
|
* supervisor to tell. */
|
|
309
333
|
async addOne(dir: string): Promise<StatusRow> {
|
|
310
|
-
const home = configHome(dir, harnessFor(this.#env, dir));
|
|
334
|
+
const home = configHome(dir, await harnessFor(this.#env, dir));
|
|
311
335
|
if (this.#units.has(home)) {
|
|
312
336
|
throw new CommandError("file_exists", `${home} は既に見ています`);
|
|
313
337
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/** 設定ファイル (`config_v2.ts` / `instances/instance-<id>.ts`) が書ける値の型。
|
|
2
|
+
*
|
|
3
|
+
* ccmsg がこのファイルを config home に `ccmsg-config_v2.d.ts` として写すので、
|
|
4
|
+
* 設定ファイルからは `import type { Instance } from "../ccmsg-config_v2"` の形で
|
|
5
|
+
* 参照できる。型だけを持ち、他の何も import しないので、tsconfig の無い場所でも解決する。 */
|
|
6
|
+
|
|
7
|
+
/** ある config home が動かすもの。 */
|
|
8
|
+
export type Harness = "claude" | "codex";
|
|
9
|
+
|
|
10
|
+
/** mesh の 1 行。endpoint は公開 base URL で、末尾の `/` まで含める。 */
|
|
11
|
+
export interface Endpoint {
|
|
12
|
+
id: string;
|
|
13
|
+
endpoint: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** どこで待ち受け、誰からを受けるか。 */
|
|
17
|
+
export interface Entry {
|
|
18
|
+
host: string;
|
|
19
|
+
/** 0 はカーネルに空きポートを選ばせる。 */
|
|
20
|
+
port: number;
|
|
21
|
+
source_ips: string[];
|
|
22
|
+
/** `X-Forwarded-For` を信じる送り元 (CIDR)。 */
|
|
23
|
+
trusted_proxies: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** 起動レシピが読む値 1 つ。 */
|
|
27
|
+
export interface LauncherParam {
|
|
28
|
+
name: string;
|
|
29
|
+
default: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface LauncherTemplate {
|
|
33
|
+
name: string;
|
|
34
|
+
command: string;
|
|
35
|
+
params?: LauncherParam[];
|
|
36
|
+
shell?: "bash" | "zsh";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface Launcher {
|
|
40
|
+
root_dirs: string[];
|
|
41
|
+
/** 並び順のまま答える。先頭が既定のレシピ。 */
|
|
42
|
+
templates: LauncherTemplate[];
|
|
43
|
+
depth?: number;
|
|
44
|
+
timeout_secs?: number;
|
|
45
|
+
clean_env?: string[];
|
|
46
|
+
keep_env?: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface Upstream {
|
|
50
|
+
gateway_url?: string;
|
|
51
|
+
gateway_webhook_source?: string;
|
|
52
|
+
gateway_webhook_token_file?: string;
|
|
53
|
+
/** 末尾に `/` を付けない base URL。 */
|
|
54
|
+
terminal_gateway?: string;
|
|
55
|
+
launcher?: Launcher;
|
|
56
|
+
/** batch を訳すプログラム。絶対パス。 */
|
|
57
|
+
translate_helper?: string;
|
|
58
|
+
sandbox_origin?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 名前の付いた dump の選択。`types` は型名・その prefix・`-` 付きの除外・
|
|
62
|
+
* 他の preset を差し込む `@name`。 */
|
|
63
|
+
export interface DumpPreset {
|
|
64
|
+
name: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
opts: { types: string[] };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface Dump {
|
|
70
|
+
presets: DumpPreset[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 1 instance 分の設定。`config_v2.ts` が返すのも、`instances/instance-<id>.ts` が
|
|
74
|
+
* `dir` を足して返すのも、これ。 */
|
|
75
|
+
export interface Config {
|
|
76
|
+
harness: Harness;
|
|
77
|
+
/** mesh の全 instance (自分も含む)。`endpoints.json` が正で、読むのは自由だが
|
|
78
|
+
* 違う物を返したら config error。自分がどれかは自分の id の行。 */
|
|
79
|
+
endpoints: Endpoint[];
|
|
80
|
+
/** 無ければ unix socket だけで serve する。 */
|
|
81
|
+
entry?: Entry;
|
|
82
|
+
upstream: Upstream;
|
|
83
|
+
direct_delivery: boolean;
|
|
84
|
+
fork_origin: boolean;
|
|
85
|
+
dump: Dump;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** instance の設定。`dir` (= config home の絶対パス) が instance を決める。 */
|
|
89
|
+
export interface InstanceConfig extends Config {
|
|
90
|
+
dir: string;
|
|
91
|
+
/** 人向けのラベル。書かなければ id。ファイル名は id なので、変えても何も動かない。 */
|
|
92
|
+
name?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** `config_v2.ts` が default export する関数。
|
|
96
|
+
*
|
|
97
|
+
* `builtin` は組み込みの既定値で、凍らせてあるので書き換えられない。
|
|
98
|
+
* `config` はそのコピーなので、好きに書き換えて返す。 */
|
|
99
|
+
export type Defaults = (ctx: {
|
|
100
|
+
readonly builtin: Readonly<Config>;
|
|
101
|
+
config: Config;
|
|
102
|
+
}) => Config | Promise<Config>;
|
|
103
|
+
|
|
104
|
+
/** `instances/instance-<id>.ts` が default export する関数。
|
|
105
|
+
*
|
|
106
|
+
* `default` は `config_v2.ts` が返した値 (凍結済み)、`config` はそのコピーに
|
|
107
|
+
* `dir` の場所を空で足した物。 */
|
|
108
|
+
export type Instance = (ctx: {
|
|
109
|
+
readonly builtin: Readonly<Config>;
|
|
110
|
+
readonly default: Readonly<Config>;
|
|
111
|
+
config: InstanceConfig;
|
|
112
|
+
}) => InstanceConfig | Promise<InstanceConfig>;
|