clankerbend 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEVELOPERS.md +63 -0
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/apps/README.md +11 -0
- package/apps/sticky-notes/README.md +11 -0
- package/apps/sticky-notes/onewhack.manifest.json +74 -0
- package/apps/sticky-notes/package.json +14 -0
- package/apps/sticky-notes/public/app.js +117 -0
- package/apps/sticky-notes/public/index.html +23 -0
- package/apps/sticky-notes/public/styles.css +84 -0
- package/apps/sticky-notes/src/sticky-notes-app.js +413 -0
- package/apps/vim-nav/README.md +126 -0
- package/apps/vim-nav/onewhack.manifest.json +69 -0
- package/apps/vim-nav/package.json +16 -0
- package/apps/vim-nav/public/app.js +276 -0
- package/apps/vim-nav/public/index.html +53 -0
- package/apps/vim-nav/public/styles.css +211 -0
- package/apps/vim-nav/server.mjs +10 -0
- package/apps/vim-nav/src/vim-nav-app.js +221 -0
- package/assets/onewhack.jpg +0 -0
- package/cli.mjs +91 -0
- package/docs/app-lifecycle.md +63 -0
- package/docs/app-manifest.md +130 -0
- package/docs/author-guide.md +126 -0
- package/docs/launcher-profiles.md +50 -0
- package/docs/protocol.md +1935 -0
- package/host/README.md +18 -0
- package/host/src/app-registry.js +315 -0
- package/host/src/codex-desktop-cdp-adapter.js +1826 -0
- package/host/src/codex-desktop-renderer-bridge.js +3536 -0
- package/host/src/index.js +1177 -0
- package/launch/profiles.mjs +93 -0
- package/launch/runtime-paths.mjs +21 -0
- package/package.json +66 -0
- package/scripts/release-npm.mjs +202 -0
- package/server.mjs +58 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import {
|
|
4
|
+
enabledManifestPathsFromConfig,
|
|
5
|
+
loadProfileFromManifests,
|
|
6
|
+
loadRegistryConfig,
|
|
7
|
+
mergeManifestPaths,
|
|
8
|
+
providersFromRendererBridges,
|
|
9
|
+
readAppManifest
|
|
10
|
+
} from "../host/src/app-registry.js";
|
|
11
|
+
import { oneWhackRuntimePaths } from "./runtime-paths.mjs";
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const ROOT_DIR = join(__dirname, "..");
|
|
15
|
+
|
|
16
|
+
export const PROFILE_NAVIGATE = "navigate";
|
|
17
|
+
export const VIM_NAV_MANIFEST_PATH = join(ROOT_DIR, "apps/vim-nav/onewhack.manifest.json");
|
|
18
|
+
export const STICKY_NOTES_MANIFEST_PATH = join(ROOT_DIR, "apps/sticky-notes/onewhack.manifest.json");
|
|
19
|
+
export const CODEX_DESKTOP_RENDERER_BRIDGE_PATH = join(ROOT_DIR, "host/src/codex-desktop-renderer-bridge.js");
|
|
20
|
+
export const VIM_NAV_APP_ID = readAppManifest(VIM_NAV_MANIFEST_PATH).appId;
|
|
21
|
+
export const STICKY_NOTES_APP_ID = readAppManifest(STICKY_NOTES_MANIFEST_PATH).appId;
|
|
22
|
+
|
|
23
|
+
export async function navigateProfile(options = {}) {
|
|
24
|
+
const runtimePaths = oneWhackRuntimePaths({ stateDir: options.stateDir });
|
|
25
|
+
const runDir = options.runDir || runtimePaths.runDir;
|
|
26
|
+
const profile = await loadProfileFromManifests({
|
|
27
|
+
profileId: PROFILE_NAVIGATE,
|
|
28
|
+
name: "Navigate",
|
|
29
|
+
description: "Codex Desktop with OneWill Navigate transcript controls.",
|
|
30
|
+
hostId: "onewill.onewhack.host",
|
|
31
|
+
hostName: "OneWhack Navigate",
|
|
32
|
+
runDir,
|
|
33
|
+
runtimePaths,
|
|
34
|
+
defaultPanelAppId: VIM_NAV_APP_ID,
|
|
35
|
+
manifestPaths: configuredManifestPaths([VIM_NAV_MANIFEST_PATH, STICKY_NOTES_MANIFEST_PATH], {
|
|
36
|
+
registryConfigPath: options.registryConfigPath || runtimePaths.registryConfigPath,
|
|
37
|
+
registryProfileId: options.registryProfileId || "public"
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
const bridge = codexDesktopRendererBridge();
|
|
41
|
+
profile.rendererBridges = [bridge, ...profile.rendererBridges];
|
|
42
|
+
profile.providers = providersFromRendererBridges(profile.rendererBridges);
|
|
43
|
+
return profile;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function configuredManifestPaths(baseManifestPaths, options = {}) {
|
|
47
|
+
const runtimePaths = oneWhackRuntimePaths({ stateDir: options.stateDir });
|
|
48
|
+
const configPath = options.registryConfigPath || process.env.ONEWILL_ONEWHACK_REGISTRY_CONFIG || runtimePaths.registryConfigPath;
|
|
49
|
+
const profileId = options.registryProfileId || process.env.ONEWILL_ONEWHACK_PROFILE || "default";
|
|
50
|
+
const config = loadRegistryConfig(configPath);
|
|
51
|
+
return mergeManifestPaths(baseManifestPaths, enabledManifestPathsFromConfig(config, profileId));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function navigateProviders() {
|
|
55
|
+
return providersFromRendererBridges([codexDesktopRendererBridge(), {
|
|
56
|
+
appId: STICKY_NOTES_APP_ID,
|
|
57
|
+
provides: [
|
|
58
|
+
"composerContext",
|
|
59
|
+
"composerDraft"
|
|
60
|
+
]
|
|
61
|
+
}]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function codexDesktopRendererBridge() {
|
|
65
|
+
return {
|
|
66
|
+
appId: VIM_NAV_APP_ID,
|
|
67
|
+
injectedScriptPath: CODEX_DESKTOP_RENDERER_BRIDGE_PATH,
|
|
68
|
+
openPanelMethod: "openPanel",
|
|
69
|
+
scrollMethod: "scrollToAnchor",
|
|
70
|
+
highlightMethod: "highlightAnchor",
|
|
71
|
+
primary: true,
|
|
72
|
+
provides: [
|
|
73
|
+
"transcriptSnapshot",
|
|
74
|
+
"transcriptOrder",
|
|
75
|
+
"transcriptNavigation",
|
|
76
|
+
"transcriptHighlight"
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function printLaunchStatus(profile, host, options = {}) {
|
|
82
|
+
const mode = options.mockMode ? "Mock transcript" : "Codex Desktop";
|
|
83
|
+
console.log("");
|
|
84
|
+
console.log(`OneWhack: ${profile.name}`);
|
|
85
|
+
console.log(`Status: ${mode} is running`);
|
|
86
|
+
console.log(`Panel: ${host.state.panel.url}`);
|
|
87
|
+
console.log(`Host: ${host.state.host.url}`);
|
|
88
|
+
if (!options.mockMode) {
|
|
89
|
+
console.log("Codex Desktop is open. Use the Browser side panel for OneWhack apps.");
|
|
90
|
+
}
|
|
91
|
+
console.log("Press Ctrl+C to stop OneWhack and the launched Codex Desktop process.");
|
|
92
|
+
console.log("");
|
|
93
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { homedir, platform } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
export function oneWhackStateDir() {
|
|
5
|
+
if (process.env.ONEWILL_ONEWHACK_STATE_DIR) return process.env.ONEWILL_ONEWHACK_STATE_DIR;
|
|
6
|
+
if (platform() === "darwin") {
|
|
7
|
+
return join(homedir(), "Library/Application Support/OneWill/OneWhack");
|
|
8
|
+
}
|
|
9
|
+
return join(homedir(), ".local/state/onewill/onewhack");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function oneWhackRuntimePaths(options = {}) {
|
|
13
|
+
const root = options.stateDir || oneWhackStateDir();
|
|
14
|
+
return {
|
|
15
|
+
root,
|
|
16
|
+
runDir: join(root, "run"),
|
|
17
|
+
registryConfigPath: join(root, "registry.json"),
|
|
18
|
+
appInstallDir: join(root, "apps"),
|
|
19
|
+
codexProfileDir: join(root, "codex-profile")
|
|
20
|
+
};
|
|
21
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clankerbend",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OneWill Extension Hacks protocol host and public reference apps.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"codex",
|
|
9
|
+
"clankerbend",
|
|
10
|
+
"desktop",
|
|
11
|
+
"extensions"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/OneWillAI/OneWhack#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/OneWillAI/OneWhack/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/OneWillAI/OneWhack.git"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"clankerbend": "./cli.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"cli.mjs",
|
|
26
|
+
"server.mjs",
|
|
27
|
+
"assets/onewhack.jpg",
|
|
28
|
+
"scripts/release-npm.mjs",
|
|
29
|
+
"host/src",
|
|
30
|
+
"launch",
|
|
31
|
+
"apps/README.md",
|
|
32
|
+
"apps/vim-nav/onewhack.manifest.json",
|
|
33
|
+
"apps/vim-nav/package.json",
|
|
34
|
+
"apps/vim-nav/public",
|
|
35
|
+
"apps/vim-nav/src",
|
|
36
|
+
"apps/vim-nav/README.md",
|
|
37
|
+
"apps/sticky-notes/onewhack.manifest.json",
|
|
38
|
+
"apps/sticky-notes/package.json",
|
|
39
|
+
"apps/sticky-notes/public",
|
|
40
|
+
"apps/sticky-notes/src",
|
|
41
|
+
"apps/sticky-notes/README.md",
|
|
42
|
+
"docs",
|
|
43
|
+
"DEVELOPERS.md",
|
|
44
|
+
"README.md",
|
|
45
|
+
"LICENSE"
|
|
46
|
+
],
|
|
47
|
+
"workspaces": [
|
|
48
|
+
"host",
|
|
49
|
+
"apps/*"
|
|
50
|
+
],
|
|
51
|
+
"scripts": {
|
|
52
|
+
"start": "node cli.mjs codex",
|
|
53
|
+
"start:mock": "node cli.mjs codex --mock",
|
|
54
|
+
"test": "node scripts/test.mjs",
|
|
55
|
+
"test:vim-nav": "npm --prefix apps/vim-nav test",
|
|
56
|
+
"test:sticky-notes": "npm --prefix apps/sticky-notes test",
|
|
57
|
+
"test:vim-nav:desktop-real": "npm --prefix apps/vim-nav run test:desktop-real",
|
|
58
|
+
"test:sticky-notes:desktop-real": "npm --prefix apps/sticky-notes run test:desktop-real",
|
|
59
|
+
"test:desktop-real:integration": "npm run test:vim-nav:desktop-real && npm run test:sticky-notes:desktop-real",
|
|
60
|
+
"release:pack": "node scripts/release-npm.mjs pack",
|
|
61
|
+
"release:publish": "node scripts/release-npm.mjs publish"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=22"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { execFile, spawn } from "node:child_process";
|
|
2
|
+
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, join, resolve } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
|
|
9
|
+
const ROOT = resolve(new URL("..", import.meta.url).pathname);
|
|
10
|
+
const DIST_DIR = join(ROOT, "dist/npm");
|
|
11
|
+
const PACKAGE_NAMES = ["clankerbend", "@onewillai/clankerbend"];
|
|
12
|
+
|
|
13
|
+
const command = process.argv[2] || "pack";
|
|
14
|
+
|
|
15
|
+
if (!["pack", "publish"].includes(command)) {
|
|
16
|
+
console.error("Usage: node scripts/release-npm.mjs pack|publish");
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
if (command === "pack") {
|
|
22
|
+
await packRelease();
|
|
23
|
+
} else {
|
|
24
|
+
await publishRelease();
|
|
25
|
+
}
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.error(formatReleaseError(err));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function packRelease() {
|
|
32
|
+
await rm(DIST_DIR, { recursive: true, force: true });
|
|
33
|
+
await mkdir(DIST_DIR, { recursive: true });
|
|
34
|
+
|
|
35
|
+
const basePack = await npm(["pack", "--json", "--pack-destination", DIST_DIR], ROOT);
|
|
36
|
+
const base = JSON.parse(basePack.stdout)[0];
|
|
37
|
+
const baseTarball = join(DIST_DIR, base.filename);
|
|
38
|
+
const scopedTarball = await repackWithName(baseTarball, PACKAGE_NAMES[1]);
|
|
39
|
+
|
|
40
|
+
console.log(JSON.stringify({
|
|
41
|
+
ok: true,
|
|
42
|
+
packages: [
|
|
43
|
+
{ name: PACKAGE_NAMES[0], tarball: baseTarball },
|
|
44
|
+
{ name: PACKAGE_NAMES[1], tarball: scopedTarball }
|
|
45
|
+
]
|
|
46
|
+
}, null, 2));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function publishRelease() {
|
|
50
|
+
const args = process.argv.slice(3);
|
|
51
|
+
const yes = args.includes("--yes");
|
|
52
|
+
if (!yes) {
|
|
53
|
+
console.error("Refusing to publish without --yes. Run `npm run release:publish -- --yes [--otp=123456]`.");
|
|
54
|
+
process.exit(2);
|
|
55
|
+
}
|
|
56
|
+
const otp = args.find((arg) => arg.startsWith("--otp="));
|
|
57
|
+
const useProvenance = args.includes("--provenance") || isKnownProvenanceCi();
|
|
58
|
+
|
|
59
|
+
await packRelease();
|
|
60
|
+
const rootPackage = JSON.parse(await readFile(join(ROOT, "package.json"), "utf8"));
|
|
61
|
+
const version = rootPackage.version;
|
|
62
|
+
const tarballs = [
|
|
63
|
+
join(DIST_DIR, `clankerbend-${version}.tgz`),
|
|
64
|
+
join(DIST_DIR, `onewillai-clankerbend-${version}.tgz`)
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
await npmInteractive(
|
|
68
|
+
publishArgs(tarballs[1], ["--access", "public"], { otp, useProvenance }),
|
|
69
|
+
ROOT,
|
|
70
|
+
{ packageName: PACKAGE_NAMES[1] }
|
|
71
|
+
);
|
|
72
|
+
await npmInteractive(
|
|
73
|
+
publishArgs(tarballs[0], [], { otp, useProvenance }),
|
|
74
|
+
ROOT,
|
|
75
|
+
{ packageName: PACKAGE_NAMES[0] }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function publishArgs(tarball, extraArgs, { otp, useProvenance }) {
|
|
80
|
+
const args = ["publish", tarball, ...extraArgs];
|
|
81
|
+
if (useProvenance) {
|
|
82
|
+
args.push("--provenance");
|
|
83
|
+
}
|
|
84
|
+
if (otp) {
|
|
85
|
+
args.push(otp);
|
|
86
|
+
}
|
|
87
|
+
return args;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isKnownProvenanceCi() {
|
|
91
|
+
return Boolean(
|
|
92
|
+
process.env.GITHUB_ACTIONS ||
|
|
93
|
+
process.env.GITLAB_CI
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function repackWithName(tarball, packageName) {
|
|
98
|
+
const stageRoot = await mkdtemp(join(tmpdir(), "onewhack-npm-release-"));
|
|
99
|
+
try {
|
|
100
|
+
await execFileAsync("tar", ["-xzf", tarball, "-C", stageRoot], { cwd: ROOT });
|
|
101
|
+
const packageDir = join(stageRoot, "package");
|
|
102
|
+
const packageJsonPath = join(packageDir, "package.json");
|
|
103
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
104
|
+
packageJson.name = packageName;
|
|
105
|
+
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
106
|
+
|
|
107
|
+
const output = await npm(["pack", packageDir, "--json", "--pack-destination", DIST_DIR], ROOT);
|
|
108
|
+
const packed = JSON.parse(output.stdout)[0];
|
|
109
|
+
return join(DIST_DIR, basename(packed.filename));
|
|
110
|
+
} finally {
|
|
111
|
+
await rm(stageRoot, { recursive: true, force: true });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function npm(args, cwd) {
|
|
116
|
+
return execFileAsync("npm", args, {
|
|
117
|
+
cwd,
|
|
118
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
119
|
+
env: process.env
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function npmInteractive(args, cwd, context = {}) {
|
|
124
|
+
await new Promise((resolve, reject) => {
|
|
125
|
+
const stderr = [];
|
|
126
|
+
const child = spawn("npm", args, {
|
|
127
|
+
cwd,
|
|
128
|
+
env: process.env,
|
|
129
|
+
stdio: ["inherit", "inherit", "pipe"]
|
|
130
|
+
});
|
|
131
|
+
child.stderr.on("data", (chunk) => {
|
|
132
|
+
stderr.push(chunk);
|
|
133
|
+
process.stderr.write(chunk);
|
|
134
|
+
});
|
|
135
|
+
child.on("error", reject);
|
|
136
|
+
child.on("exit", (code, signal) => {
|
|
137
|
+
if (code === 0) {
|
|
138
|
+
resolve();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
reject(releaseCommandError(args, signal || `exit code ${code}`, {
|
|
142
|
+
...context,
|
|
143
|
+
stderr: Buffer.concat(stderr).toString("utf8")
|
|
144
|
+
}));
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function releaseCommandError(args, reason, context) {
|
|
150
|
+
const err = new Error(`npm ${args.join(" ")} failed with ${reason}`);
|
|
151
|
+
err.releaseCommand = true;
|
|
152
|
+
err.args = args;
|
|
153
|
+
err.reason = reason;
|
|
154
|
+
err.stderr = context.stderr || "";
|
|
155
|
+
err.packageName = context.packageName || "";
|
|
156
|
+
return err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function formatReleaseError(err) {
|
|
160
|
+
if (err?.releaseCommand && /That word is not allowed/i.test(err.stderr || "")) {
|
|
161
|
+
const packageName = err.packageName || "the package";
|
|
162
|
+
const candidates = candidateNameTokens(packageName);
|
|
163
|
+
return [
|
|
164
|
+
"",
|
|
165
|
+
`npm rejected ${packageName}: "That word is not allowed."`,
|
|
166
|
+
"",
|
|
167
|
+
"npm's registry response does not disclose the exact blocked token. The",
|
|
168
|
+
"only package-name tokens we can identify locally are:",
|
|
169
|
+
` ${candidates.map((token) => `- ${token}`).join("\n ")}`,
|
|
170
|
+
"",
|
|
171
|
+
"If npm support has unblocked the name, retry after they confirm the change",
|
|
172
|
+
"has propagated. Otherwise ask support to allow this exact package id:",
|
|
173
|
+
` ${packageName}`,
|
|
174
|
+
""
|
|
175
|
+
].join("\n");
|
|
176
|
+
}
|
|
177
|
+
if (err?.releaseCommand) {
|
|
178
|
+
return `\n${err.message}\n`;
|
|
179
|
+
}
|
|
180
|
+
return err?.stack || String(err);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function candidateNameTokens(packageName) {
|
|
184
|
+
const withoutScope = packageName.replace(/^@/, "");
|
|
185
|
+
const tokens = new Set(
|
|
186
|
+
withoutScope
|
|
187
|
+
.split(/[\/._-]+/)
|
|
188
|
+
.flatMap((part) => splitCompoundName(part))
|
|
189
|
+
.filter(Boolean)
|
|
190
|
+
);
|
|
191
|
+
return [...tokens];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function splitCompoundName(part) {
|
|
195
|
+
const tokens = [part];
|
|
196
|
+
if (part.includes("clanker")) tokens.push("clanker");
|
|
197
|
+
if (part.includes("bend")) tokens.push("bend");
|
|
198
|
+
if (part.includes("whack")) tokens.push("whack");
|
|
199
|
+
if (part.includes("onewill")) tokens.push("onewill");
|
|
200
|
+
if (part.includes("ai")) tokens.push("ai");
|
|
201
|
+
return tokens;
|
|
202
|
+
}
|
package/server.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
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";
|
|
4
|
+
import { navigateProfile, printLaunchStatus } from "./launch/profiles.mjs";
|
|
5
|
+
|
|
6
|
+
export async function launchOneWhackCodex(options = {}) {
|
|
7
|
+
const mockMode = Boolean(options.mock);
|
|
8
|
+
const localDevInsecure = options.localDevInsecure === true || process.env.ONEWILL_ONEWHACK_DISABLE_AUTH === "1";
|
|
9
|
+
const profile = await navigateProfile({
|
|
10
|
+
stateDir: options.stateDir,
|
|
11
|
+
runDir: options.runDir,
|
|
12
|
+
registryConfigPath: options.registryConfigPath,
|
|
13
|
+
registryProfileId: options.registryProfileId
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const host = new OneWhackHost({
|
|
17
|
+
hostId: profile.hostId,
|
|
18
|
+
hostName: profile.hostName,
|
|
19
|
+
token: options.token || process.env.ONEWILL_ONEWHACK_TOKEN || undefined,
|
|
20
|
+
localDevInsecure,
|
|
21
|
+
runDir: profile.runDir,
|
|
22
|
+
transcriptAdapter: mockMode
|
|
23
|
+
? 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
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
for (const app of profile.apps) host.registerApp(app);
|
|
33
|
+
host.setActivePanelApp(profile.defaultPanelAppId);
|
|
34
|
+
|
|
35
|
+
const cleanupAndExit = async (code = 0) => {
|
|
36
|
+
await host.stop().catch(() => {});
|
|
37
|
+
process.exit(code);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (options.installSignalHandlers !== false) {
|
|
41
|
+
process.once("SIGINT", () => cleanupAndExit(0));
|
|
42
|
+
process.once("SIGTERM", () => cleanupAndExit(0));
|
|
43
|
+
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}`);
|
|
45
|
+
cleanupAndExit(1);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await host.start();
|
|
50
|
+
printLaunchStatus(profile, host, { mockMode });
|
|
51
|
+
return { host, profile, mockMode };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (import.meta.url === pathToFileURL(process.argv[1] || "").href) {
|
|
55
|
+
await launchOneWhackCodex({
|
|
56
|
+
mock: process.argv.includes("--mock")
|
|
57
|
+
});
|
|
58
|
+
}
|