airchat 1.0.0 → 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/dist/index.js +48 -20
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3337,7 +3337,7 @@ import * as fs4 from "node:fs";
|
|
|
3337
3337
|
import * as path4 from "node:path";
|
|
3338
3338
|
import * as os3 from "node:os";
|
|
3339
3339
|
import * as crypto2 from "node:crypto";
|
|
3340
|
-
import { execSync as execSync2 } from "node:child_process";
|
|
3340
|
+
import { execSync as execSync2, execFileSync as execFileSync2 } from "node:child_process";
|
|
3341
3341
|
import { createClient } from "@supabase/supabase-js";
|
|
3342
3342
|
|
|
3343
3343
|
// ../../node_modules/commander/esm.mjs
|
|
@@ -3486,6 +3486,20 @@ function unwrapEnvelope(body) {
|
|
|
3486
3486
|
}
|
|
3487
3487
|
return body;
|
|
3488
3488
|
}
|
|
3489
|
+
var AirChatHttpError = class extends Error {
|
|
3490
|
+
status;
|
|
3491
|
+
/** From the `Retry-After` header, in ms. Undefined when absent or unparseable. */
|
|
3492
|
+
retryAfterMs;
|
|
3493
|
+
constructor(message, status2, headers) {
|
|
3494
|
+
super(message);
|
|
3495
|
+
this.name = "AirChatHttpError";
|
|
3496
|
+
this.status = status2;
|
|
3497
|
+
const seconds = Number(headers?.get("retry-after"));
|
|
3498
|
+
if (Number.isFinite(seconds) && seconds > 0) {
|
|
3499
|
+
this.retryAfterMs = seconds * 1e3;
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
};
|
|
3489
3503
|
var AirChatRestClient = class _AirChatRestClient {
|
|
3490
3504
|
webUrl;
|
|
3491
3505
|
machineName;
|
|
@@ -3772,17 +3786,17 @@ var AirChatRestClient = class _AirChatRestClient {
|
|
|
3772
3786
|
const result = await this.doFetch(method, pathname, params, body);
|
|
3773
3787
|
if (result.status === 401) {
|
|
3774
3788
|
this.derivedKey = null;
|
|
3775
|
-
await this.register();
|
|
3789
|
+
await this.register(true);
|
|
3776
3790
|
const retry = await this.doFetch(method, pathname, params, body);
|
|
3777
3791
|
if (!retry.ok) {
|
|
3778
3792
|
const text = await retry.text().catch(() => "");
|
|
3779
|
-
throw new
|
|
3793
|
+
throw new AirChatHttpError(`AirChat API ${method} ${pathname} failed after re-registration: HTTP ${retry.status} \u2014 ${text}`, retry.status, retry.headers);
|
|
3780
3794
|
}
|
|
3781
3795
|
return unwrapEnvelope(await retry.json());
|
|
3782
3796
|
}
|
|
3783
3797
|
if (!result.ok) {
|
|
3784
3798
|
const text = await result.text().catch(() => "");
|
|
3785
|
-
throw new
|
|
3799
|
+
throw new AirChatHttpError(`AirChat API ${method} ${pathname} failed: HTTP ${result.status} \u2014 ${text}`, result.status, result.headers);
|
|
3786
3800
|
}
|
|
3787
3801
|
return unwrapEnvelope(await result.json());
|
|
3788
3802
|
}
|
|
@@ -3816,8 +3830,16 @@ var AirChatRestClient = class _AirChatRestClient {
|
|
|
3816
3830
|
this.registering = null;
|
|
3817
3831
|
}
|
|
3818
3832
|
}
|
|
3819
|
-
|
|
3820
|
-
|
|
3833
|
+
/**
|
|
3834
|
+
* @param ignoreCache Skip the on-disk key and register with the server for
|
|
3835
|
+
* real. Required when recovering from a 401: the cached key *is* the
|
|
3836
|
+
* credential the server just rejected, so reloading it sends the same bad
|
|
3837
|
+
* key again. Without this the retry path could never recover — it reported
|
|
3838
|
+
* "failed after re-registration" having made no registration request at
|
|
3839
|
+
* all, which is how deactivated agents came to look permanently broken.
|
|
3840
|
+
*/
|
|
3841
|
+
async register(ignoreCache = false) {
|
|
3842
|
+
const cachedKey = ignoreCache ? null : this.loadCachedKey();
|
|
3821
3843
|
if (cachedKey) {
|
|
3822
3844
|
this.derivedKey = cachedKey;
|
|
3823
3845
|
return;
|
|
@@ -3847,7 +3869,7 @@ var AirChatRestClient = class _AirChatRestClient {
|
|
|
3847
3869
|
}
|
|
3848
3870
|
if (!res.ok) {
|
|
3849
3871
|
const body = await res.text().catch(() => "");
|
|
3850
|
-
throw new
|
|
3872
|
+
throw new AirChatHttpError(`Registration failed: HTTP ${res.status} \u2014 ${body}`, res.status, res.headers);
|
|
3851
3873
|
}
|
|
3852
3874
|
this.saveCachedKey(derivedKey);
|
|
3853
3875
|
this.derivedKey = derivedKey;
|
|
@@ -4681,7 +4703,7 @@ async function run(argv = process.argv) {
|
|
|
4681
4703
|
// src/harnesses.ts
|
|
4682
4704
|
import * as fs3 from "node:fs";
|
|
4683
4705
|
import * as path3 from "node:path";
|
|
4684
|
-
import { execSync } from "node:child_process";
|
|
4706
|
+
import { execSync, execFileSync } from "node:child_process";
|
|
4685
4707
|
function binaryExists(bin) {
|
|
4686
4708
|
try {
|
|
4687
4709
|
execSync(process.platform === "win32" ? `where ${bin}` : `command -v ${bin}`, { stdio: "pipe" });
|
|
@@ -4726,14 +4748,14 @@ function mergeJsonFile(filePath, mutate, manualSnippet) {
|
|
|
4726
4748
|
fs3.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n");
|
|
4727
4749
|
return { ok: true, message: filePath };
|
|
4728
4750
|
}
|
|
4729
|
-
function tryCliRegister(
|
|
4751
|
+
function tryCliRegister(bin, argv, manualSnippet) {
|
|
4730
4752
|
try {
|
|
4731
|
-
|
|
4753
|
+
execFileSync(bin, argv, { stdio: "pipe" });
|
|
4732
4754
|
return { ok: true, message: "Registered via CLI" };
|
|
4733
4755
|
} catch {
|
|
4734
4756
|
return {
|
|
4735
4757
|
ok: false,
|
|
4736
|
-
message: `Could not run "${
|
|
4758
|
+
message: `Could not run "${[bin, ...argv.slice(0, 2)].join(" ")} \u2026". Add manually:`,
|
|
4737
4759
|
manualSnippet
|
|
4738
4760
|
};
|
|
4739
4761
|
}
|
|
@@ -4746,8 +4768,9 @@ var HARNESSES = [
|
|
|
4746
4768
|
detect: (home, hasBinary) => fs3.existsSync(path3.join(home, ".claude")) || hasBinary("claude"),
|
|
4747
4769
|
registerMcp(launch) {
|
|
4748
4770
|
const { command, args } = launchParts(launch);
|
|
4749
|
-
const
|
|
4750
|
-
|
|
4771
|
+
const argv = ["mcp", "add", "airchat", "-s", "user", "--", command, ...args];
|
|
4772
|
+
const display = `claude mcp add airchat -s user -- "${command}" ${args.map((a) => `"${a}"`).join(" ")}`;
|
|
4773
|
+
return tryCliRegister("claude", argv, display);
|
|
4751
4774
|
}
|
|
4752
4775
|
},
|
|
4753
4776
|
{
|
|
@@ -4757,14 +4780,14 @@ var HARNESSES = [
|
|
|
4757
4780
|
detect: (home, hasBinary) => fs3.existsSync(path3.join(home, ".codex")) || hasBinary("codex"),
|
|
4758
4781
|
registerMcp(launch) {
|
|
4759
4782
|
const { command, args } = launchParts(launch);
|
|
4760
|
-
const
|
|
4783
|
+
const argv = ["mcp", "add", "airchat", "--", command, ...args];
|
|
4761
4784
|
const toml = [
|
|
4762
4785
|
"# ~/.codex/config.toml",
|
|
4763
4786
|
"[mcp_servers.airchat]",
|
|
4764
4787
|
`command = "${command}"`,
|
|
4765
4788
|
`args = [${args.map((a) => `"${a}"`).join(", ")}]`
|
|
4766
4789
|
].join("\n");
|
|
4767
|
-
return tryCliRegister(
|
|
4790
|
+
return tryCliRegister("codex", argv, toml);
|
|
4768
4791
|
}
|
|
4769
4792
|
},
|
|
4770
4793
|
{
|
|
@@ -4865,7 +4888,7 @@ function installInstructions(filePath, content) {
|
|
|
4865
4888
|
}
|
|
4866
4889
|
|
|
4867
4890
|
// src/index.ts
|
|
4868
|
-
var AIRCHAT_VERSION = true ? "1.0.
|
|
4891
|
+
var AIRCHAT_VERSION = true ? "1.0.1" : "dev";
|
|
4869
4892
|
var DEFAULT_AIRCHAT_URL2 = "https://supernode-web-production.up.railway.app";
|
|
4870
4893
|
var GREEN = "\x1B[32m";
|
|
4871
4894
|
var YELLOW = "\x1B[33m";
|
|
@@ -5091,7 +5114,9 @@ async function cloneAndInstall(config) {
|
|
|
5091
5114
|
}
|
|
5092
5115
|
try {
|
|
5093
5116
|
console.log(` Cloning airchat...`);
|
|
5094
|
-
|
|
5117
|
+
execFileSync2("git", ["clone", "https://github.com/prone/airchat.git", config.airchatDir], {
|
|
5118
|
+
stdio: "pipe"
|
|
5119
|
+
});
|
|
5095
5120
|
console.log(` Installing dependencies...`);
|
|
5096
5121
|
execSync2("npm install", { cwd: config.airchatDir, stdio: "pipe" });
|
|
5097
5122
|
return { name, ok: true, message: "Cloned and installed" };
|
|
@@ -5114,7 +5139,7 @@ async function runMigrations(config) {
|
|
|
5114
5139
|
}
|
|
5115
5140
|
try {
|
|
5116
5141
|
execSync2("which supabase", { stdio: "pipe" });
|
|
5117
|
-
|
|
5142
|
+
execFileSync2("supabase", ["db", "push", "--db-url", config.supabaseUrl], {
|
|
5118
5143
|
cwd: config.airchatDir,
|
|
5119
5144
|
stdio: "pipe"
|
|
5120
5145
|
});
|
|
@@ -5150,7 +5175,9 @@ async function runMigrations(config) {
|
|
|
5150
5175
|
const files = fs4.readdirSync(migrationsDir).filter((f) => f.endsWith(".sql")).sort();
|
|
5151
5176
|
try {
|
|
5152
5177
|
for (const file of files) {
|
|
5153
|
-
|
|
5178
|
+
execFileSync2("psql", [config.databaseUrl, "-f", path4.join(migrationsDir, file)], {
|
|
5179
|
+
stdio: "pipe"
|
|
5180
|
+
});
|
|
5154
5181
|
}
|
|
5155
5182
|
return { name, ok: true, message: `Applied ${files.length} migrations` };
|
|
5156
5183
|
} catch (e) {
|
|
@@ -5284,7 +5311,8 @@ function writeWebEnv(config) {
|
|
|
5284
5311
|
if (config.databaseUrl) {
|
|
5285
5312
|
lines.push(`DATABASE_URL=${config.databaseUrl}`);
|
|
5286
5313
|
}
|
|
5287
|
-
fs4.writeFileSync(envPath, lines.join("\n") + "\n");
|
|
5314
|
+
fs4.writeFileSync(envPath, lines.join("\n") + "\n", { mode: 384 });
|
|
5315
|
+
fs4.chmodSync(envPath, 384);
|
|
5288
5316
|
return { name, ok: true, message: envPath };
|
|
5289
5317
|
} catch (e) {
|
|
5290
5318
|
return { name, ok: false, message: e.message };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "airchat",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AirChat \u2014 one command to set up and use a shared message board for your AI agents",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@airchat/shared": "*",
|
|
29
29
|
"@types/node": "^22.0.0",
|
|
30
30
|
"esbuild": "^0.28.1",
|
|
31
|
-
"tsx": "^4.23.
|
|
31
|
+
"tsx": "^4.23.7",
|
|
32
32
|
"typescript": "^6.0.0"
|
|
33
33
|
}
|
|
34
34
|
}
|