typeclaw 0.36.8 → 0.37.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.
Files changed (111) hide show
  1. package/README.md +2 -2
  2. package/package.json +3 -2
  3. package/src/agent/index.ts +31 -11
  4. package/src/agent/live-sessions.ts +12 -0
  5. package/src/agent/model-fallback.ts +17 -15
  6. package/src/agent/model-overrides.ts +2 -2
  7. package/src/agent/session-meta.ts +10 -0
  8. package/src/agent/subagents.ts +11 -2
  9. package/src/agent/system-prompt.ts +9 -3
  10. package/src/agent/todo/continuation-policy.ts +6 -3
  11. package/src/agent/todo/continuation-wiring.ts +4 -2
  12. package/src/agent/todo/continuation.ts +3 -3
  13. package/src/agent/tools/todo/index.ts +27 -4
  14. package/src/bundled-plugins/agent-browser/index.ts +33 -108
  15. package/src/bundled-plugins/agent-browser/shim.ts +3 -94
  16. package/src/bundled-plugins/agent-browser/skills/agent-browser/SKILL.md +8 -33
  17. package/src/bundled-plugins/doc-render/skills/typeclaw-render-pdf/SKILL.md +2 -2
  18. package/src/bundled-plugins/guard/policies/memory-retrieval-cache-write.ts +7 -1
  19. package/src/bundled-plugins/memory/README.md +80 -23
  20. package/src/bundled-plugins/memory/append-tool.ts +74 -53
  21. package/src/bundled-plugins/memory/citation-superset.ts +4 -0
  22. package/src/bundled-plugins/memory/citations.ts +54 -0
  23. package/src/bundled-plugins/memory/dreaming-metrics.ts +30 -0
  24. package/src/bundled-plugins/memory/dreaming.ts +444 -21
  25. package/src/bundled-plugins/memory/index.ts +544 -400
  26. package/src/bundled-plugins/memory/load-memory.ts +87 -10
  27. package/src/bundled-plugins/memory/load-shards.ts +48 -22
  28. package/src/bundled-plugins/memory/memory-logger.ts +95 -106
  29. package/src/bundled-plugins/memory/memory-retrieval.ts +3 -3
  30. package/src/bundled-plugins/memory/parent-link.ts +33 -0
  31. package/src/bundled-plugins/memory/paths.ts +12 -0
  32. package/src/bundled-plugins/memory/references/frontmatter.ts +197 -0
  33. package/src/bundled-plugins/memory/references/load-references.ts +212 -0
  34. package/src/bundled-plugins/memory/references/store-reference-tool.ts +59 -0
  35. package/src/bundled-plugins/memory/search-tool.ts +282 -45
  36. package/src/bundled-plugins/memory/stream-events.ts +1 -0
  37. package/src/bundled-plugins/memory/stream-io.ts +28 -3
  38. package/src/bundled-plugins/memory/turn-dedup.ts +40 -0
  39. package/src/bundled-plugins/memory/vector/cache-write.ts +19 -0
  40. package/src/bundled-plugins/memory/vector/config.ts +28 -0
  41. package/src/bundled-plugins/memory/vector/doctor.ts +124 -0
  42. package/src/bundled-plugins/memory/vector/embedder.ts +246 -0
  43. package/src/bundled-plugins/memory/vector/hybrid.ts +439 -0
  44. package/src/bundled-plugins/memory/vector/index-on-write.ts +34 -0
  45. package/src/bundled-plugins/memory/vector/inspect.ts +111 -0
  46. package/src/bundled-plugins/memory/vector/passages.ts +125 -0
  47. package/src/bundled-plugins/memory/vector/reference-index-on-write.ts +50 -0
  48. package/src/bundled-plugins/memory/vector/relevance-gate.ts +93 -0
  49. package/src/bundled-plugins/memory/vector/startup.ts +71 -0
  50. package/src/bundled-plugins/memory/vector/store.ts +203 -0
  51. package/src/bundled-plugins/memory/vector/truncation.ts +124 -0
  52. package/src/bundled-plugins/security/policies/outbound-secret-scan.ts +2 -0
  53. package/src/channels/router.ts +239 -40
  54. package/src/cli/incomplete-init.ts +57 -0
  55. package/src/cli/init.ts +143 -12
  56. package/src/cli/inspect.ts +11 -5
  57. package/src/cli/model.ts +112 -34
  58. package/src/cli/restart.ts +24 -0
  59. package/src/cli/start.ts +24 -0
  60. package/src/cli/tunnel.ts +53 -8
  61. package/src/config/config.ts +110 -19
  62. package/src/config/index.ts +5 -1
  63. package/src/config/models-mutation.ts +29 -11
  64. package/src/config/providers-mutation.ts +2 -2
  65. package/src/config/providers.ts +146 -12
  66. package/src/container/shared.ts +9 -0
  67. package/src/container/start.ts +87 -4
  68. package/src/cron/consumer.ts +13 -7
  69. package/src/hostd/models.ts +64 -0
  70. package/src/hostd/paths.ts +6 -0
  71. package/src/hostd/portbroker-manager.ts +2 -2
  72. package/src/init/checkpoint.ts +201 -0
  73. package/src/init/dockerfile.ts +121 -34
  74. package/src/init/gitignore.ts +7 -7
  75. package/src/init/index.ts +41 -9
  76. package/src/init/models-dev.ts +96 -21
  77. package/src/init/oauth-login.ts +3 -3
  78. package/src/init/progress.ts +29 -0
  79. package/src/init/validate-api-key.ts +4 -0
  80. package/src/inspect/index.ts +13 -6
  81. package/src/inspect/item-list.ts +11 -2
  82. package/src/inspect/live-list.ts +65 -0
  83. package/src/inspect/open-item.ts +22 -1
  84. package/src/inspect/session-list.ts +29 -0
  85. package/src/models/embedding-model.ts +114 -0
  86. package/src/models/transformers-version.ts +55 -0
  87. package/src/plugin/types.ts +3 -0
  88. package/src/portbroker/container-server.ts +23 -0
  89. package/src/portbroker/forward-request-bus.ts +35 -0
  90. package/src/portbroker/forward-result-bus.ts +2 -3
  91. package/src/portbroker/hostd-client.ts +182 -36
  92. package/src/portbroker/index.ts +6 -1
  93. package/src/portbroker/protocol.ts +9 -2
  94. package/src/run/channel-session-factory.ts +11 -1
  95. package/src/run/index.ts +41 -7
  96. package/src/server/command-runner.ts +24 -1
  97. package/src/server/index.ts +42 -8
  98. package/src/shared/index.ts +2 -0
  99. package/src/shared/protocol.ts +31 -0
  100. package/src/skills/typeclaw-channels/SKILL.md +4 -4
  101. package/src/skills/typeclaw-config/SKILL.md +2 -2
  102. package/src/skills/typeclaw-memory/SKILL.md +3 -1
  103. package/src/skills/typeclaw-permissions/SKILL.md +3 -3
  104. package/src/skills/typeclaw-skills/SKILL.md +1 -1
  105. package/src/skills/typeclaw-tunnels/SKILL.md +22 -1
  106. package/src/tunnels/providers/cloudflare-quick.ts +65 -7
  107. package/src/tunnels/upstream-probe.ts +25 -0
  108. package/typeclaw.schema.json +156 -67
  109. package/src/bundled-plugins/agent-browser/dashboard-discovery.ts +0 -170
  110. package/src/bundled-plugins/agent-browser/dashboard-proxy.ts +0 -421
  111. package/src/portbroker/bind-with-forward.ts +0 -102
