clankerbend 0.1.0 → 0.1.2

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 (38) hide show
  1. package/DEVELOPERS.md +6 -6
  2. package/README.md +31 -14
  3. package/apps/README.md +3 -3
  4. package/apps/sticky-notes/README.md +2 -2
  5. package/apps/sticky-notes/{onewhack.manifest.json → clankerbend.manifest.json} +1 -1
  6. package/apps/sticky-notes/package.json +3 -3
  7. package/apps/sticky-notes/public/app.js +42 -9
  8. package/apps/sticky-notes/src/sticky-notes-app.js +17 -21
  9. package/apps/vim-nav/README.md +22 -22
  10. package/apps/vim-nav/{onewhack.manifest.json → clankerbend.manifest.json} +4 -4
  11. package/apps/vim-nav/package.json +3 -3
  12. package/apps/vim-nav/public/app.js +44 -11
  13. package/apps/vim-nav/public/index.html +2 -2
  14. package/apps/vim-nav/server.mjs +2 -2
  15. package/apps/vim-nav/src/vim-nav-app.js +5 -5
  16. package/assets/clankerbend-banner.webp +0 -0
  17. package/assets/clankerbend-demo-thumbnail.webp +0 -0
  18. package/assets/clankerbend.svg +26 -0
  19. package/cli.mjs +22 -11
  20. package/docs/app-lifecycle.md +9 -9
  21. package/docs/app-manifest.md +4 -4
  22. package/docs/author-guide.md +5 -5
  23. package/docs/launcher-profiles.md +45 -10
  24. package/docs/protocol.md +248 -241
  25. package/host/README.md +4 -4
  26. package/host/src/app-registry.js +8 -6
  27. package/host/src/codex-desktop-cdp-adapter.js +85 -65
  28. package/host/src/codex-desktop-renderer-bridge.js +839 -270
  29. package/host/src/index.js +186 -34
  30. package/launch/accounts.mjs +360 -0
  31. package/launch/codex-mux-adapter.mjs +175 -0
  32. package/launch/profiles.mjs +40 -16
  33. package/launch/runtime-paths.mjs +9 -6
  34. package/launch/test-accounts.mjs +71 -0
  35. package/package.json +12 -10
  36. package/scripts/release-npm.mjs +1 -2
  37. package/server.mjs +21 -14
  38. package/assets/onewhack.jpg +0 -0
@@ -0,0 +1,71 @@
1
+ import assert from "node:assert/strict";
2
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { ClankerBendHost, createMockTranscriptAdapter } from "../host/src/index.js";
6
+ import { CodexAccountRegistry, PRIMARY_ACCOUNT_ID } from "./accounts.mjs";
7
+
8
+ const root = mkdtempSync(join(tmpdir(), "clankerbend-accounts-test-"));
9
+
10
+ try {
11
+ const primaryHome = join(root, "primary-codex-home");
12
+ const primaryElectronProfile = join(root, "primary-electron-profile");
13
+ mkdirSync(primaryHome, { recursive: true });
14
+ mkdirSync(primaryElectronProfile, { recursive: true });
15
+ writeFileSync(join(primaryHome, "config.toml"), "model = \"gpt-5.4\"\n");
16
+ writeFileSync(join(primaryHome, "auth.json"), JSON.stringify({ auth_mode: "chatgpt", tokens: {} }));
17
+
18
+ const registry = new CodexAccountRegistry({
19
+ root: join(root, "state"),
20
+ primaryCodexHome: primaryHome,
21
+ primaryElectronProfile
22
+ });
23
+
24
+ const listed = registry.list();
25
+ assert.equal(listed.accounts.length, 1);
26
+ assert.equal(listed.accounts[0].id, PRIMARY_ACCOUNT_ID);
27
+ assert.equal(listed.accounts[0].codexHome, primaryHome);
28
+
29
+ const work = registry.createManaged({ id: "work", label: "Work" });
30
+ assert.equal(work.id, "work");
31
+ assert.equal(existsSync(work.codexHome), true);
32
+ assert.equal(existsSync(work.electronProfile), true);
33
+ assert.equal(readFileSync(join(work.codexHome, "config.toml"), "utf8"), "cli_auth_credentials_store = \"file\"\n");
34
+
35
+ const duplicateLabel = registry.createManaged({ label: "Work" });
36
+ assert.equal(duplicateLabel.id, "work-2");
37
+ const numericLabel = registry.createManaged({ label: "123" });
38
+ assert.equal(numericLabel.id, "account-123");
39
+
40
+ writeFileSync(join(work.codexHome, "auth.json"), JSON.stringify({ auth_mode: "chatgpt", tokens: { account: "work" } }));
41
+ const adoption = registry.adoptAsPrimary("work");
42
+ assert.equal(existsSync(primaryHome), true);
43
+ assert.equal(JSON.parse(readFileSync(join(primaryHome, "auth.json"), "utf8")).tokens.account, "work");
44
+ assert.equal(adoption.previousPrimary.kind, "managed");
45
+ assert.equal(existsSync(adoption.backup.codexHome), true);
46
+ assert.equal(registry.list().accounts.some((account) => account.id === "work"), false);
47
+
48
+ const rollback = registry.rollbackPrimary({ backupId: adoption.previousPrimary.id });
49
+ assert.equal(rollback.restoredAccountId, adoption.previousPrimary.id);
50
+ assert.equal(JSON.parse(readFileSync(join(primaryHome, "auth.json"), "utf8")).tokens.account, undefined);
51
+ assert.equal(registry.list().accounts.some((account) => account.id === rollback.replacedPrimary.id), true);
52
+
53
+ const temp = registry.createManaged({ id: "temp", label: "Temp" });
54
+ const deleted = registry.deleteManaged("temp");
55
+ assert.equal(registry.list().accounts.some((account) => account.id === "temp"), false);
56
+ assert.equal(existsSync(deleted.deletedRoot), true);
57
+ assert.equal(existsSync(deleted.codexHome), true);
58
+
59
+ const fresh = registry.createManaged({ id: "fresh", label: "Fresh" });
60
+ const host = new ClankerBendHost({
61
+ accountRegistry: registry,
62
+ transcriptAdapter: createMockTranscriptAdapter()
63
+ });
64
+ assert.equal(host.publicState().codexAccounts.accounts.find((account) => account.id === "fresh").auth.authJson, false);
65
+ writeFileSync(join(fresh.codexHome, "auth.json"), JSON.stringify({ auth_mode: "chatgpt", tokens: { account: "fresh" } }));
66
+ assert.equal(host.publicState().codexAccounts.accounts.find((account) => account.id === "fresh").auth.authJson, true);
67
+
68
+ console.log("clankerbend account registry tests passed");
69
+ } finally {
70
+ rmSync(root, { recursive: true, force: true });
71
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "clankerbend",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
- "description": "OneWill Extension Hacks protocol host and public reference apps.",
5
+ "description": "OneWill ClankerBend protocol host and public reference apps.",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "codex",
@@ -10,13 +10,13 @@
10
10
  "desktop",
11
11
  "extensions"
12
12
  ],
