@hua-labs/tap 0.5.1 → 0.6.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.
Files changed (47) hide show
  1. package/AI_GUIDE.md +165 -0
  2. package/CHANGELOG.md +67 -0
  3. package/README.md +201 -12
  4. package/dist/bridges/codex-app-server-auth-gateway.mjs +16 -1
  5. package/dist/bridges/codex-app-server-auth-gateway.mjs.map +1 -1
  6. package/dist/bridges/codex-app-server-bridge.d.mts +105 -12
  7. package/dist/bridges/codex-app-server-bridge.mjs +3149 -251
  8. package/dist/bridges/codex-app-server-bridge.mjs.map +1 -1
  9. package/dist/bridges/codex-bridge-runner.d.mts +4 -1
  10. package/dist/bridges/codex-bridge-runner.mjs +512 -58
  11. package/dist/bridges/codex-bridge-runner.mjs.map +1 -1
  12. package/dist/bridges/codex-remote-ipc-relay.d.mts +1 -0
  13. package/dist/bridges/codex-remote-ipc-relay.mjs +1912 -0
  14. package/dist/bridges/codex-remote-ipc-relay.mjs.map +1 -0
  15. package/dist/bridges/gemini-ide-companion-runner.mjs.map +1 -1
  16. package/dist/cli.mjs +30944 -8415
  17. package/dist/cli.mjs.map +1 -1
  18. package/dist/codex-a2a/index.d.mts +2 -0
  19. package/dist/codex-a2a/index.mjs +416 -0
  20. package/dist/codex-a2a/index.mjs.map +1 -0
  21. package/dist/codex-health/index.d.mts +76 -0
  22. package/dist/codex-health/index.mjs +153 -0
  23. package/dist/codex-health/index.mjs.map +1 -0
  24. package/dist/codex-ipc/index.d.mts +2 -0
  25. package/dist/codex-ipc/index.mjs +1834 -0
  26. package/dist/codex-ipc/index.mjs.map +1 -0
  27. package/dist/index-D4Khz2Mh.d.mts +206 -0
  28. package/dist/index-DMToLyGd.d.mts +256 -0
  29. package/dist/index.d.mts +763 -8
  30. package/dist/index.mjs +11600 -3449
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/mcp-server.mjs +8838 -811
  33. package/dist/mcp-server.mjs.map +1 -1
  34. package/dist/types-FWvKrFUt.d.mts +43 -0
  35. package/examples/01-logic-battle-known-broken.md +46 -0
  36. package/examples/02-cross-model-review-root-cause.md +37 -0
  37. package/examples/03-convergence-pattern.md +42 -0
  38. package/examples/04-tower-broadcast.md +41 -0
  39. package/examples/05-self-awareness-paradox.md +49 -0
  40. package/examples/06-session-resurrection.md +37 -0
  41. package/examples/07-ghost-agent.md +31 -0
  42. package/examples/08-naming-creates-identity.md +36 -0
  43. package/examples/09-ceo-as-middleware.md +52 -0
  44. package/examples/10-files-as-interface.md +67 -0
  45. package/examples/README.md +34 -0
  46. package/examples/tap-profile-pack.example.json +71 -0
  47. package/package.json +21 -3
@@ -1,5 +1,7 @@
1
1
  type BusyMode = "wait" | "steer";
2
2
  type LogLevel = "debug" | "info" | "warn" | "error";