@@ -20,84 +20,158 @@
20
20
  "additionalProperties": {
21
21
  "anyOf": [
22
22
  {
23
- "type": "string",
24
- "enum": [
25
- "openai/gpt-5.4-nano",
26
- "openai/gpt-5.4-mini",
27
- "openai/gpt-5.4",
28
- "openai/gpt-5.5",
29
- "openai-codex/gpt-5.4-mini",
30
- "openai-codex/gpt-5.4",
31
- "openai-codex/gpt-5.5",
32
- "anthropic/claude-haiku-4-5",
33
- "anthropic/claude-sonnet-4-6",
34
- "anthropic/claude-opus-4-7",
35
- "anthropic/claude-opus-4-8",
36
- "fireworks/accounts/fireworks/routers/kimi-k2p6-turbo",
37
- "zai/glm-4.5-air",
38
- "zai/glm-4.6",
39
- "zai/glm-4.7",
40
- "zai-coding/glm-4.5-air",
41
- "zai-coding/glm-4.7",
42
- "zai-coding/glm-5",
43
- "zai-coding/glm-5-turbo",
44
- "zai-coding/glm-5.1",
45
- "xai/grok-4.3",
46
- "xai/grok-4.20-0309-reasoning",
47
- "xai/grok-4.20-0309-non-reasoning",
48
- "xai/grok-build-0.1",
49
- "minimax/MiniMax-M3",
50
- "minimax/MiniMax-M2.7",
51
- "minimax/MiniMax-M2.5",
52
- "minimax/MiniMax-M2.1",
53
- "minimax/MiniMax-M2",
54
- "deepseek/deepseek-v4-flash",
55
- "deepseek/deepseek-v4-pro"
23
+ "anyOf": [
24
+ {
25
+ "type": "string",
26
+ "enum": [
27
+ "openai/gpt-5.4-nano",
28
+ "openai/gpt-5.4-mini",
29
+ "openai/gpt-5.4",
30
+ "openai/gpt-5.5",
31
+ "openai-codex/gpt-5.4-mini",
32
+ "openai-codex/gpt-5.4",
33
+ "openai-codex/gpt-5.5",
34
+ "anthropic/claude-haiku-4-5",
35
+ "anthropic/claude-sonnet-4-6",
36
+ "anthropic/claude-opus-4-7",
37
+ "anthropic/claude-opus-4-8",
38
+ "fireworks/accounts/fireworks/routers/kimi-k2p6-turbo",
39
+ "zai/glm-4.5-air",
40
+ "zai/glm-4.6",
41
+ "zai/glm-4.7",
42
+ "zai-coding/glm-4.5-air",
43
+ "zai-coding/glm-4.7",
44
+ "zai-coding/glm-5",
45
+ "zai-coding/glm-5-turbo",
46
+ "zai-coding/glm-5.1",
47
+ "xai/grok-4.3",
48
+ "xai/grok-4.20-0309-reasoning",
49
+ "xai/grok-4.20-0309-non-reasoning",
50
+ "xai/grok-build-0.1",
51
+ "minimax/MiniMax-M3",
52
+ "minimax/MiniMax-M2.7",
53
+ "minimax/MiniMax-M2.5",
54
+ "minimax/MiniMax-M2.1",
55
+ "minimax/MiniMax-M2",
56
+ "deepseek/deepseek-v4-flash",
57
+ "deepseek/deepseek-v4-pro",
58
+ "moonshot/kimi-k2.7-code",
59
+ "moonshot/kimi-k2.6",
60
+ "moonshot/kimi-k2.5",
61
+ "moonshot-coding/kimi-for-coding"
62
+ ]
63
+ },
64
+ {
65
+ "type": "string"
66
+ }
56
67
  ]
57
68
  },
58
69
  {
59
70
  "minItems": 1,
60
71
  "type": "array",
61
72
  "items": {
62
- "type": "string",
63
- "enum": [
64
- "openai/gpt-5.4-nano",
65
- "openai/gpt-5.4-mini",
66
- "openai/gpt-5.4",
67
- "openai/gpt-5.5",
68
- "openai-codex/gpt-5.4-mini",
69
- "openai-codex/gpt-5.4",
70
- "openai-codex/gpt-5.5",
71
- "anthropic/claude-haiku-4-5",
72
- "anthropic/claude-sonnet-4-6",
73
- "anthropic/claude-opus-4-7",
74
- "anthropic/claude-opus-4-8",
75
- "fireworks/accounts/fireworks/routers/kimi-k2p6-turbo",
76
- "zai/glm-4.5-air",
77
- "zai/glm-4.6",
78
- "zai/glm-4.7",
79
- "zai-coding/glm-4.5-air",
80
- "zai-coding/glm-4.7",
81
- "zai-coding/glm-5",
82
- "zai-coding/glm-5-turbo",
83
- "zai-coding/glm-5.1",
84
- "xai/grok-4.3",
85
- "xai/grok-4.20-0309-reasoning",
86
- "xai/grok-4.20-0309-non-reasoning",
87
- "xai/grok-build-0.1",
88
- "minimax/MiniMax-M3",
89
- "minimax/MiniMax-M2.7",
90
- "minimax/MiniMax-M2.5",
91
- "minimax/MiniMax-M2.1",
92
- "minimax/MiniMax-M2",
93
- "deepseek/deepseek-v4-flash",
94
- "deepseek/deepseek-v4-pro"
73
+ "anyOf": [
74
+ {
75
+ "type": "string",
76
+ "enum": [
77
+ "openai/gpt-5.4-nano",
78
+ "openai/gpt-5.4-mini",
79
+ "openai/gpt-5.4",
80
+ "openai/gpt-5.5",
81
+ "openai-codex/gpt-5.4-mini",
82
+ "openai-codex/gpt-5.4",
83
+ "openai-codex/gpt-5.5",
84
+ "anthropic/claude-haiku-4-5",
85
+ "anthropic/claude-sonnet-4-6",
86
+ "anthropic/claude-opus-4-7",
87
+ "anthropic/claude-opus-4-8",
88
+ "fireworks/accounts/fireworks/routers/kimi-k2p6-turbo",
89
+ "zai/glm-4.5-air",
90
+ "zai/glm-4.6",
91
+ "zai/glm-4.7",
92
+ "zai-coding/glm-4.5-air",
93
+ "zai-coding/glm-4.7",
94
+ "zai-coding/glm-5",
95
+ "zai-coding/glm-5-turbo",
96
+ "zai-coding/glm-5.1",
97
+ "xai/grok-4.3",
98
+ "xai/grok-4.20-0309-reasoning",
99
+ "xai/grok-4.20-0309-non-reasoning",
100
+ "xai/grok-build-0.1",
101
+ "minimax/MiniMax-M3",
102
+ "minimax/MiniMax-M2.7",
103
+ "minimax/MiniMax-M2.5",
104
+ "minimax/MiniMax-M2.1",
105
+ "minimax/MiniMax-M2",
106
+ "deepseek/deepseek-v4-flash",
107
+ "deepseek/deepseek-v4-pro",
108
+ "moonshot/kimi-k2.7-code",
109
+ "moonshot/kimi-k2.6",
110
+ "moonshot/kimi-k2.5",
111
+ "moonshot-coding/kimi-for-coding"
112
+ ]
113
+ },
114
+ {
115
+ "type": "string"
116
+ }
95
117
  ]
96
118
  }
97
119
  }
98
120
  ]
99
121
  }
100
122
  },
123
+ "customModels": {
124
+ "default": {},
125
+ "type": "object",
126
+ "propertyNames": {
127
+ "type": "string",
128
+ "minLength": 1
129
+ },
130
+ "additionalProperties": {
131
+ "type": "object",
132
+ "properties": {
133
+ "name": {
134
+ "type": "string",
135
+ "minLength": 1
136
+ },
137
+ "reasoning": {
138
+ "type": "boolean"
139
+ },
140
+ "input": {
141
+ "type": "array",
142
+ "items": {
143
+ "type": "string",
144
+ "minLength": 1
145
+ }
146
+ },
147
+ "contextWindow": {
148
+ "type": "number"
149
+ },
150
+ "maxTokens": {
151
+ "type": "number"
152
+ },
153
+ "cost": {
154
+ "type": "object",
155
+ "properties": {
156
+ "input": {
157
+ "type": "number"
158
+ },
159
+ "output": {
160
+ "type": "number"
161
+ },
162
+ "cacheRead": {
163
+ "type": "number"
164
+ },
165
+ "cacheWrite": {
166
+ "type": "number"
167
+ }
168
+ },
169
+ "additionalProperties": {}
170
+ }
171
+ },
172
+ "additionalProperties": {}
173
+ }
174
+ },
101
175
  "mounts": {
102
176
  "default": [],
103
177
  "type": "array",
@@ -1632,7 +1706,10 @@
1632
1706
  "injectionBudgetBytes": 16384,
1633
1707
  "minIdleDeltaLines": 3,
1634
1708
  "spawnTimeoutMs": 50000,
1635
- "retrievalSpawnTimeoutMs": 30000
1709
+ "retrievalSpawnTimeoutMs": 30000,
1710
+ "vector": {
1711
+ "enabled": false
1712
+ }
1636
1713
  },
1637
1714
  "type": "object",
1638
1715
  "properties": {
@@ -1680,6 +1757,18 @@
1680
1757
  "minLength": 1
1681
1758
  }
1682
1759
  }