13
- "homepage": "https://github.com/OneWillAI/OneWhack#readme",
13
+ "homepage": "https://github.com/OneWillAI/clankerbend#readme",
14
14
  "bugs": {
15
- "url": "https://github.com/OneWillAI/OneWhack/issues"
15
+ "url": "https://github.com/OneWillAI/clankerbend/issues"
16
16
  },
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "git+https://github.com/OneWillAI/OneWhack.git"
19
+ "url": "git+https://github.com/OneWillAI/clankerbend.git"
20
20
  },
21
21
  "bin": {
22
22
  "clankerbend": "./cli.mjs"
@@ -24,17 +24,19 @@
24
24
  "files": [
25
25
  "cli.mjs",
26
26
  "server.mjs",
27
- "assets/onewhack.jpg",
27
+ "assets/clankerbend-banner.webp",
28
+ "assets/clankerbend-demo-thumbnail.webp",
29
+ "assets/clankerbend.svg",
28
30
  "scripts/release-npm.mjs",
29
31
  "host/src",
30
32
  "launch",
31
33
  "apps/README.md",
32
- "apps/vim-nav/onewhack.manifest.json",
34
+ "apps/vim-nav/clankerbend.manifest.json",
33
35
  "apps/vim-nav/package.json",
34
36
  "apps/vim-nav/public",
35
37
  "apps/vim-nav/src",
36
38
  "apps/vim-nav/README.md",
37
- "apps/sticky-notes/onewhack.manifest.json",
39
+ "apps/sticky-notes/clankerbend.manifest.json",
38
40
  "apps/sticky-notes/package.json",
39
41
  "apps/sticky-notes/public",
40
42
  "apps/sticky-notes/src",
@@ -49,8 +51,8 @@
49
51
  "apps/*"
50
52
  ],
51
53
  "scripts": {
52
- "start": "node cli.mjs codex",
53
- "start:mock": "node cli.mjs codex --mock",
54
+ "start": "node cli.mjs",
55
+ "start:mock": "node cli.mjs --mock",
54
56
  "test": "node scripts/test.mjs",
55
57
  "test:vim-nav": "npm --prefix apps/vim-nav test",
56
58
  "test:sticky-notes": "npm --prefix apps/sticky-notes test",
@@ -95,7 +95,7 @@ function isKnownProvenanceCi() {
95
95
  }
96
96
 
97
97
  async function repackWithName(tarball, packageName) {
98
- const stageRoot = await mkdtemp(join(tmpdir(), "onewhack-npm-release-"));
98
+ const stageRoot = await mkdtemp(join(tmpdir(), "clankerbend-npm-release-"));
99
99
  try {
100
100
  await execFileAsync("tar", ["-xzf", tarball, "-C", stageRoot], { cwd: ROOT });
101
101
  const packageDir = join(stageRoot, "package");
@@ -195,7 +195,6 @@ function splitCompoundName(part) {
195
195
  const tokens = [part];
196
196
  if (part.includes("clanker")) tokens.push("clanker");
197
197
  if (part.includes("bend")) tokens.push("bend");
198
- if (part.includes("whack")) tokens.push("whack");
199
198
  if (part.includes("onewill")) tokens.push("onewill");
200
199
  if (part.includes("ai")) tokens.push("ai");
201
200
  return tokens;
package/server.mjs CHANGED
@@ -1,31 +1,38 @@
1
1
  import { pathToFileURL } from "node:url";
2
- import { createCodexDesktopCdpAdapter } from "./host/src/codex-desktop-cdp-adapter.js";
3
- import { OneWhackHost, createMockTranscriptAdapter } from "./host/src/index.js";
2
+ import { ClankerBendHost, createMockTranscriptAdapter } from "./host/src/index.js";
3
+ import { createCodexDesktopMuxAdapter } from "./launch/codex-mux-adapter.mjs";
4
4
  import { navigateProfile, printLaunchStatus } from "./launch/profiles.mjs";
5
5
 
6
- export async function launchOneWhackCodex(options = {}) {
6
+ export async function launchClankerBendCodex(options = {}) {
7
7
  const mockMode = Boolean(options.mock);
8
- const localDevInsecure = options.localDevInsecure === true || process.env.ONEWILL_ONEWHACK_DISABLE_AUTH === "1";
8
+ const localDevInsecure = options.localDevInsecure === true || process.env.ONEWILL_CLANKERBEND_DISABLE_AUTH === "1";
9
9
  const profile = await navigateProfile({
10
10
  stateDir: options.stateDir,
11
11
  runDir: options.runDir,
12
12
  registryConfigPath: options.registryConfigPath,
13
- registryProfileId: options.registryProfileId
13
+ registryProfileId: options.registryProfileId,
14
+ accountId: options.accountId,
15
+ primaryCodexHome: options.primaryCodexHome
14
16
  });
15
17
 
16
- const host = new OneWhackHost({
18
+ const host = new ClankerBendHost({
17
19
  hostId: profile.hostId,
18
20
  hostName: profile.hostName,
19
- token: options.token || process.env.ONEWILL_ONEWHACK_TOKEN || undefined,
21
+ token: options.token || process.env.ONEWILL_CLANKERBEND_TOKEN || undefined,
20
22
  localDevInsecure,
21
23
  runDir: profile.runDir,
24
+ accountRegistry: profile.accountRegistry,
22
25
  transcriptAdapter: mockMode
23
26
  ? createMockTranscriptAdapter({ defaultAppId: profile.defaultPanelAppId, providers: profile.providers })
24
- : createCodexDesktopCdpAdapter({
25
- runDir: profile.runDir,
26
- profileDir: profile.runtimePaths?.codexProfileDir,
27
- rendererBridges: profile.rendererBridges,
28
- providers: profile.providers
27
+ : createCodexDesktopMuxAdapter({
28
+ accountRegistry: profile.accountRegistry,
29
+ startAccountId: profile.startAccountId,
30
+ providers: profile.providers,
31
+ adapterOptions: {
32
+ runDir: profile.runDir,
33
+ rendererBridges: profile.rendererBridges,
34
+ providers: profile.providers
35
+ }
29
36
  })
30
37
  });
31
38
 
@@ -41,7 +48,7 @@ export async function launchOneWhackCodex(options = {}) {
41
48
  process.once("SIGINT", () => cleanupAndExit(0));
42
49
  process.once("SIGTERM", () => cleanupAndExit(0));
43
50
  process.once("uncaughtException", (err) => {
44
- console.error(`OneWhack could not start. Close any OneWhack-launched Codex Desktop window, then run this command again. Details: ${err.message}`);
51
+ console.error(`ClankerBend could not start. Close any ClankerBend-launched Codex Desktop window, then run this command again. Details: ${err.message}`);
45
52
  cleanupAndExit(1);
46
53
  });
47
54
  }
@@ -52,7 +59,7 @@ export async function launchOneWhackCodex(options = {}) {
52
59
  }
53
60
 
54
61
  if (import.meta.url === pathToFileURL(process.argv[1] || "").href) {
55
- await launchOneWhackCodex({
62
+ await launchClankerBendCodex({
56
63
  mock: process.argv.includes("--mock")
57
64
  });
58
65
  }
Binary file