@excitedjs/dreamux 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +223 -0
- package/bin/dreamux +31 -0
- package/bin/server +35 -0
- package/bin/server-ctl +28 -0
- package/db/migrations/0001_init.sql +49 -0
- package/dist/admin/methods.js +103 -0
- package/dist/admin/methods.js.map +1 -0
- package/dist/admin/protocol.js +15 -0
- package/dist/admin/protocol.js.map +1 -0
- package/dist/admin/socket.js +251 -0
- package/dist/admin/socket.js.map +1 -0
- package/dist/cli/dreamux.js +105 -0
- package/dist/cli/dreamux.js.map +1 -0
- package/dist/cli/server-ctl.js +172 -0
- package/dist/cli/server-ctl.js.map +1 -0
- package/dist/cli/server.js +88 -0
- package/dist/cli/server.js.map +1 -0
- package/dist/codex/events.js +82 -0
- package/dist/codex/events.js.map +1 -0
- package/dist/codex/handshake.js +85 -0
- package/dist/codex/handshake.js.map +1 -0
- package/dist/codex/rpc.js +200 -0
- package/dist/codex/rpc.js.map +1 -0
- package/dist/codex/supervisor.js +184 -0
- package/dist/codex/supervisor.js.map +1 -0
- package/dist/codex/types.js +10 -0
- package/dist/codex/types.js.map +1 -0
- package/dist/db/repository.js +207 -0
- package/dist/db/repository.js.map +1 -0
- package/dist/db/schema.js +29 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/dispatcher/approval.js +43 -0
- package/dist/dispatcher/approval.js.map +1 -0
- package/dist/dispatcher/runtime.js +262 -0
- package/dist/dispatcher/runtime.js.map +1 -0
- package/dist/dispatcher/turn-manager.js +167 -0
- package/dist/dispatcher/turn-manager.js.map +1 -0
- package/dist/feishu/bot.js +137 -0
- package/dist/feishu/bot.js.map +1 -0
- package/dist/feishu/content.js +108 -0
- package/dist/feishu/content.js.map +1 -0
- package/dist/feishu/render.js +600 -0
- package/dist/feishu/render.js.map +1 -0
- package/dist/feishu/types.js +9 -0
- package/dist/feishu/types.js.map +1 -0
- package/dist/runtime/codex-args.js +92 -0
- package/dist/runtime/codex-args.js.map +1 -0
- package/dist/runtime/config.js +351 -0
- package/dist/runtime/config.js.map +1 -0
- package/dist/runtime/paths.js +77 -0
- package/dist/runtime/paths.js.map +1 -0
- package/dist/runtime/secrets.js +18 -0
- package/dist/runtime/secrets.js.map +1 -0
- package/dist/server.js +234 -0
- package/dist/server.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse `dispatchers.codex_args_json` into the CLI-arg array passed to
|
|
3
|
+
* the codex app-server child, AND validate that the trusted-local
|
|
4
|
+
* invariants from issue #2 §"信任模型" hold.
|
|
5
|
+
*
|
|
6
|
+
* Canonical shape:
|
|
7
|
+
* {
|
|
8
|
+
* "approvalPolicy": "never", // overrides global default if set
|
|
9
|
+
* "sandboxMode": "workspace-write", // overrides global default if set
|
|
10
|
+
* "extraArgs": ["--model", "..."] // appended after global extra_args
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* Precedence for each field (highest wins):
|
|
14
|
+
* 1. dispatchers.codex_args_json (this JSON)
|
|
15
|
+
* 2. global defaults from ~/.dreamux/config.toml (passed in as `defaults`)
|
|
16
|
+
* 3. hardcoded fallbacks (`'never'`, `'workspace-write'`, `[]`)
|
|
17
|
+
* Per the feat/global-config-dir work — see decision 0003.
|
|
18
|
+
*
|
|
19
|
+
* `approvalPolicy` not in the trusted-local allowlist fails-fast at startup
|
|
20
|
+
* (issue #2 §"实现陷阱"): dispatcher refuses to come up if the policy may
|
|
21
|
+
* request approval AND no approval handler is wired.
|
|
22
|
+
*
|
|
23
|
+
* `sandboxMode` is similarly validated against the codex 0.134 enum so a
|
|
24
|
+
* typo doesn't reach the daemon (where the only feedback is a fatal early
|
|
25
|
+
* exit).
|
|
26
|
+
*/
|
|
27
|
+
const TRUSTED_LOCAL_APPROVAL_POLICIES = new Set([
|
|
28
|
+
'never',
|
|
29
|
+
'auto',
|
|
30
|
+
'auto-approve',
|
|
31
|
+
'on-failure',
|
|
32
|
+
]);
|
|
33
|
+
const ALLOWED_SANDBOX_MODES = new Set([
|
|
34
|
+
'read-only',
|
|
35
|
+
'workspace-write',
|
|
36
|
+
'danger-full-access',
|
|
37
|
+
]);
|
|
38
|
+
export function parseCodexArgs(json, defaults = {}) {
|
|
39
|
+
let raw;
|
|
40
|
+
try {
|
|
41
|
+
raw = json.trim() === '' ? {} : JSON.parse(json);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
throw new Error(`codex_args_json is not valid JSON: ${e.message}`);
|
|
45
|
+
}
|
|
46
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
47
|
+
throw new Error('codex_args_json must be a JSON object');
|
|
48
|
+
}
|
|
49
|
+
const obj = raw;
|
|
50
|
+
const approvalPolicy = typeof obj['approvalPolicy'] === 'string'
|
|
51
|
+
? obj['approvalPolicy']
|
|
52
|
+
: (defaults.approvalPolicy ?? 'never');
|
|
53
|
+
const sandboxMode = typeof obj['sandboxMode'] === 'string'
|
|
54
|
+
? obj['sandboxMode']
|
|
55
|
+
: (defaults.sandboxMode ?? 'workspace-write');
|
|
56
|
+
const perDispatcherExtra = Array.isArray(obj['extraArgs'])
|
|
57
|
+
? obj['extraArgs'].map((x) => String(x))
|
|
58
|
+
: [];
|
|
59
|
+
// Global extra_args go first; per-dispatcher extra_args are appended.
|
|
60
|
+
// codex's CLI is order-sensitive for `-c key=value` overrides — the
|
|
61
|
+
// last write wins — so per-dispatcher always overrides a same-key
|
|
62
|
+
// global.
|
|
63
|
+
const extraArgs = [
|
|
64
|
+
...(defaults.extraArgs ?? []),
|
|
65
|
+
...perDispatcherExtra,
|
|
66
|
+
];
|
|
67
|
+
if (!TRUSTED_LOCAL_APPROVAL_POLICIES.has(approvalPolicy)) {
|
|
68
|
+
throw new Error(`dispatcher startup refused: approvalPolicy='${approvalPolicy}' may request approval, ` +
|
|
69
|
+
`but the dreamux MVP only ships with a fail-fast approval handler ` +
|
|
70
|
+
`(issue #2 §"信任模型"). Configure approvalPolicy='never' or extend the trust model first.`);
|
|
71
|
+
}
|
|
72
|
+
if (!ALLOWED_SANDBOX_MODES.has(sandboxMode)) {
|
|
73
|
+
throw new Error(`dispatcher startup refused: sandboxMode='${sandboxMode}' is not one of ` +
|
|
74
|
+
`${Array.from(ALLOWED_SANDBOX_MODES).join(' | ')} (codex 0.134 enum).`);
|
|
75
|
+
}
|
|
76
|
+
return { approvalPolicy, sandboxMode, extraArgs };
|
|
77
|
+
}
|
|
78
|
+
export function codexArgsToCli(parsed) {
|
|
79
|
+
// codex >= 0.134 dropped --approval-policy and --sandbox at the
|
|
80
|
+
// app-server level; the remaining mechanism is `-c key=value` config
|
|
81
|
+
// overrides for both. Pass approval_policy first, then sandbox_mode,
|
|
82
|
+
// then per-dispatcher / global extra args — letting extra_args contain
|
|
83
|
+
// a same-key `-c` override that wins (codex parses last write wins).
|
|
84
|
+
return [
|
|
85
|
+
'-c',
|
|
86
|
+
`approval_policy=${parsed.approvalPolicy}`,
|
|
87
|
+
'-c',
|
|
88
|
+
`sandbox_mode=${parsed.sandboxMode}`,
|
|
89
|
+
...parsed.extraArgs,
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=codex-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-args.js","sourceRoot":"","sources":["../../src/runtime/codex-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAC;IAC9C,OAAO;IACP,MAAM;IACN,cAAc;IACd,YAAY;CACb,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,WAAW;IACX,iBAAiB;IACjB,oBAAoB;CACrB,CAAC,CAAC;AAcH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,WAA8B,EAAE;IAEhC,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,sCAAuC,CAAW,CAAC,OAAO,EAAE,CAC7D,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,cAAc,GAClB,OAAO,GAAG,CAAC,gBAAgB,CAAC,KAAK,QAAQ;QACvC,CAAC,CAAE,GAAG,CAAC,gBAAgB,CAAY;QACnC,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,CAAC;IAC3C,MAAM,WAAW,GACf,OAAO,GAAG,CAAC,aAAa,CAAC,KAAK,QAAQ;QACpC,CAAC,CAAE,GAAG,CAAC,aAAa,CAAY;QAChC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,IAAI,iBAAiB,CAAC,CAAC;IAClD,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACxD,CAAC,CAAE,GAAG,CAAC,WAAW,CAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,EAAE,CAAC;IACP,sEAAsE;IACtE,oEAAoE;IACpE,kEAAkE;IAClE,UAAU;IACV,MAAM,SAAS,GAAG;QAChB,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;QAC7B,GAAG,kBAAkB;KACtB,CAAC;IAEF,IAAI,CAAC,+BAA+B,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,+CAA+C,cAAc,0BAA0B;YACrF,mEAAmE;YACnE,uFAAuF,CAC1F,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,4CAA4C,WAAW,kBAAkB;YACvE,GAAG,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CACzE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAuB;IACpD,gEAAgE;IAChE,qEAAqE;IACrE,qEAAqE;IACrE,uEAAuE;IACvE,qEAAqE;IACrE,OAAO;QACL,IAAI;QACJ,mBAAmB,MAAM,CAAC,cAAc,EAAE;QAC1C,IAAI;QACJ,gBAAgB,MAAM,CAAC,WAAW,EAAE;QACpC,GAAG,MAAM,CAAC,SAAS;KACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global dreamux configuration loaded from `~/.dreamux/config.toml`.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists: pre-config, every dispatcher had to repeat the same
|
|
5
|
+
* `approval_policy=never`, every operator had to remember
|
|
6
|
+
* `CODEX_HOST_CODEX_BIN`, every retry/timeout tuning was buried in
|
|
7
|
+
* source-level constants. This file is the user-editable surface for
|
|
8
|
+
* machine-wide defaults; per-dispatcher settings still override it, and
|
|
9
|
+
* the existing env vars still override everything (escape hatch for CI
|
|
10
|
+
* and one-off debug runs).
|
|
11
|
+
*
|
|
12
|
+
* Layout — separation of concerns:
|
|
13
|
+
* ~/.dreamux/ user-editable configuration (this module)
|
|
14
|
+
* ~/.codex-host/ runtime data (SQLite, sockets, dispatcher logs)
|
|
15
|
+
* Mixing them was the original sin; keeping them apart is what makes a
|
|
16
|
+
* `rm -rf ~/.codex-host` recovery safe.
|
|
17
|
+
*
|
|
18
|
+
* Format: TOML (matches codex's own `~/.codex/config.toml`).
|
|
19
|
+
* Parse failures fail-fast with the offending line.
|
|
20
|
+
*/
|
|
21
|
+
import { homedir } from 'node:os';
|
|
22
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
23
|
+
import { closeSync, mkdirSync, openSync, readFileSync, writeSync, } from 'node:fs';
|
|
24
|
+
import { parse as parseToml, TomlError } from 'smol-toml';
|
|
25
|
+
/**
|
|
26
|
+
* Built-in defaults — identical to what individual modules used before this
|
|
27
|
+
* config existed. Anything you change here is a behavior change for fresh
|
|
28
|
+
* installs (and only fresh installs; existing `~/.dreamux/config.toml`
|
|
29
|
+
* files are not touched on upgrade).
|
|
30
|
+
*/
|
|
31
|
+
export const BUILT_IN_DEFAULTS = {
|
|
32
|
+
runtime_dir: '~/.codex-host',
|
|
33
|
+
admin_socket: null,
|
|
34
|
+
codex: {
|
|
35
|
+
bin: 'codex',
|
|
36
|
+
approval_policy: 'never',
|
|
37
|
+
sandbox_mode: 'workspace-write',
|
|
38
|
+
extra_args: [],
|
|
39
|
+
initialize_timeout_ms: 10_000,
|
|
40
|
+
},
|
|
41
|
+
outbound: {
|
|
42
|
+
retries: 3,
|
|
43
|
+
retry_delay_ms: 1000,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Codex 0.134 sandbox modes (from `codex --help`'s `-s, --sandbox` choices).
|
|
48
|
+
* Kept in sync with `codex-args.ts` (same allowlist enforced at the
|
|
49
|
+
* per-dispatcher level).
|
|
50
|
+
*/
|
|
51
|
+
export const ALLOWED_SANDBOX_MODES = new Set([
|
|
52
|
+
'read-only',
|
|
53
|
+
'workspace-write',
|
|
54
|
+
'danger-full-access',
|
|
55
|
+
]);
|
|
56
|
+
/**
|
|
57
|
+
* The literal TOML text written on first boot. Comments are part of the
|
|
58
|
+
* UX — they tell an operator opening the file for the first time what
|
|
59
|
+
* each key means and where to read more.
|
|
60
|
+
*/
|
|
61
|
+
export const DEFAULT_CONFIG_TOML = `# dreamux global configuration (~/.dreamux/config.toml)
|
|
62
|
+
#
|
|
63
|
+
# Edit this file and restart \`dreamux server start\` to apply changes.
|
|
64
|
+
# Runtime data (SQLite, sockets, dispatcher logs) lives separately in
|
|
65
|
+
# \`runtime_dir\` below — this file holds only user-editable settings.
|
|
66
|
+
# See .agents/decisions/0003-global-config-dir.md for the design rationale.
|
|
67
|
+
#
|
|
68
|
+
# Precedence (highest wins):
|
|
69
|
+
# 1. environment variables (CODEX_HOST_RUNTIME_DIR, CODEX_HOST_ADMIN_SOCKET,
|
|
70
|
+
# CODEX_HOST_CODEX_BIN) — escape hatch for CI and one-off debug runs
|
|
71
|
+
# 2. per-dispatcher fields (codex_args_json: approvalPolicy, extraArgs)
|
|
72
|
+
# 3. this file
|
|
73
|
+
# 4. built-in defaults baked into the binary
|
|
74
|
+
|
|
75
|
+
# Where dreamux stores runtime state (SQLite database, admin Unix socket,
|
|
76
|
+
# per-dispatcher Codex sockets and logs).
|
|
77
|
+
#
|
|
78
|
+
# \`~/\` is expanded to your home directory. Relative paths are not supported.
|
|
79
|
+
runtime_dir = "~/.codex-host"
|
|
80
|
+
|
|
81
|
+
# Admin Unix socket path. Leave commented to derive as <runtime_dir>/admin.sock.
|
|
82
|
+
# admin_socket = "~/.codex-host/admin.sock"
|
|
83
|
+
|
|
84
|
+
[codex]
|
|
85
|
+
# Path to the codex CLI. Bare name (\`codex\`) resolves via $PATH; an
|
|
86
|
+
# absolute path (\`/opt/codex/bin/codex\`) skips the lookup.
|
|
87
|
+
bin = "codex"
|
|
88
|
+
|
|
89
|
+
# Default approval policy applied to every dispatcher. A per-dispatcher
|
|
90
|
+
# \`codex_args_json\` (set via \`dreamux dispatcher add --codex-args-json ...\`)
|
|
91
|
+
# overrides this when present. Must be one of:
|
|
92
|
+
# never | auto | auto-approve | on-failure
|
|
93
|
+
# See issue #2 §"信任模型" for the trust-model implications of \`never\`.
|
|
94
|
+
approval_policy = "never"
|
|
95
|
+
|
|
96
|
+
# Default sandbox mode codex executes shell commands under. Per-dispatcher
|
|
97
|
+
# \`codex_args_json.sandboxMode\` overrides this when present.
|
|
98
|
+
# Must be one of:
|
|
99
|
+
# read-only — codex cannot write any files
|
|
100
|
+
# workspace-write — codex can write inside its cwd; recommended
|
|
101
|
+
# baseline for trusted-local
|
|
102
|
+
# danger-full-access — no sandbox; pair with approval_policy="never"
|
|
103
|
+
# only when codex must spawn helpers that chdir
|
|
104
|
+
# out of its cwd (e.g. tm dispatching into other
|
|
105
|
+
# worktrees). Trust model becomes equivalent to
|
|
106
|
+
# giving any allowed bot user shell access.
|
|
107
|
+
sandbox_mode = "workspace-write"
|
|
108
|
+
|
|
109
|
+
# Extra args appended to every codex app-server invocation. Per-dispatcher
|
|
110
|
+
# extra_args (in codex_args_json) are appended *after* these.
|
|
111
|
+
extra_args = []
|
|
112
|
+
|
|
113
|
+
# Handshake timeout. Without this, dreamux would hang forever on a codex
|
|
114
|
+
# that accepts the WebSocket upgrade but never replies to \`initialize\`
|
|
115
|
+
# (PR #5). 0 is not a valid value — set to a positive integer.
|
|
116
|
+
initialize_timeout_ms = 10000
|
|
117
|
+
|
|
118
|
+
[outbound]
|
|
119
|
+
# How many times to retry a failed Feishu send before parking the inbound
|
|
120
|
+
# row in \`outbound_failed\`. The Codex turn never re-runs on retry — only
|
|
121
|
+
# the outbound delivery is retried (PR #3 review #1).
|
|
122
|
+
retries = 3
|
|
123
|
+
|
|
124
|
+
# Initial delay between outbound retries (ms).
|
|
125
|
+
retry_delay_ms = 1000
|
|
126
|
+
`;
|
|
127
|
+
export function globalConfigDir(overrides = {}) {
|
|
128
|
+
if (overrides.configDir !== undefined)
|
|
129
|
+
return overrides.configDir;
|
|
130
|
+
return process.env['DREAMUX_CONFIG_DIR'] || join(homedir(), '.dreamux');
|
|
131
|
+
}
|
|
132
|
+
export function globalConfigFile(overrides = {}) {
|
|
133
|
+
return join(globalConfigDir(overrides), 'config.toml');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Load `<configDir>/config.toml`, creating it with default content on
|
|
137
|
+
* first boot. Throws with a file-line-pointing message when TOML parsing
|
|
138
|
+
* fails so the operator can fix the file without spelunking through
|
|
139
|
+
* libraries.
|
|
140
|
+
*
|
|
141
|
+
* Safe to call from `server start` on every boot — first call ensures
|
|
142
|
+
* the directory and file exist with sensible defaults; subsequent calls
|
|
143
|
+
* just read.
|
|
144
|
+
*
|
|
145
|
+
* PR #8 review #1: create the file with the atomic `wx` (O_CREAT|O_EXCL)
|
|
146
|
+
* flag, not check-then-write. Two server processes booting concurrently
|
|
147
|
+
* against the same `~/.dreamux/` would otherwise both see "file absent"
|
|
148
|
+
* and one would overwrite what the other wrote. Posix guarantees only
|
|
149
|
+
* one `wx` open wins; the loser gets EEXIST and falls through to the
|
|
150
|
+
* read path.
|
|
151
|
+
*/
|
|
152
|
+
export function loadOrInitConfig(overrides = {}) {
|
|
153
|
+
const file = globalConfigFile(overrides);
|
|
154
|
+
// Parent dir creation is idempotent under `recursive: true` (no race),
|
|
155
|
+
// but it can still legitimately fail (e.g. parent is unwritable). Let
|
|
156
|
+
// the EACCES propagate — the user needs to see it.
|
|
157
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
158
|
+
const createdOnThisBoot = atomicWriteIfAbsent(file, DEFAULT_CONFIG_TOML);
|
|
159
|
+
const raw = readFileSync(file, 'utf8');
|
|
160
|
+
let parsed;
|
|
161
|
+
try {
|
|
162
|
+
parsed = parseToml(raw);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
throw formatTomlError(err, file);
|
|
166
|
+
}
|
|
167
|
+
const config = mergeWithDefaults(parsed, file);
|
|
168
|
+
return { config, configFile: file, createdOnThisBoot };
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Atomic create-if-absent. Returns true if this call created the file.
|
|
172
|
+
*
|
|
173
|
+
* Uses Node's `wx` flag, which maps to POSIX `open(O_CREAT | O_EXCL)`.
|
|
174
|
+
* Two processes racing the same path see exactly one EEXIST and exactly
|
|
175
|
+
* one success — no torn writes, no overwriting each other.
|
|
176
|
+
*/
|
|
177
|
+
function atomicWriteIfAbsent(file, content) {
|
|
178
|
+
let fd;
|
|
179
|
+
try {
|
|
180
|
+
fd = openSync(file, 'wx', 0o600);
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
if (err.code === 'EEXIST')
|
|
184
|
+
return false;
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
writeSync(fd, content);
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
closeSync(fd);
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
function formatTomlError(err, file) {
|
|
196
|
+
if (err instanceof TomlError) {
|
|
197
|
+
const where = typeof err.line === 'number' && typeof err.column === 'number'
|
|
198
|
+
? `${file}:${err.line}:${err.column}`
|
|
199
|
+
: file;
|
|
200
|
+
return new Error(`dreamux config parse error at ${where}: ${err.message}\n` +
|
|
201
|
+
`Fix the TOML syntax in ${file} and restart, or delete the file to regenerate defaults.`);
|
|
202
|
+
}
|
|
203
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
204
|
+
return new Error(`dreamux config parse error in ${file}: ${msg}\n` +
|
|
205
|
+
`Fix the TOML syntax in ${file} and restart, or delete the file to regenerate defaults.`);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Merge user-supplied TOML object with built-in defaults. Unknown top-level
|
|
209
|
+
* keys are tolerated (forward-compat with newer config files); known keys
|
|
210
|
+
* are validated for type and (where relevant) value membership.
|
|
211
|
+
*/
|
|
212
|
+
function mergeWithDefaults(raw, file) {
|
|
213
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
214
|
+
throw new Error(`dreamux config error in ${file}: top-level must be a table`);
|
|
215
|
+
}
|
|
216
|
+
const obj = raw;
|
|
217
|
+
const codexIn = isPlainObject(obj['codex']) ? obj['codex'] : {};
|
|
218
|
+
const outboundIn = isPlainObject(obj['outbound']) ? obj['outbound'] : {};
|
|
219
|
+
const runtime_dir = expandHome(requireString(obj, 'runtime_dir', BUILT_IN_DEFAULTS.runtime_dir, file));
|
|
220
|
+
const admin_socket_raw = obj['admin_socket'];
|
|
221
|
+
const admin_socket = admin_socket_raw === undefined || admin_socket_raw === null
|
|
222
|
+
? null
|
|
223
|
+
: expandHome(ensureString(admin_socket_raw, 'admin_socket', file));
|
|
224
|
+
const approval_policy = requireString(codexIn, 'approval_policy', BUILT_IN_DEFAULTS.codex.approval_policy, file, 'codex.');
|
|
225
|
+
// Validate approval_policy against the same allowlist as codex-args.ts.
|
|
226
|
+
// Keep the two in sync — see decision 0001 / issue #2 §"信任模型".
|
|
227
|
+
const ALLOWED_POLICIES = new Set([
|
|
228
|
+
'never',
|
|
229
|
+
'auto',
|
|
230
|
+
'auto-approve',
|
|
231
|
+
'on-failure',
|
|
232
|
+
]);
|
|
233
|
+
if (!ALLOWED_POLICIES.has(approval_policy)) {
|
|
234
|
+
throw new Error(`dreamux config error in ${file}: codex.approval_policy='${approval_policy}' ` +
|
|
235
|
+
`is not one of ${Array.from(ALLOWED_POLICIES).join(' | ')}`);
|
|
236
|
+
}
|
|
237
|
+
const sandbox_mode = requireString(codexIn, 'sandbox_mode', BUILT_IN_DEFAULTS.codex.sandbox_mode, file, 'codex.');
|
|
238
|
+
if (!ALLOWED_SANDBOX_MODES.has(sandbox_mode)) {
|
|
239
|
+
throw new Error(`dreamux config error in ${file}: codex.sandbox_mode='${sandbox_mode}' ` +
|
|
240
|
+
`is not one of ${Array.from(ALLOWED_SANDBOX_MODES).join(' | ')}`);
|
|
241
|
+
}
|
|
242
|
+
const extra_args = requireStringArray(codexIn, 'extra_args', BUILT_IN_DEFAULTS.codex.extra_args, file, 'codex.');
|
|
243
|
+
const initialize_timeout_ms = requirePositiveInt(codexIn, 'initialize_timeout_ms', BUILT_IN_DEFAULTS.codex.initialize_timeout_ms, file, 'codex.');
|
|
244
|
+
const retries = requireNonNegativeInt(outboundIn, 'retries', BUILT_IN_DEFAULTS.outbound.retries, file, 'outbound.');
|
|
245
|
+
const retry_delay_ms = requireNonNegativeInt(outboundIn, 'retry_delay_ms', BUILT_IN_DEFAULTS.outbound.retry_delay_ms, file, 'outbound.');
|
|
246
|
+
return {
|
|
247
|
+
runtime_dir,
|
|
248
|
+
admin_socket,
|
|
249
|
+
codex: {
|
|
250
|
+
bin: requireString(codexIn, 'bin', BUILT_IN_DEFAULTS.codex.bin, file, 'codex.'),
|
|
251
|
+
approval_policy,
|
|
252
|
+
sandbox_mode,
|
|
253
|
+
extra_args,
|
|
254
|
+
initialize_timeout_ms,
|
|
255
|
+
},
|
|
256
|
+
outbound: { retries, retry_delay_ms },
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function isPlainObject(v) {
|
|
260
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
261
|
+
}
|
|
262
|
+
function requireString(obj, key, fallback, file, prefix = '') {
|
|
263
|
+
const v = obj[key];
|
|
264
|
+
if (v === undefined)
|
|
265
|
+
return fallback;
|
|
266
|
+
return ensureString(v, `${prefix}${key}`, file);
|
|
267
|
+
}
|
|
268
|
+
function ensureString(v, key, file) {
|
|
269
|
+
if (typeof v !== 'string') {
|
|
270
|
+
throw new Error(`dreamux config error in ${file}: ${key} must be a string (got ${describeType(v)})`);
|
|
271
|
+
}
|
|
272
|
+
return v;
|
|
273
|
+
}
|
|
274
|
+
function requireStringArray(obj, key, fallback, file, prefix = '') {
|
|
275
|
+
const v = obj[key];
|
|
276
|
+
if (v === undefined)
|
|
277
|
+
return fallback;
|
|
278
|
+
if (!Array.isArray(v)) {
|
|
279
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key} must be an array of strings (got ${describeType(v)})`);
|
|
280
|
+
}
|
|
281
|
+
return v.map((item, i) => {
|
|
282
|
+
if (typeof item !== 'string') {
|
|
283
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key}[${i}] must be a string (got ${describeType(item)})`);
|
|
284
|
+
}
|
|
285
|
+
return item;
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function requirePositiveInt(obj, key, fallback, file, prefix = '') {
|
|
289
|
+
const n = readInt(obj, key, file, prefix);
|
|
290
|
+
if (n === null)
|
|
291
|
+
return fallback;
|
|
292
|
+
if (n <= 0) {
|
|
293
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key} must be > 0 (got ${n})`);
|
|
294
|
+
}
|
|
295
|
+
return n;
|
|
296
|
+
}
|
|
297
|
+
function requireNonNegativeInt(obj, key, fallback, file, prefix = '') {
|
|
298
|
+
const n = readInt(obj, key, file, prefix);
|
|
299
|
+
if (n === null)
|
|
300
|
+
return fallback;
|
|
301
|
+
if (n < 0) {
|
|
302
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key} must be >= 0 (got ${n})`);
|
|
303
|
+
}
|
|
304
|
+
return n;
|
|
305
|
+
}
|
|
306
|
+
function readInt(obj, key, file, prefix) {
|
|
307
|
+
const v = obj[key];
|
|
308
|
+
if (v === undefined)
|
|
309
|
+
return null;
|
|
310
|
+
// smol-toml returns BigInt for integers; accept both.
|
|
311
|
+
if (typeof v === 'bigint') {
|
|
312
|
+
if (v < BigInt(Number.MIN_SAFE_INTEGER) || v > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
313
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key}=${v} is outside safe integer range`);
|
|
314
|
+
}
|
|
315
|
+
return Number(v);
|
|
316
|
+
}
|
|
317
|
+
if (typeof v === 'number') {
|
|
318
|
+
if (!Number.isInteger(v)) {
|
|
319
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key} must be an integer (got ${v})`);
|
|
320
|
+
}
|
|
321
|
+
return v;
|
|
322
|
+
}
|
|
323
|
+
throw new Error(`dreamux config error in ${file}: ${prefix}${key} must be an integer (got ${describeType(v)})`);
|
|
324
|
+
}
|
|
325
|
+
function describeType(v) {
|
|
326
|
+
if (v === null)
|
|
327
|
+
return 'null';
|
|
328
|
+
if (Array.isArray(v))
|
|
329
|
+
return 'array';
|
|
330
|
+
return typeof v;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Expand a leading `~/` (or bare `~`) to the user's home directory.
|
|
334
|
+
* Absolute paths and other relative paths pass through unchanged; the
|
|
335
|
+
* latter aren't supported by callers but we leave them alone so a typo
|
|
336
|
+
* surfaces as a missing-path error rather than silent expansion.
|
|
337
|
+
*/
|
|
338
|
+
export function expandHome(path) {
|
|
339
|
+
if (path === '~')
|
|
340
|
+
return homedir();
|
|
341
|
+
if (path.startsWith('~/'))
|
|
342
|
+
return join(homedir(), path.slice(2));
|
|
343
|
+
if (!isAbsolute(path)) {
|
|
344
|
+
// Pass through; downstream consumers will error if they need an
|
|
345
|
+
// absolute path. (We considered erroring here, but bash-style configs
|
|
346
|
+
// sometimes use bare names that get resolved later.)
|
|
347
|
+
return path;
|
|
348
|
+
}
|
|
349
|
+
return path;
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/runtime/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem layout for the codex-host server runtime.
|
|
3
|
+
*
|
|
4
|
+
* Default root: ~/.codex-host/ (override via env CODEX_HOST_RUNTIME_DIR
|
|
5
|
+
* or `runtime_dir` in ~/.dreamux/config.toml — env wins, see config.ts).
|
|
6
|
+
* Layout:
|
|
7
|
+
* <root>/
|
|
8
|
+
* state.db SQLite database (dispatchers + inbound_buffer)
|
|
9
|
+
* admin.sock server-ctl admin Unix socket
|
|
10
|
+
* dispatchers/<id>/
|
|
11
|
+
* cwd/ Codex app-server cwd
|
|
12
|
+
* socket Codex Unix socket
|
|
13
|
+
* stdout.log Codex stdout
|
|
14
|
+
* stderr.log Codex stderr (load-bearing for debug)
|
|
15
|
+
*
|
|
16
|
+
* Issue #2 §"核心设计要点": Dispatcher does NOT bind a worktree; cwd above
|
|
17
|
+
* is the codex daemon's own (intentionally empty) workdir. The dispatcher
|
|
18
|
+
* picks worktree per tm-call by passing `--worktree /repos/...` in shell.
|
|
19
|
+
*
|
|
20
|
+
* Issue ~/.dreamux/ config (feat/global-config-dir): paths.* functions
|
|
21
|
+
* read an optionally-injected `DreamuxConfig` snapshot for non-env
|
|
22
|
+
* defaults. Server.start() calls setRuntimeConfig() once at boot; bare
|
|
23
|
+
* tests / standalone callers fall back to the built-in defaults.
|
|
24
|
+
*/
|
|
25
|
+
import { homedir } from 'node:os';
|
|
26
|
+
import { join } from 'node:path';
|
|
27
|
+
import { BUILT_IN_DEFAULTS, expandHome, } from './config.js';
|
|
28
|
+
let currentConfig = BUILT_IN_DEFAULTS;
|
|
29
|
+
/**
|
|
30
|
+
* Set the active configuration snapshot. Called once by Server.start() with
|
|
31
|
+
* the result of loadOrInitConfig(); tests can call it to inject a custom
|
|
32
|
+
* snapshot. Idempotent.
|
|
33
|
+
*/
|
|
34
|
+
export function setRuntimeConfig(config) {
|
|
35
|
+
currentConfig = config;
|
|
36
|
+
}
|
|
37
|
+
/** Test hook: revert to the built-in defaults. */
|
|
38
|
+
export function resetRuntimeConfig() {
|
|
39
|
+
currentConfig = BUILT_IN_DEFAULTS;
|
|
40
|
+
}
|
|
41
|
+
export function getRuntimeConfig() {
|
|
42
|
+
return currentConfig;
|
|
43
|
+
}
|
|
44
|
+
export function runtimeRoot() {
|
|
45
|
+
const fromEnv = process.env['CODEX_HOST_RUNTIME_DIR'];
|
|
46
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
47
|
+
return fromEnv;
|
|
48
|
+
return expandHome(currentConfig.runtime_dir) || join(homedir(), '.codex-host');
|
|
49
|
+
}
|
|
50
|
+
export function databasePath() {
|
|
51
|
+
return join(runtimeRoot(), 'state.db');
|
|
52
|
+
}
|
|
53
|
+
export function adminSocketPath() {
|
|
54
|
+
const fromEnv = process.env['CODEX_HOST_ADMIN_SOCKET'];
|
|
55
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
56
|
+
return fromEnv;
|
|
57
|
+
if (currentConfig.admin_socket !== null) {
|
|
58
|
+
return expandHome(currentConfig.admin_socket);
|
|
59
|
+
}
|
|
60
|
+
return join(runtimeRoot(), 'admin.sock');
|
|
61
|
+
}
|
|
62
|
+
export function dispatcherDir(id) {
|
|
63
|
+
return join(runtimeRoot(), 'dispatchers', id);
|
|
64
|
+
}
|
|
65
|
+
export function dispatcherCodexCwd(id) {
|
|
66
|
+
return join(dispatcherDir(id), 'cwd');
|
|
67
|
+
}
|
|
68
|
+
export function dispatcherSocketPath(id) {
|
|
69
|
+
return join(dispatcherDir(id), 'socket');
|
|
70
|
+
}
|
|
71
|
+
export function dispatcherStdoutLog(id) {
|
|
72
|
+
return join(dispatcherDir(id), 'stdout.log');
|
|
73
|
+
}
|
|
74
|
+
export function dispatcherStderrLog(id) {
|
|
75
|
+
return join(dispatcherDir(id), 'stderr.log');
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/runtime/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EACL,iBAAiB,EACjB,UAAU,GAEX,MAAM,aAAa,CAAC;AAErB,IAAI,aAAa,GAAkB,iBAAiB,CAAC;AAErD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,aAAa,GAAG,MAAM,CAAC;AACzB,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,kBAAkB;IAChC,aAAa,GAAG,iBAAiB,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,OAAO,CAAC;IAC5D,OAAO,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,OAAO,CAAC;IAC5D,IAAI,aAAa,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QACxC,OAAO,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,YAAY,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAU;IAC3C,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,EAAU;IAC5C,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,EAAU;IAC5C,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve `bot_secret_ref` into the actual app secret.
|
|
3
|
+
*
|
|
4
|
+
* Issue #2 §"开放问题 Q9": P0 supports `env:VAR_NAME` only. Future references
|
|
5
|
+
* (keyring, 1Password, vault) are out of scope.
|
|
6
|
+
*/
|
|
7
|
+
export function resolveBotSecret(ref) {
|
|
8
|
+
if (!ref.startsWith('env:')) {
|
|
9
|
+
throw new Error(`unsupported bot_secret_ref scheme: ${ref}. P0 only supports env:<VAR>.`);
|
|
10
|
+
}
|
|
11
|
+
const varName = ref.slice('env:'.length);
|
|
12
|
+
const value = process.env[varName];
|
|
13
|
+
if (value === undefined || value === '') {
|
|
14
|
+
throw new Error(`bot secret env var '${varName}' is not set (referenced by bot_secret_ref=${ref})`);
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/runtime/secrets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,sCAAsC,GAAG,+BAA+B,CACzE,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,uBAAuB,OAAO,8CAA8C,GAAG,GAAG,CACnF,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|