@codegrammer/co-od 0.1.5 → 0.1.7
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/dist/adapters/codex.js +127 -6
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +1 -1
- package/dist/adapters/openclaw.js +92 -3
- package/dist/api-client.js +1 -1
- package/dist/commands/join.js +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/start.d.ts +1 -1
- package/dist/commands/start.js +48 -12
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
package/dist/adapters/codex.js
CHANGED
|
@@ -1,9 +1,73 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
function which(cmd) {
|
|
4
5
|
const paths = (process.env.PATH || "").split(":");
|
|
5
6
|
return paths.some((dir) => existsSync(`${dir}/${cmd}`));
|
|
6
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse a Codex JSONL event and report it as an agent step to co-ode.
|
|
10
|
+
* Codex events: thread.started, turn.started, turn.completed,
|
|
11
|
+
* item.started, item.completed (with item types: command_execution,
|
|
12
|
+
* file_change, mcp_tool_call, agent_message, reasoning, plan_update)
|
|
13
|
+
*/
|
|
14
|
+
async function reportCodexEvent(event, config) {
|
|
15
|
+
const type = event.type;
|
|
16
|
+
const item = event.item;
|
|
17
|
+
// Only report completed items as steps
|
|
18
|
+
if (type !== "item.completed" || !item)
|
|
19
|
+
return;
|
|
20
|
+
const itemType = item.type;
|
|
21
|
+
let stepKind;
|
|
22
|
+
let description;
|
|
23
|
+
let payload = {};
|
|
24
|
+
switch (itemType) {
|
|
25
|
+
case "command_execution":
|
|
26
|
+
stepKind = "tool_call";
|
|
27
|
+
description = item.command || "exec";
|
|
28
|
+
payload = { command: item.command, exitCode: item.exit_code };
|
|
29
|
+
break;
|
|
30
|
+
case "file_change":
|
|
31
|
+
stepKind = "tool_call";
|
|
32
|
+
description = `write ${item.path || "file"}`;
|
|
33
|
+
payload = { path: item.path };
|
|
34
|
+
break;
|
|
35
|
+
case "mcp_tool_call":
|
|
36
|
+
stepKind = "tool_call";
|
|
37
|
+
description = item.tool_name || "mcp_tool";
|
|
38
|
+
payload = { tool: item.tool_name };
|
|
39
|
+
break;
|
|
40
|
+
case "agent_message":
|
|
41
|
+
stepKind = "observation";
|
|
42
|
+
description = (item.text || "").slice(0, 200);
|
|
43
|
+
payload = { text: (item.text || "").slice(0, 4000) };
|
|
44
|
+
break;
|
|
45
|
+
case "plan_update":
|
|
46
|
+
stepKind = "plan";
|
|
47
|
+
description = "plan updated";
|
|
48
|
+
payload = { plan: item.plan };
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
return; // Skip reasoning, web_search, etc.
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await fetch(`${config.serverUrl}/api/rooms/${config.roomId}/agent-runs/${config.runId}/steps`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: {
|
|
57
|
+
"content-type": "application/json",
|
|
58
|
+
authorization: `Bearer ${config.sessionToken}`,
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
kind: stepKind,
|
|
62
|
+
input: { description, payload },
|
|
63
|
+
output: { success: true, payload },
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Non-fatal — don't break Codex execution
|
|
69
|
+
}
|
|
70
|
+
}
|
|
7
71
|
export class CodexAdapter {
|
|
8
72
|
name = "codex";
|
|
9
73
|
async available() {
|
|
@@ -11,25 +75,82 @@ export class CodexAdapter {
|
|
|
11
75
|
}
|
|
12
76
|
async execute(goal, options) {
|
|
13
77
|
const { workDir, onOutput, signal } = options;
|
|
78
|
+
const hasRoomContext = Boolean(options.roomId && options.runId && options.serverUrl && options.sessionToken);
|
|
79
|
+
// Use --json for JSONL event streaming when we have room context
|
|
80
|
+
const args = ["exec", "--full-auto"];
|
|
81
|
+
if (hasRoomContext)
|
|
82
|
+
args.push("--json");
|
|
83
|
+
args.push("--", goal);
|
|
14
84
|
return new Promise((resolve, reject) => {
|
|
15
|
-
const child = spawn("codex",
|
|
85
|
+
const child = spawn("codex", args, {
|
|
16
86
|
cwd: workDir,
|
|
17
|
-
env: {
|
|
87
|
+
env: {
|
|
88
|
+
...process.env,
|
|
89
|
+
CO_OD_ROOM_ID: options.roomId || "",
|
|
90
|
+
CO_OD_RUN_ID: options.runId || "",
|
|
91
|
+
},
|
|
18
92
|
stdio: ["pipe", "pipe", "pipe"],
|
|
19
93
|
});
|
|
20
94
|
let stdout = "";
|
|
21
95
|
let stderr = "";
|
|
96
|
+
let lastAgentMessage = "";
|
|
22
97
|
child.stdout?.setEncoding("utf-8");
|
|
23
98
|
child.stderr?.setEncoding("utf-8");
|
|
24
|
-
|
|
25
|
-
stdout
|
|
26
|
-
|
|
27
|
-
|
|
99
|
+
if (hasRoomContext) {
|
|
100
|
+
// Parse JSONL events from stdout for real-time reporting
|
|
101
|
+
const rl = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
102
|
+
rl.on("line", (line) => {
|
|
103
|
+
stdout += line + "\n";
|
|
104
|
+
try {
|
|
105
|
+
const event = JSON.parse(line);
|
|
106
|
+
// Extract final agent message for display
|
|
107
|
+
if (event.type === "item.completed" &&
|
|
108
|
+
event.item?.type === "agent_message") {
|
|
109
|
+
lastAgentMessage =
|
|
110
|
+
event.item.text || "";
|
|
111
|
+
}
|
|
112
|
+
// Report progress to co-ode
|
|
113
|
+
const config = {
|
|
114
|
+
roomId: options.roomId,
|
|
115
|
+
runId: options.runId,
|
|
116
|
+
serverUrl: options.serverUrl,
|
|
117
|
+
sessionToken: options.sessionToken,
|
|
118
|
+
};
|
|
119
|
+
void reportCodexEvent(event, config);
|
|
120
|
+
// Feed human-readable output to onOutput
|
|
121
|
+
const itemType = event.item?.type;
|
|
122
|
+
if (event.type === "item.completed" && itemType === "command_execution") {
|
|
123
|
+
onOutput?.(`$ ${event.item.command}\n`);
|
|
124
|
+
}
|
|
125
|
+
else if (event.type === "item.completed" && itemType === "file_change") {
|
|
126
|
+
onOutput?.(`[write] ${event.item.path}\n`);
|
|
127
|
+
}
|
|
128
|
+
else if (event.type === "item.completed" && itemType === "agent_message") {
|
|
129
|
+
onOutput?.(`${(event.item.text || "").slice(0, 500)}\n`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Not valid JSON — pass through as raw output
|
|
134
|
+
onOutput?.(line + "\n");
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// No room context — raw output mode (original behavior)
|
|
140
|
+
child.stdout?.on("data", (chunk) => {
|
|
141
|
+
stdout += chunk;
|
|
142
|
+
onOutput?.(chunk);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
28
145
|
child.stderr?.on("data", (chunk) => {
|
|
29
146
|
stderr += chunk;
|
|
30
147
|
onOutput?.(chunk);
|
|
31
148
|
});
|
|
32
149
|
child.on("exit", (code) => {
|
|
150
|
+
// If we parsed JSONL, include the last agent message in stdout for the caller
|
|
151
|
+
if (hasRoomContext && lastAgentMessage) {
|
|
152
|
+
stdout += `\n--- Agent Response ---\n${lastAgentMessage}\n`;
|
|
153
|
+
}
|
|
33
154
|
resolve({ exitCode: code ?? 1, stdout, stderr });
|
|
34
155
|
});
|
|
35
156
|
child.on("error", (err) => {
|
package/dist/adapters/index.d.ts
CHANGED
package/dist/adapters/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
*
|
|
5
5
|
* Supports both the legacy `openclaw` CLI and the newer `zeroclaw` CLI.
|
|
6
6
|
* Sends tasks via `zeroclaw agent -m <goal>` (non-interactive single-shot mode).
|
|
7
|
-
*
|
|
7
|
+
* Reports tool calls and file changes as agent steps when room context is available.
|
|
8
8
|
*/
|
|
9
9
|
const ZEROCLAW_BIN = process.env.ZEROCLAW_BIN || "zeroclaw";
|
|
10
10
|
const OPENCLAW_BIN = process.env.OPENCLAW_BIN || "openclaw";
|
|
@@ -28,6 +28,62 @@ async function findBinary() {
|
|
|
28
28
|
}
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Report a step to the co-ode room.
|
|
33
|
+
*/
|
|
34
|
+
async function reportStep(config, kind, description, payload = {}) {
|
|
35
|
+
try {
|
|
36
|
+
await fetch(`${config.serverUrl}/api/rooms/${config.roomId}/agent-runs/${config.runId}/steps`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
"content-type": "application/json",
|
|
40
|
+
authorization: `Bearer ${config.sessionToken}`,
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
kind,
|
|
44
|
+
input: { description, payload },
|
|
45
|
+
output: { success: true, payload },
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Non-fatal
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse openclaw/zeroclaw output lines for tool calls and file changes.
|
|
55
|
+
* ZeroClaw outputs structured markers like:
|
|
56
|
+
* [TOOL] tool_name: description
|
|
57
|
+
* [FILE] path/to/file
|
|
58
|
+
* [EXEC] command
|
|
59
|
+
* [DONE] summary
|
|
60
|
+
*/
|
|
61
|
+
function parseOutputLine(line) {
|
|
62
|
+
const trimmed = line.trim();
|
|
63
|
+
if (trimmed.startsWith("[TOOL]")) {
|
|
64
|
+
return { kind: "tool_call", description: trimmed.slice(6).trim(), payload: {} };
|
|
65
|
+
}
|
|
66
|
+
if (trimmed.startsWith("[FILE]")) {
|
|
67
|
+
const path = trimmed.slice(6).trim();
|
|
68
|
+
return { kind: "tool_call", description: `write ${path}`, payload: { path } };
|
|
69
|
+
}
|
|
70
|
+
if (trimmed.startsWith("[EXEC]")) {
|
|
71
|
+
const cmd = trimmed.slice(6).trim();
|
|
72
|
+
return { kind: "tool_call", description: cmd, payload: { command: cmd } };
|
|
73
|
+
}
|
|
74
|
+
if (trimmed.startsWith("[DONE]")) {
|
|
75
|
+
return { kind: "observation", description: trimmed.slice(6).trim(), payload: {} };
|
|
76
|
+
}
|
|
77
|
+
// Also detect common patterns from unstructured output
|
|
78
|
+
if (trimmed.match(/^(reading|writing|creating|editing|modifying)\s/i)) {
|
|
79
|
+
return { kind: "tool_call", description: trimmed.slice(0, 100), payload: {} };
|
|
80
|
+
}
|
|
81
|
+
if (trimmed.match(/^\$\s+/)) {
|
|
82
|
+
const cmd = trimmed.slice(2).trim();
|
|
83
|
+
return { kind: "tool_call", description: cmd, payload: { command: cmd } };
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
31
87
|
export class OpenClawAdapter {
|
|
32
88
|
name = "openclaw";
|
|
33
89
|
async available() {
|
|
@@ -44,26 +100,52 @@ export class OpenClawAdapter {
|
|
|
44
100
|
};
|
|
45
101
|
}
|
|
46
102
|
const { bin } = found;
|
|
103
|
+
const hasRoomContext = Boolean(options.roomId && options.runId && options.serverUrl && options.sessionToken);
|
|
104
|
+
const reportConfig = hasRoomContext
|
|
105
|
+
? {
|
|
106
|
+
roomId: options.roomId,
|
|
107
|
+
runId: options.runId,
|
|
108
|
+
serverUrl: options.serverUrl,
|
|
109
|
+
sessionToken: options.sessionToken,
|
|
110
|
+
}
|
|
111
|
+
: null;
|
|
47
112
|
// zeroclaw agent -m "goal" — single-shot non-interactive mode
|
|
48
113
|
const args = ["agent", "-m", goal];
|
|
49
114
|
return new Promise((resolve) => {
|
|
50
115
|
const child = spawn(bin, args, {
|
|
51
116
|
cwd: options.workDir,
|
|
52
|
-
env: {
|
|
117
|
+
env: {
|
|
118
|
+
...process.env,
|
|
119
|
+
CO_OD_ROOM_ID: options.roomId || "",
|
|
120
|
+
CO_OD_RUN_ID: options.runId || "",
|
|
121
|
+
},
|
|
53
122
|
stdio: ["pipe", "pipe", "pipe"],
|
|
54
123
|
});
|
|
55
124
|
if (options.signal) {
|
|
56
125
|
options.signal.addEventListener("abort", () => {
|
|
57
126
|
child.kill("SIGTERM");
|
|
58
|
-
});
|
|
127
|
+
}, { once: true });
|
|
59
128
|
}
|
|
60
129
|
let stdout = "";
|
|
61
130
|
let stderr = "";
|
|
131
|
+
let lineBuffer = "";
|
|
62
132
|
child.stdout?.setEncoding("utf-8");
|
|
63
133
|
child.stderr?.setEncoding("utf-8");
|
|
64
134
|
child.stdout?.on("data", (chunk) => {
|
|
65
135
|
stdout += chunk;
|
|
66
136
|
options.onOutput?.(chunk);
|
|
137
|
+
// Parse lines for step reporting
|
|
138
|
+
if (reportConfig) {
|
|
139
|
+
lineBuffer += chunk;
|
|
140
|
+
const lines = lineBuffer.split("\n");
|
|
141
|
+
lineBuffer = lines.pop() || "";
|
|
142
|
+
for (const line of lines) {
|
|
143
|
+
const parsed = parseOutputLine(line);
|
|
144
|
+
if (parsed) {
|
|
145
|
+
void reportStep(reportConfig, parsed.kind, parsed.description, parsed.payload);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
67
149
|
});
|
|
68
150
|
child.stderr?.on("data", (chunk) => {
|
|
69
151
|
stderr += chunk;
|
|
@@ -77,6 +159,13 @@ export class OpenClawAdapter {
|
|
|
77
159
|
});
|
|
78
160
|
});
|
|
79
161
|
child.on("close", (code) => {
|
|
162
|
+
// Flush remaining line buffer
|
|
163
|
+
if (reportConfig && lineBuffer.trim()) {
|
|
164
|
+
const parsed = parseOutputLine(lineBuffer);
|
|
165
|
+
if (parsed) {
|
|
166
|
+
void reportStep(reportConfig, parsed.kind, parsed.description, parsed.payload);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
80
169
|
resolve({
|
|
81
170
|
exitCode: code ?? 1,
|
|
82
171
|
stdout,
|
package/dist/api-client.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
const CONFIG_DIR = join(homedir(), ".co-ode");
|
|
5
5
|
const SESSION_FILE = join(CONFIG_DIR, "session.json");
|
|
6
6
|
function getBaseUrl() {
|
|
7
|
-
return (process.env.CO_ODE_SERVER || "https://co-
|
|
7
|
+
return (process.env.CO_ODE_SERVER || "https://co-od.dev");
|
|
8
8
|
}
|
|
9
9
|
function getSessionToken() {
|
|
10
10
|
try {
|
package/dist/commands/join.js
CHANGED
|
@@ -26,7 +26,7 @@ export async function run(args) {
|
|
|
26
26
|
}
|
|
27
27
|
const serverUrl = parsed.server ||
|
|
28
28
|
process.env.CO_ODE_SERVER ||
|
|
29
|
-
"https://co-
|
|
29
|
+
"https://co-od.dev";
|
|
30
30
|
console.error(`[co-od] Joining room ${parsed.roomId}...`);
|
|
31
31
|
console.error(`[co-od] Server: ${serverUrl}`);
|
|
32
32
|
console.error(`[co-od] Working directory: ${parsed.dir}`);
|
package/dist/commands/login.js
CHANGED
|
@@ -76,7 +76,7 @@ export async function run(args) {
|
|
|
76
76
|
const parsed = parseArgs(args);
|
|
77
77
|
const serverUrl = parsed.server ||
|
|
78
78
|
process.env.CO_ODE_SERVER ||
|
|
79
|
-
"https://co-
|
|
79
|
+
"https://co-od.dev";
|
|
80
80
|
// --token flag: headless/CI mode
|
|
81
81
|
if (parsed.token) {
|
|
82
82
|
saveSession(parsed.token);
|
package/dist/commands/start.d.ts
CHANGED
package/dist/commands/start.js
CHANGED
|
@@ -129,9 +129,37 @@ async function openBrowser(url) {
|
|
|
129
129
|
log(`Open in browser: ${url}`);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
async function isBridgeRunning() {
|
|
133
|
+
try {
|
|
134
|
+
const res = await fetch("http://127.0.0.1:4786/health", { signal: AbortSignal.timeout(1500) });
|
|
135
|
+
return res.ok;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export async function run(args) {
|
|
133
142
|
const dir = process.cwd();
|
|
134
143
|
const projectName = basename(dir);
|
|
144
|
+
const existing = findExistingConfig(dir);
|
|
145
|
+
const bridgeUp = await isBridgeRunning();
|
|
146
|
+
const hasToken = !!api.getSessionToken();
|
|
147
|
+
// ── FAST PATH: everything's already set up ──
|
|
148
|
+
// If config exists + bridge running + logged in → just show status, don't open browser
|
|
149
|
+
if (existing && bridgeUp && hasToken && !args.includes("--open")) {
|
|
150
|
+
const url = `${api.getBaseUrl()}/rooms/${existing.roomId}`;
|
|
151
|
+
console.error(` co-od · ${existing.roomName}\n`);
|
|
152
|
+
console.error(` room: ${url}`);
|
|
153
|
+
console.error(` bridge: running (port 4786)`);
|
|
154
|
+
console.error(` project: ${dir}\n`);
|
|
155
|
+
console.error(` Everything is running. Commands:\n`);
|
|
156
|
+
console.error(` co-od run ${existing.roomId.slice(0, 12)} "your task" # single task`);
|
|
157
|
+
console.error(` co-od daemon ${existing.roomId.slice(0, 12)} --auto-execute # autonomous`);
|
|
158
|
+
console.error(` co-od share # invite teammate`);
|
|
159
|
+
console.error(` co-od --open # open browser\n`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// ── SETUP PATH: first time or something needs fixing ──
|
|
135
163
|
console.error(`
|
|
136
164
|
┌─────────────────────────────┐
|
|
137
165
|
│ co-od │
|
|
@@ -140,13 +168,18 @@ export async function run(_args) {
|
|
|
140
168
|
└─────────────────────────────┘
|
|
141
169
|
`);
|
|
142
170
|
// Step 1: Login
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
171
|
+
if (!hasToken) {
|
|
172
|
+
log("[1/5] Checking authentication...");
|
|
173
|
+
const loggedIn = await ensureLoggedIn();
|
|
174
|
+
if (!loggedIn) {
|
|
175
|
+
log("✗ Login required. Run: co-od login");
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
log("✓ logged in\n");
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
log("[1/5] ✓ logged in");
|
|
148
182
|
}
|
|
149
|
-
log("✓ logged in\n");
|
|
150
183
|
// Step 2: Detect environment
|
|
151
184
|
log("[2/5] Detecting environment...");
|
|
152
185
|
const provider = detectProvider();
|
|
@@ -162,7 +195,6 @@ export async function run(_args) {
|
|
|
162
195
|
log(`✓ project: ${dir}\n`);
|
|
163
196
|
// Step 3: Find or create room
|
|
164
197
|
log("[3/5] Setting up room...");
|
|
165
|
-
const existing = findExistingConfig(dir);
|
|
166
198
|
let roomId;
|
|
167
199
|
let roomName;
|
|
168
200
|
if (existing) {
|
|
@@ -171,7 +203,6 @@ export async function run(_args) {
|
|
|
171
203
|
log(`✓ found existing room: ${roomName}`);
|
|
172
204
|
}
|
|
173
205
|
else {
|
|
174
|
-
// Create new room
|
|
175
206
|
roomName = projectName;
|
|
176
207
|
try {
|
|
177
208
|
const res = await api.post("/api/rooms", { name: roomName });
|
|
@@ -222,9 +253,14 @@ export async function run(_args) {
|
|
|
222
253
|
}
|
|
223
254
|
}
|
|
224
255
|
console.error("");
|
|
225
|
-
// Step 4: Start bridge
|
|
226
|
-
|
|
227
|
-
|
|
256
|
+
// Step 4: Start bridge (only if not already running)
|
|
257
|
+
if (bridgeUp) {
|
|
258
|
+
log("[4/5] ✓ local bridge already running");
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
log("[4/5] Starting local bridge...");
|
|
262
|
+
startBridgeBackground();
|
|
263
|
+
}
|
|
228
264
|
console.error("");
|
|
229
265
|
// Step 5: Open browser
|
|
230
266
|
log("[5/5] Opening workspace...\n");
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
const VERSION = "0.1.
|
|
3
|
+
const VERSION = "0.1.6";
|
|
4
4
|
const COMMANDS = {
|
|
5
5
|
init: { desc: "Set up a new co-ode project", usage: "co-od init [name] [--dir <path>] [--provider claude|codex|openclaw]" },
|
|
6
6
|
login: { desc: "Authenticate with co-ode", usage: "co-od login [--token <t>]" },
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codegrammer/co-od",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "CLI for co-ode
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "CLI for co-ode — run AI agents in shared rooms from the command line",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"co-ode": "./dist/index.js",
|
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
"@types/ws": "^8.5.13",
|
|
50
50
|
"typescript": "^5.6.2"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|