@sleep2agi/agent-network 2.3.0-preview.4 → 2.3.0-preview.41
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/README.md +35 -324
- package/dist/bin/anet.cjs +101 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +20 -1
- package/dist/bin/goal-wake-log-render.d.ts +31 -0
- package/dist/src/batch-workdir.d.ts +9 -0
- package/dist/src/bootstrap-password-db.d.ts +13 -0
- package/dist/src/channel-attachments.d.ts +29 -0
- package/dist/src/channel-task-trace.d.ts +10 -0
- package/dist/src/claude-vendor-env.d.ts +28 -0
- package/dist/src/cli-args.d.ts +8 -0
- package/dist/src/client-task-trace.d.ts +9 -0
- package/dist/src/client.js +1 -1
- package/dist/src/codex-copresence-preflight.d.ts +65 -0
- package/dist/src/codex-copresence-profile.d.ts +68 -0
- package/dist/src/codex-model-default.d.ts +6 -0
- package/dist/src/controlled-upload.d.ts +83 -0
- package/dist/src/copresence-deps.d.ts +20 -0
- package/dist/src/copresence-identity.d.ts +339 -0
- package/dist/src/dashboard-managed-process.d.ts +35 -0
- package/dist/src/environ-alias.d.ts +14 -0
- package/dist/src/grok-attach-client.d.ts +115 -0
- package/dist/src/grok-copresence-disclosure.d.ts +11 -0
- package/dist/src/grok-copresence-profile.d.ts +65 -0
- package/dist/src/im/feishu/adapter.d.ts +149 -1
- package/dist/src/im/feishu/bridge.d.ts +9 -0
- package/dist/src/im/feishu/config.d.ts +31 -0
- package/dist/src/im/feishu/hub-upload.d.ts +88 -0
- package/dist/src/im/feishu/markdown-image-renderer.d.ts +61 -0
- package/dist/src/im/feishu/outbound-marker.d.ts +140 -0
- package/dist/src/im/feishu/outbound-paths.d.ts +50 -0
- package/dist/src/im/feishu/outbound-route.d.ts +62 -0
- package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
- package/dist/src/im/feishu/worker.js +391 -16
- package/dist/src/im/types.d.ts +38 -1
- package/dist/src/locale-diagnostic.d.ts +12 -0
- package/dist/src/mock-llm.d.ts +12 -0
- package/dist/src/node-server.js +7 -1
- package/dist/src/normalize-runtime.d.ts +14 -2
- package/dist/src/opencode-agent-node-pair.d.ts +14 -0
- package/dist/src/opencode-auth-login.d.ts +43 -0
- package/dist/src/opencode-launch-env.d.ts +13 -0
- package/dist/src/opencode-owner-mode.d.ts +6 -0
- package/dist/src/opencode-package-binary.d.ts +21 -0
- package/dist/src/opencode-pin.d.ts +44 -0
- package/dist/src/opencode-preset.d.ts +73 -0
- package/dist/src/opencode-runtime-binding.d.ts +30 -0
- package/dist/src/opencode-safe-root.d.ts +27 -0
- package/dist/src/opencode-smoke-env.d.ts +1 -0
- package/dist/src/outbound-tool-names.d.ts +1 -0
- package/dist/src/owner-env-file.d.ts +2 -0
- package/dist/src/package-mode-preflight.d.ts +31 -0
- package/dist/src/primary-network.d.ts +23 -0
- package/dist/src/private-state.d.ts +10 -0
- package/dist/src/project-key.d.ts +1 -0
- package/dist/src/secret-shell-guidance.d.ts +3 -0
- package/dist/src/task-trace.d.ts +33 -0
- package/dist/src/tmux-attach.d.ts +8 -0
- package/dist/src/tmux-capability.d.ts +58 -0
- package/dist/src/tmux-exact-target.d.ts +34 -0
- package/dist/src/tmux-pane-prompt.d.ts +22 -0
- package/dist/src/token-cli.d.ts +13 -0
- package/dist/src/unsafe-package-path-reason.d.ts +17 -0
- package/package.json +10 -6
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface WakeLogEntryShape {
|
|
2
|
+
ts?: string;
|
|
3
|
+
status?: string;
|
|
4
|
+
summary?: string;
|
|
5
|
+
task_id?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface WakeLogGoalShape {
|
|
8
|
+
goal_id: string;
|
|
9
|
+
progress_log?: WakeLogEntryShape[];
|
|
10
|
+
}
|
|
11
|
+
export interface WakeLogRenderOpts {
|
|
12
|
+
/** Trim to the last N entries. undefined = all. */
|
|
13
|
+
tail?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Format progress_log as a JSON object suitable for `--json` output.
|
|
17
|
+
* Pure. Never reads/writes filesystem. Legacy goals without
|
|
18
|
+
* progress_log render as empty array (not error).
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderWakeLogJson(goal: WakeLogGoalShape, opts?: WakeLogRenderOpts): {
|
|
21
|
+
goal_id: string;
|
|
22
|
+
total: number;
|
|
23
|
+
returned: number;
|
|
24
|
+
entries: WakeLogEntryShape[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Format progress_log as a table for human console output.
|
|
28
|
+
* Column layout mirrors printGoalShow so the two commands read
|
|
29
|
+
* consistently. Empty log renders a single "(none)" line, not an error.
|
|
30
|
+
*/
|
|
31
|
+
export declare function renderWakeLogText(goal: WakeLogGoalShape, opts?: WakeLogRenderOpts): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve one batch workdir before any mkdir/chdir loop starts.
|
|
3
|
+
*
|
|
4
|
+
* Node does not expand shell tildes. Leaving `~/team` relative means every
|
|
5
|
+
* iteration can resolve it from the previous node's cwd and create paths such
|
|
6
|
+
* as `/work/~/team/~/team`. Only the current user's `~` form is supported;
|
|
7
|
+
* `~other` is rejected instead of being written as a literal directory.
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeBatchWorkdir(input: string, cwd?: string, home?: string): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface BootstrapPasswordUpdateInvocation {
|
|
2
|
+
argv: string[];
|
|
3
|
+
env: NodeJS.ProcessEnv;
|
|
4
|
+
script: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the database selected for the local Hub into an explicit absolute
|
|
8
|
+
* path before launching the bootstrap helper. The helper must never infer a
|
|
9
|
+
* database from its own HOME/cwd: those can differ from the parent process.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveBootstrapDatabasePath(env: NodeJS.ProcessEnv, home: string, cwd: string): string;
|
|
12
|
+
export declare const BOOTSTRAP_PASSWORD_UPDATE_SCRIPT: string;
|
|
13
|
+
export declare function buildBootstrapPasswordUpdateInvocation(userId: string, dbPath: string, baseEnv?: NodeJS.ProcessEnv): BootstrapPasswordUpdateInvocation;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface AttachmentDescriptor {
|
|
2
|
+
type?: unknown;
|
|
3
|
+
file_id?: unknown;
|
|
4
|
+
path?: unknown;
|
|
5
|
+
mime?: unknown;
|
|
6
|
+
name?: unknown;
|
|
7
|
+
size?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface ChannelAttachmentDeps {
|
|
10
|
+
hubUrl: string;
|
|
11
|
+
authToken: string;
|
|
12
|
+
cacheDir: string;
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
maxBytes?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ChannelAttachmentResult {
|
|
17
|
+
paths: string[];
|
|
18
|
+
failures: Array<{
|
|
19
|
+
fileId: string;
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
export declare function readableAttachmentsFromInbox(message: any): AttachmentDescriptor[];
|
|
25
|
+
export declare function channelAttachmentCacheDir(home: string, alias: string): string;
|
|
26
|
+
export declare function downloadChannelAttachments(message: any, deps: ChannelAttachmentDeps): Promise<ChannelAttachmentResult>;
|
|
27
|
+
export declare const downloadChannelImageAttachments: typeof downloadChannelAttachments;
|
|
28
|
+
export declare function appendChannelAttachmentPaths(content: string, paths: readonly string[]): string;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function sendChannelTaskWithTrace(input: {
|
|
2
|
+
alias: string;
|
|
3
|
+
task: string;
|
|
4
|
+
priority?: string;
|
|
5
|
+
fromAlias: string;
|
|
6
|
+
networkId?: string | null;
|
|
7
|
+
}, deps: {
|
|
8
|
+
send: (args: Record<string, unknown>) => Promise<any>;
|
|
9
|
+
log: (line: string) => void;
|
|
10
|
+
}): Promise<any>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const CLAUDE_VENDOR_ENV_KEYS: readonly ["ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_API_KEY"];
|
|
2
|
+
export type PlainSecretEnvRewrite = {
|
|
3
|
+
key: string;
|
|
4
|
+
refName: string;
|
|
5
|
+
value: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Plan the values that the node-create writer will move into its line-oriented
|
|
9
|
+
* `.env` file. This is deliberately side-effect free: callers can run it as a
|
|
10
|
+
* preflight before creating a node directory, changing process.env, or writing
|
|
11
|
+
* config.json. Keeping the line-break rejection here makes it cover every
|
|
12
|
+
* caller of the dotenv writer, including the no-name interactive wizard.
|
|
13
|
+
*/
|
|
14
|
+
export declare function planPlainSecretEnvRewrites(input: {
|
|
15
|
+
env: unknown;
|
|
16
|
+
nodeId: string;
|
|
17
|
+
}): PlainSecretEnvRewrite[];
|
|
18
|
+
/**
|
|
19
|
+
* Persist the exact Anthropic-compatible vendor environment used by an
|
|
20
|
+
* explicit claude-agent-sdk create. Explicit --env values retain precedence;
|
|
21
|
+
* ambient shell values only fill missing known keys. Other environment values
|
|
22
|
+
* are intentionally ignored so node create never snapshots the whole shell.
|
|
23
|
+
*/
|
|
24
|
+
export declare function collectClaudeVendorEnvForCreate(input: {
|
|
25
|
+
runtime: string;
|
|
26
|
+
explicitEnv: readonly string[];
|
|
27
|
+
shellEnv: Readonly<Record<string, string | undefined>>;
|
|
28
|
+
}): string[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ParsedCliOptions = {
|
|
2
|
+
[key: string]: string | string[];
|
|
3
|
+
_channels: string[];
|
|
4
|
+
_envs: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare const BOOLEAN_FLAGS: Set<string>;
|
|
7
|
+
export declare function parseCliOptions(argv: string[]): ParsedCliOptions;
|
|
8
|
+
export declare function positionalArgs(argv: string[]): string[];
|
package/dist/src/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function a0_0x1b4a(_0x20b83e,_0x424c1c){_0x20b83e=_0x20b83e-0x1b9;const _0x1be9b5=a0_0x1be9();let _0x1b4afe=_0x1be9b5[_0x20b83e];return _0x1b4afe;}const a0_0x18f1eb=a0_0x1b4a;function a0_0x1be9(){const _0x53ac8f=['application/json','sdk-','processInbox','sdk','parse','body','ack_inbox','agent','text','POST','cwd','9FEzhgA','status','text/event-stream','send_reply','log','slice','min','connectSSE','new_task','new_message','tools/call','35826gtIMkF','report_status','reconnectDelay','send','205361RXDODK','match','type','messages','call','6315128hpwPVu','s...','heartbeat\x20failed:\x20','token','234GjDFCc','url','toTimeString','SSE\x20failed:\x20','alias','decode','pop','get_inbox','result','/mcp','57550NbZbyM','broadcast','SSE\x20connected','connect','connected','Authorization','12030630sgXszq','autoConnect','toString','getReader','data:\x20','sseAbort','content','signal','idle','error','emit',']\x20[commhub:','resumeId','4801734hWoLCt','message','getAllStatus','inbox\x20error:\x20','send_task','server','disconnected','reply','heartbeatInterval','from_session','Bearer\x20','2.0','send_message','2037516OMBPBZ','stringify','completed','registered','sleep','now','heartbeatTimer','AbortError','catch','running','118lrtnUT','offline'];a0_0x1be9=function(){return _0x53ac8f;};return a0_0x1be9();}(function(_0x1bbcb7,_0x59746d){const _0x17ce5b=a0_0x1b4a,_0x8590de=_0x1bbcb7();while(!![]){try{const _0x3684fa=-parseInt(_0x17ce5b(0x1ea))/0x1+parseInt(_0x17ce5b(0x1ce))/0x2*(-parseInt(_0x17ce5b(0x1e6))/0x3)+parseInt(_0x17ce5b(0x1c4))/0x4+parseInt(_0x17ce5b(0x1fd))/0x5*(-parseInt(_0x17ce5b(0x1f3))/0x6)+-parseInt(_0x17ce5b(0x210))/0x7+-parseInt(_0x17ce5b(0x1ef))/0x8*(-parseInt(_0x17ce5b(0x1db))/0x9)+parseInt(_0x17ce5b(0x203))/0xa;if(_0x3684fa===_0x59746d)break;else _0x8590de['push'](_0x8590de['shift']());}catch(_0x5b3a29){_0x8590de['push'](_0x8590de['shift']());}}}(a0_0x1be9,0x6f952));import{EventEmitter as a0_0x2ec4a1}from'events';import{hostname as a0_0xcedff1}from'os';class T extends a0_0x2ec4a1{[a0_0x18f1eb(0x1f4)];['alias'];[a0_0x18f1eb(0x1f2)];[a0_0x18f1eb(0x1d7)];[a0_0x18f1eb(0x20f)];['heartbeatInterval'];['reconnectDelay'];['heartbeatTimer'];[a0_0x18f1eb(0x208)];[a0_0x18f1eb(0x1cd)]=!0x1;constructor(_0x75a67){const _0x5655a=a0_0x18f1eb;super();if(this[_0x5655a(0x1f4)]=_0x75a67[_0x5655a(0x1f4)]['replace'](/\/$/,''),this['alias']=_0x75a67[_0x5655a(0x1f7)],this['token']=_0x75a67[_0x5655a(0x1f2)],this['agent']=_0x75a67[_0x5655a(0x1d7)]||_0x5655a(0x1d3),this['resumeId']=_0x5655a(0x1d1)+_0x75a67[_0x5655a(0x1f7)]+'-'+Date[_0x5655a(0x1c9)]()[_0x5655a(0x205)](0x24),this[_0x5655a(0x1bf)]=_0x75a67['heartbeatInterval']??0x2bf20,this['reconnectDelay']=_0x75a67[_0x5655a(0x1e8)]??0xbb8,_0x75a67[_0x5655a(0x204)]!==!0x1)this[_0x5655a(0x200)]();}[a0_0x18f1eb(0x1df)](_0x1239eb){const _0x408863=a0_0x18f1eb;console[_0x408863(0x1df)]('['+new Date()[_0x408863(0x1f5)]()['slice'](0x0,0x8)+_0x408863(0x20e)+this['alias']+']\x20'+_0x1239eb);}async[a0_0x18f1eb(0x1ee)](_0x28565e,_0x5c96aa){const _0x5347fc=a0_0x18f1eb;let _0x432bd8={'Content-Type':_0x5347fc(0x1d0),'Accept':'application/json,\x20text/event-stream'};if(this[_0x5347fc(0x1f2)])_0x432bd8[_0x5347fc(0x202)]=_0x5347fc(0x1c1)+this['token'];let _0x41a028=await(await fetch(this[_0x5347fc(0x1f4)]+_0x5347fc(0x1fc),{'method':_0x5347fc(0x1d9),'headers':_0x432bd8,'body':JSON[_0x5347fc(0x1c5)]({'jsonrpc':_0x5347fc(0x1c2),'id':Date[_0x5347fc(0x1c9)](),'method':_0x5347fc(0x1e5),'params':{'name':_0x28565e,'arguments':_0x5c96aa}})}))[_0x5347fc(0x1d8)](),_0x12da1a=_0x41a028[_0x5347fc(0x1eb)](/data: (.+)/),_0x2f5dbd=_0x12da1a?JSON[_0x5347fc(0x1d4)](_0x12da1a[0x1]):JSON[_0x5347fc(0x1d4)](_0x41a028),_0x438df3=_0x2f5dbd?.[_0x5347fc(0x1fb)]?.['content']?.[0x0]?.[_0x5347fc(0x1d8)];return _0x438df3?JSON[_0x5347fc(0x1d4)](_0x438df3):_0x2f5dbd;}async[a0_0x18f1eb(0x200)](){const _0x156b7e=a0_0x18f1eb;if(this['running'])return;this[_0x156b7e(0x1cd)]=!0x0,await this['status'](_0x156b7e(0x20b)),this[_0x156b7e(0x1df)](_0x156b7e(0x1c7)),this[_0x156b7e(0x1ca)]=setInterval(()=>{const _0xf9a1a2=_0x156b7e;this[_0xf9a1a2(0x1dc)](_0xf9a1a2(0x20b))[_0xf9a1a2(0x1cc)](_0x441651=>this[_0xf9a1a2(0x1df)](_0xf9a1a2(0x1f1)+_0x441651[_0xf9a1a2(0x211)]));},this[_0x156b7e(0x1bf)]),this[_0x156b7e(0x1e2)]();}async['disconnect'](){const _0x89c940=a0_0x18f1eb;if(this[_0x89c940(0x1cd)]=!0x1,this[_0x89c940(0x208)]?.['abort'](),this[_0x89c940(0x1ca)])clearInterval(this[_0x89c940(0x1ca)]);await this['status'](_0x89c940(0x1cf))[_0x89c940(0x1cc)](()=>{}),this[_0x89c940(0x1df)](_0x89c940(0x1bd));}async[a0_0x18f1eb(0x1e9)](_0x50240f,_0x5f075d,_0x540d03='normal'){const _0x504586=a0_0x18f1eb;return this['call'](_0x504586(0x1bb),{'alias':_0x50240f,'task':_0x5f075d,'priority':_0x540d03,'from_session':this['alias']});}async[a0_0x18f1eb(0x211)](_0x581196,_0x1e7262){const _0xd29dd9=a0_0x18f1eb;return this[_0xd29dd9(0x1ee)](_0xd29dd9(0x1c3),{'alias':_0x581196,'message':_0x1e7262,'from_session':this[_0xd29dd9(0x1f7)]});}async[a0_0x18f1eb(0x1be)](_0x480f4a,_0x408973,_0x1d4426=a0_0x18f1eb(0x1c6)){const _0x4f9f77=a0_0x18f1eb;return this[_0x4f9f77(0x1ee)](_0x4f9f77(0x1de),{'in_reply_to':_0x480f4a,'text':_0x408973,'status':_0x1d4426});}async[a0_0x18f1eb(0x1dc)](_0x141b38,_0x22c6d0){const _0x592027=a0_0x18f1eb;return this['call'](_0x592027(0x1e7),{'resume_id':this[_0x592027(0x20f)],'alias':this[_0x592027(0x1f7)],'status':_0x141b38,'server':a0_0xcedff1(),'hostname':a0_0xcedff1(),'agent':this[_0x592027(0x1d7)],'project_dir':process[_0x592027(0x1da)](),..._0x22c6d0});}async[a0_0x18f1eb(0x1b9)](){const _0x29fdbf=a0_0x18f1eb;return this[_0x29fdbf(0x1ee)]('get_all_status',{});}async[a0_0x18f1eb(0x1fe)](_0x2094b1,_0x138c23){const _0x221f79=a0_0x18f1eb;return this[_0x221f79(0x1ee)](_0x221f79(0x1fe),{'message':_0x2094b1,'filter_server':_0x138c23?.[_0x221f79(0x1bc)],'filter_status':_0x138c23?.[_0x221f79(0x1dc)]});}async[a0_0x18f1eb(0x1e2)](){const _0x5bd1b0=a0_0x18f1eb;let _0x99902=encodeURIComponent(this[_0x5bd1b0(0x1f7)]),_0x59f477=this[_0x5bd1b0(0x1f4)]+'/events/'+_0x99902,_0x1d1e41=this[_0x5bd1b0(0x1e8)];while(this[_0x5bd1b0(0x1cd)]){try{this[_0x5bd1b0(0x208)]=new AbortController();let _0x247406={'Accept':_0x5bd1b0(0x1dd)};if(this[_0x5bd1b0(0x1f2)])_0x247406[_0x5bd1b0(0x202)]='Bearer\x20'+this['token'];let _0x5afda3=await fetch(_0x59f477,{'headers':_0x247406,'signal':this[_0x5bd1b0(0x208)][_0x5bd1b0(0x20a)]});if(!_0x5afda3['ok']||!_0x5afda3[_0x5bd1b0(0x1d5)]){this[_0x5bd1b0(0x1df)](_0x5bd1b0(0x1f6)+_0x5afda3[_0x5bd1b0(0x1dc)]),await this[_0x5bd1b0(0x1c8)](_0x1d1e41),_0x1d1e41=Math[_0x5bd1b0(0x1e1)](_0x1d1e41*1.5,0xea60);continue;}_0x1d1e41=this[_0x5bd1b0(0x1e8)];let _0x1c50a0=_0x5afda3['body'][_0x5bd1b0(0x206)](),_0x22cd7d=new TextDecoder(),_0x3c7634='';while(this[_0x5bd1b0(0x1cd)]){let {done:_0x8ef69c,value:_0x58e2bf}=await _0x1c50a0['read']();if(_0x8ef69c)break;_0x3c7634+=_0x22cd7d[_0x5bd1b0(0x1f8)](_0x58e2bf,{'stream':!0x0});let _0x551170=_0x3c7634['split']('\x0a');_0x3c7634=_0x551170[_0x5bd1b0(0x1f9)]()||'';for(let _0x4581b3 of _0x551170){if(!_0x4581b3['startsWith'](_0x5bd1b0(0x207)))continue;try{let _0x320e27=JSON[_0x5bd1b0(0x1d4)](_0x4581b3[_0x5bd1b0(0x1e0)](0x6));if(_0x320e27[_0x5bd1b0(0x1ec)]==='connected'){this[_0x5bd1b0(0x1df)](_0x5bd1b0(0x1ff)),this['emit'](_0x5bd1b0(0x201));continue;}if(_0x320e27['type']===_0x5bd1b0(0x1e3)||_0x320e27['type']===_0x5bd1b0(0x1e4)||_0x320e27[_0x5bd1b0(0x1ec)]===_0x5bd1b0(0x1fe))await this[_0x5bd1b0(0x1d2)]();}catch{}}}}catch(_0x23760d){if(_0x23760d['name']===_0x5bd1b0(0x1cb))break;this[_0x5bd1b0(0x20d)](_0x5bd1b0(0x20c),_0x23760d),this[_0x5bd1b0(0x1df)]('SSE\x20error:\x20'+_0x23760d[_0x5bd1b0(0x211)]);}if(this[_0x5bd1b0(0x1cd)])this[_0x5bd1b0(0x20d)](_0x5bd1b0(0x1bd)),this[_0x5bd1b0(0x1df)]('SSE\x20reconnecting\x20in\x20'+_0x1d1e41/0x3e8+_0x5bd1b0(0x1f0)),await this['sleep'](_0x1d1e41),_0x1d1e41=Math[_0x5bd1b0(0x1e1)](_0x1d1e41*1.5,0xea60);}}async['processInbox'](){const _0x2decae=a0_0x18f1eb;try{let _0x19d6da=(await this[_0x2decae(0x1ee)](_0x2decae(0x1fa),{'alias':this[_0x2decae(0x1f7)],'limit':0xa}))?.[_0x2decae(0x1ed)]||[];for(let _0x4134f1 of _0x19d6da)await this[_0x2decae(0x1ee)](_0x2decae(0x1d6),{'alias':this['alias'],'message_id':_0x4134f1['id']}),this[_0x2decae(0x1df)]('←\x20'+_0x4134f1[_0x2decae(0x1c0)]+':\x20'+_0x4134f1[_0x2decae(0x209)]['slice'](0x0,0x3c)),this[_0x2decae(0x20d)]('task',_0x4134f1),this['emit']('message',_0x4134f1);}catch(_0x4e427b){this[_0x2decae(0x1df)](_0x2decae(0x1ba)+_0x4e427b[_0x2decae(0x211)]);}}['sleep'](_0x46346e){return new Promise(_0xc44451=>setTimeout(_0xc44451,_0x46346e));}}var $=T;export{$ as default,T as CommHub};
|
|
1
|
+
const a0_0x201ef5=a0_0x4006;(function(_0x72921b,_0x413af7){const _0x175ee8=a0_0x4006,_0x42b67e=_0x72921b();while(!![]){try{const _0x2aa7c4=parseInt(_0x175ee8(0xe6))/0x1+-parseInt(_0x175ee8(0x7f))/0x2*(-parseInt(_0x175ee8(0xa6))/0x3)+-parseInt(_0x175ee8(0xeb))/0x4+parseInt(_0x175ee8(0xba))/0x5+parseInt(_0x175ee8(0x8d))/0x6+parseInt(_0x175ee8(0x90))/0x7*(-parseInt(_0x175ee8(0xca))/0x8)+-parseInt(_0x175ee8(0xa4))/0x9;if(_0x2aa7c4===_0x413af7)break;else _0x42b67e['push'](_0x42b67e['shift']());}catch(_0x365aef){_0x42b67e['push'](_0x42b67e['shift']());}}}(a0_0x75ed,0xdc2e0));import{EventEmitter as a0_0x519a93}from'events';import{hostname as a0_0xec13ab}from'os';function a0_0x4006(_0x2fb5fe,_0x2c624c){_0x2fb5fe=_0x2fb5fe-0x7f;const _0x75edec=a0_0x75ed();let _0x400615=_0x75edec[_0x2fb5fe];return _0x400615;}var K=/(?:atok|ntok|utok|ghp|github_pat)_[A-Za-z0-9_-]+|Bearer\s+\S+/gi,L=(_0x59027c,_0x3198e5)=>(_0x59027c??_0x3198e5)[a0_0x201ef5(0x97)](/[\r\n\x00-\x1f\x7f]/g,'\x20')[a0_0x201ef5(0xb1)](0x0,0xf0);function N(_0x3aad14){const _0x2c4d61=a0_0x201ef5;return(_0x3aad14 instanceof Error?_0x3aad14[_0x2c4d61(0xd9)]:String(_0x3aad14??_0x2c4d61(0xdf)))[_0x2c4d61(0x97)](K,_0x2c4d61(0xee))[_0x2c4d61(0x97)](/[\r\n\x00-\x1f\x7f]/g,'\x20')['slice'](0x0,0xf0);}function O(_0xb17fa7,_0x8841d9=process.env.ANET_TASK_TRACE_FORMAT===a0_0x201ef5(0xbe)){const _0x489d1e=a0_0x201ef5;if(_0x8841d9)return JSON[_0x489d1e(0xd1)](_0xb17fa7);let _0x2c3336=L(_0xb17fa7[_0x489d1e(0x8f)],'<missing>'),_0x3c6f57=L(_0xb17fa7[_0x489d1e(0xd7)],_0x489d1e(0xd8)),_0x3cb598=_0xb17fa7[_0x489d1e(0x88)]?_0x489d1e(0xc0)+_0xb17fa7[_0x489d1e(0x88)]+':'+(_0xb17fa7['error_message']??''):'';return'[commhub:task]\x20'+_0xb17fa7['status']+_0x489d1e(0x9c)+L(_0xb17fa7['from_alias'],'<unknown>')+_0x489d1e(0x9b)+L(_0xb17fa7[_0x489d1e(0xc2)],'<unknown>')+'\x20task_id='+_0x3c6f57+_0x489d1e(0xc9)+_0x2c3336+_0x489d1e(0x9e)+L(_0xb17fa7[_0x489d1e(0x96)],_0x489d1e(0xb5))+_0x489d1e(0x9f)+_0xb17fa7[_0x489d1e(0xad)]+'\x20duration_ms='+_0xb17fa7[_0x489d1e(0xb0)]+'\x20lifecycle='+_0xb17fa7[_0x489d1e(0xcc)]+_0x3cb598;}function U(_0x4142ca){const _0xffbf38=a0_0x201ef5;return{'event':{'sending':_0xffbf38(0xb9),'delivered':_0xffbf38(0xdc),'failed':_0xffbf38(0xef),'acked':'task.ack','started':_0xffbf38(0xe1),'replied':_0xffbf38(0xb8),'expired':_0xffbf38(0xa1)}[_0x4142ca[_0xffbf38(0xe0)]],..._0x4142ca};}function j(_0x1d4bd3){const _0x5c3a31=a0_0x201ef5;let _0x64f346=_0x1d4bd3?.[_0x5c3a31(0xd7)]||_0x1d4bd3?.[_0x5c3a31(0xb3)]||_0x1d4bd3?.['id'];if(_0x64f346)return String(_0x64f346);let _0x27d308=_0x1d4bd3?.[_0x5c3a31(0xe9)]?.[0x0]?.['text'];if(typeof _0x27d308!==_0x5c3a31(0x8a))return null;try{let _0x143880=JSON['parse'](_0x27d308);return _0x143880?.[_0x5c3a31(0xd7)]||_0x143880?.[_0x5c3a31(0xb3)]||_0x143880?.['id']||null;}catch{return null;}}function a0_0x75ed(){const _0x4741b6=['CommHub\x20response\x20omitted\x20task_id','data:\x20','heartbeatInterval','alias','stringify','lifecycleTracking','emit','signal','token','running','task_id','<pending>','message','from_session','log','task.send.delivered','fromAlias','Authorization','unknown\x20error','status','task.started','CommHub\x20rejected\x20task','parse','error','POST','601813HYJjzX','registered','sseAbort','content','resumeId','5667628ezIEQD','2.0','failed','[REDACTED]','task.send.failed','networkId','394GlSesT','result','reply','task','s...','type','toTimeString','/mcp','send_failed','error_code','reconnectDelay','string','not_tracked','disconnect','9382710bGKQDp','pop','parent_task_id','3403806iGdtSt','send_reply','name','AbortError','new_task','send_task','network_id','replace','offline','call','Bearer\x20','\x20to=','\x20from=','completed','\x20network_id=','\x20transport=','parentTaskId','task.expired','heartbeatTimer','idle','19660770LtwaZb','sdk-','16449cTFlMU','/events/','toString','now','connect','split','agent','transport','abort','match','duration_ms','slice','sleep','message_id','application/json','<unknown>','SSE\x20error:\x20','server','task.replied','task.send.start','8719010OEkLHx','disconnected','connectSSE','min','json','send_message','\x20error=','normal','to_alias','text/event-stream','getAllStatus','send','processInbox','url','SSE\x20reconnecting\x20in\x20','\x20parent_task_id=','8pbvRWE','broadcast','lifecycle_tracking'];a0_0x75ed=function(){return _0x4741b6;};return a0_0x75ed();}async function X(_0xe254d7,_0x1f591f){const _0x41a39a=a0_0x201ef5;let _0x4094ca=_0x1f591f['now']??Date[_0x41a39a(0xa9)],_0x3992fc=_0x4094ca(),_0x2688f2=(_0x19a154,_0x4a7f77,_0xc44c7f,_0x12379a)=>{const _0x1f65bc=_0x41a39a;_0x1f591f['log'](O(U({'from_alias':_0xe254d7[_0x1f65bc(0xdd)],'to_alias':_0xe254d7['toAlias'],'task_id':_0x4a7f77,'parent_task_id':_0xe254d7[_0x1f65bc(0xa0)],'network_id':_0xe254d7[_0x1f65bc(0xf0)],'transport':_0xe254d7['transport'],'status':_0x19a154,'duration_ms':_0x4094ca()-_0x3992fc,'lifecycle_tracking':_0xe254d7[_0x1f65bc(0xd2)],..._0xc44c7f!==void 0x0?{'error_code':_0x12379a||_0x1f65bc(0x87),'error_message':N(_0xc44c7f)}:{}})));};_0x2688f2('sending',null);try{let _0x4b1610=await _0x1f591f[_0x41a39a(0xc5)](),_0x351c58=j(_0x4b1610);if(_0x351c58)_0x2688f2('delivered',_0x351c58);else{if(_0x4b1610?.['ok']===!0x1||_0x4b1610?.[_0x41a39a(0xe4)])_0x2688f2('failed',_0x351c58,_0x4b1610?.[_0x41a39a(0xe4)]||_0x41a39a(0xe2),'send_rejected');else _0x2688f2(_0x41a39a(0xed),null,_0x41a39a(0xcd),'missing_task_id');}return _0x4b1610;}catch(_0xef0fbf){throw _0x2688f2('failed',null,_0xef0fbf,'send_failed'),_0xef0fbf;}}async function Y(_0x5e7684,_0x2cd395){const _0x11f573=a0_0x201ef5;return X({'fromAlias':_0x5e7684[_0x11f573(0xdd)],'toAlias':_0x5e7684[_0x11f573(0xd0)],'parentTaskId':_0x5e7684[_0x11f573(0xa0)]||null,'networkId':_0x5e7684[_0x11f573(0xf0)]||null,'transport':'mcp_http','lifecycleTracking':_0x11f573(0x8b)},_0x2cd395);}class $ extends a0_0x519a93{[a0_0x201ef5(0xc7)];[a0_0x201ef5(0xd0)];[a0_0x201ef5(0xd5)];[a0_0x201ef5(0xac)];['resumeId'];[a0_0x201ef5(0xcf)];[a0_0x201ef5(0x89)];['heartbeatTimer'];['sseAbort'];[a0_0x201ef5(0xd6)]=!0x1;constructor(_0x5aaa80){const _0x437422=a0_0x201ef5;super();if(this['url']=_0x5aaa80['url']['replace'](/\/$/,''),this[_0x437422(0xd0)]=_0x5aaa80[_0x437422(0xd0)],this['token']=_0x5aaa80[_0x437422(0xd5)],this[_0x437422(0xac)]=_0x5aaa80[_0x437422(0xac)]||'sdk',this[_0x437422(0xea)]=_0x437422(0xa5)+_0x5aaa80[_0x437422(0xd0)]+'-'+Date[_0x437422(0xa9)]()[_0x437422(0xa8)](0x24),this['heartbeatInterval']=_0x5aaa80['heartbeatInterval']??0x2bf20,this[_0x437422(0x89)]=_0x5aaa80[_0x437422(0x89)]??0xbb8,_0x5aaa80['autoConnect']!==!0x1)this['connect']();}[a0_0x201ef5(0xdb)](_0x5acda0){const _0x494c8f=a0_0x201ef5;console[_0x494c8f(0xdb)]('['+new Date()[_0x494c8f(0x85)]()[_0x494c8f(0xb1)](0x0,0x8)+']\x20[commhub:'+this[_0x494c8f(0xd0)]+']\x20'+_0x5acda0);}async[a0_0x201ef5(0x99)](_0x5dcf2c,_0x290b41){const _0x5f5969=a0_0x201ef5;let _0x5cf61f={'Content-Type':_0x5f5969(0xb4),'Accept':'application/json,\x20text/event-stream'};if(this[_0x5f5969(0xd5)])_0x5cf61f[_0x5f5969(0xde)]=_0x5f5969(0x9a)+this[_0x5f5969(0xd5)];let _0x4cfde6=await(await fetch(this['url']+_0x5f5969(0x86),{'method':_0x5f5969(0xe5),'headers':_0x5cf61f,'body':JSON[_0x5f5969(0xd1)]({'jsonrpc':_0x5f5969(0xec),'id':Date[_0x5f5969(0xa9)](),'method':'tools/call','params':{'name':_0x5dcf2c,'arguments':_0x290b41}})}))['text'](),_0x584f66=_0x4cfde6[_0x5f5969(0xaf)](/data: (.+)/),_0x28cc34=_0x584f66?JSON[_0x5f5969(0xe3)](_0x584f66[0x1]):JSON['parse'](_0x4cfde6),_0x3834bd=_0x28cc34?.[_0x5f5969(0x80)]?.[_0x5f5969(0xe9)]?.[0x0]?.['text'];return _0x3834bd?JSON[_0x5f5969(0xe3)](_0x3834bd):_0x28cc34;}async[a0_0x201ef5(0xaa)](){const _0x2fc055=a0_0x201ef5;if(this[_0x2fc055(0xd6)])return;this['running']=!0x0,await this[_0x2fc055(0xe0)](_0x2fc055(0xa3)),this[_0x2fc055(0xdb)](_0x2fc055(0xe7)),this[_0x2fc055(0xa2)]=setInterval(()=>{const _0xe28570=_0x2fc055;this['status'](_0xe28570(0xa3))['catch'](_0x4a3b3e=>this['log']('heartbeat\x20failed:\x20'+_0x4a3b3e[_0xe28570(0xd9)]));},this['heartbeatInterval']),this[_0x2fc055(0xbc)]();}async[a0_0x201ef5(0x8c)](){const _0x189f20=a0_0x201ef5;if(this[_0x189f20(0xd6)]=!0x1,this[_0x189f20(0xe8)]?.[_0x189f20(0xae)](),this[_0x189f20(0xa2)])clearInterval(this[_0x189f20(0xa2)]);await this['status'](_0x189f20(0x98))['catch'](()=>{}),this[_0x189f20(0xdb)]('disconnected');}async['send'](_0x49a76a,_0x110232,_0x2de63d=a0_0x201ef5(0xc1)){const _0x42ab62=a0_0x201ef5;return Y({'alias':_0x49a76a,'fromAlias':this['alias']},{'log':_0x18aeaa=>console[_0x42ab62(0xdb)](_0x18aeaa),'send':()=>this['call'](_0x42ab62(0x95),{'alias':_0x49a76a,'task':_0x110232,'priority':_0x2de63d,'from_session':this[_0x42ab62(0xd0)]})});}async[a0_0x201ef5(0xd9)](_0x1a7e98,_0x4c9fed){const _0x3298ed=a0_0x201ef5;return this['call'](_0x3298ed(0xbf),{'alias':_0x1a7e98,'message':_0x4c9fed,'from_session':this[_0x3298ed(0xd0)]});}async[a0_0x201ef5(0x81)](_0x5dfeff,_0x54c264,_0x1ba680=a0_0x201ef5(0x9d)){const _0x379ad9=a0_0x201ef5;return this[_0x379ad9(0x99)](_0x379ad9(0x91),{'in_reply_to':_0x5dfeff,'text':_0x54c264,'status':_0x1ba680});}async[a0_0x201ef5(0xe0)](_0x2f96f3,_0x37110c){const _0x173ecb=a0_0x201ef5;return this[_0x173ecb(0x99)]('report_status',{'resume_id':this[_0x173ecb(0xea)],'alias':this[_0x173ecb(0xd0)],'status':_0x2f96f3,'server':a0_0xec13ab(),'hostname':a0_0xec13ab(),'agent':this['agent'],'project_dir':process['cwd'](),..._0x37110c});}async[a0_0x201ef5(0xc4)](){const _0x54a950=a0_0x201ef5;return this[_0x54a950(0x99)]('get_all_status',{});}async[a0_0x201ef5(0xcb)](_0x499070,_0x43f84d){const _0x3e8601=a0_0x201ef5;return this[_0x3e8601(0x99)](_0x3e8601(0xcb),{'message':_0x499070,'filter_server':_0x43f84d?.[_0x3e8601(0xb7)],'filter_status':_0x43f84d?.['status']});}async[a0_0x201ef5(0xbc)](){const _0x24a59a=a0_0x201ef5;let _0x41d80e=encodeURIComponent(this['alias']),_0x5a84bf=this[_0x24a59a(0xc7)]+_0x24a59a(0xa7)+_0x41d80e,_0x532f69=this['reconnectDelay'];while(this[_0x24a59a(0xd6)]){try{this['sseAbort']=new AbortController();let _0x61455a={'Accept':_0x24a59a(0xc3)};if(this[_0x24a59a(0xd5)])_0x61455a[_0x24a59a(0xde)]=_0x24a59a(0x9a)+this[_0x24a59a(0xd5)];let _0x32fb69=await fetch(_0x5a84bf,{'headers':_0x61455a,'signal':this['sseAbort'][_0x24a59a(0xd4)]});if(!_0x32fb69['ok']||!_0x32fb69['body']){this[_0x24a59a(0xdb)]('SSE\x20failed:\x20'+_0x32fb69['status']),await this['sleep'](_0x532f69),_0x532f69=Math[_0x24a59a(0xbd)](_0x532f69*1.5,0xea60);continue;}_0x532f69=this['reconnectDelay'];let _0x364de0=_0x32fb69['body']['getReader'](),_0x102c31=new TextDecoder(),_0x3b01e2='';while(this[_0x24a59a(0xd6)]){let {done:_0x37a74c,value:_0x47c135}=await _0x364de0['read']();if(_0x37a74c)break;_0x3b01e2+=_0x102c31['decode'](_0x47c135,{'stream':!0x0});let _0x29baa3=_0x3b01e2[_0x24a59a(0xab)]('\x0a');_0x3b01e2=_0x29baa3[_0x24a59a(0x8e)]()||'';for(let _0x2604b7 of _0x29baa3){if(!_0x2604b7['startsWith'](_0x24a59a(0xce)))continue;try{let _0x3baa81=JSON[_0x24a59a(0xe3)](_0x2604b7['slice'](0x6));if(_0x3baa81['type']==='connected'){this[_0x24a59a(0xdb)]('SSE\x20connected'),this[_0x24a59a(0xd3)]('connected');continue;}if(_0x3baa81['type']===_0x24a59a(0x94)||_0x3baa81['type']==='new_message'||_0x3baa81[_0x24a59a(0x84)]==='broadcast')await this[_0x24a59a(0xc6)]();}catch{}}}}catch(_0x50be44){if(_0x50be44[_0x24a59a(0x92)]===_0x24a59a(0x93))break;this[_0x24a59a(0xd3)](_0x24a59a(0xe4),_0x50be44),this[_0x24a59a(0xdb)](_0x24a59a(0xb6)+_0x50be44[_0x24a59a(0xd9)]);}if(this[_0x24a59a(0xd6)])this['emit'](_0x24a59a(0xbb)),this[_0x24a59a(0xdb)](_0x24a59a(0xc8)+_0x532f69/0x3e8+_0x24a59a(0x83)),await this['sleep'](_0x532f69),_0x532f69=Math[_0x24a59a(0xbd)](_0x532f69*1.5,0xea60);}}async['processInbox'](){const _0x45702f=a0_0x201ef5;try{let _0x2bf4f0=(await this['call']('get_inbox',{'alias':this[_0x45702f(0xd0)],'limit':0xa}))?.['messages']||[];for(let _0x37e832 of _0x2bf4f0)await this[_0x45702f(0x99)]('ack_inbox',{'alias':this['alias'],'message_id':_0x37e832['id']}),this[_0x45702f(0xdb)]('←\x20'+_0x37e832[_0x45702f(0xda)]+':\x20'+_0x37e832[_0x45702f(0xe9)][_0x45702f(0xb1)](0x0,0x3c)),this[_0x45702f(0xd3)](_0x45702f(0x82),_0x37e832),this[_0x45702f(0xd3)](_0x45702f(0xd9),_0x37e832);}catch(_0x152332){this[_0x45702f(0xdb)]('inbox\x20error:\x20'+_0x152332[_0x45702f(0xd9)]);}}[a0_0x201ef5(0xb2)](_0x342326){return new Promise(_0x1648d5=>setTimeout(_0x1648d5,_0x342326));}}var F=$;export{F as default,$ as CommHub};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface CodexHomeInheritedFile {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly mode: number;
|
|
4
|
+
/** Why a node needs it — printed when staged, so the action is legible. */
|
|
5
|
+
readonly because: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const CODEX_HOME_INHERITED_FILES: readonly CodexHomeInheritedFile[];
|
|
8
|
+
export interface StatLike {
|
|
9
|
+
readonly mtimeMs: number;
|
|
10
|
+
}
|
|
11
|
+
export type StatFn = (path: string) => StatLike | null;
|
|
12
|
+
export interface CodexHomeStageStep {
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly src: string;
|
|
15
|
+
readonly dst: string;
|
|
16
|
+
readonly mode: number;
|
|
17
|
+
readonly reason: "missing" | "host-newer";
|
|
18
|
+
readonly because: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* What to copy from the host CODEX_HOME into the node's, right now.
|
|
22
|
+
*
|
|
23
|
+
* Pure: takes the stat function so the ordering rules are testable without a
|
|
24
|
+
* filesystem. A node file that is NEWER than the host's is left alone — codex
|
|
25
|
+
* refreshes its own copy in place, and clobbering it would throw away a fresher
|
|
26
|
+
* token than the one we hold.
|
|
27
|
+
*/
|
|
28
|
+
export declare function codexHomeStagePlan(hostHome: string, nodeHome: string, stat: StatFn, join: (a: string, b: string) => string, files?: readonly CodexHomeInheritedFile[]): CodexHomeStageStep[];
|
|
29
|
+
export type CodexTuiBlocker = "sign-in" | "update-prompt" | "trust-prompt";
|
|
30
|
+
export type CodexTuiPaneState = CodexTuiBlocker | "not-painted" | "usable";
|
|
31
|
+
/**
|
|
32
|
+
* Classify the TUI, from two different reads of the same pane.
|
|
33
|
+
*
|
|
34
|
+
* They answer different questions and need different tmux flags — the same
|
|
35
|
+
* distinction `waitForTmuxPaneText` documents one screenful up:
|
|
36
|
+
*
|
|
37
|
+
* onScreen (capture-pane, no -S) → "is it sitting on a prompt right now"
|
|
38
|
+
* A prompt that was already answered stays in scrollback forever,
|
|
39
|
+
* so reading history here would report a fixed node as blocked.
|
|
40
|
+
*
|
|
41
|
+
* everSeen (capture-pane -S -N) → "did the TUI ever paint"
|
|
42
|
+
* The banner is printed once and scrolls away — an MCP error burst
|
|
43
|
+
* was enough to push it off screen in under a minute — so reading
|
|
44
|
+
* only the current screen here would report a working node as dead.
|
|
45
|
+
*
|
|
46
|
+
* 🔴 And "the pane has text" answers neither. An earlier version of this used
|
|
47
|
+
* "≥3 non-empty lines ⇒ ready" and passed a node parked on the sign-in page.
|
|
48
|
+
* Measured timeline for that start:
|
|
49
|
+
*
|
|
50
|
+
* t≈3s 22 non-empty lines ← launcher output, TUI not up yet
|
|
51
|
+
* t≈6s 0 non-empty lines ← codex clears the screen and takes over
|
|
52
|
+
* t≈9s 10 non-empty lines ← the sign-in page finally paints
|
|
53
|
+
*
|
|
54
|
+
* The rule fired at t≈3s, six seconds before the thing it was meant to catch
|
|
55
|
+
* existed.
|
|
56
|
+
*/
|
|
57
|
+
export declare function codexTuiPaneState(onScreen: string, everSeen?: string): CodexTuiPaneState;
|
|
58
|
+
/**
|
|
59
|
+
* What the operator should read when a node came up but cannot work. Names the
|
|
60
|
+
* blocker AND where to look — a launcher that only says "not ready" sends
|
|
61
|
+
* someone hunting through three tmux sessions.
|
|
62
|
+
*/
|
|
63
|
+
export declare function describeCodexTuiBlocker(blocker: CodexTuiBlocker, displayName: string, tuiSession: string): string;
|
|
64
|
+
/** The TUI never painted at all — a distinct failure from being blocked. */
|
|
65
|
+
export declare function describeCodexTuiNotPainted(displayName: string, tuiSession: string, waitedMs: number): string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export interface CodexCopresenceProfileFields {
|
|
2
|
+
readonly runtime?: string;
|
|
3
|
+
readonly codexCopresence?: boolean;
|
|
4
|
+
readonly codexCopresenceFullAccess?: boolean;
|
|
5
|
+
readonly flags?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare const CODEX_COPRESENCE_RUNTIME = "codex-app-server";
|
|
8
|
+
/**
|
|
9
|
+
* Should this `anet node start` bring up the co-presence stack?
|
|
10
|
+
*
|
|
11
|
+
* The flag still works for a one-off; the profile field is what makes the
|
|
12
|
+
* second start a single command.
|
|
13
|
+
*/
|
|
14
|
+
export declare function codexCopresenceRequested(flagPassed: boolean, profile: CodexCopresenceProfileFields): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* True when a plain `anet node start` just became enough for this node — i.e.
|
|
17
|
+
* the flag was passed and the profile had not recorded it yet. Callers persist
|
|
18
|
+
* `codexCopresence: true` and tell the user they can drop the flag.
|
|
19
|
+
*/
|
|
20
|
+
export declare function shouldPersistCodexCopresence(flagPassed: boolean, profile: CodexCopresenceProfileFields): boolean;
|
|
21
|
+
export interface CodexCopresencePosture {
|
|
22
|
+
readonly sandboxMode: "danger-full-access" | "read-only";
|
|
23
|
+
readonly approvalPolicy: "never" | "on-request";
|
|
24
|
+
/** Set when the node asked for full access and is NOT getting it. */
|
|
25
|
+
readonly downgradeNotice?: string;
|
|
26
|
+
/** Set when a remembered grant (not this invocation's flag) opened it up. */
|
|
27
|
+
readonly grantedFromProfile: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the sandbox the co-presence app-server runs under.
|
|
31
|
+
*
|
|
32
|
+
* Precedence: this invocation's flag → a grant already recorded on the profile
|
|
33
|
+
* → read-only. `flags.sandboxMode` alone never opens the sandbox; it only
|
|
34
|
+
* decides whether staying closed is worth telling the user about.
|
|
35
|
+
*/
|
|
36
|
+
export declare function codexCopresencePosture(dangerFlagPassed: boolean, profile: CodexCopresenceProfileFields, displayName?: string): CodexCopresencePosture;
|
|
37
|
+
/** True when an explicit grant should be written to the profile for next time. */
|
|
38
|
+
export declare function shouldPersistCodexFullAccess(dangerFlagPassed: boolean, profile: CodexCopresenceProfileFields): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* What `anet node create --runtime codex-app-server` should record, so that a
|
|
41
|
+
* later `anet node start <name>` is a single command with no flag.
|
|
42
|
+
*
|
|
43
|
+
* Shape copied from opencode, which already does exactly this at create time:
|
|
44
|
+
*
|
|
45
|
+
* ...(runtime === "opencode-cli"
|
|
46
|
+
* ? { opencodeMode: opts.mode === "copresence" || opts.copresence === "true"
|
|
47
|
+
* ? "copresence" : "headless" }
|
|
48
|
+
* : {}),
|
|
49
|
+
*
|
|
50
|
+
* Deliberately NOT keyed on which alias the operator typed. `codex-tui`,
|
|
51
|
+
* `codex-appserver` and `codex-app-server` are documented as aliases of one
|
|
52
|
+
* runtime (agent-node/src/cli.ts); giving one of them a different default would
|
|
53
|
+
* quietly break that contract, and "I typed the short name" is not a reliable
|
|
54
|
+
* statement of intent. Opting in stays explicit, exactly as it is for opencode.
|
|
55
|
+
*/
|
|
56
|
+
export declare function codexCopresenceCreateFields(normalizedRuntime: string | undefined, copresenceOpt: string | boolean | undefined): {
|
|
57
|
+
codexCopresence?: true;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* One line at create time for a node that will start headless.
|
|
61
|
+
*
|
|
62
|
+
* NOT keyed on which alias the operator typed: by the time create builds the
|
|
63
|
+
* profile, `opts.runtime` has already been normalized to `codex-app-server`, so
|
|
64
|
+
* `codex-tui` is simply not recoverable here — a hint that tried to read it
|
|
65
|
+
* would never fire. (It didn't; that is how this was found.) Keying on the
|
|
66
|
+
* runtime instead also keeps the aliases true synonyms.
|
|
67
|
+
*/
|
|
68
|
+
export declare function codexCopresenceCreateHint(normalizedRuntime: string | undefined, copresenceOpt: string | boolean | undefined, displayName: string): string | undefined;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #693 — token-bound node controlled local file → Hub /api/upload bridge.
|
|
3
|
+
*
|
|
4
|
+
* Security boundary (hard gates):
|
|
5
|
+
* 1. Cross-host: bytes travel over HTTP multipart; Hub never reads agent FS.
|
|
6
|
+
* 2. Identity: caller supplies the node's bearer token; ntok binds network.
|
|
7
|
+
* 3. Path safety: realpath + allowlisted roots; reject NUL, symlink, traversal.
|
|
8
|
+
* 4. Size ≤ 12 MiB enforced with same-fd fstat + bounded read (no full slurp).
|
|
9
|
+
* 5. Hub /api/upload is the sole write surface (atomic on hub side).
|
|
10
|
+
*
|
|
11
|
+
* Adversarial add-only (#694 DO-NOT-MERGE fixes):
|
|
12
|
+
* - TOCTOU: open O_NOFOLLOW → fstat(fd) → read(fd) only; no re-open by path.
|
|
13
|
+
* - Bounded read: never allocate/read past CONTROLLED_UPLOAD_MAX_BYTES.
|
|
14
|
+
* - NUL guard is live and reachable before any fs call.
|
|
15
|
+
*/
|
|
16
|
+
/** Mirrors server/src/uploads.ts MAX_UPLOAD_BYTES. */
|
|
17
|
+
export declare const CONTROLLED_UPLOAD_MAX_BYTES: number;
|
|
18
|
+
/** Chunk size for bounded streaming read from a single fd. */
|
|
19
|
+
export declare const CONTROLLED_UPLOAD_READ_CHUNK: number;
|
|
20
|
+
export type ControlledUploadErrorCode = "path_required" | "path_nul" | "path_not_found" | "path_untrusted" | "path_symlink" | "path_not_regular" | "path_empty" | "payload_too_large" | "read_failed" | "auth_required" | "hub_url_required" | "upload_failed" | "bad_response" | "missing_file_id";
|
|
21
|
+
export type ControlledUploadFail = {
|
|
22
|
+
ok: false;
|
|
23
|
+
error: ControlledUploadErrorCode;
|
|
24
|
+
message: string;
|
|
25
|
+
};
|
|
26
|
+
export type ControlledUploadOk = {
|
|
27
|
+
ok: true;
|
|
28
|
+
file_id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
mime: string;
|
|
31
|
+
size: number;
|
|
32
|
+
url?: string;
|
|
33
|
+
};
|
|
34
|
+
export type ControlledUploadResult = ControlledUploadOk | ControlledUploadFail;
|
|
35
|
+
export interface ControlledUploadDeps {
|
|
36
|
+
hubUrl: string;
|
|
37
|
+
authToken: string;
|
|
38
|
+
allowedRoots?: string[];
|
|
39
|
+
alias?: string;
|
|
40
|
+
nodeDir?: string;
|
|
41
|
+
fetch?: typeof fetch;
|
|
42
|
+
home?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Normalize a client filename: basename only, strip controls, cap 255. */
|
|
45
|
+
export declare function normalizeUploadName(input: string | undefined | null, fallback?: string): string;
|
|
46
|
+
export declare function defaultControlledUploadRoots(opts?: {
|
|
47
|
+
home?: string;
|
|
48
|
+
alias?: string;
|
|
49
|
+
nodeDir?: string;
|
|
50
|
+
cwd?: string;
|
|
51
|
+
env?: NodeJS.ProcessEnv;
|
|
52
|
+
}): string[];
|
|
53
|
+
/** True iff canonicalPath is strictly inside one of the allowlisted roots. */
|
|
54
|
+
export declare function isPathInsideAllowedRoots(canonicalPath: string, allowedRoots: string[]): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a user-supplied path to a canonical path under an allowlisted root.
|
|
57
|
+
* Does not open the file for reading — open+fstat+read is a separate same-fd step.
|
|
58
|
+
*/
|
|
59
|
+
export declare function resolveControlledUploadPath(rawPath: string, allowedRoots: string[]): {
|
|
60
|
+
ok: true;
|
|
61
|
+
canonicalPath: string;
|
|
62
|
+
} | ControlledUploadFail;
|
|
63
|
+
export type ControlledFileBytes = {
|
|
64
|
+
ok: true;
|
|
65
|
+
bytes: Buffer;
|
|
66
|
+
size: number;
|
|
67
|
+
canonicalPath: string;
|
|
68
|
+
} | ControlledUploadFail;
|
|
69
|
+
/**
|
|
70
|
+
* Open → fstat(fd) → bounded read(fd) on the **same fd** (TOCTOU hard gate).
|
|
71
|
+
* Uses O_NOFOLLOW when available so a symlink swap at open is rejected.
|
|
72
|
+
* Never uses path-based readFileSync after the initial open.
|
|
73
|
+
*/
|
|
74
|
+
export declare function openFstatBoundedReadControlledFile(canonicalPath: string, allowedRoots: string[], maxBytes?: number): ControlledFileBytes;
|
|
75
|
+
/**
|
|
76
|
+
* Upload a controlled local file to Hub POST /api/upload.
|
|
77
|
+
* Returns file_id + metadata for send_reply attachments.
|
|
78
|
+
* Never falls back to sending a raw path to the Hub.
|
|
79
|
+
*/
|
|
80
|
+
export declare function uploadControlledLocalFile(rawPath: string, deps: ControlledUploadDeps, opts?: {
|
|
81
|
+
name?: string;
|
|
82
|
+
mime?: string;
|
|
83
|
+
}): Promise<ControlledUploadResult>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface CopresenceDep {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly present: boolean;
|
|
4
|
+
/** Exact command for this platform, or null when we cannot name one. */
|
|
5
|
+
readonly install: string | null;
|
|
6
|
+
readonly why: string;
|
|
7
|
+
}
|
|
8
|
+
export type CommandProbe = (cmd: string) => boolean;
|
|
9
|
+
export declare function copresenceDeps(probe: CommandProbe, platform?: NodeJS.Platform): CopresenceDep[];
|
|
10
|
+
export declare function missingCopresenceDeps(probe: CommandProbe, platform?: NodeJS.Platform): CopresenceDep[];
|
|
11
|
+
/** One block naming every gap and how to close it — never one gap at a time. */
|
|
12
|
+
export declare function describeMissingDeps(missing: readonly CopresenceDep[], displayName: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* May we start this hub ourselves?
|
|
15
|
+
*
|
|
16
|
+
* Only a loopback hub. A remote URL that refuses the connection is somebody
|
|
17
|
+
* else's service — spawning a local one would silently point the node at a
|
|
18
|
+
* DIFFERENT hub than its profile names, which is worse than failing.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isLoopbackHub(hubUrl: string): boolean;
|