golem-kit 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +8 -5
- package/docs/agents.md +64 -0
- package/docs/app-backend.md +261 -0
- package/docs/architecture.md +93 -0
- package/docs/builder.md +15 -0
- package/docs/knowledge.md +35 -0
- package/docs/local-cli.md +22 -12
- package/docs/source-development.md +31 -0
- package/index.html +9 -0
- package/package.json +24 -5
- package/src/backend/accounts.ts +287 -0
- package/src/backend/app.ts +269 -0
- package/src/backend/files.ts +68 -0
- package/src/backend/http.ts +276 -0
- package/src/backend/index.ts +10 -0
- package/src/backend/jobs.ts +302 -0
- package/src/backend/jsonl.ts +87 -0
- package/src/backend/knowledge.ts +264 -0
- package/src/backend/model.ts +129 -0
- package/src/backend/rules.ts +53 -0
- package/src/backend/sqlite.ts +73 -0
- package/src/backend/views.ts +216 -0
- package/src/brain.ts +94 -0
- package/src/browser/adapters.ts +229 -53
- package/src/browser/ansi.ts +104 -0
- package/src/browser/app.d.ts +5 -2
- package/src/browser/app.tsx +167 -39
- package/src/browser/groups.tsx +29 -0
- package/src/browser/main.tsx +1 -0
- package/src/browser/panekeys.ts +34 -0
- package/src/browser/sources.tsx +113 -0
- package/src/browser/styles.css +36 -0
- package/src/browser/terminal.tsx +89 -0
- package/src/browser-build.ts +25 -7
- package/src/chat.ts +74 -0
- package/src/cli.ts +103 -14
- package/src/client.ts +205 -0
- package/src/config.ts +139 -5
- package/src/dev-server.ts +336 -39
- package/src/entry.mjs +23 -0
- package/src/eslint.mjs +55 -0
- package/src/operations.ts +169 -0
- package/src/runtime/assistant.ts +141 -0
- package/src/runtime/discovery.ts +13 -7
- package/src/runtime/harness/agent-status.js +388 -0
- package/src/runtime/harness/claude-tmux.js +573 -0
- package/src/runtime/harness/codex-notify.js +95 -0
- package/src/runtime/harness/codex-tmux.js +292 -0
- package/src/runtime/harness/fake.js +430 -0
- package/src/runtime/harness/package.json +1 -0
- package/src/runtime/harness/port.js +208 -0
- package/src/runtime/harness/tmux-session.js +556 -0
- package/src/runtime/harness/tmux.js +285 -0
- package/src/runtime/harness/turnend-hook.js +105 -0
- package/src/runtime/session.ts +171 -34
- package/src/runtime/tmux.ts +173 -0
- package/src/runtime/tool-names.ts +19 -0
- package/src/source-mode.ts +56 -0
- package/vite.config.ts +2 -4
- package/src/runtime/codex.ts +0 -119
package/src/runtime/codex.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { spawn, type ChildProcess } from 'node:child_process'
|
|
2
|
-
import type { BackendEvent, SessionBackend } from './session.ts'
|
|
3
|
-
|
|
4
|
-
type JsonEvent = { type?: string; thread_id?: string; item?: { type?: string; text?: string }; error?: string; message?: string }
|
|
5
|
-
export type SandboxMode = 'read-only' | 'danger-full-access'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* One native `codex exec --json` process per turn; the thread id preserves continuity.
|
|
9
|
-
* `mode` is chosen by the caller (the dev server, from the session's explicit build intent),
|
|
10
|
-
* never defaulted here: an explicit build intent selects `danger-full-access`, a supported
|
|
11
|
-
* `-s`/`--sandbox` value (`codex exec --help`) that runs with the account's own ordinary
|
|
12
|
-
* filesystem permissions — not the `--dangerously-bypass-approvals-and-sandbox` omnibus flag,
|
|
13
|
-
* which is never used here; every other session stays `read-only`.
|
|
14
|
-
*
|
|
15
|
-
* `cwd`/`-C` are pinned to the resolved app root so Codex resolves relative paths correctly —
|
|
16
|
-
* not as a security boundary. A build-mode session can write anywhere this account can.
|
|
17
|
-
*/
|
|
18
|
-
export class CodexBackend implements SessionBackend {
|
|
19
|
-
private emit!: (event: BackendEvent) => void
|
|
20
|
-
private nativeThreadId: string | undefined
|
|
21
|
-
private child: ChildProcess | undefined
|
|
22
|
-
private request: Promise<void> | undefined
|
|
23
|
-
private interrupted = false
|
|
24
|
-
private childClosed: Promise<void> | undefined
|
|
25
|
-
private readonly cwd: string
|
|
26
|
-
private readonly mode: SandboxMode
|
|
27
|
-
private readonly executable: string
|
|
28
|
-
private readonly prefixArgs: string[]
|
|
29
|
-
|
|
30
|
-
constructor(cwd: string, mode: SandboxMode, executable = 'codex', prefixArgs: string[] = [], threadId?: string) {
|
|
31
|
-
this.cwd = cwd
|
|
32
|
-
this.mode = mode
|
|
33
|
-
this.executable = executable
|
|
34
|
-
this.prefixArgs = prefixArgs
|
|
35
|
-
this.nativeThreadId = threadId
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async start(emit: (event: BackendEvent) => void): Promise<void> { this.emit = emit }
|
|
39
|
-
|
|
40
|
-
threadId(): string | undefined { return this.nativeThreadId }
|
|
41
|
-
|
|
42
|
-
send(text: string): Promise<void> {
|
|
43
|
-
if (this.request) return Promise.reject(new Error('Codex is already handling a request'))
|
|
44
|
-
const args = this.nativeThreadId
|
|
45
|
-
? [...this.prefixArgs, 'exec', 'resume', this.nativeThreadId, '--json', '-c', `sandbox_mode="${this.mode}"`, '--skip-git-repo-check', text]
|
|
46
|
-
: [...this.prefixArgs, 'exec', '--json', '-s', this.mode, '-C', this.cwd, '--skip-git-repo-check', text]
|
|
47
|
-
this.request = new Promise((resolve, reject) => {
|
|
48
|
-
this.interrupted = false
|
|
49
|
-
const child = spawn(this.executable, args, { cwd: this.cwd, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, detached: process.platform !== 'win32' })
|
|
50
|
-
this.child = child
|
|
51
|
-
this.childClosed = new Promise((resolve) => child.once('close', () => resolve()))
|
|
52
|
-
let stderr = ''
|
|
53
|
-
let output = ''
|
|
54
|
-
let settled = false
|
|
55
|
-
const fail = (message: string) => {
|
|
56
|
-
if (settled) return
|
|
57
|
-
settled = true
|
|
58
|
-
this.emit({ type: 'error', message })
|
|
59
|
-
reject(new Error(message))
|
|
60
|
-
void this.stopChild(child)
|
|
61
|
-
}
|
|
62
|
-
child.stderr.setEncoding('utf8').on('data', (chunk) => { stderr += chunk })
|
|
63
|
-
child.stdout.setEncoding('utf8').on('data', (chunk) => {
|
|
64
|
-
output += String(chunk)
|
|
65
|
-
const lines = output.split('\n')
|
|
66
|
-
output = lines.pop() ?? ''
|
|
67
|
-
for (const line of lines.filter(Boolean)) {
|
|
68
|
-
let event: JsonEvent
|
|
69
|
-
try { event = JSON.parse(line) } catch { continue }
|
|
70
|
-
if (event.type === 'thread.started' && event.thread_id) this.nativeThreadId = event.thread_id
|
|
71
|
-
if (event.type === 'item.completed' && event.item?.type === 'agent_message' && event.item.text) {
|
|
72
|
-
this.emit({ type: 'message', text: event.item.text })
|
|
73
|
-
}
|
|
74
|
-
if (event.type === 'error' || event.type === 'turn.failed') fail(event.error ?? event.message ?? 'Codex request failed')
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
child.once('error', (error) => fail(error.message))
|
|
78
|
-
child.once('close', (code, signal) => {
|
|
79
|
-
this.child = undefined
|
|
80
|
-
this.childClosed = undefined
|
|
81
|
-
this.request = undefined
|
|
82
|
-
if (settled) return
|
|
83
|
-
if (code === 0 || this.interrupted) { settled = true; resolve(); return }
|
|
84
|
-
fail(stderr.trim() || (signal ? `Codex terminated by ${signal}` : `Codex exited with code ${code}`))
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
return this.request
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async interrupt(): Promise<void> {
|
|
91
|
-
if (!this.child) return
|
|
92
|
-
this.interrupted = true
|
|
93
|
-
await this.stopChild(this.child)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async shutdown(): Promise<void> {
|
|
97
|
-
if (this.child) await this.stopChild(this.child)
|
|
98
|
-
if (this.request) await this.request.catch(() => {})
|
|
99
|
-
this.child = undefined
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private async stopChild(child: ChildProcess): Promise<void> {
|
|
103
|
-
const closed = this.childClosed ?? new Promise<void>((resolve) => child.once('close', () => resolve()))
|
|
104
|
-
this.signal(child, 'SIGTERM')
|
|
105
|
-
// Always escalate the request group: its leader may exit after TERM while a child survives.
|
|
106
|
-
await new Promise<void>((resolve) => setTimeout(resolve, 250))
|
|
107
|
-
this.signal(child, 'SIGKILL')
|
|
108
|
-
await Promise.race([closed, new Promise<void>((resolve) => setTimeout(resolve, 750))])
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private signal(child: ChildProcess, signal: NodeJS.Signals): void {
|
|
112
|
-
try {
|
|
113
|
-
if (process.platform !== 'win32' && child.pid) process.kill(-child.pid, signal)
|
|
114
|
-
else child.kill(signal)
|
|
115
|
-
} catch (error) {
|
|
116
|
-
if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|