@inetafrica/open-claudia 3.0.9 → 3.0.10
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 +7 -0
- package/core/access.js +13 -0
- package/health.js +16 -8
- package/package.json +3 -2
- package/test-kazee-channel-health.js +135 -0
- package/test-provider-language.js +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.10 — Kazee-only pods are first-class
|
|
4
|
+
|
|
5
|
+
- **/doctor no longer demands Telegram env on a Kazee-only install.** `health.js` required `TELEGRAM_BOT_TOKEN`/`TELEGRAM_CHAT_ID` unconditionally — a pod provisioned with `CHANNELS=kazee` failed its env check despite being perfectly configured. Required keys are now derived from `CHANNELS` (default `telegram`, preserving legacy behaviour): telegram installs require the Telegram pair, kazee installs require `KAZEE_BOT_TOKEN`, and `WORKSPACE` stays universal.
|
|
6
|
+
- **Kazee owner bootstrap stores the right identity in the right key.** `/auth` bootstrap on a kazee transport wrote the chat-document id into `TELEGRAM_CHAT_ID` — the wrong id (owner checks compare the Kazee *user* id) in the wrong key (polluting Telegram's authorized list). It now writes `KAZEE_OWNER_USER_ID` with the sender's user id and updates the in-memory config so ownership is live without a restart.
|
|
7
|
+
- **An env-provisioned Kazee owner counts as an owner.** `hasOwner()` only looked at `TELEGRAM_CHAT_ID` and auth.json — on a Kazee-only pod provisioned with `KAZEE_OWNER_USER_ID` (the agent-space wizard path), the first stranger to send `/auth` would have been crowned bootstrap owner. `KAZEE_OWNER_USER_ID` now counts.
|
|
8
|
+
- **Agent-space / OpenClaw:** no new deps, no new env, no schema change; Docker image builds identically (FROM the pre-baked `:base`). This is the bot-side half of Kazee pod provisioning via the agent-space wizard (wizard + provisioner land in agent-space itself). Coverage: new hermetic `test-kazee-channel-health.js` (required-key matrix; kazee bootstrap env writes; provisioned-owner /auth guard), wired into `npm test` and shipped in `files`.
|
|
9
|
+
|
|
3
10
|
## v3.0.9 — one fat record no longer kills the turn
|
|
4
11
|
|
|
5
12
|
- **Decoder failures are warnings, not run failures.** The v3 JSONL stream decoder capped provider records at 1MB and surfaced any oversized or malformed line as a terminal `error` event — so a single base64-image tool result (routine in image workflows) killed an otherwise healthy live turn with `Claude Code run failed: Provider JSONL record exceeded 1048576 bytes` (rahil, v3.0.8, 2026-07-12). `LINE_TOO_LARGE` / `MALFORMED_JSON` now normalize to a new non-terminal `warning` event: the record is skipped, the stream continues, and the warning is logged. If the dropped line happened to be the terminal record, the existing `PROVIDER_MISSING_TERMINAL` net still fails the run cleanly.
|
package/core/access.js
CHANGED
|
@@ -169,6 +169,10 @@ function listAuthorizedRaw() {
|
|
|
169
169
|
|
|
170
170
|
function hasOwner() {
|
|
171
171
|
if (CHAT_ID) return true;
|
|
172
|
+
// A provisioned Kazee owner (env-injected or set via /channel add) counts
|
|
173
|
+
// before their first message — otherwise a stranger's /auth on a
|
|
174
|
+
// Kazee-only pod would seize ownership.
|
|
175
|
+
if (config.KAZEE_OWNER_USER_ID) return true;
|
|
172
176
|
try {
|
|
173
177
|
const auth = JSON.parse(fs.readFileSync(AUTH_FILE, "utf-8"));
|
|
174
178
|
return Array.isArray(auth.authorized) && auth.authorized.some((a) => a.isOwner === true);
|
|
@@ -190,6 +194,15 @@ function bootstrapOwner({ chatId, name, username }) {
|
|
|
190
194
|
authorizedAt: new Date().toISOString(),
|
|
191
195
|
});
|
|
192
196
|
saveAuth(auth);
|
|
197
|
+
if (currentTransport() === "kazee") {
|
|
198
|
+
// Kazee owner identity is the user id (what transportOwnerUserId
|
|
199
|
+
// compares), not the chat-document id the envelope carries as chatId —
|
|
200
|
+
// and it must never be written into TELEGRAM_CHAT_ID.
|
|
201
|
+
const ownerUserId = String(currentUserId() || id);
|
|
202
|
+
saveEnvKey("KAZEE_OWNER_USER_ID", ownerUserId);
|
|
203
|
+
config.KAZEE_OWNER_USER_ID = ownerUserId;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
193
206
|
if (!CHAT_IDS.includes(id)) CHAT_IDS.push(id);
|
|
194
207
|
saveEnvKey("TELEGRAM_CHAT_ID", CHAT_IDS.join(","));
|
|
195
208
|
}
|
package/health.js
CHANGED
|
@@ -8,12 +8,20 @@ const { inspectProviderConfiguration } = require("./core/provider-status");
|
|
|
8
8
|
const ENV_FILE = path.join(CONFIG_DIR, ".env");
|
|
9
9
|
const AUTH_FILE = path.join(CONFIG_DIR, "auth.json");
|
|
10
10
|
|
|
11
|
-
// Required env keys
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
11
|
+
// Required env keys depend on which channels the install runs: WORKSPACE is
|
|
12
|
+
// universal, and each channel listed in CHANNELS (default telegram) adds its
|
|
13
|
+
// own keys — a Kazee-only pod must not fail /doctor over missing Telegram env.
|
|
14
|
+
function requiredEnvKeys(env = {}) {
|
|
15
|
+
const channels = String(env.CHANNELS || "telegram")
|
|
16
|
+
.split(",")
|
|
17
|
+
.map((entry) => entry.trim().split(":")[0])
|
|
18
|
+
.filter(Boolean);
|
|
19
|
+
const keys = [];
|
|
20
|
+
if (channels.includes("telegram")) keys.push("TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID");
|
|
21
|
+
if (channels.includes("kazee")) keys.push("KAZEE_BOT_TOKEN");
|
|
22
|
+
keys.push("WORKSPACE");
|
|
23
|
+
return keys;
|
|
24
|
+
}
|
|
17
25
|
|
|
18
26
|
// Optional but recommended
|
|
19
27
|
const OPTIONAL_ENV_KEYS = [
|
|
@@ -255,7 +263,7 @@ async function runHealthChecks(options = {}) {
|
|
|
255
263
|
return results;
|
|
256
264
|
}
|
|
257
265
|
|
|
258
|
-
const missingKeys =
|
|
266
|
+
const missingKeys = requiredEnvKeys(env).filter((k) => !env[k]);
|
|
259
267
|
if (missingKeys.length > 0) {
|
|
260
268
|
results.checks.env = { ok: false, reason: "missing_keys", message: `Missing required config: ${missingKeys.join(", ")}`, missingKeys };
|
|
261
269
|
results.ok = false;
|
|
@@ -471,6 +479,6 @@ module.exports = {
|
|
|
471
479
|
ensureSetup,
|
|
472
480
|
formatSetupResults,
|
|
473
481
|
ensureAgentBrowser,
|
|
474
|
-
|
|
482
|
+
requiredEnvKeys,
|
|
475
483
|
OPTIONAL_ENV_KEYS,
|
|
476
484
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.10",
|
|
4
4
|
"description": "An always-on, provider-agnostic coding-agent harness for Claude Code and OpenAI Codex via chat",
|
|
5
5
|
"main": "bot.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"setup": "node setup.js",
|
|
11
11
|
"start": "node bot.js",
|
|
12
|
-
"pretest": "node test-provider-fixture.js && node test-provider-core-prompt.js && node test-provider-prompt-parity.js && node test-provider-env-isolation.js && node test-provider-resume-parity.js && node test-provider-bootstrap.js && node test-provider-registry.js && node test-provider-stream-decoder.js && node test-provider-events.js && node test-provider-claude.js && node test-provider-codex.js && node test-provider-runner.js && node test-provider-run-lifecycle.js && node test-provider-gateway.js && node test-provider-side-chat.js && node test-single-runtime.js && node test-provider-migration-backup.js && node test-provider-state-migration.js && node test-provider-session-history.js && node test-provider-session-commands.js && node test-provider-compaction.js && node test-provider-scheduler.js && node test-cursor-removal.js && node test-utility-provider-policy.js && node test-provider-subagent.js && node test-provider-recall.js && node test-provider-pack-review.js && node test-memory-mutation-queue.js && node test-provider-dream.js && node test-provider-enforcer.js && node test-provider-tool-hooks.js && node test-provider-boot-matrix.js && node test-provider-capabilities.js && node test-provider-language.js && node test-provider-coupling-audit.js && node test-provider-parity-e2e.js",
|
|
12
|
+
"pretest": "node test-provider-fixture.js && node test-provider-core-prompt.js && node test-provider-prompt-parity.js && node test-provider-env-isolation.js && node test-provider-resume-parity.js && node test-provider-bootstrap.js && node test-provider-registry.js && node test-provider-stream-decoder.js && node test-provider-events.js && node test-provider-claude.js && node test-provider-codex.js && node test-provider-runner.js && node test-provider-run-lifecycle.js && node test-provider-gateway.js && node test-provider-side-chat.js && node test-single-runtime.js && node test-provider-migration-backup.js && node test-provider-state-migration.js && node test-provider-session-history.js && node test-provider-session-commands.js && node test-provider-compaction.js && node test-provider-scheduler.js && node test-cursor-removal.js && node test-utility-provider-policy.js && node test-provider-subagent.js && node test-provider-recall.js && node test-provider-pack-review.js && node test-memory-mutation-queue.js && node test-provider-dream.js && node test-provider-enforcer.js && node test-provider-tool-hooks.js && node test-provider-boot-matrix.js && node test-provider-capabilities.js && node test-provider-language.js && node test-provider-coupling-audit.js && node test-provider-parity-e2e.js && node test-kazee-channel-health.js",
|
|
13
13
|
"test": "OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node -e \"require('./vault'); console.log('OK')\" && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-runner-watchdog-static.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-usage-accounting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-engine.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-discoverer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-project-transcripts-smoke.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-abilities.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-extraction.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-couse.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-transfer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-tiers.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-merge-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-learning-e2e.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-nesting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-dedupe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-signal.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tools.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tooling-mode.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-manifest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-evolution.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-async.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-unified-identity.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-queue-routing.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-packs.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-persona.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-pipeline.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-relationship-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-relationship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-enforcer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-identity-prune.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-message-id.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-delivery-contract.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-lock.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-web-sessions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-poll-recovery.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-409-grace.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-conflict-heal-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-single-instance.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-streaming-split.js"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"test-enforcer.js",
|
|
66
66
|
"test-identity-prune.js",
|
|
67
67
|
"test-kazee-message-id.js",
|
|
68
|
+
"test-kazee-channel-health.js",
|
|
68
69
|
"test-delivery-contract.js",
|
|
69
70
|
"test-run-lock.js",
|
|
70
71
|
"test-web-sessions.js",
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const assert = require("assert");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const { spawnSync } = require("child_process");
|
|
10
|
+
|
|
11
|
+
if (process.argv[2] === "--owner-probe") {
|
|
12
|
+
(async () => {
|
|
13
|
+
const { runInChat } = require("./core/context");
|
|
14
|
+
const access = require("./core/access");
|
|
15
|
+
const { config } = require("./core/config");
|
|
16
|
+
|
|
17
|
+
if (process.env.PROBE_MODE === "provisioned") {
|
|
18
|
+
// Agent-space injects KAZEE_OWNER_USER_ID at provision time: the owner
|
|
19
|
+
// exists before their first message, so a stranger's /auth must not
|
|
20
|
+
// reach the bootstrap path.
|
|
21
|
+
assert.strictEqual(access.hasOwner(), true, "env-provisioned kazee owner counts as owner");
|
|
22
|
+
console.log("OWNER_PROBE_OK");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
assert.strictEqual(access.hasOwner(), false, "fresh kazee pod starts ownerless");
|
|
27
|
+
await runInChat({
|
|
28
|
+
adapter: { type: "kazee", id: "kazee" },
|
|
29
|
+
channelId: "chat-doc-1",
|
|
30
|
+
canonicalUserId: "kazee:user-77",
|
|
31
|
+
userId: "user-77",
|
|
32
|
+
transport: "kazee",
|
|
33
|
+
}, async () => {
|
|
34
|
+
access.bootstrapOwner({ chatId: "chat-doc-1", name: "Owner", username: "" });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const env = fs.readFileSync(path.join(process.env.OPEN_CLAUDIA_CONFIG_DIR, ".env"), "utf8");
|
|
38
|
+
assert.match(env, /^KAZEE_OWNER_USER_ID=user-77$/m, "kazee bootstrap stores the owner USER id");
|
|
39
|
+
assert.ok(!/^TELEGRAM_CHAT_ID=.*(chat-doc-1|user-77)/m.test(env), "kazee ids must never land in TELEGRAM_CHAT_ID");
|
|
40
|
+
assert.strictEqual(config.KAZEE_OWNER_USER_ID, "user-77", "owner is live without a restart");
|
|
41
|
+
assert.strictEqual(access.hasOwner(), true);
|
|
42
|
+
|
|
43
|
+
await runInChat({
|
|
44
|
+
adapter: { type: "kazee", id: "kazee" },
|
|
45
|
+
channelId: "chat-doc-2",
|
|
46
|
+
canonicalUserId: "kazee:user-77",
|
|
47
|
+
userId: "user-77",
|
|
48
|
+
transport: "kazee",
|
|
49
|
+
}, async () => {
|
|
50
|
+
assert.strictEqual(access.isChatOwner("chat-doc-2"), true, "owner matches by user id from any kazee chat");
|
|
51
|
+
assert.strictEqual(access.isChatAuthorized("chat-doc-2"), true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await runInChat({
|
|
55
|
+
adapter: { type: "kazee", id: "kazee" },
|
|
56
|
+
channelId: "chat-doc-3",
|
|
57
|
+
canonicalUserId: "kazee:stranger-1",
|
|
58
|
+
userId: "stranger-1",
|
|
59
|
+
transport: "kazee",
|
|
60
|
+
}, async () => {
|
|
61
|
+
assert.strictEqual(access.isChatOwner("chat-doc-3"), false, "strangers are not owner");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log("OWNER_PROBE_OK");
|
|
65
|
+
})().catch((error) => {
|
|
66
|
+
process.stderr.write(`${error.stack || error.message}\n`);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
const { requiredEnvKeys } = require("./health");
|
|
71
|
+
|
|
72
|
+
assert.deepStrictEqual(
|
|
73
|
+
requiredEnvKeys({}),
|
|
74
|
+
["TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID", "WORKSPACE"],
|
|
75
|
+
"no CHANNELS keeps the legacy telegram requirement",
|
|
76
|
+
);
|
|
77
|
+
assert.deepStrictEqual(
|
|
78
|
+
requiredEnvKeys({ CHANNELS: "kazee" }),
|
|
79
|
+
["KAZEE_BOT_TOKEN", "WORKSPACE"],
|
|
80
|
+
"a kazee-only pod must not require telegram env",
|
|
81
|
+
);
|
|
82
|
+
assert.deepStrictEqual(
|
|
83
|
+
requiredEnvKeys({ CHANNELS: "telegram, kazee:main" }),
|
|
84
|
+
["TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID", "KAZEE_BOT_TOKEN", "WORKSPACE"],
|
|
85
|
+
"dual-channel installs require both, id overrides included",
|
|
86
|
+
);
|
|
87
|
+
assert.deepStrictEqual(requiredEnvKeys({ CHANNELS: "voice" }), ["WORKSPACE"]);
|
|
88
|
+
|
|
89
|
+
const scenarios = [
|
|
90
|
+
{ name: "bootstrap", mode: "bootstrap", envLines: [
|
|
91
|
+
"CHANNELS=kazee",
|
|
92
|
+
"KAZEE_BOT_TOKEN=fixture-kazee-token",
|
|
93
|
+
"KAZEE_BOT_USER_ID=bot-1",
|
|
94
|
+
] },
|
|
95
|
+
{ name: "provisioned", mode: "provisioned", envLines: [
|
|
96
|
+
"CHANNELS=kazee",
|
|
97
|
+
"KAZEE_BOT_TOKEN=fixture-kazee-token",
|
|
98
|
+
"KAZEE_BOT_USER_ID=bot-1",
|
|
99
|
+
"KAZEE_OWNER_USER_ID=owner-1",
|
|
100
|
+
] },
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
for (const scenario of scenarios) {
|
|
104
|
+
const temp = fs.mkdtempSync(path.join(os.tmpdir(), `open-claudia-kazee-${scenario.name}-`));
|
|
105
|
+
try {
|
|
106
|
+
const configDir = path.join(temp, "config");
|
|
107
|
+
const workspace = path.join(temp, "workspace");
|
|
108
|
+
fs.mkdirSync(configDir);
|
|
109
|
+
fs.mkdirSync(workspace);
|
|
110
|
+
fs.writeFileSync(
|
|
111
|
+
path.join(configDir, ".env"),
|
|
112
|
+
`${scenario.envLines.join("\n")}\nWORKSPACE=${workspace}\n`,
|
|
113
|
+
);
|
|
114
|
+
const child = spawnSync(process.execPath, [__filename, "--owner-probe"], {
|
|
115
|
+
cwd: __dirname,
|
|
116
|
+
env: {
|
|
117
|
+
HOME: path.join(temp, "config"),
|
|
118
|
+
PATH: [path.dirname(process.execPath), "/usr/bin", "/bin"].join(path.delimiter),
|
|
119
|
+
OPEN_CLAUDIA_CONFIG_DIR: configDir,
|
|
120
|
+
OPEN_CLAUDIA_TEST: "1",
|
|
121
|
+
PROBE_MODE: scenario.mode,
|
|
122
|
+
},
|
|
123
|
+
encoding: "utf8",
|
|
124
|
+
timeout: 30000,
|
|
125
|
+
});
|
|
126
|
+
assert.ifError(child.error);
|
|
127
|
+
assert.strictEqual(child.status, 0, `${scenario.name}: ${child.stderr || child.stdout}`);
|
|
128
|
+
assert.match(child.stdout, /OWNER_PROBE_OK/, scenario.name);
|
|
129
|
+
} finally {
|
|
130
|
+
fs.rmSync(temp, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.log("kazee channel health OK");
|
|
135
|
+
}
|
|
@@ -32,11 +32,11 @@ assert.doesNotMatch(setup, /Your Claude Code bot is connected|Description=Claude
|
|
|
32
32
|
|
|
33
33
|
const pkg = JSON.parse(read("package.json"));
|
|
34
34
|
assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
35
|
-
// 3.0.
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
assert.strictEqual(pkg.version, "3.0.
|
|
35
|
+
// 3.0.10 approved by Sumeet 2026-07-13 ("Do the whole stack from end go
|
|
36
|
+
// finish now then deploy it all out for me"): Kazee-only pods for the
|
|
37
|
+
// agent-space wizard — channel-aware required env keys in health.js, and
|
|
38
|
+
// kazee owner bootstrap writes KAZEE_OWNER_USER_ID, never TELEGRAM_CHAT_ID.
|
|
39
|
+
assert.strictEqual(pkg.version, "3.0.10", "release version must remain unchanged without explicit approval");
|
|
40
40
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
41
41
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
42
42
|
}
|