@mininglamp-oss/cc-channel-octo 1.0.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 +349 -0
- package/LICENSE +191 -0
- package/README.md +577 -0
- package/config.bot.example.json +15 -0
- package/config.example.json +33 -0
- package/dist/agent-bridge.d.ts +79 -0
- package/dist/agent-bridge.js +392 -0
- package/dist/agent-bridge.js.map +1 -0
- package/dist/commands.d.ts +57 -0
- package/dist/commands.js +121 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +278 -0
- package/dist/config.js +330 -0
- package/dist/config.js.map +1 -0
- package/dist/cron-evaluator.d.ts +53 -0
- package/dist/cron-evaluator.js +191 -0
- package/dist/cron-evaluator.js.map +1 -0
- package/dist/cron-fire-marker.d.ts +24 -0
- package/dist/cron-fire-marker.js +25 -0
- package/dist/cron-fire-marker.js.map +1 -0
- package/dist/cron-scheduler.d.ts +46 -0
- package/dist/cron-scheduler.js +114 -0
- package/dist/cron-scheduler.js.map +1 -0
- package/dist/cron-store.d.ts +62 -0
- package/dist/cron-store.js +63 -0
- package/dist/cron-store.js.map +1 -0
- package/dist/cron-tool.d.ts +44 -0
- package/dist/cron-tool.js +151 -0
- package/dist/cron-tool.js.map +1 -0
- package/dist/cwd-resolver.d.ts +72 -0
- package/dist/cwd-resolver.js +166 -0
- package/dist/cwd-resolver.js.map +1 -0
- package/dist/db-adapter.d.ts +21 -0
- package/dist/db-adapter.js +64 -0
- package/dist/db-adapter.js.map +1 -0
- package/dist/file-inline-wrap.d.ts +94 -0
- package/dist/file-inline-wrap.js +243 -0
- package/dist/file-inline-wrap.js.map +1 -0
- package/dist/gateway.d.ts +100 -0
- package/dist/gateway.js +420 -0
- package/dist/gateway.js.map +1 -0
- package/dist/group-config.d.ts +41 -0
- package/dist/group-config.js +104 -0
- package/dist/group-config.js.map +1 -0
- package/dist/group-context.d.ts +64 -0
- package/dist/group-context.js +396 -0
- package/dist/group-context.js.map +1 -0
- package/dist/inbound.d.ts +136 -0
- package/dist/inbound.js +667 -0
- package/dist/inbound.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +922 -0
- package/dist/index.js.map +1 -0
- package/dist/media-inbound.d.ts +38 -0
- package/dist/media-inbound.js +131 -0
- package/dist/media-inbound.js.map +1 -0
- package/dist/mention-utils.d.ts +99 -0
- package/dist/mention-utils.js +185 -0
- package/dist/mention-utils.js.map +1 -0
- package/dist/octo/api.d.ts +148 -0
- package/dist/octo/api.js +320 -0
- package/dist/octo/api.js.map +1 -0
- package/dist/octo/socket.d.ts +102 -0
- package/dist/octo/socket.js +793 -0
- package/dist/octo/socket.js.map +1 -0
- package/dist/octo/types.d.ts +126 -0
- package/dist/octo/types.js +35 -0
- package/dist/octo/types.js.map +1 -0
- package/dist/prompt-safety.d.ts +78 -0
- package/dist/prompt-safety.js +148 -0
- package/dist/prompt-safety.js.map +1 -0
- package/dist/session-router.d.ts +127 -0
- package/dist/session-router.js +432 -0
- package/dist/session-router.js.map +1 -0
- package/dist/session-store.d.ts +89 -0
- package/dist/session-store.js +297 -0
- package/dist/session-store.js.map +1 -0
- package/dist/skill-linker.d.ts +31 -0
- package/dist/skill-linker.js +160 -0
- package/dist/skill-linker.js.map +1 -0
- package/dist/stream-relay.d.ts +42 -0
- package/dist/stream-relay.js +243 -0
- package/dist/stream-relay.js.map +1 -0
- package/dist/url-policy.d.ts +103 -0
- package/dist/url-policy.js +290 -0
- package/dist/url-policy.js.map +1 -0
- package/package.json +79 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
While the major version is `0`, minor releases may carry breaking changes.
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [1.0.1] - 2026-06-10
|
|
12
|
+
|
|
13
|
+
The first npm-installable release. No runtime behavior change — packaging only.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Published to npm as `@mininglamp-oss/cc-channel-octo`** — install with
|
|
18
|
+
`npm install -g @mininglamp-oss/cc-channel-octo` or run via
|
|
19
|
+
`npx @mininglamp-oss/cc-channel-octo`. A new GitHub Actions workflow
|
|
20
|
+
(`npm-publish.yml`) publishes on a released tag (and via manual dispatch),
|
|
21
|
+
with OIDC build provenance; it refuses to publish unless the tag matches
|
|
22
|
+
`package.json`.
|
|
23
|
+
- **`cc-channel-octo` CLI bin** — the package now exposes a `bin`, so a global
|
|
24
|
+
install / `npx` starts the gateway directly (no clone + build needed).
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **Gateway auto-start when launched via the installed bin** — the main-module
|
|
29
|
+
guard compared `import.meta.url` against `process.argv[1]` verbatim, but the
|
|
30
|
+
installed bin is a symlink under `node_modules/.bin/`, so the paths never
|
|
31
|
+
matched and `main()` never fired (the command exited silently). The guard now
|
|
32
|
+
canonicalizes both sides with `realpath`.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **`package.json` packaging metadata** — scoped name, a `files` allowlist
|
|
37
|
+
(so the compiled `dist/` is actually shipped despite being `.gitignore`d),
|
|
38
|
+
`publishConfig` (public + provenance), `repository` / `bugs` / `homepage`,
|
|
39
|
+
and a `prepublishOnly` build hook.
|
|
40
|
+
|
|
41
|
+
## [1.0.0] - 2026-06-10
|
|
42
|
+
|
|
43
|
+
First stable release. Consolidates everything merged since `0.2.0` — the v0.3
|
|
44
|
+
line (slash commands, tool progress, multi-bot, v2 Session API), the v1.0 line
|
|
45
|
+
(per-group `GROUP.md` instructions), scheduled tasks (cron), skill-as-data
|
|
46
|
+
external tooling, the frozen-system-prompt / SDK-session-owned-history rework,
|
|
47
|
+
and a large batch of security hardening. **Contains breaking changes** —
|
|
48
|
+
configuration is now JSON-only and the `sdk.persistentSession` flag was removed
|
|
49
|
+
(see Changed / Migration notes below).
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- **Scheduled tasks (cron)** (#115) — set `sdk.cron: true` to give the agent a
|
|
54
|
+
`cron` tool set (`cron_create` / `cron_list` / `cron_delete`). Tasks (5-field
|
|
55
|
+
cron or one-shot ISO) persist to `<baseDir>/<id>/cron.json` and are fired by a
|
|
56
|
+
resident per-bot gateway scheduler through the normal `handleMessage` pipeline,
|
|
57
|
+
bound to the session that created them (reply posts back to that channel). Fills
|
|
58
|
+
RUNTIME.md's scheduled-tasks gap. **Security:** creation/deletion is owner-gated
|
|
59
|
+
(`registerBot.owner_uid`), server-enforced — a prompt-injected agent cannot
|
|
60
|
+
register a malicious unattended task; defense-in-depth line added to the
|
|
61
|
+
security prompt. Synthetic fires carry `payload._cronFire` + a per-process
|
|
62
|
+
nonce (`cron-fire-marker.ts`) to bypass the group @mention gate without being
|
|
63
|
+
forgeable from an inbound payload (rate limiting still applies). All cron.json
|
|
64
|
+
writes go through an atomic `CronStore.update()` read-modify-write (no
|
|
65
|
+
lost-update race). A fired task is offered the cron tools (can self-schedule) —
|
|
66
|
+
intentional for self-management; enable only for trusted-context bots. New
|
|
67
|
+
`src/cron-{evaluator,store,tool,scheduler}.ts` + `cron-fire-marker.ts`; no new
|
|
68
|
+
dependency (self-contained cron evaluator).
|
|
69
|
+
|
|
70
|
+
- **`sdk.skills` per-bot skill selection** (#110) — a bot enables a subset of the
|
|
71
|
+
centrally-maintained skill library via `sdk.skills: string[] | 'all'`
|
|
72
|
+
(per-bot). Maintain skills once in `~/.cc-channel-octo/skills/`; each bot picks
|
|
73
|
+
what it uses. Strengthens the multi-bot identity model alongside per-bot
|
|
74
|
+
`SOUL.md` + `<id>/CLAUDE.md`. `settingSources` stays `['project']` (not
|
|
75
|
+
`['user']`) to avoid coupling bots to the host's personal `~/.claude`. Note:
|
|
76
|
+
CLAUDE.md's upward-walk has no project boundary — keep the host `$HOME` (and
|
|
77
|
+
ancestors) free of `CLAUDE.md`; see README.
|
|
78
|
+
|
|
79
|
+
- **`sdk.env` config** (#107) — declare extra environment variables, injected
|
|
80
|
+
verbatim into the agent's tool subprocess. Generic (cc doesn't interpret them)
|
|
81
|
+
and per-bot. Primary use: give a multi-bot deploy's shared CLI its identity
|
|
82
|
+
selector, e.g. `{ "sdk": { "env": { "OCTO_BOT_ID": "<robotId>" } } }` so each
|
|
83
|
+
bot's `octo-cli` calls pick the right stored profile (a bare call errors "no
|
|
84
|
+
bot selected" once ≥2 profiles exist).
|
|
85
|
+
|
|
86
|
+
- **Agent skills — generic external tooling** (#100) — external CLIs (octo-cli,
|
|
87
|
+
gh, anything on `PATH`) are integrated as DATA, not code. Drop a standard Claude
|
|
88
|
+
skill (`SKILL.md` + optional `references/`/`scripts/`) into
|
|
89
|
+
`~/.cc-channel-octo/skills/` (all bots) or `~/.cc-channel-octo/<id>/skills/`
|
|
90
|
+
(per-bot, overrides global on a name collision). cc symlinks both layers into
|
|
91
|
+
each session sandbox's `.claude/skills/` per turn (`src/skill-linker.ts`), and
|
|
92
|
+
the SDK discovers them via the new `sdk.settingSources` default `['project']`.
|
|
93
|
+
**No CLI name appears in cc code** — adding a tool needs zero code change.
|
|
94
|
+
cc handles NO credentials: the operator installs + authenticates the underlying
|
|
95
|
+
CLI out-of-band (`octo-cli auth login`, `gh auth login`). Memory isolation is
|
|
96
|
+
preserved despite the `project` source because the auto-memory directory is
|
|
97
|
+
pinned via inline `settings.autoMemoryDirectory` (ranked above projectSettings;
|
|
98
|
+
verified). New `src/skill-linker.ts`; `Config` gains derived `skillsDir` /
|
|
99
|
+
`globalSkillsDir`. `sdk.settingSources` default flipped `[]` → `['project']`.
|
|
100
|
+
|
|
101
|
+
- **Per-group instructions** (v1.0, GROUP.md) — set `groupConfigDir`
|
|
102
|
+
(`CC_OCTO_GROUP_CONFIG_DIR`) to a directory of `<groupId>.md` files; a matching
|
|
103
|
+
file's contents are injected into that group's system prompt as a trusted
|
|
104
|
+
`[Group instructions]` block, so a group can have its own persona/rules without
|
|
105
|
+
code changes. Operator-controlled; id is filename-pinned to a safe slug (no
|
|
106
|
+
traversal), content capped at 16 KiB, groups only. Boot-time check (re-run
|
|
107
|
+
per-bot) rejects a `groupConfigDir` equal to or nested under the agent-writable
|
|
108
|
+
`cwdBase`, using realpath canonicalization. Because the agent can still write
|
|
109
|
+
absolute paths under default Bash/bypassPermissions, the block is a trusted
|
|
110
|
+
prompt-injection sink whose safety requires OS-level file permissions + a
|
|
111
|
+
hardened deployment — documented prominently, with a defense-in-depth refusal
|
|
112
|
+
to inject a group/world-writable file. New `src/group-config.ts`.
|
|
113
|
+
- **Persistent sessions** (v0.3, opt-in) — with `sdk.persistentSession`
|
|
114
|
+
(`CC_OCTO_SDK_PERSISTENT_SESSION=true`), agent workspace state persists across
|
|
115
|
+
messages via the SDK v2 Session API. Each session's SDK session id is stored
|
|
116
|
+
(new `sdk_sessions` table) and `resume`d on the next turn; on resume the
|
|
117
|
+
history prefix is suppressed (the SDK session already holds it). `/reset`
|
|
118
|
+
clears the stored session id so a cleared conversation is not resumed.
|
|
119
|
+
`queryAgent` gained an `opts.resume` + `opts.onSessionId` channel (both
|
|
120
|
+
guarded). Default off — the proven stateless v1 `query()` path is unchanged.
|
|
121
|
+
- **Multi-bot support** (v0.3) — run several independent bots in one process via
|
|
122
|
+
a top-level `bots[]` config array. Each entry needs its own `botToken` + `id`,
|
|
123
|
+
inherits all top-level fields, and may override `apiUrl`/`dataDir`/`cwdBase`/
|
|
124
|
+
`model`/`systemPrompt`/blocklists. Each bot gets a fully independent stack
|
|
125
|
+
(gateway + router + store); `dataDir` and `cwdBase` are namespaced by id by
|
|
126
|
+
default so bots never share history or sandboxes. Bot ids are validated as
|
|
127
|
+
conservative slugs (no path separators) to keep that namespacing safe.
|
|
128
|
+
`resolveBotConfigs()` expands the config and fails fast on missing/duplicate
|
|
129
|
+
tokens or duplicate/invalid ids. All bot ids are registered into every router
|
|
130
|
+
so a mention-free group can't trigger bot-to-bot reply loops, and the
|
|
131
|
+
cold-start backfill sentinel is keyed per bot. In multi-bot mode the
|
|
132
|
+
orchestrator owns a single SIGINT/SIGTERM shutdown that drains all bots
|
|
133
|
+
(gateways skip their own signal handlers via a new `handleSignals` option).
|
|
134
|
+
Single-bot configs are unchanged.
|
|
135
|
+
- **Tool progress display** (v0.3, opt-in) — with `sdk.toolProgress`
|
|
136
|
+
(`CC_OCTO_SDK_TOOL_PROGRESS=true`), the bot posts brief `🔧 Running <tool>…`
|
|
137
|
+
notices as the agent invokes tools. `queryAgent` gained a non-breaking
|
|
138
|
+
`onToolUse` callback (guarded so a throwing callback never breaks the stream);
|
|
139
|
+
`index.ts` dedups consecutive repeats and caps notices per turn.
|
|
140
|
+
- **In-chat slash commands** (v0.3) — `/reset` clears the current session's
|
|
141
|
+
history, `/config` shows the active non-sensitive settings, `/help` lists
|
|
142
|
+
commands. Handled before the agent query, scoped per-user (even in groups), so
|
|
143
|
+
a command never reaches the LLM or leaks into another member's group context.
|
|
144
|
+
`/reset` records a persisted reset barrier (by `message_seq`) so group
|
|
145
|
+
cold-start backfill cannot resurrect the cleared history, even across a
|
|
146
|
+
process restart. Commands are subject to the normal per-session rate limit.
|
|
147
|
+
|
|
148
|
+
### Changed
|
|
149
|
+
|
|
150
|
+
- **Frozen system prompt + SDK-session-owned history** — the bot's
|
|
151
|
+
`systemPrompt.append` now carries ONLY stable, operator-controlled content
|
|
152
|
+
(security prefix + SOUL + group instructions). Per-turn-variable content —
|
|
153
|
+
conversation history (B5) and group context (B4) — no longer sits inside the
|
|
154
|
+
SDK's cached system block, so the prompt-caching prefix is byte-identical
|
|
155
|
+
turn-to-turn and actually hits (previously every turn was a cache-write with zero
|
|
156
|
+
reads, because the changing history/context lived inside the `cache_control`
|
|
157
|
+
block). Follows Anthropic's own guidance ("keep the system prompt frozen; inject
|
|
158
|
+
dynamic context in a user message"). **Conversation history is now owned by the
|
|
159
|
+
SDK session:** cc always `resume`s the stored session id; only a session's FIRST
|
|
160
|
+
turn (or a migration from existing SQLite history) injects prior history ONCE as
|
|
161
|
+
a `[Prior conversation history]` block in the user message. **Group context** is
|
|
162
|
+
injected as a delta — only messages new since a per-channel consumption cursor
|
|
163
|
+
(`group_context_cursors`), not the whole window every turn. **`sdk.cron`-style
|
|
164
|
+
flag removed:** `sdk.persistentSession` is gone — SDK sessions are always on (with
|
|
165
|
+
the flag off and history out of the prompt, "off" would mean no memory at all).
|
|
166
|
+
**Stale-resume recovery:** an expired/invalid session id (the SDK throws "No
|
|
167
|
+
conversation found with session ID …") is caught, the bad id cleared, and the turn
|
|
168
|
+
retried once without resume — re-injecting history from SQLite so a conversation is
|
|
169
|
+
never silently lost. SQLite's role is now state/cursors/mappings + a durable record
|
|
170
|
+
(migration & recovery substrate), not live prompt-history reconstruction.
|
|
171
|
+
`buildSystemPrompt(customPrompt?, groupInstructions?)` and `queryAgent(userMessage,
|
|
172
|
+
config, sessionCtx?, onToolUse?, opts?)` lost their history/context params.
|
|
173
|
+
**Migration:** drop any `sdk.persistentSession` / `CC_OCTO_SDK_PERSISTENT_SESSION`
|
|
174
|
+
from config — it's ignored now; existing SQLite history is injected once on each
|
|
175
|
+
session's next turn, then carried by the SDK session.
|
|
176
|
+
- **Config is JSON-only — all environment-variable overrides removed** (#103).
|
|
177
|
+
The entire `CC_OCTO_*` env surface and the `ANTHROPIC_BASE_URL` env read are
|
|
178
|
+
gone; `applyEnv()` (and its `parseCsv`/`parseIntStrict` helpers) were deleted.
|
|
179
|
+
Configuration now comes solely from the two-layer config.json (global +
|
|
180
|
+
per-bot). `sdk.anthropicBaseUrl` remains a config.json field (still forwarded
|
|
181
|
+
to the SDK subprocess as `ANTHROPIC_BASE_URL`). **Migration:** move any
|
|
182
|
+
`CC_OCTO_*` / `ANTHROPIC_BASE_URL` values into `~/.cc-channel-octo/config.json`
|
|
183
|
+
(or the per-bot file). Old env vars are now silently ignored.
|
|
184
|
+
|
|
185
|
+
### Removed
|
|
186
|
+
|
|
187
|
+
- **Dead Octo API functions** — removed `fetchBotGroups`, `getGroupInfo`,
|
|
188
|
+
`searchSpaceMembers` (originally G15/G16/G17) and their `BotGroup` / `GroupInfo`
|
|
189
|
+
/ `SpaceMember` interfaces from `octo/api.ts`. They had **zero production callers**
|
|
190
|
+
(only tests referenced them) — these read-only group/space queries are covered by
|
|
191
|
+
the agent's octo-cli skill (`octo-cli group list` / `group get` / `bot space-members`).
|
|
192
|
+
No runtime behavior change.
|
|
193
|
+
- **Dead media-upload pipeline + `cos-nodejs-sdk-v5`** — removed `media-upload.ts`
|
|
194
|
+
(`uploadAndSendMedia` / `sendRichTextCombined` / `uploadFileToCOS`) and the
|
|
195
|
+
`sendMediaMessage` / `sendRichTextMessage` API functions. This outbound media /
|
|
196
|
+
rich-text pipeline had **zero production callers** (born-dead) — outbound media is
|
|
197
|
+
handled by the agent's octo-cli skill (`octo-cli file upload` + `message send`)
|
|
198
|
+
under the skill-as-data model. Dropping it removes the direct dependency on
|
|
199
|
+
`cos-nodejs-sdk-v5`, which transitively pulled in the deprecated `request@2.88.2`
|
|
200
|
+
chain and an old `fast-xml-parser` — clearing **11 Dependabot alerts** (2 critical,
|
|
201
|
+
2 high incl. an unpatchable `request` SSRF) with no runtime behavior change.
|
|
202
|
+
Inbound media (`media-inbound.ts`) and the startup CDN-host probe
|
|
203
|
+
(`getUploadCredentials` in `index.ts`) are unaffected.
|
|
204
|
+
- **Webhook transport** (#105) — removed; the Octo server does not POST to the
|
|
205
|
+
bot, so webhook mode was dead code. WebSocket is the only transport.
|
|
206
|
+
- **In-process Octo MCP tool server** (#87, never released) — the read-only
|
|
207
|
+
`mcp__octo__*` tools (`list_groups`, `group_info`, `group_members`,
|
|
208
|
+
`search_members`) and the `sdk.octoTools` toggle are removed in favor of the
|
|
209
|
+
generic skill-based external tooling (#100), which covers any CLI's full
|
|
210
|
+
surface without re-implementing operations in cc.
|
|
211
|
+
- **octo-cli-specific integration code** (#94, never released) — the brief
|
|
212
|
+
`sdk.octoCli` toggle, the hand-maintained `OCTO_CLI_GUIDE`, the startup profile
|
|
213
|
+
seeding, and the `OCTO_API_BASE_URL`/`OCTO_BOT_ID` env injection are removed.
|
|
214
|
+
They baked one CLI into cc's core; #100 replaces them with the generic,
|
|
215
|
+
zero-CLI-name skill loader.
|
|
216
|
+
|
|
217
|
+
### Fixed
|
|
218
|
+
|
|
219
|
+
- **Cron robustness — review follow-ups** (#115) — four operational-hardening
|
|
220
|
+
fixes from the xhigh review: (1/5) cron fires now **bypass the rate limit**
|
|
221
|
+
(like the @mention gate) so an operator-scheduled task isn't silently dropped
|
|
222
|
+
when the owner's bucket is exhausted, and the scheduler **logs an async fire
|
|
223
|
+
failure attributed to the specific task** (delivery errors were previously
|
|
224
|
+
invisible); (2) a **startup warning** when `sdk.cron` is on but the bot has no
|
|
225
|
+
`owner_uid` (the owner-gate would otherwise reject every `cron_create` with no
|
|
226
|
+
hint why); (3) a synthetic cron fire's `message_seq=0` **no longer poisons the
|
|
227
|
+
history-segmentation cursor** (`setLastBotReplySeq` is skipped for non-positive
|
|
228
|
+
seq); (6) **strict ISO-8601 validation** for one-shot schedules
|
|
229
|
+
(`parseOneShot`) so a lenient rollover like `2026-13-13T…` is rejected instead
|
|
230
|
+
of silently firing at a shifted time.
|
|
231
|
+
- **Router drops non-conversation channel types** (#68) — found in live
|
|
232
|
+
deployment: on connect the bot received a system message on `channel_type: 8`
|
|
233
|
+
(`systemcmdonline`) and replied to it. `SessionRouter` now allowlists only DM /
|
|
234
|
+
Group / CommunityTopic as repliable; any other (system/command) channel type is
|
|
235
|
+
dropped before the agent is invoked.
|
|
236
|
+
|
|
237
|
+
### Security
|
|
238
|
+
|
|
239
|
+
- **WebSocket transport must be `wss://`** — the WuKongIM payload layer is
|
|
240
|
+
AES-CBC without an auth tag, so transport integrity is the only tamper guarantee.
|
|
241
|
+
`gateway.connect()` now refuses a plaintext `ws://` endpoint for any non-loopback
|
|
242
|
+
host (`isAllowedWsUrl` in `url-policy.ts`); `ws://localhost` stays allowed for
|
|
243
|
+
local dev / a co-located TLS-terminating proxy.
|
|
244
|
+
- **Binary protocol decoder bounds-checked** — `Decoder` (`octo/socket.ts`) now
|
|
245
|
+
throws `RangeError` on any over-read (truncated packet, or a string length field
|
|
246
|
+
exceeding the remaining buffer) instead of silently reading `undefined`
|
|
247
|
+
(→ 0/NaN coercion → corrupt parses, wrong messageID/seq → ack mismatch). The
|
|
248
|
+
packet-decode loop already catches and reconnects, so a malformed packet now
|
|
249
|
+
fails cleanly.
|
|
250
|
+
- **Partial agent output no longer lost on stream error** — if the agent stream
|
|
251
|
+
throws mid-delivery, `StreamRelay.deliver` now flushes the already-accumulated
|
|
252
|
+
text to the channel before re-throwing, instead of dropping a real partial reply.
|
|
253
|
+
- **`@all` / `@所有人` broadcast detection tightened** — the trailing-boundary
|
|
254
|
+
check used `[^\w]`, so `@all-members` / `@all.foo` wrongly triggered a
|
|
255
|
+
broadcast-to-everyone. It now excludes name-continuation chars (`-`, `.`, CJK),
|
|
256
|
+
while still matching a standalone token followed by space, CJK punctuation, or
|
|
257
|
+
end-of-string.
|
|
258
|
+
|
|
259
|
+
## [0.2.0] - 2026-06-07
|
|
260
|
+
|
|
261
|
+
The first feature release after the initial `0.1.0` tag. It adds the full
|
|
262
|
+
inbound/outbound media and group-chat capabilities, per-session working-directory
|
|
263
|
+
isolation, a self-hosted gateway endpoint, and a large batch of security
|
|
264
|
+
hardening across the SSRF, prompt-injection, and protocol-DoS surfaces.
|
|
265
|
+
|
|
266
|
+
### Added
|
|
267
|
+
|
|
268
|
+
- **Self-hosted gateway endpoint** — `sdk.anthropicBaseUrl` config field (and the
|
|
269
|
+
standard `ANTHROPIC_BASE_URL` env var) to route the Claude Agent SDK through a
|
|
270
|
+
proxy/regional endpoint. SSRF-validated at boot like `apiUrl`.
|
|
271
|
+
- **Per-session `cwd` isolation** — each session (DM peer, or individual group
|
|
272
|
+
member) gets its own hashed sandbox under `cwdBase`, partitioned by the same
|
|
273
|
+
key as conversation history; idle sandboxes (>7d) are reclaimed every 6h.
|
|
274
|
+
- **`allowedTools: "*"`** wildcard form to allow every SDK tool; the env var
|
|
275
|
+
accepts a `*` token or a CSV whitelist.
|
|
276
|
+
- **Inbound message resolution** — image/file/RichText payload handling, text-file
|
|
277
|
+
inlining (base64-wrapped, budgeted), and group history backfill from the Octo
|
|
278
|
+
API on cold start (G1, G2, G4, G11, G22).
|
|
279
|
+
- **Outbound capabilities** — media, RichText, and `@mention` send (G24, G5, G6, G7).
|
|
280
|
+
- **Group chat features** — Space isolation, history segmentation, `streamOn`
|
|
281
|
+
cache filter, reply/quote context, read receipts, mention-free groups, and
|
|
282
|
+
`@botname` stripping (G3, G8–G13, G9, G10, G21).
|
|
283
|
+
- **Bot/identity controls** — bot-loop prevention, owner identity, per-user rate
|
|
284
|
+
limiting, robot flags (G14, G18, G19, G20, G23).
|
|
285
|
+
- **Octo API surface** — `fetchBotGroups`, `getGroupInfo`, `searchSpaceMembers`
|
|
286
|
+
(G15, G16, G17).
|
|
287
|
+
- **CI & repo gates** — GitHub Actions, husky pre-commit/commit-msg/pre-push,
|
|
288
|
+
coverage, strict `tsc`, commitlint (W0).
|
|
289
|
+
- **Docs** — `ARCHITECTURE.md`, `CONTRIBUTING.md`, self-hosted-gateway and
|
|
290
|
+
security-model sections in `README.md`.
|
|
291
|
+
|
|
292
|
+
### Changed
|
|
293
|
+
|
|
294
|
+
- **Default `allowedTools` flipped to `"*"`** (was a hard-coded 8-tool list). The
|
|
295
|
+
surface is bounded by `permissionMode` + per-session `cwdBase` isolation; the
|
|
296
|
+
old list also silently blocked SDK-internal tools.
|
|
297
|
+
- **`cwd` → `cwdBase`** as the canonical config field. Legacy `cwd` / `CC_OCTO_CWD`
|
|
298
|
+
still accepted with a one-time deprecation warning.
|
|
299
|
+
- **`dataDir` created with `0700`** permissions, enforced via `chmod` regardless of
|
|
300
|
+
umask or a pre-existing directory (previously used the umask default).
|
|
301
|
+
- Response truncation limit, heartbeat logging, and runtime version now read from
|
|
302
|
+
`package.json` (Q31, Q32, Q36).
|
|
303
|
+
|
|
304
|
+
### Fixed
|
|
305
|
+
|
|
306
|
+
- **Protocol DoS / correctness (D1)** — socket temp-buffer cap, base64 cap, system
|
|
307
|
+
prompt cap, SDK null guard.
|
|
308
|
+
- **RichText pipeline (C1)** — crash on array payloads, per-payload budgets, G4
|
|
309
|
+
payload merge, rejection-cache guard, `O(n)` byte-safe truncation.
|
|
310
|
+
- **Media pipeline (C2)** — output + media defects (P0-1, P1-3..6), inline-image
|
|
311
|
+
safety gate, data-URI MIME-param parsing, legacy `image/svg` MIME rejection.
|
|
312
|
+
- **Byte-safe truncation (S2)** — correct handling of N×4-byte UTF-8 boundaries
|
|
313
|
+
(no stray U+FFFD).
|
|
314
|
+
- Shutdown resilience — drain in-flight handlers, explicit `store.close()` WAL
|
|
315
|
+
checkpoint, `unhandledRejection` handler (Q6, Q7, Q8).
|
|
316
|
+
- Rate limiting — peek-then-consume with per-bucket debounce (G20); global
|
|
317
|
+
per-minute limit (Q13).
|
|
318
|
+
- Heartbeat restored on token-refresh failure; WS listener cleanup; 30s default
|
|
319
|
+
`postJson` timeout (Q2, Q30, Q33, Q35).
|
|
320
|
+
- **e2e tests now drive the real `handleMessage` pipeline** instead of a
|
|
321
|
+
hand-copied replica, closing a coverage gap around the per-session cwd wiring.
|
|
322
|
+
|
|
323
|
+
### Security
|
|
324
|
+
|
|
325
|
+
- **SSRF defense (S1, S2, S4, S5, S6)** — shared `url-policy.ts`; reject
|
|
326
|
+
`file://`/non-http(s) schemes, private/loopback/link-local/CGN IPs (incl.
|
|
327
|
+
v4-mapped IPv6 hex), `https://` to private hosts; per-hop redirect re-validation
|
|
328
|
+
with cross-host `Authorization` scoping; WHATWG-canonical path-traversal check
|
|
329
|
+
for encoded dot-segments; `%2F` encoded-slash rejection. **(breaking)**
|
|
330
|
+
- **Prompt-injection defense** — structural role separation with a non-overridable
|
|
331
|
+
security prefix (Q3, Q9); sanitize reply quotes and group context (S3); inlined
|
|
332
|
+
file content wrapped in base64 with a total payload cap (S2). **(breaking)**
|
|
333
|
+
- Replace `Math.random` DH seed with `crypto.randomBytes`; fix spread-induced stack
|
|
334
|
+
overflow (Q4, Q5).
|
|
335
|
+
- Message-length limit, sanitized credential/error logs, config-file permission
|
|
336
|
+
warning (Q10, Q11, Q12).
|
|
337
|
+
- `anthropicBaseUrl` SSRF-validated at boot so a stray endpoint cannot exfiltrate
|
|
338
|
+
the API key; forwarded via scoped subprocess env (no global `process.env`
|
|
339
|
+
mutation, no cross-request leak).
|
|
340
|
+
|
|
341
|
+
## [0.1.0]
|
|
342
|
+
|
|
343
|
+
Initial tagged baseline: text messaging, streaming output, SQLite session
|
|
344
|
+
persistence, rate limiting, and the core security model.
|
|
345
|
+
|
|
346
|
+
[1.0.1]: https://github.com/Mininglamp-OSS/cc-channel-octo/compare/v1.0.0...v1.0.1
|
|
347
|
+
[1.0.0]: https://github.com/Mininglamp-OSS/cc-channel-octo/compare/v0.2.0...v1.0.0
|
|
348
|
+
[0.2.0]: https://github.com/Mininglamp-OSS/cc-channel-octo/compare/v0.1.0...v0.2.0
|
|
349
|
+
[0.1.0]: https://github.com/Mininglamp-OSS/cc-channel-octo/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding any notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
Copyright 2026 Mininglamp-OSS
|
|
180
|
+
|
|
181
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
182
|
+
you may not use this file except in compliance with the License.
|
|
183
|
+
You may obtain a copy of the License at
|
|
184
|
+
|
|
185
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
186
|
+
|
|
187
|
+
Unless required by applicable law or agreed to in writing, software
|
|
188
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
189
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
190
|
+
See the License for the specific language governing permissions and
|
|
191
|
+
limitations under the License.
|