1760
+ },
1761
+ "vector": {
1762
+ "default": {
1763
+ "enabled": false
1764
+ },
1765
+ "type": "object",
1766
+ "properties": {
1767
+ "enabled": {
1768
+ "default": false,
1769
+ "type": "boolean"
1770
+ }
1771
+ }
1683
1772
  }
1684
1773
  }
1685
1774
  },
@@ -1,170 +0,0 @@
1
- // Discovers the actual port the agent-browser dashboard daemon is listening
2
- // on. Necessary because the previous design hardcoded 4849 in the proxy and
3
- // trusted the shim to force upstream onto that port — but the shim is bypass-
4
- // able (someone runs `bunx agent-browser dashboard --port 9999`, the binary
5
- // gets invoked from a path that isn't shimmed, an old container leaves a
6
- // stale daemon, etc.). The proxy now consults this module to find the
7
- // dashboard wherever it actually is.
8
- //
9
- // Two-stage discovery, fastest signal first:
10
- //
11
- // 1. Hint file at PORT_HINT_PATH. The shim writes the port it asked
12
- // upstream to bind to (via the rewritten --port). If the file exists,
13
- // points at a port, AND that port currently has a LISTEN socket we
14
- // can fast-probe with HEAD /api/sessions, we use it. Zero I/O on the
15
- // hot path beyond a small file read.
16
- //
17
- // 2. Fallback: read the dashboard's own pidfile at DASHBOARD_PID_PATH
18
- // (written by upstream itself). If the PID is alive, scan
19
- // /proc/<pid>/fd for socket inodes, cross-reference with /proc/net/tcp
20
- // to find LISTEN sockets owned by that PID, drop the proxy's own port,
21
- // probe each remaining port with HEAD /api/sessions, return the
22
- // first that responds 2xx. Linux-only, which is fine — typeclaw runs
23
- // in a Linux container.
24
- //
25
- // The fallback is what makes "agent uses other port" work when the shim
26
- // doesn't catch the call. Without it, the proxy is stuck at whatever port
27
- // it was configured with and silently 502s on a moved dashboard.
28
-
29
- import { existsSync, readdirSync, readFileSync, readlinkSync } from 'node:fs'
30
-
31
- export const PORT_HINT_PATH = '/tmp/typeclaw-agent-browser-upstream-port'
32
- export const DASHBOARD_PID_PATH = '/root/.agent-browser/dashboard.pid'
33
- const DEFAULT_PROBE_TIMEOUT_MS = 250
34
-
35
- export type DiscoveryOptions = {
36
- hintPath?: string
37
- pidPath?: string
38
- excludePort?: number
39
- fetchImpl?: typeof fetch
40
- probeTimeoutMs?: number
41
- procfs?: ProcFs
42
- }
43
-
44
- export type ProcFs = {
45
- pidExists: (pid: number) => boolean
46
- listenInodesForPid: (pid: number) => Set<string>
47
- listenSockets: () => Array<{ port: number; inode: string }>
48
- }
49
-
50
- export async function discoverDashboardPort(opts: DiscoveryOptions = {}): Promise<number | null> {
51
- const hintPath = opts.hintPath ?? PORT_HINT_PATH
52
- const pidPath = opts.pidPath ?? DASHBOARD_PID_PATH
53
- const fetcher = opts.fetchImpl ?? fetch
54
- const probeTimeout = opts.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS
55
- const procfs = opts.procfs ?? defaultProcFs()
56
-
57
- const hint = readPortHint(hintPath)
58
- if (hint !== null && (await isDashboardPort(hint, fetcher, probeTimeout))) return hint
59
-
60
- const pidContents = readPidFile(pidPath)
61
- if (pidContents === null) return null
62
- if (!procfs.pidExists(pidContents)) return null
63
-
64
- const pidInodes = procfs.listenInodesForPid(pidContents)
65
- const candidates: number[] = []
66
- for (const socket of procfs.listenSockets()) {
67
- if (!pidInodes.has(socket.inode)) continue
68
- if (opts.excludePort !== undefined && socket.port === opts.excludePort) continue
69
- candidates.push(socket.port)
70
- }
71
-
72
- for (const port of candidates) {
73
- if (await isDashboardPort(port, fetcher, probeTimeout)) return port
74
- }
75
- return null
76
- }
77
-
78
- export function writePortHint(port: number, hintPath: string = PORT_HINT_PATH): void {
79
- Bun.write(hintPath, String(port))
80
- }
81
-
82
- function readPortHint(path: string): number | null {
83
- try {
84
- const raw = readFileSync(path, 'utf-8').trim()
85
- const port = Number(raw)
86
- if (!Number.isInteger(port) || port < 1 || port > 65_535) return null
87
- return port
88
- } catch {
89
- return null
90
- }
91
- }
92
-
93
- function readPidFile(path: string): number | null {
94
- try {
95
- const raw = readFileSync(path, 'utf-8').trim()
96
- const pid = Number(raw)
97
- if (!Number.isInteger(pid) || pid < 1) return null
98
- return pid
99
- } catch {
100
- return null
101
- }
102
- }
103
-
104
- async function isDashboardPort(port: number, fetcher: typeof fetch, timeoutMs: number): Promise<boolean> {
105
- const ctrl = new AbortController()
106
- const timer = setTimeout(() => ctrl.abort(), timeoutMs)
107
- try {
108
- const res = await fetcher(`http://127.0.0.1:${port}/api/sessions`, {
109
- method: 'GET',
110
- signal: ctrl.signal,
111
- })
112
- return res.ok
113
- } catch {
114
- return false
115
- } finally {
116
- clearTimeout(timer)
117
- }
118
- }
119
-
120
- function defaultProcFs(): ProcFs {
121
- return {
122
- pidExists: (pid) => existsSync(`/proc/${pid}`),
123
- listenInodesForPid: (pid) => {
124
- const inodes = new Set<string>()
125
- const fdDir = `/proc/${pid}/fd`
126
- let entries: string[]
127
- try {
128
- entries = readdirSync(fdDir)
129
- } catch {
130
- return inodes
131
- }
132
- for (const entry of entries) {
133
- try {
134
- const target = readlinkSync(`${fdDir}/${entry}`)
135
- const match = target.match(/^socket:\[(\d+)\]$/)
136
- if (match) inodes.add(match[1]!)
137
- } catch {
138
- continue
139
- }
140
- }
141
- return inodes
142
- },
143
- listenSockets: () => {
144
- const out: Array<{ port: number; inode: string }> = []
145
- for (const file of ['/proc/net/tcp', '/proc/net/tcp6']) {
146
- let raw: string
147
- try {
148
- raw = readFileSync(file, 'utf-8')
149
- } catch {
150
- continue
151
- }
152
- const lines = raw.split('\n').slice(1)
153
- for (const line of lines) {
154
- const cols = line.trim().split(/\s+/)
155
- if (cols.length < 10) continue
156
- if (cols[3] !== '0A') continue
157
- const local = cols[1] ?? ''
158
- const colonIdx = local.lastIndexOf(':')
159
- if (colonIdx < 0) continue
160
- const port = Number.parseInt(local.slice(colonIdx + 1), 16)
161
- if (!Number.isInteger(port) || port < 1 || port > 65_535) continue
162
- const inode = cols[9]
163
- if (inode === undefined) continue
164
- out.push({ port, inode })
165
- }
166
- }
167
- return out
168
- },
169
- }
170
- }