typeclaw 0.1.4 → 0.1.6
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/README.md +15 -13
- package/auth.schema.json +41 -0
- package/cron.schema.json +8 -0
- package/package.json +1 -1
- package/secrets.schema.json +41 -0
- package/src/agent/auth.ts +45 -22
- package/src/agent/index.ts +189 -19
- package/src/agent/multimodal/index.ts +12 -0
- package/src/agent/multimodal/look-at.ts +185 -0
- package/src/agent/multimodal/looker.ts +145 -0
- package/src/agent/plugin-tools.ts +30 -1
- package/src/agent/session-origin.ts +194 -46
- package/src/agent/subagents.ts +57 -1
- package/src/agent/system-prompt.ts +1 -1
- package/src/agent/tool-result-budget.ts +121 -0
- package/src/bundled-plugins/backup/index.ts +23 -8
- package/src/bundled-plugins/backup/runner.ts +22 -0
- package/src/bundled-plugins/memory/README.md +13 -10
- package/src/bundled-plugins/memory/append-tool.ts +87 -61
- package/src/bundled-plugins/memory/dreaming.ts +137 -7
- package/src/bundled-plugins/memory/find-entry-tool.ts +62 -0
- package/src/bundled-plugins/memory/fragment-parser.ts +19 -44
- package/src/bundled-plugins/memory/index.ts +91 -8
- package/src/bundled-plugins/memory/load-memory.ts +74 -34
- package/src/bundled-plugins/memory/memory-logger.ts +72 -29
- package/src/bundled-plugins/memory/migration.ts +276 -0
- package/src/bundled-plugins/memory/stream-events.ts +55 -0
- package/src/bundled-plugins/memory/stream-io.ts +63 -0
- package/src/bundled-plugins/memory/watermark.ts +48 -8
- package/src/bundled-plugins/security/index.ts +103 -10
- package/src/bundled-plugins/security/permissions.ts +12 -0
- package/src/bundled-plugins/security/policies/git-exfil.ts +51 -18
- package/src/bundled-plugins/tool-result-cap/README.md +9 -4
- package/src/bundled-plugins/tool-result-cap/cap-jsonl.ts +115 -0
- package/src/bundled-plugins/tool-result-cap/cap-result.ts +25 -13
- package/src/bundled-plugins/tool-result-cap/index.ts +16 -2
- package/src/channels/adapters/discord-bot-classify.ts +2 -6
- package/src/channels/adapters/discord-bot.ts +4 -45
- package/src/channels/adapters/kakaotalk-classify.ts +3 -7
- package/src/channels/adapters/kakaotalk.ts +28 -47
- package/src/channels/adapters/slack-bot-classify.ts +2 -6
- package/src/channels/adapters/slack-bot.ts +4 -50
- package/src/channels/adapters/telegram-bot-classify.ts +8 -10
- package/src/channels/adapters/telegram-bot.ts +3 -16
- package/src/channels/index.ts +3 -2
- package/src/channels/manager.ts +15 -1
- package/src/channels/persistence.ts +44 -10
- package/src/channels/router.ts +228 -19
- package/src/channels/schema.ts +6 -156
- package/src/cli/channel.ts +200 -4
- package/src/cli/compose-usage.ts +182 -0
- package/src/cli/compose.ts +33 -0
- package/src/cli/hostd.ts +49 -1
- package/src/cli/index.ts +4 -0
- package/src/cli/init.ts +809 -300
- package/src/cli/model.ts +244 -0
- package/src/cli/provider.ts +404 -0
- package/src/cli/reload.ts +11 -3
- package/src/cli/role.ts +156 -0
- package/src/cli/run.ts +3 -1
- package/src/cli/tui.ts +13 -3
- package/src/cli/usage-args.ts +47 -0
- package/src/cli/usage.ts +97 -0
- package/src/compose/index.ts +1 -0
- package/src/compose/usage.ts +65 -0
- package/src/config/config.ts +491 -19
- package/src/config/index.ts +15 -1
- package/src/config/models-mutation.ts +200 -0
- package/src/config/providers-mutation.ts +250 -0
- package/src/config/providers.ts +141 -2
- package/src/config/reloadable.ts +15 -4
- package/src/container/index.ts +6 -1
- package/src/container/port.ts +10 -0
- package/src/container/require-running.ts +33 -0
- package/src/container/start.ts +81 -63
- package/src/cron/consumer.ts +22 -2
- package/src/cron/index.ts +45 -4
- package/src/cron/schema.ts +104 -0
- package/src/doctor/checks.ts +51 -34
- package/src/doctor/plugin-bridge.ts +28 -4
- package/src/git/system-commit.ts +103 -0
- package/src/hostd/daemon.ts +16 -0
- package/src/hostd/kakao-renewal-manager.ts +223 -0
- package/src/hostd/paths.ts +7 -0
- package/src/init/dockerfile.ts +36 -10
- package/src/init/gitignore.ts +1 -1
- package/src/init/index.ts +213 -85
- package/src/init/kakaotalk-auth.ts +18 -1
- package/src/init/models-dev.ts +26 -1
- package/src/init/run-owner-claim.ts +77 -0
- package/src/permissions/builtins.ts +70 -0
- package/src/permissions/grant.ts +99 -0
- package/src/permissions/index.ts +29 -0
- package/src/permissions/match-rule.ts +305 -0
- package/src/permissions/permissions.ts +196 -0
- package/src/permissions/resolve.ts +80 -0
- package/src/permissions/schema.ts +79 -0
- package/src/plugin/context.ts +8 -4
- package/src/plugin/define.ts +2 -0
- package/src/plugin/index.ts +2 -0
- package/src/plugin/manager.ts +41 -0
- package/src/plugin/registry.ts +9 -0
- package/src/plugin/types.ts +35 -1
- package/src/reload/client.ts +25 -1
- package/src/role-claim/client.ts +182 -0
- package/src/role-claim/code.ts +53 -0
- package/src/role-claim/controller.ts +194 -0
- package/src/role-claim/index.ts +19 -0
- package/src/role-claim/match-rule.ts +43 -0
- package/src/role-claim/pending.ts +100 -0
- package/src/run/channel-session-factory.ts +76 -5
- package/src/run/index.ts +68 -7
- package/src/secrets/encryption.ts +116 -0
- package/src/secrets/kakao-renewal.ts +248 -0
- package/src/secrets/kakao-store.ts +66 -7
- package/src/secrets/keys.ts +173 -0
- package/src/secrets/schema.ts +23 -0
- package/src/secrets/storage.ts +83 -0
- package/src/server/index.ts +198 -71
- package/src/shared/index.ts +4 -0
- package/src/shared/protocol.ts +27 -0
- package/src/skills/typeclaw-channel-kakaotalk/SKILL.md +3 -3
- package/src/skills/typeclaw-config/SKILL.md +104 -112
- package/src/skills/typeclaw-memory/SKILL.md +9 -9
- package/src/skills/typeclaw-permissions/SKILL.md +166 -0
- package/src/stream/types.ts +7 -1
- package/src/tui/client.ts +66 -5
- package/src/tui/index.ts +61 -9
- package/src/usage/aggregate.ts +117 -0
- package/src/usage/format.ts +30 -0
- package/src/usage/index.ts +68 -0
- package/src/usage/report.ts +354 -0
- package/src/usage/scan.ts +186 -0
- package/typeclaw.schema.json +134 -98
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ The bundled `memory` plugin turns lived experience into reusable knowledge. No m
|
|
|
43
43
|
|
|
44
44
|
1. **Observe.** After every idle turn, a `memory-logger` subagent reads the transcript and appends notable fragments to `memory/yyyy-MM-dd.md`. Cheap, frequent, lossy by design.
|
|
45
45
|
2. **Dream.** On a cron schedule (default 4am), a `dreaming` subagent consolidates daily streams into `MEMORY.md`, and — when it spots a procedure worth remembering — writes it as **muscle memory**: a new skill at `memory/skills/<name>/SKILL.md`.
|
|
46
|
-
3. **Apply.** Tomorrow's prompt sees the updated `MEMORY.md`. Muscle-memory skills sit alongside bundled and user-installed ones, loaded on demand. Every dream is
|
|
46
|
+
3. **Apply.** Tomorrow's prompt sees the updated `MEMORY.md`. Muscle-memory skills sit alongside bundled and user-installed ones, loaded on demand. Every dream is committed with a one-line summary — e.g. `dream: 3 fragments + new skill 'pr-review' 🔮` — so growth is auditable.
|
|
47
47
|
|
|
48
48
|
See [`src/bundled-plugins/memory/README.md`](./src/bundled-plugins/memory/README.md) for the full contract.
|
|
49
49
|
|
|
@@ -68,18 +68,20 @@ That's it. The agent is now alive, listening on a websocket, ready to receive pr
|
|
|
68
68
|
|
|
69
69
|
## CLI
|
|
70
70
|
|
|
71
|
-
| Command
|
|
72
|
-
|
|
|
73
|
-
| `typeclaw init`
|
|
74
|
-
| `typeclaw start`
|
|
75
|
-
| `typeclaw stop`
|
|
76
|
-
| `typeclaw restart`
|
|
77
|
-
| `typeclaw status`
|
|
78
|
-
| `typeclaw logs`
|
|
79
|
-
| `typeclaw tui`
|
|
80
|
-
| `typeclaw shell`
|
|
81
|
-
| `typeclaw reload`
|
|
82
|
-
| `typeclaw compose`
|
|
71
|
+
| Command | Purpose |
|
|
72
|
+
| ----------------------------------- | ---------------------------------------------------------------------------------- |
|
|
73
|
+
| `typeclaw init` | Scaffold a new agent folder |
|
|
74
|
+
| `typeclaw start` | Build and run the container |
|
|
75
|
+
| `typeclaw stop` | Stop the container |
|
|
76
|
+
| `typeclaw restart` | `stop` then `start` |
|
|
77
|
+
| `typeclaw status` | Show container + daemon registration state |
|
|
78
|
+
| `typeclaw logs` | Stream container stdout/stderr with local timestamps; `-f` to follow |
|
|
79
|
+
| `typeclaw tui` | Attach a terminal UI over the agent's websocket |
|
|
80
|
+
| `typeclaw shell` | Open a shell inside the running container |
|
|
81
|
+
| `typeclaw reload` | Push a live config reload to the running agent |
|
|
82
|
+
| `typeclaw compose` | Orchestrate multiple agents |
|
|
83
|
+
| `typeclaw channel add <kind>` | Wire a new channel adapter (Slack, Discord, Telegram, KakaoTalk) |
|
|
84
|
+
| `typeclaw channel reauth kakaotalk` | Re-authenticate KakaoTalk after a stale-token 401 or to rotate the stored password |
|
|
83
85
|
|
|
84
86
|
## Configuration
|
|
85
87
|
|
package/auth.schema.json
CHANGED
|
@@ -233,6 +233,47 @@
|
|
|
233
233
|
},
|
|
234
234
|
"updated_at": {
|
|
235
235
|
"type": "string"
|
|
236
|
+
},
|
|
237
|
+
"email": {
|
|
238
|
+
"type": "string"
|
|
239
|
+
},
|
|
240
|
+
"encryptedPassword": {
|
|
241
|
+
"type": "object",
|
|
242
|
+
"properties": {
|
|
243
|
+
"v": {
|
|
244
|
+
"type": "number",
|
|
245
|
+
"const": 1
|
|
246
|
+
},
|
|
247
|
+
"alg": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"const": "AES-256-GCM"
|
|
250
|
+
},
|
|
251
|
+
"kid": {
|
|
252
|
+
"type": "string"
|
|
253
|
+
},
|
|
254
|
+
"iv": {
|
|
255
|
+
"type": "string"
|
|
256
|
+
},
|
|
257
|
+
"ciphertext": {
|
|
258
|
+
"type": "string"
|
|
259
|
+
},
|
|
260
|
+
"authTag": {
|
|
261
|
+
"type": "string"
|
|
262
|
+
},
|
|
263
|
+
"createdAt": {
|
|
264
|
+
"type": "string"
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
"required": [
|
|
268
|
+
"v",
|
|
269
|
+
"alg",
|
|
270
|
+
"kid",
|
|
271
|
+
"iv",
|
|
272
|
+
"ciphertext",
|
|
273
|
+
"authTag",
|
|
274
|
+
"createdAt"
|
|
275
|
+
],
|
|
276
|
+
"additionalProperties": false
|
|
236
277
|
}
|
|
237
278
|
},
|
|
238
279
|
"required": [
|
package/cron.schema.json
CHANGED
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"timezone": {
|
|
30
30
|
"type": "string"
|
|
31
31
|
},
|
|
32
|
+
"scheduledByRole": {
|
|
33
|
+
"type": "string"
|
|
34
|
+
},
|
|
35
|
+
"scheduledByOrigin": {},
|
|
32
36
|
"kind": {
|
|
33
37
|
"type": "string",
|
|
34
38
|
"const": "prompt"
|
|
@@ -69,6 +73,10 @@
|
|
|
69
73
|
"timezone": {
|
|
70
74
|
"type": "string"
|
|
71
75
|
},
|
|
76
|
+
"scheduledByRole": {
|
|
77
|
+
"type": "string"
|
|
78
|
+
},
|
|
79
|
+
"scheduledByOrigin": {},
|
|
72
80
|
"kind": {
|
|
73
81
|
"type": "string",
|
|
74
82
|
"const": "exec"
|
package/package.json
CHANGED
package/secrets.schema.json
CHANGED
|
@@ -233,6 +233,47 @@
|
|
|
233
233
|
},
|
|
234
234
|
"updated_at": {
|
|
235
235
|
"type": "string"
|
|
236
|
+
},
|
|
237
|
+
"email": {
|
|
238
|
+
"type": "string"
|
|
239
|
+
},
|
|
240
|
+
"encryptedPassword": {
|
|
241
|
+
"type": "object",
|
|
242
|
+
"properties": {
|
|
243
|
+
"v": {
|
|
244
|
+
"type": "number",
|
|
245
|
+
"const": 1
|
|
246
|
+
},
|
|
247
|
+
"alg": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"const": "AES-256-GCM"
|
|
250
|
+
},
|
|
251
|
+
"kid": {
|
|
252
|
+
"type": "string"
|
|
253
|
+
},
|
|
254
|
+
"iv": {
|
|
255
|
+
"type": "string"
|
|
256
|
+
},
|
|
257
|
+
"ciphertext": {
|
|
258
|
+
"type": "string"
|
|
259
|
+
},
|
|
260
|
+
"authTag": {
|
|
261
|
+
"type": "string"
|
|
262
|
+
},
|
|
263
|
+
"createdAt": {
|
|
264
|
+
"type": "string"
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
"required": [
|
|
268
|
+
"v",
|
|
269
|
+
"alg",
|
|
270
|
+
"kid",
|
|
271
|
+
"iv",
|
|
272
|
+
"ciphertext",
|
|
273
|
+
"authTag",
|
|
274
|
+
"createdAt"
|
|
275
|
+
],
|
|
276
|
+
"additionalProperties": false
|
|
236
277
|
}
|
|
237
278
|
},
|
|
238
279
|
"required": [
|
package/src/agent/auth.ts
CHANGED
|
@@ -23,12 +23,18 @@ function secretsJsonPath(): string {
|
|
|
23
23
|
return join(process.cwd(), 'secrets.json')
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// Per-provider cache. Sessions that use a profile mapped to provider X share
|
|
27
|
+
// a single AuthStorage + ModelRegistry for that provider; first use of a new
|
|
28
|
+
// provider lazily resolves its credentials. This replaces the singleton
|
|
29
|
+
// `getAuth()` from before multi-model — the singleton couldn't represent
|
|
30
|
+
// "auth for `default` is OpenAI, auth for `vision` is Fireworks" without
|
|
31
|
+
// constructing both at boot.
|
|
32
|
+
const cached = new Map<KnownProviderId, Auth>()
|
|
33
|
+
|
|
34
|
+
export function getAuthFor(providerId: KnownProviderId): Auth {
|
|
35
|
+
const existing = cached.get(providerId)
|
|
36
|
+
if (existing) return existing
|
|
27
37
|
|
|
28
|
-
export function getAuth(): Auth {
|
|
29
|
-
if (cached) return cached
|
|
30
|
-
|
|
31
|
-
const providerId = providerForModelRef(getConfig().model)
|
|
32
38
|
const provider = KNOWN_PROVIDERS[providerId]
|
|
33
39
|
|
|
34
40
|
if (process.env.NODE_ENV === 'test' && !hasAnyCredentialInEnv(provider.apiKeyEnv)) {
|
|
@@ -37,8 +43,9 @@ export function getAuth(): Auth {
|
|
|
37
43
|
authStorage.setRuntimeApiKey(provider.id, TEST_DUMMY_API_KEY)
|
|
38
44
|
}
|
|
39
45
|
const modelRegistry = ModelRegistry.create(authStorage)
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
const auth = { authStorage, modelRegistry }
|
|
47
|
+
cached.set(providerId, auth)
|
|
48
|
+
return auth
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
const authStorage = createSecretsStoreForAgent(secretsJsonPath())
|
|
@@ -53,16 +60,11 @@ export function getAuth(): Auth {
|
|
|
53
60
|
// is set. OAuth credentials in the file still take precedence on read
|
|
54
61
|
// because AuthStorage's hasAuth checks runtimeOverrides first only for
|
|
55
62
|
// api-key-shaped credentials — OAuth on disk wins on its own.
|
|
56
|
-
//
|
|
57
|
-
// The previous code branch that wrote the env value into secrets.json and
|
|
58
|
-
// stripped the matching `.env` line has been removed. Env values stay in
|
|
59
|
-
// env; the file stays user-owned. See src/secrets/hydrate.ts for the same
|
|
60
|
-
// policy on the channels side.
|
|
61
63
|
if (supportsApiKey(provider) && provider.apiKeyEnv) {
|
|
62
64
|
const envKey = process.env[provider.apiKeyEnv]
|
|
63
65
|
if (envKey !== undefined && envKey !== '') {
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
+
const existingCred = authStorage.get(provider.id)
|
|
67
|
+
if (existingCred === undefined || existingCred.type === 'api_key') {
|
|
66
68
|
authStorage.setRuntimeApiKey(provider.id, envKey)
|
|
67
69
|
}
|
|
68
70
|
}
|
|
@@ -74,12 +76,20 @@ export function getAuth(): Auth {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
const modelRegistry = ModelRegistry.create(authStorage)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
const auth = { authStorage, modelRegistry }
|
|
80
|
+
cached.set(providerId, auth)
|
|
81
|
+
return auth
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Back-compat shim for callers that still want the `default` profile's auth
|
|
85
|
+
// (the main session path). Equivalent to `getAuthFor(provider-of-default)`.
|
|
86
|
+
export function getAuth(): Auth {
|
|
87
|
+
const defaultRef = getConfig().models.default
|
|
88
|
+
return getAuthFor(providerForModelRef(defaultRef))
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
export function resetAuthForTesting(): void {
|
|
82
|
-
cached
|
|
92
|
+
cached.clear()
|
|
83
93
|
}
|
|
84
94
|
|
|
85
95
|
function hasAnyCredentialInEnv(apiKeyEnv: string | null): boolean {
|
|
@@ -88,19 +98,32 @@ function hasAnyCredentialInEnv(apiKeyEnv: string | null): boolean {
|
|
|
88
98
|
|
|
89
99
|
function missingCredentialMessage(providerId: KnownProviderId): string {
|
|
90
100
|
const provider = KNOWN_PROVIDERS[providerId]
|
|
91
|
-
const
|
|
92
|
-
const
|
|
101
|
+
const defaultRef = getConfig().models.default
|
|
102
|
+
const defaultProviderId = providerForModelRef(defaultRef)
|
|
103
|
+
// For the `default` profile, name the model in the error message (matches
|
|
104
|
+
// pre-multi-model behavior). For any other profile, the user is mixing
|
|
105
|
+
// providers across profiles and the error must name the failing provider
|
|
106
|
+
// without claiming it's tied to the `default` model.
|
|
107
|
+
const isDefault = defaultProviderId === providerId
|
|
108
|
+
const ref = isDefault ? defaultRef : null
|
|
93
109
|
const modelName =
|
|
94
|
-
|
|
110
|
+
ref !== null
|
|
111
|
+
? ((provider.models as Record<string, { name: string }>)[ref.slice(ref.indexOf('/') + 1)]?.name ??
|
|
112
|
+
ref.slice(ref.indexOf('/') + 1))
|
|
113
|
+
: null
|
|
95
114
|
|
|
96
115
|
const oauthOnly = supportsOAuth(provider) && !supportsApiKey(provider)
|
|
97
116
|
const apiKeyOnly = supportsApiKey(provider) && !supportsOAuth(provider)
|
|
98
117
|
|
|
99
118
|
if (oauthOnly) {
|
|
100
|
-
return
|
|
119
|
+
return modelName
|
|
120
|
+
? `No credentials for ${provider.name}. Run \`typeclaw init\` and pick "OAuth" to log in to ${modelName}.`
|
|
121
|
+
: `No credentials for ${provider.name} (referenced by a non-default profile). Run \`typeclaw init\` and pick "OAuth" to log in.`
|
|
101
122
|
}
|
|
102
123
|
if (apiKeyOnly && provider.apiKeyEnv) {
|
|
103
|
-
return
|
|
124
|
+
return modelName
|
|
125
|
+
? `Set ${provider.apiKeyEnv} in .env (or secrets.json#providers.${provider.id}.key.value) to use ${modelName} via ${provider.name}.`
|
|
126
|
+
: `Set ${provider.apiKeyEnv} in .env (or secrets.json#providers.${provider.id}.key.value) to use ${provider.name} (referenced by a non-default profile).`
|
|
104
127
|
}
|
|
105
128
|
return `No credentials for ${provider.name}. Either set ${provider.apiKeyEnv ?? '<api-key-env>'} in .env or run \`typeclaw init\` and pick "OAuth".`
|
|
106
129
|
}
|