@addai/node 0.8.1 → 0.9.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.
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ // Open a URL in whatever the user calls their browser.
3
+ //
4
+ // No dependency for this. The three commands are stable, and a package that
5
+ // shells out for you is a package that can break pairing on a platform we
6
+ // cannot test from here.
7
+ //
8
+ // Windows deliberately does NOT go through cmd.exe. `start` is a shell
9
+ // builtin, so reaching it means spawning a shell around a URL, and this
10
+ // codebase has already been burned by putting cmd.exe near strings it did not
11
+ // control. rundll32 takes the URL as a plain argument and hands it to the
12
+ // registered handler.
13
+ //
14
+ // Everything here is best-effort by design. A browser that fails to open is
15
+ // not a failed pairing — the terminal still shows the code and the link, and
16
+ // the user carries on by hand. So this never throws and never blocks: it
17
+ // reports whether the launch was ACCEPTED, which is all the caller can
18
+ // honestly say.
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.openBrowser = openBrowser;
21
+ const child_process_1 = require("child_process");
22
+ function openBrowser(url, platform = process.platform) {
23
+ const [cmd, args] = platform === 'darwin' ? ['open', [url]]
24
+ : platform === 'win32' ? ['rundll32', ['url.dll,FileProtocolHandler', url]]
25
+ : ['xdg-open', [url]];
26
+ try {
27
+ const child = (0, child_process_1.spawn)(cmd, args, {
28
+ stdio: 'ignore',
29
+ // The browser outlives us — and on a machine where the daemon is about
30
+ // to take over the terminal, a child holding the TTY would fight it.
31
+ detached: true,
32
+ });
33
+ // A missing xdg-open surfaces here rather than as an unhandled error that
34
+ // takes the daemon down with it.
35
+ child.on('error', () => { });
36
+ child.unref();
37
+ return true;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
@@ -0,0 +1,20 @@
1
+ export interface PairDestination {
2
+ /** What to call it on screen. */
3
+ product: string;
4
+ /** Where the user goes to confirm. */
5
+ url: string;
6
+ /** That URL carrying the code, which is what actually gets opened. */
7
+ link(code: string): string;
8
+ }
9
+ /**
10
+ * @param argv process.argv.slice(2)
11
+ * @param env process.env
12
+ */
13
+ export declare function pairDestination(argv: string[], env?: NodeJS.ProcessEnv): PairDestination;
14
+ export interface BrowserEnv {
15
+ isTTY: boolean;
16
+ platform: NodeJS.Platform | string;
17
+ env: NodeJS.ProcessEnv;
18
+ }
19
+ /** Would opening a browser here actually show the user anything? */
20
+ export declare function canOpenBrowser({ isTTY, platform, env }: BrowserEnv): boolean;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ // Which product this machine is joining, and whether we can open a browser
3
+ // to finish the job.
4
+ //
5
+ // The command the user ran is the answer to the first question. They copied it
6
+ // off a page that already knew — so asking "which product?" in the terminal
7
+ // would be asking them to repeat themselves. `ainode entities` goes to Entity
8
+ // Studio; everything else keeps going to Vault, exactly as it always has.
9
+ //
10
+ // The second question is the one that decides whether pairing feels like
11
+ // magic or like a broken promise. Opening a browser on a machine nobody is
12
+ // sitting at does nothing; opening one over SSH opens it on the wrong
13
+ // computer entirely. Both are common, so both are checked, and when the
14
+ // answer is no the code gets printed like it always did.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.pairDestination = pairDestination;
17
+ exports.canOpenBrowser = canOpenBrowser;
18
+ const config_1 = require("./config");
19
+ const destination = (product, url) => ({
20
+ product,
21
+ url,
22
+ link: (code) => `${url}/${encodeURIComponent(code)}`,
23
+ });
24
+ /**
25
+ * @param argv process.argv.slice(2)
26
+ * @param env process.env
27
+ */
28
+ function pairDestination(argv, env = process.env) {
29
+ const entities = argv[0] === 'entities';
30
+ // A dev override has to move BOTH products or a local Studio ends up
31
+ // pairing against production Vault, which is a confusing way to lose an
32
+ // afternoon.
33
+ const base = env.AINODE_PAIR_BASE?.replace(/\/+$/, '');
34
+ if (base) {
35
+ return entities
36
+ ? destination('+Ai Entities', `${base}/connect`)
37
+ : destination('+Ai Vault', `${base}/add/entity`);
38
+ }
39
+ return entities
40
+ ? destination('+Ai Entities', config_1.ENTITIES_PAIR_URL)
41
+ : destination('+Ai Vault', config_1.VAULT_PAIR_URL);
42
+ }
43
+ /** Would opening a browser here actually show the user anything? */
44
+ function canOpenBrowser({ isTTY, platform, env }) {
45
+ if (!isTTY)
46
+ return false;
47
+ if (env.AINODE_NO_BROWSER === '1')
48
+ return false;
49
+ // Over SSH the browser would open on the machine being administered, where
50
+ // nobody is looking at it — and the terminal would sit there claiming it
51
+ // had done something helpful.
52
+ if (env.SSH_TTY || env.SSH_CONNECTION)
53
+ return false;
54
+ // A Linux box with no display server has no browser to open. macOS and
55
+ // Windows always have one.
56
+ if (platform === 'linux' && !env.DISPLAY && !env.WAYLAND_DISPLAY)
57
+ return false;
58
+ return true;
59
+ }
package/dist/pairing.d.ts CHANGED
@@ -14,7 +14,9 @@ export declare function requestPairCode(): Promise<string>;
14
14
  */
15
15
  export declare function awaitPairing(code: string): Promise<FinalizeResult>;
16
16
  /**
17
- * Print the human-facing instructions for a fresh pairing.
17
+ * Run the whole first-run flow: ask, open, wait, save.
18
+ *
19
+ * @param argv process.argv.slice(2) — decides which product to join
18
20
  */
19
- export declare function printPairingInstructions(code: string): void;
21
+ export declare function runPairing(argv: string[]): Promise<FinalizeResult>;
20
22
  export {};
package/dist/pairing.js CHANGED
@@ -1,7 +1,15 @@
1
1
  "use strict";
2
- // First-run pairing flow. Called when state.json doesn't exist. Walks the
3
- // user through obtaining a 5-letter code and entering it at
4
- // vault.add.ai/add/entity. Once finalized, persists the daemon_token.
2
+ // First-run pairing flow. Called when state.json doesn't exist.
3
+ //
4
+ // The machine now does the walking. It asks one question, opens the user's
5
+ // browser at the confirm page carrying its own code, and waits — so the
6
+ // person types nothing and never has to know a code existed. Where that
7
+ // cannot work (no terminal, over SSH, headless Linux) it prints the code and
8
+ // the link exactly as it always did, because those machines are real and are
9
+ // often the ones that most need a node on them.
10
+ //
11
+ // Which product the browser lands on comes from the command the user ran:
12
+ // `ainode entities` goes to Entity Studio, everything else to Vault.
5
13
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
14
  if (k2 === undefined) k2 = k;
7
15
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -38,10 +46,13 @@ var __importStar = (this && this.__importStar) || (function () {
38
46
  Object.defineProperty(exports, "__esModule", { value: true });
39
47
  exports.requestPairCode = requestPairCode;
40
48
  exports.awaitPairing = awaitPairing;
41
- exports.printPairingInstructions = printPairingInstructions;
49
+ exports.runPairing = runPairing;
42
50
  const os = __importStar(require("os"));
43
51
  const supabase_client_1 = require("./supabase-client");
44
52
  const store_1 = require("./store");
53
+ const pair_destination_1 = require("./pair-destination");
54
+ const open_browser_1 = require("./open-browser");
55
+ const pair_1 = require("./tui/pair");
45
56
  const config_1 = require("./config");
46
57
  function platform() {
47
58
  const p = process.platform;
@@ -113,17 +124,54 @@ async function awaitPairing(code) {
113
124
  throw new Error('pair_timeout');
114
125
  }
115
126
  /**
116
- * Print the human-facing instructions for a fresh pairing.
127
+ * Run the whole first-run flow: ask, open, wait, save.
128
+ *
129
+ * @param argv process.argv.slice(2) — decides which product to join
117
130
  */
118
- function printPairingInstructions(code) {
119
- console.log('');
120
- console.log(' ── Setup needed ──');
121
- console.log('');
122
- console.log(` 1. Open ${config_1.VAULT_PAIR_URL}`);
123
- console.log(` 2. Enter this code: ${code}`);
124
- console.log('');
125
- console.log(` (or click: ${config_1.VAULT_PAIR_URL}/${code})`);
126
- console.log('');
127
- console.log(' Waiting for pairing… (expires in 15 minutes)');
128
- console.log('');
131
+ async function runPairing(argv) {
132
+ const dest = (0, pair_destination_1.pairDestination)(argv);
133
+ const hostname = os.hostname();
134
+ const interactive = (0, pair_destination_1.canOpenBrowser)({
135
+ isTTY: Boolean(process.stdout.isTTY) && Boolean(process.stdin.isTTY),
136
+ platform: process.platform,
137
+ env: process.env,
138
+ });
139
+ // Ask BEFORE minting a code. A code starts a 15-minute clock the moment it
140
+ // exists, and someone who walks away at the question should not come back
141
+ // to an expired one.
142
+ const choice = interactive ? await (0, pair_1.promptConnect)({ product: dest.product, hostname }) : 'manual';
143
+ const code = await requestPairCode();
144
+ const link = dest.link(code);
145
+ const opened = choice === 'open' ? (0, open_browser_1.openBrowser)(link) : false;
146
+ let waiting = null;
147
+ if (interactive) {
148
+ waiting = (0, pair_1.renderWaiting)({ product: dest.product, link, code, opened });
149
+ }
150
+ else {
151
+ // Headless: plain lines, no spinner, no cursor games. This output ends up
152
+ // in a log file as often as on a screen.
153
+ console.log('');
154
+ console.log(` Connect this machine to ${dest.product}`);
155
+ console.log('');
156
+ console.log(` 1. Open ${dest.url}`);
157
+ console.log(` 2. Enter this code: ${code}`);
158
+ console.log('');
159
+ console.log(` (or open directly: ${link})`);
160
+ console.log('');
161
+ console.log(' Waiting for pairing… (expires in 15 minutes)');
162
+ console.log('');
163
+ }
164
+ try {
165
+ const result = await awaitPairing(code);
166
+ waiting?.stop();
167
+ if (interactive)
168
+ (0, pair_1.renderConnected)(hostname);
169
+ else
170
+ console.log(` ✓ Connected as ${hostname}`);
171
+ return result;
172
+ }
173
+ catch (err) {
174
+ waiting?.stop();
175
+ throw err;
176
+ }
129
177
  }
@@ -1,4 +1,5 @@
1
1
  export declare function inflightCount(): number;
2
+ export declare function activeRequestIdList(): string[];
2
3
  export declare function start(): void;
3
4
  export declare function stop(): void;
4
5
  /**
@@ -5,6 +5,7 @@
5
5
  // arrives.
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.inflightCount = inflightCount;
8
+ exports.activeRequestIdList = activeRequestIdList;
8
9
  exports.start = start;
9
10
  exports.stop = stop;
10
11
  exports.drain = drain;
@@ -59,6 +60,14 @@ let lastHealthBlockAt = 0;
59
60
  // Exported so /stats can surface "pump stuck at N inflight" without
60
61
  // having to guess.
61
62
  function inflightCount() { return inflight; }
63
+ // The runs this daemon is holding a child process for, right now. This is the
64
+ // only honest answer to "is that run alive?" — the server used to infer it from
65
+ // how recently the agent emitted an event, which measures how chatty the agent
66
+ // is, not whether it is alive. A grok turn routinely goes ten minutes between
67
+ // its last streamed token and turn_complete, and the server was failing those
68
+ // runs mid-flight and apologising to the user for a reply that had already
69
+ // arrived. Reported every 30s by the heartbeat.
70
+ function activeRequestIdList() { return [...activeRequestIds]; }
62
71
  async function tick() {
63
72
  if (stopped)
64
73
  return;
@@ -2206,7 +2206,8 @@ async function runRequest(req) {
2206
2206
  if (installed.mcps?.some((m) => m.slug === 'entity-self-mcp')) {
2207
2207
  const livingPresence = [
2208
2208
  'LIVING PRESENCE — narrate your work so people can see what you are doing in real time.',
2209
- 'Whenever you are working on a specific table record (a card / task / row), call the `report_status` tool at your real milestones: when you claim/start it (status "working", a low progress, a short human note like "Reviewing"), at each checkpoint (bump progress + update the note), if you get stuck and need a human (status "blocked", note why), and when you finish (status "done"). ALWAYS pass the record_id you are working on; if you are working on several records at once, report each separately with its own record_id so they never overwrite each other. This is lightweight — a handful of milestone updates per task; progress is a rough milestone percent (0-100), not a precise measurement.',
2209
+ 'Whenever you are working on a specific table record (a card / task / row), call the `report_status` tool at your real milestones: when you claim/start it (status "working", a low progress, a short note), at each checkpoint (bump progress + update the note), if you get stuck and need a human (status "blocked"), and when you finish (status "done"). ALWAYS pass the record_id you are working on; if you are working on several records at once, report each separately with its own record_id so they never overwrite each other. This is lightweight — a handful of milestone updates per task; progress is a rough milestone percent (0-100), not a precise measurement.',
2210
+ 'THE `note` MUST BE ULTRA-SHORT — 1 to 3 plain, friendly words a teammate could read at a glance, e.g. "Reviewing", "Playing widget", "Writing summary", "Checking design", "Almost done". It renders in a tiny bubble, so NEVER write a sentence and NEVER use technical or internal jargon (not "waiting for publish propagation" — just "Publishing"). Think status label, not explanation.',
2210
2211
  ].join('\n');
2211
2212
  req.system_prompt =
2212
2213
  req.system_prompt && req.system_prompt.trim().length > 0
@@ -0,0 +1,33 @@
1
+ export type PairChoice = 'open' | 'manual';
2
+ interface PromptOpts {
3
+ /** '+Ai Entities' — what the user thinks they are joining. */
4
+ product: string;
5
+ hostname: string;
6
+ }
7
+ /**
8
+ * Ask whether to open the browser. Resolves the user's answer; never rejects.
9
+ *
10
+ * Ctrl-C here means "I did not want to do this at all", so it exits rather
11
+ * than falling through to a code the user never asked for.
12
+ */
13
+ export declare function promptConnect({ product, hostname }: PromptOpts): Promise<PairChoice>;
14
+ export interface WaitingHandle {
15
+ /** Stop the spinner and leave the block on screen. */
16
+ stop(): void;
17
+ }
18
+ /**
19
+ * The block that stays up while the daemon waits to be claimed.
20
+ *
21
+ * It shows the code and the link even when the browser opened fine. That is
22
+ * not clutter — a browser that opened on the wrong profile, or behind another
23
+ * window, is invisible from here, and the only recovery is the thing this
24
+ * block is holding.
25
+ */
26
+ export declare function renderWaiting(opts: {
27
+ product: string;
28
+ link: string;
29
+ code: string;
30
+ opened: boolean;
31
+ }): WaitingHandle;
32
+ export declare function renderConnected(name: string): void;
33
+ export {};
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ // The first thing anyone sees: one question, then the browser opens.
3
+ //
4
+ // This is not a screen on the console stack, and deliberately so. That stack
5
+ // owns the alt screen and exits the process when it quits — both wrong here.
6
+ // Pairing has to hand back to a daemon that then runs for months, and the code
7
+ // and link have to stay in scrollback afterwards, because the most likely
8
+ // reason someone is still reading this block is that the browser didn't open.
9
+ //
10
+ // So: no alt screen, no takeover. A question that repaints in place, then a
11
+ // block that stays on the terminal and a spinner line that updates until the
12
+ // machine is through.
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.promptConnect = promptConnect;
48
+ exports.renderWaiting = renderWaiting;
49
+ exports.renderConnected = renderConnected;
50
+ const readline = __importStar(require("readline"));
51
+ const render_1 = require("./render");
52
+ const E = '\x1b[';
53
+ const write = (s) => { process.stdout.write(s); };
54
+ /** Move up n lines and clear from there down — how a block repaints in place. */
55
+ const rewind = (n) => { if (n > 0)
56
+ write(`${E}${n}A${E}0J`); };
57
+ const CHOICES = [
58
+ { id: 'open', label: 'Yes, open my browser' },
59
+ { id: 'manual', label: 'No, show me a code instead' },
60
+ ];
61
+ /**
62
+ * Ask whether to open the browser. Resolves the user's answer; never rejects.
63
+ *
64
+ * Ctrl-C here means "I did not want to do this at all", so it exits rather
65
+ * than falling through to a code the user never asked for.
66
+ */
67
+ function promptConnect({ product, hostname }) {
68
+ return new Promise(resolve => {
69
+ let sel = 0;
70
+ let painted = 0;
71
+ const frame = () => [
72
+ '',
73
+ ` ${(0, render_1.bold)((0, render_1.cyan)('✦'))} ${(0, render_1.bold)('+Ai Node')}`,
74
+ '',
75
+ ` Connect ${(0, render_1.bold)(hostname)} to ${(0, render_1.bold)(product)}?`,
76
+ '',
77
+ ...CHOICES.map((c, i) => i === sel ? ` ${(0, render_1.green)('▸')} ${c.label}` : ` ${(0, render_1.grey)(c.label)}`),
78
+ '',
79
+ ` ${(0, render_1.dim)('↑↓ to choose · ⏎ to continue · ^C to cancel')}`,
80
+ '',
81
+ ];
82
+ const paint = () => {
83
+ rewind(painted);
84
+ const lines = frame();
85
+ write(lines.join('\n') + '\n');
86
+ painted = lines.length;
87
+ };
88
+ const done = (choice) => {
89
+ rewind(painted);
90
+ process.stdin.off('keypress', onKey);
91
+ if (process.stdin.isTTY)
92
+ process.stdin.setRawMode(false);
93
+ process.stdin.pause();
94
+ resolve(choice);
95
+ };
96
+ function onKey(_s, key) {
97
+ if (!key)
98
+ return;
99
+ if (key.ctrl && key.name === 'c') {
100
+ rewind(painted);
101
+ write(` ${(0, render_1.dim)('Cancelled. Run the command again when you are ready.')}\n\n`);
102
+ process.exit(130);
103
+ }
104
+ if (key.name === 'up' || key.name === 'k') {
105
+ sel = (sel + CHOICES.length - 1) % CHOICES.length;
106
+ paint();
107
+ }
108
+ else if (key.name === 'down' || key.name === 'j') {
109
+ sel = (sel + 1) % CHOICES.length;
110
+ paint();
111
+ }
112
+ else if (key.name === 'y')
113
+ done('open');
114
+ else if (key.name === 'n')
115
+ done('manual');
116
+ else if (key.name === 'return' || key.name === 'space')
117
+ done(CHOICES[sel].id);
118
+ }
119
+ readline.emitKeypressEvents(process.stdin);
120
+ if (process.stdin.isTTY)
121
+ process.stdin.setRawMode(true);
122
+ process.stdin.resume();
123
+ process.stdin.on('keypress', onKey);
124
+ paint();
125
+ });
126
+ }
127
+ /**
128
+ * The block that stays up while the daemon waits to be claimed.
129
+ *
130
+ * It shows the code and the link even when the browser opened fine. That is
131
+ * not clutter — a browser that opened on the wrong profile, or behind another
132
+ * window, is invisible from here, and the only recovery is the thing this
133
+ * block is holding.
134
+ */
135
+ function renderWaiting(opts) {
136
+ const { product, link, code, opened } = opts;
137
+ write('\n');
138
+ if (opened) {
139
+ write(` ${(0, render_1.green)('✦')} ${(0, render_1.bold)(`Waiting in your browser…`)}\n`);
140
+ write('\n');
141
+ write(` ${(0, render_1.dim)('Nothing opened? Go to')} ${(0, render_1.cyan)(link)}\n`);
142
+ }
143
+ else {
144
+ write(` ${(0, render_1.bold)(`Connect this machine to ${product}`)}\n`);
145
+ write('\n');
146
+ write(` ${(0, render_1.dim)('1.')} Open ${(0, render_1.cyan)(link.replace(`/${code}`, ''))}\n`);
147
+ write(` ${(0, render_1.dim)('2.')} Enter this code: ${(0, render_1.bold)((0, render_1.green)(code))}\n`);
148
+ write('\n');
149
+ write(` ${(0, render_1.dim)('or open this directly:')} ${(0, render_1.cyan)(link)}\n`);
150
+ }
151
+ if (opened)
152
+ write(` ${(0, render_1.dim)('or enter this code:')} ${(0, render_1.bold)((0, render_1.green)(code))}\n`);
153
+ write('\n');
154
+ let n = 0;
155
+ let painted = false;
156
+ const line = () => ` ${(0, render_1.green)(render_1.SPIN[n % render_1.SPIN.length])} ${(0, render_1.dim)('waiting for you to confirm · expires in 15 minutes')}`;
157
+ const tick = () => {
158
+ if (painted)
159
+ rewind(1);
160
+ write(line() + '\n');
161
+ painted = true;
162
+ n++;
163
+ };
164
+ tick();
165
+ const timer = setInterval(tick, 120);
166
+ // A spinner is not a reason to keep the process alive.
167
+ timer.unref?.();
168
+ return {
169
+ stop() {
170
+ clearInterval(timer);
171
+ if (painted)
172
+ rewind(1);
173
+ },
174
+ };
175
+ }
176
+ function renderConnected(name) {
177
+ write(` ${(0, render_1.green)('✓')} ${(0, render_1.bold)('Connected')} ${(0, render_1.dim)('as')} ${name}\n\n`);
178
+ }
package/package.json CHANGED
@@ -1,60 +1,60 @@
1
- {
2
- "name": "@addai/node",
3
- "version": "0.8.1",
4
- "description": "Daemon that pairs a machine with your +Ai account and runs Claude / Codex / Kimi / Gemini agents on its behalf. Reachable via Supabase from Vault, Entity Studio, or any other +Ai surface.",
5
- "license": "MIT",
6
- "keywords": [
7
- "addai",
8
- "entity-studio",
9
- "claude",
10
- "codex",
11
- "kimi",
12
- "gemini",
13
- "agent",
14
- "daemon",
15
- "supabase",
16
- "mcp"
17
- ],
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/just-AddAi/addai-entity-runtime.git"
21
- },
22
- "homepage": "https://github.com/just-AddAi/addai-entity-runtime#readme",
23
- "bugs": {
24
- "url": "https://github.com/just-AddAi/addai-entity-runtime/issues"
25
- },
26
- "type": "commonjs",
27
- "main": "dist/index.js",
28
- "bin": {
29
- "ainode": "dist/cli.js"
30
- },
31
- "publishConfig": {
32
- "access": "public"
33
- },
34
- "files": [
35
- "dist",
36
- "scripts",
37
- "README.md"
38
- ],
39
- "scripts": {
40
- "build": "tsc -p tsconfig.json",
41
- "start": "node dist/cli.js",
42
- "dev": "tsc -p tsconfig.json && node dist/cli.js",
43
- "test": "npm run build && node --test test/*.test.mjs",
44
- "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
45
- "postinstall": "node scripts/fix-pty-helper.js",
46
- "prepublishOnly": "npm run build"
47
- },
48
- "engines": {
49
- "node": ">=18"
50
- },
51
- "dependencies": {
52
- "node-pty": "^1.1.0",
53
- "ws": "^8.21.1"
54
- },
55
- "devDependencies": {
56
- "@types/node": "^20.0.0",
57
- "@types/ws": "^8.18.1",
58
- "typescript": "^5.6.0"
59
- }
60
- }
1
+ {
2
+ "name": "@addai/node",
3
+ "version": "0.9.0",
4
+ "description": "Daemon that pairs a machine with your +Ai account and runs Claude / Codex / Kimi / Gemini agents on its behalf. Reachable via Supabase from Vault, Entity Studio, or any other +Ai surface.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "addai",
8
+ "entity-studio",
9
+ "claude",
10
+ "codex",
11
+ "kimi",
12
+ "gemini",
13
+ "agent",
14
+ "daemon",
15
+ "supabase",
16
+ "mcp"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/just-AddAi/addai-entity-runtime.git"
21
+ },
22
+ "homepage": "https://github.com/just-AddAi/addai-entity-runtime#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/just-AddAi/addai-entity-runtime/issues"
25
+ },
26
+ "type": "commonjs",
27
+ "main": "dist/index.js",
28
+ "bin": {
29
+ "ainode": "dist/cli.js"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "scripts",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsc -p tsconfig.json",
41
+ "start": "node dist/cli.js",
42
+ "dev": "tsc -p tsconfig.json && node dist/cli.js",
43
+ "test": "npm run build && node --test test/*.test.mjs",
44
+ "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
45
+ "postinstall": "node scripts/fix-pty-helper.js",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
51
+ "dependencies": {
52
+ "node-pty": "^1.1.0",
53
+ "ws": "^8.21.1"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^20.0.0",
57
+ "@types/ws": "^8.18.1",
58
+ "typescript": "^5.6.0"
59
+ }
60
+ }