typeclaw 0.29.0 → 0.30.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/agent/index.ts +6 -0
- package/src/agent/live-subagents.ts +5 -0
- package/src/agent/plugin-tools.ts +66 -10
- package/src/agent/subagent-drain.ts +150 -0
- package/src/agent/subagents.ts +34 -3
- package/src/agent/tools/spawn-subagent.ts +13 -1
- package/src/bundled-plugins/bun-hygiene/README.md +12 -11
- package/src/bundled-plugins/bun-hygiene/policy.ts +8 -3
- package/src/bundled-plugins/github-cli-auth/approve-idempotency.ts +36 -16
- package/src/bundled-plugins/planner/planner.ts +2 -1
- package/src/bundled-plugins/researcher/researcher.ts +9 -2
- package/src/bundled-plugins/reviewer/reviewer.ts +2 -1
- package/src/channels/github-review-claim.ts +15 -3
- package/src/channels/router.ts +53 -0
- package/src/migrations/index.ts +35 -0
- package/src/migrations/secrets-v1-to-v2.ts +344 -0
- package/src/run/index.ts +13 -0
- package/src/sandbox/availability.ts +12 -0
- package/src/sandbox/build.ts +12 -0
- package/src/sandbox/index.ts +1 -1
- package/src/sandbox/policy.ts +8 -0
package/src/run/index.ts
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from '@/cron'
|
|
43
43
|
import { CLI_VERSION } from '@/init/cli-version'
|
|
44
44
|
import { createMcpManager } from '@/mcp'
|
|
45
|
+
import { runStartupMigrations } from '@/migrations'
|
|
45
46
|
import { loadPlugins, type LoadPluginsResult, pluginCronJobs, type PluginRegistry, summarizeLoaded } from '@/plugin'
|
|
46
47
|
import { createPluginLogger } from '@/plugin/context'
|
|
47
48
|
import type { CronHandlerContext } from '@/plugin/types'
|
|
@@ -194,6 +195,12 @@ export async function startAgent({
|
|
|
194
195
|
materializedSkills: null,
|
|
195
196
|
})
|
|
196
197
|
|
|
198
|
+
// Graduate any pre-0.20.0 on-disk shapes (v1 secrets.json, legacy auth.json)
|
|
199
|
+
// to the current v2 envelope before anything reads secrets — otherwise the
|
|
200
|
+
// v2-only parser rejects the file and hydrate below sees no channels. Runs
|
|
201
|
+
// exactly once per folder; a folder already at v2 is a no-op.
|
|
202
|
+
runStartupMigrations(cwd)
|
|
203
|
+
|
|
197
204
|
// Channel adapters read `process.env[TOKEN_ENV]` (see channels/manager.ts).
|
|
198
205
|
// Hydrate fills any unset env var from secrets.json#channels via env-wins:
|
|
199
206
|
// values already in process.env (from `docker --env-file .env`) are kept
|
|
@@ -329,6 +336,8 @@ export async function startAgent({
|
|
|
329
336
|
...(subagentOptions?.spawnedByRole !== undefined ? { spawnedByRole: subagentOptions.spawnedByRole } : {}),
|
|
330
337
|
...(subagentOptions?.spawnedByOrigin !== undefined ? { spawnedByOrigin: subagentOptions.spawnedByOrigin } : {}),
|
|
331
338
|
}
|
|
339
|
+
const allowBackgroundFromSubagent =
|
|
340
|
+
entry.pluginSubagent.canBackgroundSpawnSubagents === true && entry.pluginSubagent.canSpawnSubagents === true
|
|
332
341
|
const created = await createSessionWithDispose({
|
|
333
342
|
systemPromptOverride: entry.pluginSubagent.systemPrompt,
|
|
334
343
|
sessionManager,
|
|
@@ -359,6 +368,7 @@ export async function startAgent({
|
|
|
359
368
|
liveSubagentRegistry,
|
|
360
369
|
subagentRegistry: snap.subagents,
|
|
361
370
|
createSessionForSubagent,
|
|
371
|
+
allowBackgroundFromSubagent,
|
|
362
372
|
}
|
|
363
373
|
: {}),
|
|
364
374
|
...(entry.pluginSubagent.profile !== undefined ? { profile: entry.pluginSubagent.profile } : {}),
|
|
@@ -380,6 +390,9 @@ export async function startAgent({
|
|
|
380
390
|
agentDir: cwd,
|
|
381
391
|
origin,
|
|
382
392
|
getTranscriptPath: () => sessionManager.getSessionFile(),
|
|
393
|
+
...(allowBackgroundFromSubagent
|
|
394
|
+
? { backgroundDrain: { stream, sessionId, liveRegistry: liveSubagentRegistry } }
|
|
395
|
+
: {}),
|
|
383
396
|
}
|
|
384
397
|
}
|
|
385
398
|
return defaultCreateSessionForSubagent(subagent, subagentOptions)
|
|
@@ -33,3 +33,15 @@ async function probe(bwrap: string): Promise<boolean> {
|
|
|
33
33
|
export function _resetBwrapAvailabilityCacheForTests(): void {
|
|
34
34
|
availabilityCache.clear()
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
// The bun binary this process runs as (process.execPath). build.ts re-exposes
|
|
38
|
+
// it at /proc/self/exe over the masked /proc so sandboxed package runners can
|
|
39
|
+
// self-locate. This is correct ONLY in the bun-centric container: the base
|
|
40
|
+
// image (oven/bun:1-slim) ships no real node — `node` is a bun symlink and
|
|
41
|
+
// bunx/npx/pnpx all resolve to bun (Bun's fake-node model), so every runtime
|
|
42
|
+
// reading /proc/self/exe IS bun. A real node binary would self-locate to the
|
|
43
|
+
// wrong ELF here; if node is ever added to the image this must resolve the
|
|
44
|
+
// actual interpreter instead.
|
|
45
|
+
export function resolveProcSelfExe(): string {
|
|
46
|
+
return process.execPath
|
|
47
|
+
}
|
package/src/sandbox/build.ts
CHANGED
|
@@ -103,6 +103,18 @@ function buildArgv(command: string, policy: SandboxPolicy): string[] {
|
|
|
103
103
|
// (leaks the outer container's /proc/N/environ — including
|
|
104
104
|
// FIREWORKS_API_KEY — into the sandbox). See sandbox.mdx.
|
|
105
105
|
argv.push('--tmpfs', '/proc')
|
|
106
|
+
|
|
107
|
+
// Re-expose ONLY the bun ELF at /proc/self/exe so sandboxed package runners
|
|
108
|
+
// can self-locate; /proc/N/environ stays masked by the tmpfs above. The
|
|
109
|
+
// caller passes bun's path (see resolveProcSelfExe): in this bun-centric
|
|
110
|
+
// container bunx/npx/pnpx all resolve to bun, so bun IS the runtime reading
|
|
111
|
+
// /proc/self/exe. --symlink (not --ro-bind /proc/self/exe): /proc/self at
|
|
112
|
+
// setup time is bwrap's pid, so a bind would capture bwrap's own binary.
|
|
113
|
+
// Must come AFTER --tmpfs /proc (last-op-wins) or the tmpfs erases it.
|
|
114
|
+
if (policy.procSelfExe !== undefined) {
|
|
115
|
+
argv.push('--ro-bind', policy.procSelfExe, policy.procSelfExe)
|
|
116
|
+
argv.push('--symlink', policy.procSelfExe, '/proc/self/exe')
|
|
117
|
+
}
|
|
106
118
|
}
|
|
107
119
|
|
|
108
120
|
for (const mount of policy.mounts ?? []) {
|
package/src/sandbox/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { buildSandboxedCommand, type SandboxedCommand } from './build'
|
|
2
|
-
export { ensureBwrapAvailable, _resetBwrapAvailabilityCacheForTests } from './availability'
|
|
2
|
+
export { ensureBwrapAvailable, resolveProcSelfExe, _resetBwrapAvailabilityCacheForTests } from './availability'
|
|
3
3
|
export { resolveHiddenPaths, type HiddenPaths } from './hidden-paths'
|
|
4
4
|
export {
|
|
5
5
|
resolveProtectedZones,
|
package/src/sandbox/policy.ts
CHANGED
|
@@ -60,6 +60,14 @@ export type SandboxProtectedPolicy = {
|
|
|
60
60
|
export type SandboxPolicy = {
|
|
61
61
|
bwrapPath?: string
|
|
62
62
|
cwd?: string
|
|
63
|
+
// Concrete host interpreter ELF (the running bun binary) re-exposed at
|
|
64
|
+
// /proc/self/exe over the --tmpfs /proc mask. JS runtimes self-locate via
|
|
65
|
+
// /proc/self/exe; under the empty tmpfs /proc that read fails and bunx panics
|
|
66
|
+
// in createFakeTemporaryNodeExecutable. A direct --ro-bind of /proc/self/exe
|
|
67
|
+
// is wrong: at bwrap setup time /proc/self is bwrap's pid, so it captures the
|
|
68
|
+
// bwrap binary, not the child runtime. The caller resolves this path (I/O);
|
|
69
|
+
// the builder stays pure.
|
|
70
|
+
procSelfExe?: string
|
|
63
71
|
mounts?: SandboxMount[]
|
|
64
72
|
masks?: SandboxMaskPolicy
|
|
65
73
|
writable?: SandboxWritablePolicy
|