@ours.network/codex 1.1.0 → 1.2.0-nightly.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/.codex-plugin/plugin.json +1 -1
- package/.mcp.json +2 -2
- package/README.md +33 -5
- package/bin/container-file-transfer.mjs +147 -0
- package/bin/container-launch.mjs +40 -0
- package/bin/network-watch.mjs +8 -0
- package/bin/proxy.mjs +42 -21
- package/dist/hooks-runner.mjs +16649 -0
- package/dist/monitor-mcp.mjs +154 -24
- package/dist/network-proxy.mjs +16782 -0
- package/dist/network-watch.mjs +391 -0
- package/dist/profile.mjs +198 -0
- package/hooks/hooks.json +3 -3
- package/package.json +3 -4
- package/skills/ours/SKILL.md +2 -1
- package/src/hooks/runner.mjs +54 -7
- package/src/launcher.mjs +50 -15
- package/src/monitor-mcp.mjs +19 -6
- package/src/network-proxy.mjs +308 -0
- package/src/network-watch.mjs +45 -0
- package/src/profile.mjs +17 -2
- package/src/watcher.mjs +29 -3
package/src/profile.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
3
4
|
|
|
4
|
-
import { assertDaemonStateDir, resolveDaemonConfig } from '@ours.network/sdk';
|
|
5
|
+
import { assertDaemonStateDir, attachOursClient, resolveDaemonConfig } from '@ours.network/sdk';
|
|
6
|
+
import { hostProfileSelectionFromEnv } from '../../core/src/host-client/index.ts';
|
|
5
7
|
|
|
6
8
|
function validPort(value) {
|
|
7
9
|
const port = Number(value);
|
|
@@ -26,8 +28,21 @@ export function parseOursArgs(argv = []) {
|
|
|
26
28
|
return { port, codexArgs };
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
export async function resolveDaemonProfile({ argv = [], env = process.env, fetch: fetchImpl = globalThis.fetch } = {}) {
|
|
31
|
+
export async function resolveDaemonProfile({ argv = [], env = process.env, fetch: fetchImpl = globalThis.fetch, attach = attachOursClient } = {}) {
|
|
30
32
|
const parsed = parseOursArgs(argv);
|
|
33
|
+
const hostSelection = hostProfileSelectionFromEnv(env);
|
|
34
|
+
if (hostSelection !== null) {
|
|
35
|
+
const { profile: hostProfile, configPath } = hostSelection;
|
|
36
|
+
if (parsed.port != null) throw new Error('ours: --ours-port conflicts with host-profile mode');
|
|
37
|
+
const client = await attach({ ...hostProfile, sessionMode: 'external', leaseToken: randomUUID(), env: {} });
|
|
38
|
+
let info;
|
|
39
|
+
try {
|
|
40
|
+
info = await client.version();
|
|
41
|
+
await client.identities();
|
|
42
|
+
await client.unread();
|
|
43
|
+
} finally { await client.close(); }
|
|
44
|
+
return { profile: hostProfile, info, baseUrl: hostProfile.endpoint, configPath, codexArgs: parsed.codexArgs };
|
|
45
|
+
}
|
|
31
46
|
const selection = resolveDaemonConfig({
|
|
32
47
|
...(parsed.port == null ? {} : { port: parsed.port }),
|
|
33
48
|
env,
|
package/src/watcher.mjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { attachOursClient } from '@ours.network/sdk';
|
|
3
|
+
|
|
1
4
|
export const WAKE_PROMPT = 'New ours mail is available for the identity already bound to this session. Use the ours skill and get_messages now, then handle the unread mail. Do not change identities or reveal message bodies outside the normal get_messages result.';
|
|
2
5
|
|
|
3
6
|
export class MonitorWatcher {
|
|
4
|
-
constructor({ baseUrl, token = null, fetch: fetchImpl = globalThis.fetch, appServer, stateStore = { save: async () => {} }, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) }) {
|
|
7
|
+
constructor({ baseUrl, token = null, profile = null, clientFactory = attachOursClient, fetch: fetchImpl = globalThis.fetch, appServer, stateStore = { save: async () => {} }, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) }) {
|
|
5
8
|
this.baseUrl = baseUrl;
|
|
6
9
|
this.headers = token ? { 'x-ours-api-token': token } : {};
|
|
7
10
|
this.fetch = fetchImpl;
|
|
11
|
+
this.profile = profile;
|
|
12
|
+
this.clientFactory = clientFactory;
|
|
8
13
|
this.appServer = appServer;
|
|
9
14
|
this.stateStore = stateStore;
|
|
10
15
|
this.sleep = sleep;
|
|
@@ -23,6 +28,11 @@ export class MonitorWatcher {
|
|
|
23
28
|
});
|
|
24
29
|
}
|
|
25
30
|
|
|
31
|
+
async #client() {
|
|
32
|
+
this.clientPromise ??= this.clientFactory({ ...this.profile, sessionMode: 'external', leaseToken: randomUUID(), env: {} });
|
|
33
|
+
return this.clientPromise;
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
async #json(path, signal) {
|
|
27
37
|
const response = await this.fetch(`${this.baseUrl}${path}`, { headers: this.headers, signal });
|
|
28
38
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -62,11 +72,24 @@ export class MonitorWatcher {
|
|
|
62
72
|
|
|
63
73
|
async pollOnce({ identity, threadId, cursor }, signal) {
|
|
64
74
|
const since = cursor == null ? 'tip' : encodeURIComponent(cursor);
|
|
65
|
-
|
|
75
|
+
let data;
|
|
76
|
+
let unread;
|
|
77
|
+
try {
|
|
78
|
+
if (this.profile) {
|
|
79
|
+
const client = await this.#client();
|
|
80
|
+
data = await client.readNotificationPage(identity, { since: cursor == null ? 'tip' : Number(cursor), signal });
|
|
81
|
+
if (cursor == null) unread = await client.unread();
|
|
82
|
+
} else {
|
|
83
|
+
data = await this.#json(`/identities/${encodeURIComponent(identity)}/notifications?since=${since}`, signal);
|
|
84
|
+
if (cursor == null) unread = await this.#json('/unread', signal);
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (error?.status === 401 || error?.status === 403 || /HTTP (401|403)|authentication/i.test(error?.message || '')) this.authFailed = true;
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
66
90
|
const next = { identity, threadId, cursor: String(data.cursor ?? cursor ?? '') };
|
|
67
91
|
await this.stateStore.save(next);
|
|
68
92
|
if (cursor == null) {
|
|
69
|
-
const unread = await this.#json('/unread', signal);
|
|
70
93
|
const entry = unread.identities?.find((item) => item.name === identity);
|
|
71
94
|
if (entry && (Number(entry.count) > 0 || Number(entry.files) > 0)) await this.#wake(threadId);
|
|
72
95
|
} else if (Array.isArray(data.events) && data.events.length > 0) {
|
|
@@ -106,5 +129,8 @@ export class MonitorWatcher {
|
|
|
106
129
|
this.controller = null;
|
|
107
130
|
this.pending = false;
|
|
108
131
|
this.queued = false;
|
|
132
|
+
const clientPromise = this.clientPromise;
|
|
133
|
+
this.clientPromise = null;
|
|
134
|
+
return clientPromise ? clientPromise.then((client) => client.close()).catch(() => {}) : Promise.resolve();
|
|
109
135
|
}
|
|
110
136
|
}
|