3
+ type CandidateScope = "observe" | "suggest" | "drive";
4
+ type DispatchMode = "start" | "steer" | "drive" | "blocked" | "rejected";
3
5
  interface Options {
4
6
  repoRoot: string;
5
7
  commsDir: string;
@@ -21,11 +23,26 @@ interface Options {
21
23
  logLevel: LogLevel;
22
24
  threadId: string | null;
23
25
  ephemeral: boolean;
26
+ /**
27
+ * M392: explicit routing slot derived from the base instance id by the
28
+ * bridge launcher and forwarded via `TAP_ROUTING_SLOT`. When set, takes
29
+ * precedence over `resolveBridgeRoutingSlot(agentId)` in
30
+ * `buildBridgeAddress` so suffixed agent ids (`codex-wt1-abc123`) still
31
+ * advertise the correct slot in heartbeats / presence.
32
+ */
33
+ routingSlot: BridgeRoutingSlot | null;
24
34
  }
25
35
  interface InboxRoute {
26
36
  sender: string;
27
37
  recipient: string;
28
38
  subject: string;
39
+ messageId?: string | null;
40
+ fromAddress?: HeartbeatAddressRecord | null;
41
+ toAddress?: HeartbeatAddressRecord | null;
42
+ scope?: CandidateScope | null;
43
+ action?: string | null;
44
+ consentRef?: string | null;
45
+ validationError?: string | null;
29
46
  }
30
47
  interface Candidate {
31
48
  markerId: string;
@@ -36,6 +53,12 @@ interface Candidate {
36
53
  subject: string;
37
54
  body: string;
38
55
  mtimeMs: number;
56
+ messageId?: string | null;
57
+ fromAddress?: HeartbeatAddressRecord | null;
58
+ toAddress?: HeartbeatAddressRecord | null;
59
+ scope?: CandidateScope | null;
60
+ action?: string | null;
61
+ consentRef?: string | null;
39
62
  }
40
63
  interface ThreadStateRecord {
41
64
  threadId: string;
@@ -70,6 +93,16 @@ interface HeartbeatRecord {
70
93
  consecutiveFailureCount: number;
71
94
  busyMode: BusyMode;
72
95
  }
96
+ type BridgeRoutingSlot = "tower" | "reviewer" | `wt-${number}`;
97
+ interface HeartbeatAddressRecord {
98
+ hostId?: string | null;
99
+ clientId?: string | null;
100
+ conversationId?: string | null;
101
+ ownerClientId?: string | null;
102
+ routingAddress?: string;
103
+ slot?: BridgeRoutingSlot | null;
104
+ aliases?: string[];
105
+ }
73
106
  interface BridgeHealthState {
74
107
  consecutiveFailureCount: number;
75
108
  }
@@ -103,6 +136,8 @@ interface HeartbeatStoreRecord {
103
136
  instanceId?: string | null;
104
137
  bridgePid?: number | null;
105
138
  connectHash?: string;
139
+ address?: HeartbeatAddressRecord;
140
+ receiveTransports?: string[];
106
141
  }
107
142
  type HeartbeatStore = Record<string, HeartbeatStoreRecord>;
108
143
  interface JsonRpcResponse {
@@ -134,7 +169,9 @@ declare const STALE_TURN_MS: number;
134
169
  * M206: Re-export canonicalizeAgentId as canonicalize for backward compat.
135
170
  */
136
171
  declare function canonicalize(id: string): string;
172
+ declare function stripWindowsNamespacePrefix(cwd: string): string;
137
173
  declare function normalizeThreadCwd(cwd: string): string;
174
+ declare function normalizePersistedThreadCwd(cwd: string | null | undefined): string | null;
138
175
  declare function threadCwdMatches(expectedCwd: string, actualCwd: string | null | undefined): boolean;
139
176
  declare function chooseLoadedThreadForCwd(cwd: string, threads: LoadedThreadCandidate[]): LoadedThreadCandidate | null;
140
177
  declare function normalizeAgentToken(value?: string | null): string | null;
@@ -166,20 +203,18 @@ declare function isOwnMessageSender(sender: string, agentId: string, agentName:
166
203
  * Returns true if the turn should be treated as not active.
167
204
  */
168
205
  declare function isTurnStuckOnApproval(activeFlags: string[]): boolean;
206
+ declare function isWaitingApprovalStatus(status: string | null | undefined): boolean;
169
207
  /**
170
208
  * M203: Check if a turn has been running longer than the stale threshold.
171
209
  */
172
210
  declare function isTurnStale(turnStartedAt: string | null, nowMs?: number): boolean;
173
211
  declare function shouldRetrySteerAsStart(error: unknown): boolean;
212
+ declare const FORBIDDEN_RAW_PAIR_TOKEN_REASON = "envelope rejected: forbidden raw pairToken field present (M355 defensive drop)";
174
213
  /**
175
214
  * Parse YAML frontmatter from message content for routing.
176
215
  * Returns null if no valid frontmatter found.
177
216
  */
178
- declare function parseBridgeFrontmatter(content: string): {
179
- sender: string;
180
- recipient: string;
181
- subject: string;
182
- } | null;
217
+ declare function parseBridgeFrontmatter(content: string): InboxRoute | null;
183
218
  /**
184
219
  * Strip YAML frontmatter from message content, returning only the body.
185
220
  */
@@ -214,10 +249,35 @@ declare function sanitizeStateSegment(agentName: string): string;
214
249
  declare function buildDefaultStateDir(repoRoot: string, preferredAgentName?: string | null): string;
215
250
  declare function resolveStateDir(repoRoot: string, explicit?: string, preferredAgentName?: string | null): string;
216
251
  declare function readGatewayTokenFile(tokenFile: string): string;
252
+ declare function normalizeRoutingSlotEnv(value: string | null | undefined): BridgeRoutingSlot | null;
217
253
  declare function buildOptions(argv: string[]): Options;
218
254
 
219
255
  declare function buildMarkerId(filePath: string, mtimeMs: number): string;
220
256
  declare function getProcessedMarkerPath(stateDir: string, markerId: string): string;
257
+ interface SweepOrphanProcessedMarkersResult {
258
+ scanned: number;
259
+ removed: number;
260
+ kept: number;
261
+ errors: number;
262
+ removedMarkerIds: string[];
263
+ }
264
+ type SweepLogger = (message: string, context?: Record<string, unknown>) => void;
265
+ /**
266
+ * M362 (M346 cache-contract drift #5): scan processed markers and retire
267
+ * those whose source inbox artefact no longer exists, plus those that have
268
+ * aged past the retention window.
269
+ *
270
+ * The sweep is idempotent and failure-tolerant — unreadable payloads and
271
+ * unlink failures are counted into `errors` and skipped, never thrown. The
272
+ * intent is to run once at bridge startup; callers may also invoke it
273
+ * periodically without guard.
274
+ */
275
+ declare function sweepOrphanProcessedMarkers(stateDir: string, options?: {
276
+ nowMs?: number;
277
+ maxAgeMs?: number;
278
+ graceMs?: number;
279
+ logger?: SweepLogger;
280
+ }): SweepOrphanProcessedMarkersResult;
221
281
  declare function loadHeartbeats(commsDir: string): HeartbeatStore;
222
282
  declare function shouldSkipInHeadlessMode(fileName: string, body: string): boolean;
223
283
  declare function collectCandidates(inboxDir: string, agentId: string, agentName: string, aliasName?: string): Candidate[];
@@ -227,8 +287,15 @@ declare function getPendingCandidates(options: Options, cutoff: Date): {
227
287
  };
228
288
 
229
289
  declare function buildUserInput(candidate: Candidate, agentName: string, heartbeats: HeartbeatStore): string;
230
- declare function writeProcessedMarker(stateDir: string, candidate: Candidate, dispatchMode: "start" | "steer", threadId: string | null, turnId: string | null): void;
231
- declare function writeLastDispatch(stateDir: string, candidate: Candidate, dispatchMode: "start" | "steer", threadId: string | null, turnId: string | null): void;
290
+ declare function writeProcessedMarker(stateDir: string, candidate: Candidate, dispatchMode: DispatchMode, threadId: string | null, turnId: string | null, blockedReason?: string | null): void;
291
+ declare function writeLastDispatch(stateDir: string, candidate: Candidate, dispatchMode: DispatchMode, threadId: string | null, turnId: string | null, blockedReason?: string | null): void;
292
+
293
+ declare function isAutoElicitationRequestMethod(method: string): boolean;
294
+ interface ElicitationResult {
295
+ action: "accept" | "cancel";
296
+ content?: Record<string, unknown>;
297
+ }
298
+ declare function buildAutoElicitationResult(rawParams: unknown): ElicitationResult | null;
232
299
 
233
300
  type LogContext = Record<string, unknown>;
234
301
  interface BridgeLogger {
@@ -240,6 +307,7 @@ interface BridgeLogger {
240
307
 
241
308
  declare function readSocketData(data: unknown): Promise<string>;
242
309
  declare function formatJsonRpcError(error: JsonRpcResponse["error"]): string;
310
+ declare const DEFAULT_APP_SERVER_REQUEST_TIMEOUT_MS = 30000;
243
311
  declare class AppServerClient {
244
312
  private socket;
245
313
  private readonly url;
@@ -247,7 +315,9 @@ declare class AppServerClient {
247
315
  private readonly logger;
248
316
  private readonly clientId;
249
317
  private nextId;
250
- private pending;
318
+ private readonly requestTimeoutMs;
319
+ private readonly pending;
320
+ private readonly socketListeners;
251
321
  connected: boolean;
252
322
  initialized: boolean;
253
323
  threadId: string | null;
@@ -260,7 +330,8 @@ declare class AppServerClient {
260
330
  lastError: string | null;
261
331
  lastSuccessfulAppServerAt: string | null;
262
332
  lastSuccessfulAppServerMethod: string | null;
263
- constructor(url: string, logger: BridgeLogger, gatewayToken?: string | null);
333
+ constructor(url: string, logger: BridgeLogger, gatewayToken?: string | null, requestTimeoutMs?: number);
334
+ getPendingRequestCount(): number;
264
335
  connect(): Promise<void>;
265
336
  disconnect(): Promise<void>;
266
337
  ensureThread(explicitThreadId: string | null, savedThread: ThreadStateRecord | null, cwd: string, ephemeral: boolean): Promise<string>;
@@ -268,6 +339,7 @@ declare class AppServerClient {
268
339
  startTurn(inputText: string): Promise<string | null>;
269
340
  steerTurn(inputText: string): Promise<string>;
270
341
  isBusy(): boolean;
342
+ isWaitingOnApproval(): boolean;
271
343
  refreshCurrentThreadState(): Promise<void>;
272
344
  private requireThreadId;
273
345
  private requireActiveTurnId;
@@ -276,17 +348,38 @@ declare class AppServerClient {
276
348
  private handleMessage;
277
349
  private handleNotification;
278
350
  private request;
351
+ private sendJsonRpcResult;
279
352
  private rejectPending;
353
+ private clearPendingTimeout;
354
+ private detachSocketListeners;
355
+ private buildMetricsContext;
280
356
  }
281
357
 
358
+ declare const DRIVE_NOT_YET_WIRED_REASON = "missing pairToken / drive not yet wired (M345 Phase 2 / M355 pending)";
359
+ declare const DRIVE_ACTION_NOT_YET_SUPPORTED_REASON = "drive action is not yet wired through bridge dispatch";
360
+ interface DriveDispatchTransport {
361
+ connect(): Promise<unknown>;
362
+ disconnect(): Promise<void>;
363
+ startTurn(options: {
364
+ conversationId: string;
365
+ text: string;
366
+ action?: string | null;
367
+ consentRef?: string | null;
368
+ hostId?: string | null;
369
+ ownerClientId?: string | null;
370
+ }): Promise<unknown>;
371
+ }
372
+ type DriveDispatchTransportFactory = (options: Options) => DriveDispatchTransport;
282
373
  declare function sanitizeErrorForPersistence(error: string | null): string | null;
283
374
  declare function readThreadState(stateDir: string): ThreadStateRecord | null;
284
375
  declare function persistThreadState(stateDir: string, threadId: string, appServerUrl: string, ephemeral: boolean, cwd: string | null): void;
285
376
  declare function acquireCommsLock(lockPath: string): boolean;
286
377
  declare function releaseCommsLock(lockPath: string): void;
287
- declare function updateCommsHeartbeat(options: Options, status: string): void;
378
+ declare function updateCommsHeartbeat(options: Options, status: string, conversationId?: string | null): void;
379
+ declare function markBridgeActivity(): void;
380
+ declare function getLastBridgeActivityAt(): string | null;
288
381
  declare function writeHeartbeat(options: Options, client: AppServerClient | null, health: BridgeHealthState): void;
289
- declare function dispatchCandidate(client: AppServerClient, options: Options, candidate: Candidate, heartbeats: HeartbeatStore): Promise<boolean>;
382
+ declare function dispatchCandidate(client: AppServerClient, options: Options, candidate: Candidate, heartbeats: HeartbeatStore, driveTransportFactory?: DriveDispatchTransportFactory): Promise<boolean>;
290
383
  declare function runScan(options: Options, cutoff: Date, client: AppServerClient | null): Promise<{
291
384
  dispatched: boolean;
292
385
  maxMtimeMs: number;
@@ -301,4 +394,4 @@ declare function getGeneralInboxCutoff(stateDir: string, lookbackMinutes: number
301
394
  declare function main(): Promise<void>;
302
395
  declare function isDirectExecution(): boolean;
303
396
 
304
- export { AUTH_SUBPROTOCOL_PREFIX, AppServerClient, type BridgeHealthState, type BusyMode, COMMS_HEARTBEAT_LOCK_TIMEOUT_MS, COMMS_LOCK_STALE_AGE_MS, type Candidate, DEFAULT_AGENT, DEFAULT_APP_SERVER_URL, HEADLESS_SKIP_PATTERNS, HEADLESS_WARMUP_PROMPT, HEADLESS_WARMUP_TIMEOUT_MS, type HeadlessWarmupClient, type HeartbeatRecord, type HeartbeatStore, type HeartbeatStoreRecord, type InboxRoute, type JsonRpcResponse, type LoadedThreadCandidate, type LogLevel, type Options, PLACEHOLDER_AGENT_VALUES, type RequestRecord, STALE_TURN_MS, TURN_COMPLETION_POLL_MS, TURN_COMPLETION_REFRESH_MS, type ThreadStateRecord, acquireCommsLock, buildDefaultStateDir, buildMarkerId, buildOptions, buildUserInput, canonicalize, chooseLoadedThreadForCwd, collectCandidates, dispatchCandidate, formatAgentLabel, formatJsonRpcError, getGeneralInboxCutoff, getInboxRoute, getInboxRouteFromFilename, getPendingCandidates, getProcessedMarkerPath, isDirectExecution, isOwnMessageSender, isTurnStale, isTurnStuckOnApproval, loadHeartbeats, loadResumableThreadState, main, maybeBootstrapHeadlessTurn, normalizeAgentToken, normalizeThreadCwd, parseArgs, parseBridgeFrontmatter, persistAgentName, persistThreadState, readGatewayTokenFile, readHeartbeatState, readSocketData, readThreadState, recipientMatchesAgent, refreshAgentIdentity, releaseCommsLock, resolveAddressLabel, resolveAgentId, resolveAgentName, resolveCommsDir, resolveCurrentAgentName, resolvePreferredAgentName, resolveRepoRoot, resolveStateDir, resolveTapConfigPath, runScan, sanitizeErrorForPersistence, sanitizeStateSegment, shouldRetrySteerAsStart, shouldSkipInHeadlessMode, stripBridgeFrontmatter, threadCwdMatches, updateCommsHeartbeat, waitForTurnCompletion, waitForTurnDrain, writeHeartbeat, writeLastDispatch, writeProcessedMarker };
397
+ export { AUTH_SUBPROTOCOL_PREFIX, AppServerClient, type BridgeHealthState, type BridgeRoutingSlot, type BusyMode, COMMS_HEARTBEAT_LOCK_TIMEOUT_MS, COMMS_LOCK_STALE_AGE_MS, type Candidate, type CandidateScope, DEFAULT_AGENT, DEFAULT_APP_SERVER_REQUEST_TIMEOUT_MS, DEFAULT_APP_SERVER_URL, DRIVE_ACTION_NOT_YET_SUPPORTED_REASON, DRIVE_NOT_YET_WIRED_REASON, type DispatchMode, type ElicitationResult, FORBIDDEN_RAW_PAIR_TOKEN_REASON, HEADLESS_SKIP_PATTERNS, HEADLESS_WARMUP_PROMPT, HEADLESS_WARMUP_TIMEOUT_MS, type HeadlessWarmupClient, type HeartbeatAddressRecord, type HeartbeatRecord, type HeartbeatStore, type HeartbeatStoreRecord, type InboxRoute, type JsonRpcResponse, type LoadedThreadCandidate, type LogLevel, type Options, PLACEHOLDER_AGENT_VALUES, type RequestRecord, STALE_TURN_MS, type SweepOrphanProcessedMarkersResult, TURN_COMPLETION_POLL_MS, TURN_COMPLETION_REFRESH_MS, type ThreadStateRecord, acquireCommsLock, buildAutoElicitationResult, buildDefaultStateDir, buildMarkerId, buildOptions, buildUserInput, canonicalize, chooseLoadedThreadForCwd, collectCandidates, dispatchCandidate, formatAgentLabel, formatJsonRpcError, getGeneralInboxCutoff, getInboxRoute, getInboxRouteFromFilename, getLastBridgeActivityAt, getPendingCandidates, getProcessedMarkerPath, isAutoElicitationRequestMethod, isDirectExecution, isOwnMessageSender, isTurnStale, isTurnStuckOnApproval, isWaitingApprovalStatus, loadHeartbeats, loadResumableThreadState, main, markBridgeActivity, maybeBootstrapHeadlessTurn, normalizeAgentToken, normalizePersistedThreadCwd, normalizeRoutingSlotEnv, normalizeThreadCwd, parseArgs, parseBridgeFrontmatter, persistAgentName, persistThreadState, readGatewayTokenFile, readHeartbeatState, readSocketData, readThreadState, recipientMatchesAgent, refreshAgentIdentity, releaseCommsLock, resolveAddressLabel, resolveAgentId, resolveAgentName, resolveCommsDir, resolveCurrentAgentName, resolvePreferredAgentName, resolveRepoRoot, resolveStateDir, resolveTapConfigPath, runScan, sanitizeErrorForPersistence, sanitizeStateSegment, shouldRetrySteerAsStart, shouldSkipInHeadlessMode, stripBridgeFrontmatter, stripWindowsNamespacePrefix, sweepOrphanProcessedMarkers, threadCwdMatches, updateCommsHeartbeat, waitForTurnCompletion, waitForTurnDrain, writeHeartbeat, writeLastDispatch, writeProcessedMarker };