@bbigbang/agent-command 0.1.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,28 @@
1
+ import type { AgentCommandContext } from '../context/runtimeContext.js';
2
+ export type AgentCommandHttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE';
3
+ export type AgentApiRetryMode = 'auto' | 'never' | 'safe';
4
+ export interface AgentApiResponse<T = unknown> {
5
+ ok: boolean;
6
+ status: number;
7
+ data: T | null;
8
+ error?: string;
9
+ errorCode?: string;
10
+ suggestedNextAction?: string;
11
+ }
12
+ export interface AgentApiClientOptions {
13
+ fetch?: typeof fetch;
14
+ env?: Record<string, string | undefined>;
15
+ sleep?: (ms: number) => Promise<void>;
16
+ }
17
+ export interface AgentApiRequestOptions {
18
+ retry?: AgentApiRetryMode;
19
+ }
20
+ export declare class AgentApiClient {
21
+ private readonly context;
22
+ private readonly fetchImpl;
23
+ private readonly env;
24
+ private readonly sleep;
25
+ constructor(context: Pick<AgentCommandContext, 'serverUrl' | 'token' | 'runId' | 'turnId' | 'traceId'>, options?: AgentApiClientOptions);
26
+ request<T = unknown>(method: AgentCommandHttpMethod, path: string, body?: unknown, options?: AgentApiRequestOptions): Promise<AgentApiResponse<T>>;
27
+ private fetchOnce;
28
+ }
@@ -0,0 +1,148 @@
1
+ import { AGENT_COMMAND_ERROR_CODES, AgentCommandError } from '../errors.js';
2
+ function joinUrl(baseUrl, path) {
3
+ const normalizedBase = baseUrl.replace(/\/+$/, '');
4
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
5
+ return `${normalizedBase}${normalizedPath}`;
6
+ }
7
+ function extractString(record, ...keys) {
8
+ for (const key of keys) {
9
+ const value = record[key];
10
+ if (typeof value === 'string' && value.trim())
11
+ return value;
12
+ }
13
+ return undefined;
14
+ }
15
+ function extractSuggestedNextAction(record) {
16
+ const direct = extractString(record, 'suggestedNextAction', 'suggested_next_action', 'required_action');
17
+ if (direct)
18
+ return direct;
19
+ const details = record.details;
20
+ if (details && typeof details === 'object') {
21
+ return extractString(details, 'recommendedAction', 'recommended_action', 'suggestedNextAction', 'suggested_next_action');
22
+ }
23
+ return undefined;
24
+ }
25
+ export class AgentApiClient {
26
+ context;
27
+ fetchImpl;
28
+ env;
29
+ sleep;
30
+ constructor(context, options = {}) {
31
+ this.context = context;
32
+ this.fetchImpl = options.fetch ?? fetch;
33
+ this.env = options.env ?? process.env;
34
+ this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
35
+ }
36
+ async request(method, path, body, options = {}) {
37
+ const url = joinUrl(this.context.serverUrl, path);
38
+ const retryBudget = resolveRetryBudget(this.env, method, options.retry);
39
+ let lastNetworkError;
40
+ for (let attempt = 0; attempt <= retryBudget; attempt += 1) {
41
+ try {
42
+ const response = await this.fetchOnce(method, path, url, body);
43
+ if (!shouldRetryAgentApiResponse(response) || attempt >= retryBudget) {
44
+ return response;
45
+ }
46
+ }
47
+ catch (error) {
48
+ lastNetworkError = error;
49
+ if (!isNetworkAgentCommandError(error) || attempt >= retryBudget) {
50
+ throw error;
51
+ }
52
+ }
53
+ await this.sleep(retryDelayMs(attempt));
54
+ }
55
+ throw lastNetworkError instanceof Error
56
+ ? lastNetworkError
57
+ : new AgentCommandError(AGENT_COMMAND_ERROR_CODES.NETWORK_ERROR, 'Request to Bigbang core failed.');
58
+ }
59
+ async fetchOnce(method, path, url, body) {
60
+ let response;
61
+ try {
62
+ response = await this.fetchImpl(url, {
63
+ method,
64
+ headers: {
65
+ Authorization: `Bearer ${this.context.token}`,
66
+ 'X-Bigbang-Agent-Surface': 'bigbang',
67
+ ...(this.context.runId ? { 'X-Bigbang-Run-Id': this.context.runId } : {}),
68
+ ...(this.context.turnId ? { 'X-Bigbang-Turn-Id': this.context.turnId } : {}),
69
+ ...(this.context.traceId ? { 'X-Bigbang-Trace-Id': this.context.traceId } : {}),
70
+ ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
71
+ },
72
+ body: body !== undefined ? JSON.stringify(body) : undefined,
73
+ });
74
+ }
75
+ catch (error) {
76
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.NETWORK_ERROR, `Request to Bigbang core failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error, suggestedNextAction: 'Check that the core server is reachable from this agent runtime.' });
77
+ }
78
+ const contentType = response.headers.get('content-type') ?? '';
79
+ let data = null;
80
+ if (contentType.includes('application/json')) {
81
+ try {
82
+ data = await response.json();
83
+ }
84
+ catch (error) {
85
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_JSON_RESPONSE, `Core returned invalid JSON for ${method} ${path}.`, { status: response.status, cause: error });
86
+ }
87
+ }
88
+ else {
89
+ const text = await response.text();
90
+ return {
91
+ ok: false,
92
+ status: response.status,
93
+ data: null,
94
+ error: `Expected JSON response from core but received ${contentType || 'unknown content type'}${text.trim() ? `: ${text.slice(0, 200)}` : '.'}`,
95
+ errorCode: AGENT_COMMAND_ERROR_CODES.NON_JSON_RESPONSE,
96
+ };
97
+ }
98
+ if (response.ok) {
99
+ return { ok: true, status: response.status, data: data };
100
+ }
101
+ if (data && typeof data === 'object') {
102
+ const record = data;
103
+ const failureClass = extractString(record, 'failure_class', 'failureClass');
104
+ const errorCode = extractString(record, 'error_code', 'errorCode', 'code') ?? failureClass;
105
+ return {
106
+ ok: false,
107
+ status: response.status,
108
+ data: data,
109
+ error: extractString(record, 'error', 'message') ?? failureClass ?? `HTTP ${response.status}`,
110
+ errorCode,
111
+ suggestedNextAction: extractSuggestedNextAction(record),
112
+ };
113
+ }
114
+ return {
115
+ ok: false,
116
+ status: response.status,
117
+ data: null,
118
+ error: `HTTP ${response.status}`,
119
+ };
120
+ }
121
+ }
122
+ function resolveRetryBudget(env, method, retryMode = 'auto') {
123
+ if (retryMode === 'never')
124
+ return 0;
125
+ if (retryMode === 'auto' && method !== 'GET')
126
+ return 0;
127
+ const raw = env.BIGBANG_CLI_MAX_RETRIES?.trim();
128
+ if (raw !== undefined && raw !== '') {
129
+ const parsed = Number(raw);
130
+ if (Number.isInteger(parsed) && parsed >= 0)
131
+ return Math.min(parsed, 5);
132
+ }
133
+ return 2;
134
+ }
135
+ function retryDelayMs(attempt) {
136
+ return attempt === 0 ? 200 : 800;
137
+ }
138
+ function shouldRetryResponse(status) {
139
+ return status === 502 || status === 503 || status === 504;
140
+ }
141
+ function shouldRetryAgentApiResponse(response) {
142
+ if (response.errorCode === AGENT_COMMAND_ERROR_CODES.NON_JSON_RESPONSE)
143
+ return false;
144
+ return shouldRetryResponse(response.status);
145
+ }
146
+ function isNetworkAgentCommandError(error) {
147
+ return error instanceof AgentCommandError && error.code === AGENT_COMMAND_ERROR_CODES.NETWORK_ERROR;
148
+ }
@@ -0,0 +1,7 @@
1
+ export interface StdinLike extends AsyncIterable<Buffer | string> {
2
+ isTTY?: boolean;
3
+ setEncoding?: (encoding: BufferEncoding) => void;
4
+ }
5
+ export declare function readRequiredStdin(stream: StdinLike, label?: string): Promise<string>;
6
+ export declare function readOptionalStdin(stream: StdinLike): Promise<string | undefined>;
7
+ export declare function readRequiredJsonStdin<T = unknown>(stream: StdinLike, label?: string): Promise<T>;
@@ -0,0 +1,34 @@
1
+ import { AGENT_COMMAND_ERROR_CODES, AgentCommandError } from '../errors.js';
2
+ async function readStream(stream) {
3
+ stream.setEncoding?.('utf8');
4
+ let content = '';
5
+ for await (const chunk of stream) {
6
+ content += String(chunk);
7
+ }
8
+ return content;
9
+ }
10
+ export async function readRequiredStdin(stream, label = 'content') {
11
+ if (stream.isTTY) {
12
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MISSING_STDIN, `No ${label} received on stdin.`, { suggestedNextAction: `Pipe ${label} into this command or use a heredoc.` });
13
+ }
14
+ const content = await readStream(stream);
15
+ if (!content.trim()) {
16
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MISSING_STDIN, `No ${label} received on stdin.`, { suggestedNextAction: `Pipe ${label} into this command or use a heredoc.` });
17
+ }
18
+ return content;
19
+ }
20
+ export async function readOptionalStdin(stream) {
21
+ if (stream.isTTY)
22
+ return undefined;
23
+ const content = await readStream(stream);
24
+ return content.trim() ? content : undefined;
25
+ }
26
+ export async function readRequiredJsonStdin(stream, label = 'JSON payload') {
27
+ const content = await readRequiredStdin(stream, label);
28
+ try {
29
+ return JSON.parse(content);
30
+ }
31
+ catch (error) {
32
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_JSON_STDIN, `stdin did not contain valid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error, suggestedNextAction: 'Validate the payload with jq or node before retrying.' });
33
+ }
34
+ }
@@ -0,0 +1,25 @@
1
+ export type AgentCommandEnv = Record<string, string | undefined>;
2
+ export type AgentCommandTokenSource = 'bigbang-token-file' | 'bigbang-token-env' | 'channel-bridge-token-env';
3
+ export interface AgentCommandContext {
4
+ agentId: string;
5
+ serverUrl: string;
6
+ token: string;
7
+ tokenSource: AgentCommandTokenSource;
8
+ conversationId?: string;
9
+ runId?: string;
10
+ turnId?: string;
11
+ traceId?: string;
12
+ runContextPath?: string;
13
+ }
14
+ export interface LoadAgentCommandContextOptions {
15
+ env?: AgentCommandEnv;
16
+ readFile?: (path: string) => string;
17
+ }
18
+ export interface AgentRunContext {
19
+ runId?: string;
20
+ turnId?: string;
21
+ traceId?: string;
22
+ }
23
+ export declare function loadAgentCommandContext(options?: LoadAgentCommandContextOptions): AgentCommandContext;
24
+ export declare function resolveCurrentRunId(context: Pick<AgentCommandContext, 'runId' | 'runContextPath'>, readFile?: (path: string) => string): string | undefined;
25
+ export declare function resolveCurrentRunContext(context: Pick<AgentCommandContext, 'runId' | 'turnId' | 'traceId' | 'runContextPath'>, readFile?: (path: string) => string): AgentRunContext;
@@ -0,0 +1,106 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { AGENT_COMMAND_ERROR_CODES, AgentCommandError } from '../errors.js';
3
+ function optionalEnvString(value) {
4
+ const trimmed = value?.trim();
5
+ return trimmed || undefined;
6
+ }
7
+ function buildContextBase(params) {
8
+ return {
9
+ agentId: params.agentId,
10
+ serverUrl: params.serverUrl,
11
+ token: params.token,
12
+ tokenSource: params.tokenSource,
13
+ conversationId: optionalEnvString(params.env.BIGBANG_CONVERSATION_ID),
14
+ runId: optionalEnvString(params.env.BIGBANG_RUN_ID),
15
+ turnId: optionalEnvString(params.env.BIGBANG_TURN_ID),
16
+ traceId: optionalEnvString(params.env.BIGBANG_TRACE_ID),
17
+ runContextPath: optionalEnvString(params.env.BIGBANG_RUN_CONTEXT_PATH),
18
+ };
19
+ }
20
+ function readTrimmedTokenFile(path, readFile) {
21
+ let raw;
22
+ try {
23
+ raw = readFile(path);
24
+ }
25
+ catch (error) {
26
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.TOKEN_FILE_UNREADABLE, `BIGBANG_AUTH_TOKEN_FILE=${path} could not be read.`, {
27
+ cause: error,
28
+ suggestedNextAction: 'Restart the agent runtime so the platform can inject a readable agent auth token file.',
29
+ });
30
+ }
31
+ const token = raw.trim();
32
+ if (!token) {
33
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.TOKEN_FILE_EMPTY, `BIGBANG_AUTH_TOKEN_FILE=${path} is empty.`, { suggestedNextAction: 'Restart the agent runtime so the platform can inject a fresh agent auth token.' });
34
+ }
35
+ return token;
36
+ }
37
+ export function loadAgentCommandContext(options = {}) {
38
+ const env = options.env ?? process.env;
39
+ const readFile = options.readFile ?? ((path) => readFileSync(path, 'utf8'));
40
+ const agentId = env.BIGBANG_AGENT_ID?.trim();
41
+ if (!agentId) {
42
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MISSING_AGENT_ID, 'BIGBANG_AGENT_ID is required.', { suggestedNextAction: 'Run this command from an Bigbang managed agent runtime.' });
43
+ }
44
+ const serverUrl = env.BIGBANG_SERVER_URL?.trim();
45
+ if (!serverUrl) {
46
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MISSING_SERVER_URL, 'BIGBANG_SERVER_URL is required.', { suggestedNextAction: 'Run this command from an Bigbang managed agent runtime.' });
47
+ }
48
+ const tokenFile = env.BIGBANG_AUTH_TOKEN_FILE?.trim();
49
+ if (tokenFile) {
50
+ return buildContextBase({
51
+ agentId,
52
+ serverUrl,
53
+ token: readTrimmedTokenFile(tokenFile, readFile),
54
+ tokenSource: 'bigbang-token-file',
55
+ env,
56
+ });
57
+ }
58
+ const bigbangToken = env.BIGBANG_AUTH_TOKEN?.trim();
59
+ if (bigbangToken) {
60
+ return buildContextBase({
61
+ agentId,
62
+ serverUrl,
63
+ token: bigbangToken,
64
+ tokenSource: 'bigbang-token-env',
65
+ env,
66
+ });
67
+ }
68
+ const bridgeToken = env.CHANNEL_BRIDGE_AUTH_TOKEN?.trim();
69
+ if (bridgeToken) {
70
+ return buildContextBase({
71
+ agentId,
72
+ serverUrl,
73
+ token: bridgeToken,
74
+ tokenSource: 'channel-bridge-token-env',
75
+ env,
76
+ });
77
+ }
78
+ throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MISSING_TOKEN, 'BIGBANG_AUTH_TOKEN_FILE, BIGBANG_AUTH_TOKEN, or CHANNEL_BRIDGE_AUTH_TOKEN is required.', { suggestedNextAction: 'Restart the agent runtime so the platform can inject an agent auth token.' });
79
+ }
80
+ export function resolveCurrentRunId(context, readFile = (path) => readFileSync(path, 'utf8')) {
81
+ return resolveCurrentRunContext(context, readFile).runId;
82
+ }
83
+ export function resolveCurrentRunContext(context, readFile = (path) => readFileSync(path, 'utf8')) {
84
+ const fallback = {
85
+ runId: optionalEnvString(context.runId),
86
+ turnId: optionalEnvString(context.turnId),
87
+ traceId: optionalEnvString(context.traceId),
88
+ };
89
+ if (context.runContextPath) {
90
+ try {
91
+ const parsed = JSON.parse(readFile(context.runContextPath));
92
+ const runId = typeof parsed.runId === 'string' ? parsed.runId.trim() : '';
93
+ const turnId = typeof parsed.turnId === 'string' ? parsed.turnId.trim() : '';
94
+ const traceId = typeof parsed.traceId === 'string' ? parsed.traceId.trim() : '';
95
+ return {
96
+ runId: runId || fallback.runId,
97
+ turnId: turnId || fallback.turnId,
98
+ traceId: traceId || fallback.traceId,
99
+ };
100
+ }
101
+ catch {
102
+ // Runtime context files can be absent before the first dispatch writes them.
103
+ }
104
+ }
105
+ return fallback;
106
+ }
@@ -0,0 +1,39 @@
1
+ export declare const AGENT_COMMAND_ERROR_CODES: {
2
+ readonly FILE_TOO_LARGE: "FILE_TOO_LARGE";
3
+ readonly FILE_UNREADABLE: "FILE_UNREADABLE";
4
+ readonly INVALID_ARG: "INVALID_ARG";
5
+ readonly INVALID_INPUT: "INVALID_INPUT";
6
+ readonly INVALID_JSON_RESPONSE: "INVALID_JSON_RESPONSE";
7
+ readonly INVALID_JSON_STDIN: "INVALID_JSON_STDIN";
8
+ readonly INVALID_PANEL_PAYLOAD: "INVALID_PANEL_PAYLOAD";
9
+ readonly INVALID_TASK_STATUS: "INVALID_TASK_STATUS";
10
+ readonly MESSAGE_NOT_RESOLVED: "MESSAGE_NOT_RESOLVED";
11
+ readonly MISSING_AGENT_ID: "MISSING_AGENT_ID";
12
+ readonly MISSING_ATTACHMENT_SCOPE: "MISSING_ATTACHMENT_SCOPE";
13
+ readonly MISSING_CONVERSATION_ID: "MISSING_CONVERSATION_ID";
14
+ readonly MISSING_MESSAGE_ID: "MISSING_MESSAGE_ID";
15
+ readonly MISSING_SERVER_URL: "MISSING_SERVER_URL";
16
+ readonly MISSING_STDIN: "MISSING_STDIN";
17
+ readonly MISSING_TOKEN: "MISSING_TOKEN";
18
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
19
+ readonly NON_JSON_RESPONSE: "NON_JSON_RESPONSE";
20
+ readonly NOT_FOUND: "NOT_FOUND";
21
+ readonly REQUEST_FAILED: "REQUEST_FAILED";
22
+ readonly SERVER_5XX: "SERVER_5XX";
23
+ readonly TOKEN_FILE_EMPTY: "TOKEN_FILE_EMPTY";
24
+ readonly TOKEN_FILE_UNREADABLE: "TOKEN_FILE_UNREADABLE";
25
+ readonly UNEXPECTED_ERROR: "UNEXPECTED_ERROR";
26
+ };
27
+ export type AgentCommandErrorCode = (typeof AGENT_COMMAND_ERROR_CODES)[keyof typeof AGENT_COMMAND_ERROR_CODES];
28
+ export declare function normalizeAgentCommandErrorCode(code: AgentCommandErrorCode | string): string;
29
+ export declare class AgentCommandError extends Error {
30
+ readonly code: string;
31
+ readonly suggestedNextAction?: string;
32
+ readonly status?: number;
33
+ constructor(code: AgentCommandErrorCode | string, message: string, options?: {
34
+ suggestedNextAction?: string;
35
+ status?: number;
36
+ cause?: unknown;
37
+ });
38
+ }
39
+ export declare function toAgentCommandError(error: unknown): AgentCommandError;
package/dist/errors.js ADDED
@@ -0,0 +1,49 @@
1
+ export const AGENT_COMMAND_ERROR_CODES = {
2
+ FILE_TOO_LARGE: 'FILE_TOO_LARGE',
3
+ FILE_UNREADABLE: 'FILE_UNREADABLE',
4
+ INVALID_ARG: 'INVALID_ARG',
5
+ INVALID_INPUT: 'INVALID_INPUT',
6
+ INVALID_JSON_RESPONSE: 'INVALID_JSON_RESPONSE',
7
+ INVALID_JSON_STDIN: 'INVALID_JSON_STDIN',
8
+ INVALID_PANEL_PAYLOAD: 'INVALID_PANEL_PAYLOAD',
9
+ INVALID_TASK_STATUS: 'INVALID_TASK_STATUS',
10
+ MESSAGE_NOT_RESOLVED: 'MESSAGE_NOT_RESOLVED',
11
+ MISSING_AGENT_ID: 'MISSING_AGENT_ID',
12
+ MISSING_ATTACHMENT_SCOPE: 'MISSING_ATTACHMENT_SCOPE',
13
+ MISSING_CONVERSATION_ID: 'MISSING_CONVERSATION_ID',
14
+ MISSING_MESSAGE_ID: 'MISSING_MESSAGE_ID',
15
+ MISSING_SERVER_URL: 'MISSING_SERVER_URL',
16
+ MISSING_STDIN: 'MISSING_STDIN',
17
+ MISSING_TOKEN: 'MISSING_TOKEN',
18
+ NETWORK_ERROR: 'NETWORK_ERROR',
19
+ NON_JSON_RESPONSE: 'NON_JSON_RESPONSE',
20
+ NOT_FOUND: 'NOT_FOUND',
21
+ REQUEST_FAILED: 'REQUEST_FAILED',
22
+ SERVER_5XX: 'SERVER_5XX',
23
+ TOKEN_FILE_EMPTY: 'TOKEN_FILE_EMPTY',
24
+ TOKEN_FILE_UNREADABLE: 'TOKEN_FILE_UNREADABLE',
25
+ UNEXPECTED_ERROR: 'UNEXPECTED_ERROR',
26
+ };
27
+ // Keep this as a passthrough: core-owned business error codes must remain exact.
28
+ export function normalizeAgentCommandErrorCode(code) {
29
+ return code;
30
+ }
31
+ export class AgentCommandError extends Error {
32
+ code;
33
+ suggestedNextAction;
34
+ status;
35
+ constructor(code, message, options = {}) {
36
+ super(message, options.cause !== undefined ? { cause: options.cause } : undefined);
37
+ this.name = 'AgentCommandError';
38
+ this.code = normalizeAgentCommandErrorCode(code);
39
+ this.suggestedNextAction = options.suggestedNextAction;
40
+ this.status = options.status;
41
+ }
42
+ }
43
+ export function toAgentCommandError(error) {
44
+ if (error instanceof AgentCommandError)
45
+ return error;
46
+ if (error instanceof Error)
47
+ return new AgentCommandError(AGENT_COMMAND_ERROR_CODES.UNEXPECTED_ERROR, error.message, { cause: error });
48
+ return new AgentCommandError(AGENT_COMMAND_ERROR_CODES.UNEXPECTED_ERROR, String(error));
49
+ }
@@ -0,0 +1,11 @@
1
+ export interface HeldMessageResponse {
2
+ held?: boolean;
3
+ stale?: boolean;
4
+ message?: string;
5
+ draftId?: string;
6
+ seenUpToSeq?: number;
7
+ blockedSeqRange?: string;
8
+ latestMessages?: Array<Record<string, unknown>>;
9
+ readHistory?: string;
10
+ }
11
+ export declare function formatMessageHeld(target: string, data: HeldMessageResponse): string;
@@ -0,0 +1,40 @@
1
+ function formatLatestMessage(item) {
2
+ const seq = typeof item.seq === 'number' ? item.seq : String(item.seq ?? '?');
3
+ const sender = typeof item.senderName === 'string'
4
+ ? item.senderName
5
+ : typeof item.sender_name === 'string'
6
+ ? item.sender_name
7
+ : String(item.senderId ?? item.sender_id ?? 'unknown');
8
+ const content = typeof item.content === 'string' ? item.content : '';
9
+ return `seq=${seq} ${sender}: ${content}`;
10
+ }
11
+ export function formatMessageHeld(target, data) {
12
+ const platformMessage = typeof data.message === 'string' && data.message.trim()
13
+ ? data.message.trim()
14
+ : 'Your draft was not sent because newer messages exist on this surface.';
15
+ const blockedSeqRange = typeof data.blockedSeqRange === 'string' && data.blockedSeqRange.trim()
16
+ ? data.blockedSeqRange.trim()
17
+ : 'unknown';
18
+ const latestMessages = Array.isArray(data.latestMessages)
19
+ ? data.latestMessages
20
+ .map((item) => (item && typeof item === 'object' ? formatLatestMessage(item) : ''))
21
+ .filter(Boolean)
22
+ : [];
23
+ const lines = [
24
+ platformMessage,
25
+ '',
26
+ `Draft held for ${target}; nothing was posted.`,
27
+ `Newer seq range: ${blockedSeqRange}.`,
28
+ ];
29
+ if (data.draftId)
30
+ lines.push(`Draft ID: ${data.draftId}`);
31
+ if (typeof data.seenUpToSeq === 'number')
32
+ lines.push(`Seen up to seq: ${data.seenUpToSeq}`);
33
+ if (latestMessages.length > 0) {
34
+ lines.push('', 'Latest messages:', ...latestMessages);
35
+ }
36
+ if (data.readHistory)
37
+ lines.push(`Catch-up hint: ${data.readHistory}`);
38
+ lines.push('', 'Next: review the newer messages, then send a revised message or stop.');
39
+ return `${lines.join('\n')}\n`;
40
+ }
@@ -0,0 +1,22 @@
1
+ export interface PanelVersionConflictResponse {
2
+ error?: string;
3
+ error_code?: string;
4
+ failure_class?: string;
5
+ details?: {
6
+ panelId?: string;
7
+ panel_id?: string;
8
+ currentVersion?: number;
9
+ current_version?: number;
10
+ expectedVersion?: number;
11
+ expected_version?: number;
12
+ recommendedAction?: string;
13
+ recommended_action?: string;
14
+ };
15
+ panelId?: string;
16
+ panel_id?: string;
17
+ currentVersion?: number;
18
+ current_version?: number;
19
+ expectedVersion?: number;
20
+ expected_version?: number;
21
+ }
22
+ export declare function formatPanelVersionConflict(data: PanelVersionConflictResponse): string;
@@ -0,0 +1,19 @@
1
+ export function formatPanelVersionConflict(data) {
2
+ const details = data.details ?? {};
3
+ const panelId = data.panelId ?? data.panel_id ?? details.panelId ?? details.panel_id ?? 'panel';
4
+ const currentVersion = data.currentVersion ?? data.current_version ?? details.currentVersion ?? details.current_version;
5
+ const expectedVersion = data.expectedVersion ?? data.expected_version ?? details.expectedVersion ?? details.expected_version;
6
+ const recommendedAction = details.recommendedAction ?? details.recommended_action;
7
+ const lines = [
8
+ `Panel update conflicted for ${panelId}; nothing was overwritten.`,
9
+ '',
10
+ ];
11
+ if (expectedVersion !== undefined)
12
+ lines.push(`Expected version: ${expectedVersion}`);
13
+ if (currentVersion !== undefined)
14
+ lines.push(`Current version: ${currentVersion}`);
15
+ if (recommendedAction)
16
+ lines.push(`Core guidance: ${recommendedAction}`);
17
+ lines.push('', 'Next: run bigbang panel read-events/read-rows or read the latest panel state, merge user changes, then retry with the current expected_version.', 'Do not blindly overwrite saved user state or annotations.');
18
+ return `${lines.join('\n')}\n`;
19
+ }
@@ -0,0 +1,7 @@
1
+ export interface TaskHeldResponse {
2
+ state?: string;
3
+ error?: string;
4
+ readHistory?: string;
5
+ seenUpToSeq?: number;
6
+ }
7
+ export declare function formatTaskHeld(action: 'claim' | 'update', target: string, data: TaskHeldResponse): string;
@@ -0,0 +1,13 @@
1
+ export function formatTaskHeld(action, target, data) {
2
+ const lines = [
3
+ `Task ${action} for ${target} was held; no task mutation was applied.`,
4
+ '',
5
+ 'Reason: newer task or conversation context may exist. Review it before retrying.',
6
+ ];
7
+ if (typeof data.seenUpToSeq === 'number')
8
+ lines.push(`Seen up to seq: ${data.seenUpToSeq}`);
9
+ if (data.readHistory)
10
+ lines.push(`Catch-up hint: ${data.readHistory}`);
11
+ lines.push('', 'Next: read the latest task/thread context, then rerun the command only if the update is still correct.');
12
+ return `${lines.join('\n')}\n`;
13
+ }
@@ -0,0 +1,9 @@
1
+ export { AGENT_COMMAND_ERROR_CODES, AgentCommandError, normalizeAgentCommandErrorCode, toAgentCommandError, type AgentCommandErrorCode, } from './errors.js';
2
+ export { BIGBANG_RECEIPT_PREFIX, formatBigbangReceipt, parseBigbangReceipts, type BigbangMessageSendReceipt, type BigbangMessageSendReceiptKind, type BigbangReceipt, } from './receipt.js';
3
+ export { loadAgentCommandContext, resolveCurrentRunContext, resolveCurrentRunId, type AgentCommandContext, type AgentCommandEnv, type AgentRunContext, type AgentCommandTokenSource, type LoadAgentCommandContextOptions, } from './context/runtimeContext.js';
4
+ export { AgentApiClient, type AgentApiClientOptions, type AgentApiResponse, type AgentApiRetryMode, type AgentCommandHttpMethod, } from './client/agentApiClient.js';
5
+ export { readOptionalStdin, readRequiredJsonStdin, readRequiredStdin, type StdinLike, } from './commands/stdin.js';
6
+ export { formatMessageHeld, type HeldMessageResponse } from './formatters/message.js';
7
+ export { formatTaskHeld, type TaskHeldResponse } from './formatters/task.js';
8
+ export { formatPanelVersionConflict, type PanelVersionConflictResponse } from './formatters/panel.js';
9
+ export { BIGBANG_COMMAND_CATALOG, BIGBANG_COMMAND_SUMMARY_LINES, } from './bigbangCommandCatalog.generated.js';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export { AGENT_COMMAND_ERROR_CODES, AgentCommandError, normalizeAgentCommandErrorCode, toAgentCommandError, } from './errors.js';
2
+ export { BIGBANG_RECEIPT_PREFIX, formatBigbangReceipt, parseBigbangReceipts, } from './receipt.js';
3
+ export { loadAgentCommandContext, resolveCurrentRunContext, resolveCurrentRunId, } from './context/runtimeContext.js';
4
+ export { AgentApiClient, } from './client/agentApiClient.js';
5
+ export { readOptionalStdin, readRequiredJsonStdin, readRequiredStdin, } from './commands/stdin.js';
6
+ export { formatMessageHeld } from './formatters/message.js';
7
+ export { formatTaskHeld } from './formatters/task.js';
8
+ export { formatPanelVersionConflict } from './formatters/panel.js';
9
+ export { BIGBANG_COMMAND_CATALOG, BIGBANG_COMMAND_SUMMARY_LINES, } from './bigbangCommandCatalog.generated.js';
@@ -0,0 +1,14 @@
1
+ export declare const BIGBANG_RECEIPT_PREFIX = "@@BIGBANG_RECEIPT@@";
2
+ export type BigbangMessageSendReceiptKind = 'progress' | 'final';
3
+ export interface BigbangMessageSendReceipt {
4
+ op: 'message.send';
5
+ ok: true;
6
+ kind: BigbangMessageSendReceiptKind;
7
+ messageId: string;
8
+ target?: string;
9
+ runId?: string;
10
+ conversationId?: string;
11
+ }
12
+ export type BigbangReceipt = BigbangMessageSendReceipt;
13
+ export declare function formatBigbangReceipt(receipt: BigbangReceipt): string;
14
+ export declare function parseBigbangReceipts(text: string): BigbangReceipt[];
@@ -0,0 +1,54 @@
1
+ export const BIGBANG_RECEIPT_PREFIX = '@@BIGBANG_RECEIPT@@';
2
+ export function formatBigbangReceipt(receipt) {
3
+ return `${BIGBANG_RECEIPT_PREFIX}${JSON.stringify(receipt)}`;
4
+ }
5
+ export function parseBigbangReceipts(text) {
6
+ const receipts = [];
7
+ for (const rawLine of text.split(/\r?\n/)) {
8
+ const line = rawLine.trim();
9
+ const prefixIndex = line.indexOf(BIGBANG_RECEIPT_PREFIX);
10
+ if (prefixIndex < 0)
11
+ continue;
12
+ const jsonText = line.slice(prefixIndex + BIGBANG_RECEIPT_PREFIX.length).trim();
13
+ if (!jsonText)
14
+ continue;
15
+ try {
16
+ const parsed = JSON.parse(jsonText);
17
+ const receipt = normalizeBigbangReceipt(parsed);
18
+ if (receipt)
19
+ receipts.push(receipt);
20
+ }
21
+ catch {
22
+ // Ignore non-receipt text that happens to contain the marker.
23
+ }
24
+ }
25
+ return receipts;
26
+ }
27
+ function normalizeBigbangReceipt(value) {
28
+ if (!value || typeof value !== 'object')
29
+ return null;
30
+ const record = value;
31
+ if (record.op !== 'message.send' || record.ok !== true)
32
+ return null;
33
+ const kind = record.kind === 'final' ? 'final' : record.kind === 'progress' ? 'progress' : null;
34
+ if (!kind)
35
+ return null;
36
+ const messageId = stringValue(record.messageId) ?? stringValue(record.id);
37
+ if (!messageId)
38
+ return null;
39
+ return {
40
+ op: 'message.send',
41
+ ok: true,
42
+ kind,
43
+ messageId,
44
+ ...(stringValue(record.target) ? { target: stringValue(record.target) } : {}),
45
+ ...(stringValue(record.runId) ? { runId: stringValue(record.runId) } : {}),
46
+ ...(stringValue(record.conversationId) ? { conversationId: stringValue(record.conversationId) } : {}),
47
+ };
48
+ }
49
+ function stringValue(value) {
50
+ if (typeof value !== 'string')
51
+ return null;
52
+ const trimmed = value.trim();
53
+ return trimmed ? trimmed : null;
54
+ }