@astrosheep/square 0.4.7 → 0.4.8

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 (83) hide show
  1. package/dist/card-format.d.ts +2 -0
  2. package/dist/card-format.js +2 -0
  3. package/dist/claude-mcp-context.d.ts +0 -1
  4. package/dist/claude-mcp-context.js +0 -10
  5. package/dist/claude-mod.d.ts +2 -0
  6. package/dist/claude-mod.js +211 -0
  7. package/dist/cli/context.d.ts +1 -1
  8. package/dist/cli/context.js +1 -12
  9. package/dist/cli/express-presentation.js +6 -33
  10. package/dist/cli/json.js +1 -1
  11. package/dist/cli/observation-commands.d.ts +2 -3
  12. package/dist/cli/observation-commands.js +21 -59
  13. package/dist/cli/registry.js +3 -5
  14. package/dist/cli/square-commands.d.ts +1 -2
  15. package/dist/cli/square-commands.js +7 -17
  16. package/dist/decisions.js +5 -4
  17. package/dist/harness-claude.js +3 -3
  18. package/dist/help.js +6 -8
  19. package/dist/mcp.js +1 -1
  20. package/dist/neutral.d.ts +15 -1
  21. package/dist/notifications.js +1 -1
  22. package/dist/operation-presentation.d.ts +17 -15
  23. package/dist/operation-presentation.js +58 -32
  24. package/dist/packages/agent-delivery/src/index.d.ts +4 -9
  25. package/dist/packages/agent-delivery/src/index.js +0 -9
  26. package/dist/packages/agent-delivery/src/local-endpoint.d.ts +2 -12
  27. package/dist/packages/agent-delivery/src/local-endpoint.js +4 -48
  28. package/dist/packages/agent-delivery/src/pi-client.js +0 -2
  29. package/dist/packages/agent-delivery/src/types.d.ts +3 -37
  30. package/dist/plugins/paseo/shared/card-format.d.ts +6 -0
  31. package/dist/plugins/paseo/shared/card-format.js +38 -0
  32. package/dist/plugins/paseo/shared/card-presentation.d.ts +3 -1
  33. package/dist/plugins/paseo/shared/card-presentation.js +3 -1
  34. package/dist/presentation.d.ts +2 -20
  35. package/dist/presentation.js +11 -46
  36. package/dist/sqlite-square.js +5 -6
  37. package/dist/square-facade.d.ts +3 -12
  38. package/dist/square-posting.js +1 -1
  39. package/dist/square-tools.d.ts +0 -11
  40. package/dist/square-tools.js +33 -119
  41. package/dist/square-values.d.ts +1 -1
  42. package/dist/square-values.js +1 -1
  43. package/dist/time.d.ts +1 -0
  44. package/dist/time.js +10 -0
  45. package/dist/views.d.ts +1 -1
  46. package/dist/views.js +2 -2
  47. package/dist/wake-transports.d.ts +1 -1
  48. package/dist/wake-transports.js +1 -1
  49. package/guides/catch-cold-path-optimization.md +1 -1
  50. package/guides/claude-native.md +37 -7
  51. package/guides/delivery-primitives.md +2 -1
  52. package/guides/mcp.md +3 -3
  53. package/guides/pi-native-delivery.md +10 -2
  54. package/guides/pi-tools.md +1 -3
  55. package/guides/row-storage-design.md +1 -1
  56. package/package.json +1 -1
  57. package/plugins/claude/.claude-plugin/plugin.json +3 -2
  58. package/plugins/claude/README.md +9 -0
  59. package/plugins/claude/hooks/hooks.json +1 -9
  60. package/plugins/claude/hooks/register.js +178 -0
  61. package/plugins/claude/skills/square/SKILL.md +2 -2
  62. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  63. package/plugins/paseo/OVERVIEW.md +1 -1
  64. package/plugins/paseo/README.md +20 -23
  65. package/plugins/paseo/client/markdown.tsx +88 -95
  66. package/plugins/paseo/client/palette.ts +37 -12
  67. package/plugins/paseo/client/square-message.tsx +52 -76
  68. package/plugins/paseo/client/transform.ts +4 -6
  69. package/plugins/paseo/shared/card-format.ts +37 -0
  70. package/plugins/paseo/shared/card-presentation.ts +6 -2
  71. package/plugins/paseo/shared/message.ts +1 -6
  72. package/plugins/pi/square-pi.js +69 -50
  73. package/skills/square/SKILL.md +2 -2
  74. package/dist/claude-boundary-state.d.ts +0 -20
  75. package/dist/claude-boundary-state.js +0 -84
  76. package/dist/claude-hook.d.ts +0 -2
  77. package/dist/claude-hook.js +0 -232
  78. package/dist/packages/agent-delivery/src/claude-auth.d.ts +0 -13
  79. package/dist/packages/agent-delivery/src/claude-auth.js +0 -75
  80. package/dist/packages/agent-delivery/src/claude-native.d.ts +0 -30
  81. package/dist/packages/agent-delivery/src/claude-native.js +0 -75
  82. package/dist/packages/agent-delivery/src/claude.d.ts +0 -5
  83. package/dist/packages/agent-delivery/src/claude.js +0 -66
@@ -71,8 +71,8 @@ export async function doctorClaudePlugin(homeDir, run = runClaude) {
71
71
  return [
72
72
  fs.existsSync(bundle) ? `✓ Square Claude plugin bundle ${root}` : `○ Square Claude plugin bundle missing ${root}`,
73
73
  installed ? `✓ ${CLAUDE_PLUGIN_ID} installed` : `○ ${CLAUDE_PLUGIN_ID} unavailable`,
74
- `Claude delivery uses synchronous prompt/tool hooks and one finite 24-hour asyncRewake Stop observer; actual coverage ends at native boundaries.`,
75
- `Idle Escape cannot disarm a watcher, and already emitted notifications cannot be recalled; busy Escape disarms at the next prompt boundary.`,
76
- `Native stderr output is recorded unknown until its exact token/hash frame appears at a later prompt boundary; model comprehension is not observed.`,
74
+ `Claude delivery uses a mod: busy turns append context and log it; idle main sessions submit an attributed plugin prompt.`,
75
+ `Stop suppresses the current delivery batch; clear, resume and module reload retire the captured helper and attachment.`,
76
+ `Exact native acceptance records presentation, not model comprehension. Paseo does not yet expose Claude ui_log events.`,
77
77
  ];
78
78
  }
package/dist/help.js CHANGED
@@ -40,11 +40,10 @@ const COMMANDS = [
40
40
  { names: ['listen'], usage: '--as <name> listen <participant>', usesSquare: true, group: 'participant', summary: 'Turn an ear toward one participant\'s future activity.' },
41
41
  { names: ['unlisten'], usage: '--as <name> unlisten <participant>', usesSquare: true, group: 'participant', summary: 'Stop listening without blocking that participant\'s mentions or replies.' },
42
42
  { names: ['ignore'], usage: '--as <name> ignore <participant>', usesSquare: true, group: 'participant', summary: 'Stop hearing one participant\'s future activity, except bells.' },
43
- { names: ['listening'], usage: '--as <name> listening', usesSquare: true, group: 'participant', summary: 'Show who you are turned toward.', details: ['Listening applies to future activity. What you could hear when an activity landed does not change afterward.'] },
44
43
  {
45
- names: ['perceive'], usage: '--as <name> perceive [--id <activity-id>] [--now | --idle <duration>] [--from <names>] [--mention] [--limit <count>] [--takeover]', usesSquare: true, group: 'participant',
44
+ names: ['perceive'], usage: '--as <name> perceive [--id <activity-id>] [--idle <duration>] [--from <names>] [--mention] [--limit <count>] [--takeover]', usesSquare: true, group: 'participant',
46
45
  summary: 'Perceive directed conversation since you last looked.',
47
- details: ['Modes:', ' --id <activity-id> Perceive exactly one activity addressed to you, with its full body; implies --now.', ' Marks only this activity seen; repeats return it again. No filters, limit, idle or takeover.', ' history stays read-only; perceive --id consumes the selected activity.', ' --now Take in activity immediately; bare perceive already does this.', ' --idle <duration> Wait for something relevant, or for quiet to last this long.', '', 'Attention:', ' Mentions arrive when you are addressed; bells arrive for everyone; bare says require listen.', ' listen and ignore are future-only and fixed when each say lands.', '', 'Filters:', ' --from <names> Match only comma-separated participants.', ' --mention Match direct attention for your current participant (and bells).', ' --limit <count> Return one page (default 10, maximum 100).', '', 'Recovery:', ' --takeover Take over from another active perceive for this participant.'],
46
+ details: ['Modes:', ' --id <activity-id> Open one activity addressed to you in full; repeats work. Use it alone.', ' --idle <duration> Wait for something relevant, or for quiet to last this long.', '', 'Attention:', ' Mentions arrive when you are addressed; bells arrive for everyone; bare says require listen.', ' listen and ignore are future-only and fixed when each say lands.', '', 'Filters:', ' --from <names> Match only comma-separated participants.', ' --mention Match direct attention for your current participant (and bells).', ' --limit <count> Return one page (default 10, maximum 100).', '', 'Recovery:', ' --takeover Take over from another active perceive for this participant.'],
48
47
  },
49
48
  { names: ['done'], usage: '--as <name> done', usesSquare: true, group: 'participant', summary: 'Step out of the square.', details: ['done takes no message. Use express before leaving to send one.'] },
50
49
  {
@@ -60,12 +59,11 @@ const COMMANDS = [
60
59
  { names: ['codex-hook'], usage: '{command}', summary: 'Present pending attention at one native agent boundary.', hiddenFromIndex: true },
61
60
  { names: ['codex-watch'], usage: '{command}', summary: 'Observe pending attention from a native async Stop hook.', hiddenFromIndex: true },
62
61
  { names: ['codex-interrupt'], usage: '{command}', summary: 'Cancel pending attention at a native Interrupt boundary.', hiddenFromIndex: true },
63
- { names: ['claude-hook'], usage: '{command}', summary: 'Receive a native Claude hook event.', hiddenFromIndex: true },
64
- { names: ['claude-watch'], usage: '{command}', summary: 'Observe pending attention from a native async Stop hook.', hiddenFromIndex: true },
62
+ { names: ['claude-mod'], usage: '{command}', summary: 'Run the Claude mod delivery helper.', hiddenFromIndex: true },
65
63
  {
66
64
  names: ['history'], usage: 'history [filters] [output]', usesSquare: true, group: 'participant',
67
65
  summary: 'Read or search the archive without changing what you have perceived.',
68
- details: ['Optional --as is accepted but does not change the archive or claim a name.', '', 'Filters:', ' --from <names> Match activities from participants.', ' --since <time> Match activities after a time.', ' --grep <regex> | --fixed <s> Search activity ids, participants, and original bodies.', ' --mention <name> Match direct attention for a participant.', ' --at <ids> Center on comma-separated activity ids; may repeat.', ' -B, -A, -C <N> Set non-negative context around every --at coordinate.', ' --before <id> Read the page immediately before an activity.', ' --after <id> Read the page immediately after an activity.', '', 'Results:', ' --limit <N> Page size (default 10, maximum 100).', ' --order <asc|desc> Set display order (default oldest first).', '', 'Output:', ' --no-truncate --json --format <fields>', ' One result shows its full body; multiple results use previews.', ' --no-truncate shows every original body.'],
66
+ details: ['Filters:', ' --from <names> Match activities from participants.', ' --since <time> Match activities after a time.', ' --search <text> [--regex] Search ids, participants, and original bodies; literal by default.', ' --mention <name> Match direct attention for a participant.', ' --at <ids> Center on comma-separated activity ids; may repeat.', ' -C <N> Set symmetric context around every --at coordinate.', ' --before <id> Read the page immediately before an activity.', ' --after <id> Read the page immediately after an activity.', '', 'Results:', ' --limit <N> Page size (default 10, maximum 100).', ' --order <asc|desc> Set display order (default oldest first).', '', 'Output:', ' --full --json --format <fields>', ' One result shows its full body; multiple results use previews.', ' --full shows every original body.'],
69
67
  },
70
68
  { names: ['status'], usage: '[--as <name>] status', usesSquare: true, group: 'participant', summary: 'Show who is present and what happened most recently.' },
71
69
  {
@@ -96,7 +94,7 @@ function isHelpFlag(value) {
96
94
  }
97
95
  export function renderGlobalHelp() {
98
96
  const groups = [
99
- { key: 'participant', title: 'In the square:', order: ['join', 'express', 'listen', 'unlisten', 'ignore', 'listening', 'perceive', 'history', 'status', 'done'] },
97
+ { key: 'participant', title: 'In the square:', order: ['join', 'express', 'listen', 'unlisten', 'ignore', 'perceive', 'history', 'status', 'done'] },
100
98
  { key: 'host', title: 'Prepare and manage:', order: ['build', 'list'] },
101
99
  { key: 'maintenance', title: 'Setup:', order: ['install', 'uninstall', 'doctor'] },
102
100
  ];
@@ -112,7 +110,7 @@ export function renderGlobalHelp() {
112
110
  'Usage: square [--location <square>] [--as <name>] [--owner <id>] <command> [args...]',
113
111
  'Location: square-accessing commands require --location <square>. Use square list to find nearby squares and your joined names; use --as to select a participant.',
114
112
  'Identity: --owner overrides SQUARE_OWNER, then a complete harness identity, then user:<OS user>@<host>. Incomplete or ambiguous harness identities refuse. Owners without wake use perceive --idle.',
115
- 'Output: --json on join, express, perceive, history, listen, ignore, unlisten, listening, done, status and inbox prints the SDK result without observation; a participant handle becomes {name}.',
113
+ 'Output: --json on join, express, perceive, history, listen, ignore, unlisten, done, status and inbox prints the SDK result without observation; a participant handle becomes {name}.',
116
114
  'History emits one JSON document; stream --ndjson emits one SDK record per line.',
117
115
  '',
118
116
  ...commandLines,
package/dist/mcp.js CHANGED
@@ -20,7 +20,7 @@ export function createSquareMcpServer(options) {
20
20
  return invoke(tool, args, { signal: extra.signal }, async () => {
21
21
  const threadId = extra._meta?.threadId;
22
22
  const opencodeSessionId = extra._meta?.['ai.opencode/sessionID'];
23
- // Claude's bundled plugin requires a per-call native hook association; startup identity is not a fallback.
23
+ // Claude's bundled mod requires a per-call native association; startup identity is not a fallback.
24
24
  const claude = baseEnv.SQUARE_CLAUDE_MCP_CONTEXT === '1'
25
25
  ? await readClaudeMcpCall(extra._meta?.['claudecode/toolUseId'], baseEnv)
26
26
  : undefined;
package/dist/neutral.d.ts CHANGED
@@ -2,6 +2,16 @@
2
2
  export type Owner = string;
3
3
  export type SquareErrorCode = 'invalid_name' | 'invalid_args' | 'unknown_participant' | 'not_joined' | 'already_joined' | 'already_done' | 'capped' | 'throttled' | 'bell_quota' | 'behind' | 'io' | 'unavailable';
4
4
  export type InternalSquareErrorCode = SquareErrorCode | 'not_found' | 'cap_reached' | 'conflict' | 'pending_peer';
5
+ /** One speaker's unperceived activity, previewed by its latest body. */
6
+ export interface UnreadActivitySummary {
7
+ readonly name: string;
8
+ readonly count: number;
9
+ readonly latestActivityAgeMs: number;
10
+ readonly preview: {
11
+ readonly body?: string;
12
+ readonly structured: boolean;
13
+ };
14
+ }
5
15
  export interface SquareErrorFacts {
6
16
  /** Express admission rejected before any activity was committed. */
7
17
  activityUnsent?: true;
@@ -13,8 +23,12 @@ export interface SquareErrorFacts {
13
23
  targets?: readonly string[];
14
24
  /** Whether the artifact holds that activity at all; an unknown id needs an ordinary page. */
15
25
  activityExists?: boolean;
16
- pending?: number;
26
+ /** Who spoke while an express was away; the refusal rests on exactly these. */
27
+ activitySummaries?: readonly UnreadActivitySummary[];
17
28
  retryAfterMs?: number;
29
+ /** A capped speaker's spoken count against the square's cap. */
30
+ spoken?: number;
31
+ hardCap?: number;
18
32
  }
19
33
  export interface PerceiveWaitStart {
20
34
  readonly idleMs: number;
@@ -1,7 +1,7 @@
1
1
  import { createDefaultDeliveryTransports } from './wake-transports.js';
2
2
  export { createDefaultDeliveryTransports } from './wake-transports.js';
3
3
  const DEFAULT_DELIVERY_WAIT_MS = 5000;
4
- const NATIVE_RECEIVER_ROUTES = new Set(['codex-queue', 'claude-async-hook', 'claude-native', 'pi-native']);
4
+ const NATIVE_RECEIVER_ROUTES = new Set(['codex-queue', 'claude-mod', 'pi-native']);
5
5
  /** Best-effort dispatch for currently eligible cards, including cards restored by release. */
6
6
  export async function dispatchEligibleCards(ledger, owner, options = {}) {
7
7
  const signal = options.signal ?? AbortSignal.timeout(DEFAULT_DELIVERY_WAIT_MS);
@@ -1,4 +1,4 @@
1
- import type { PerceiveOptions, PerceiveResult, ExpressResult, HistoryQuery, HistoryResult, JoinResult, LifecycleResult, ListenerChangeResult, ListeningResult, OperationFailureDetail, StatusResult, DiscoveryResult } from './square-facade.js';
1
+ import type { PerceiveOptions, PerceiveResult, ExpressResult, HistoryQuery, HistoryResult, JoinResult, LifecycleResult, ListenerChangeResult, OperationFailureDetail, SquareErrorFacts, StatusResult, DiscoveryResult } from './square-facade.js';
2
2
  import { type PresentationSurface } from './presentation.js';
3
3
  export declare function renderSquareList(data: DiscoveryResult, projection: {
4
4
  now: number;
@@ -22,14 +22,13 @@ export declare function renderPerceiveOutcome(squarePath: string, data: Perceive
22
22
  export declare function historyContinuationCommand(squarePath: string, args: readonly string[]): string;
23
23
  export declare function renderHistoryResult(squarePath: string, data: HistoryResult, options?: {
24
24
  query?: HistoryQuery;
25
- noTruncate?: boolean;
25
+ full?: boolean;
26
26
  continuationArgs?: readonly string[];
27
27
  surface?: PresentationSurface;
28
28
  }): string | undefined;
29
29
  export declare function renderStatusResult(squarePath: string, data: StatusResult, options?: {
30
30
  surface?: PresentationSurface;
31
31
  }): string | undefined;
32
- export declare function renderListeningResult(squarePath: string, data: ListeningResult): string | undefined;
33
32
  export type ListenerVerb = 'listen' | 'ignore' | 'unlisten';
34
33
  export declare function renderListenerChange(squarePath: string, verb: ListenerVerb, data: ListenerChangeResult): string | undefined;
35
34
  export declare function renderLifecycleResult(squarePath: string, data: LifecycleResult): string | undefined;
@@ -37,18 +36,21 @@ export declare function renderLifecycleResult(squarePath: string, data: Lifecycl
37
36
  export interface FailureReport {
38
37
  readonly code: string;
39
38
  readonly message: string;
40
- readonly facts?: {
41
- readonly reason?: 'never_joined' | 'not_standing' | 'bell_mention_conflict' | 'not_addressed' | 'invalid_reply' | 'invalid_done_body' | 'needs_seat';
42
- readonly activityId?: string;
43
- readonly activityExists?: boolean;
44
- };
39
+ readonly facts?: SquareErrorFacts;
45
40
  readonly operation?: OperationFailureDetail;
46
41
  }
42
+ interface FailureOptions {
43
+ readonly squarePath?: string;
44
+ readonly name?: string;
45
+ readonly owner?: string;
46
+ readonly surface?: PresentationSurface;
47
+ readonly reply?: string;
48
+ /** CLI only: the saved draft and the full command that resends it. */
49
+ readonly draftPath?: string;
50
+ readonly retry?: string;
51
+ }
52
+ /** Express gates are physics, not mistakes: one scene for every surface, then that surface's next action. */
53
+ export declare function isExpressGate(code: string): boolean;
47
54
  /** Refusal lines with surface-specific recovery actions. */
48
- export declare function renderFailureLines(failure: FailureReport, options?: {
49
- squarePath?: string;
50
- name?: string;
51
- owner?: string;
52
- surface?: PresentationSurface;
53
- reply?: string;
54
- }): string[];
55
+ export declare function renderFailureLines(failure: FailureReport, options?: FailureOptions): string[];
56
+ export {};
@@ -1,8 +1,8 @@
1
1
  // Human-facing scenes for settled operations, with surface-specific next actions.
2
2
  import { sameName } from './model.js';
3
3
  import { formatActivityId } from './square-core.js';
4
- import { displayPath, formatToolAction, commandPrefix, joinRecoveryCommand, participantCommandPrefix, participantIdentity, quoteShell, renderAmbientEvent, renderAmbientEventFacts, renderEventCli, renderGrepActivitiesView, renderPresenceAnchor, renderWatchAlreadyActive, renderWatchReplaced, renderWatchStatus, takeoverRecoveryLines, withPathOutput, truncateChars, } from './presentation.js';
5
- import { formatRelativeTime, formatTimestamp } from './time.js';
4
+ import { displayPath, formatToolAction, commandPrefix, joinRecoveryCommand, participantCommandPrefix, participantIdentity, quoteShell, renderAmbientEvent, renderAmbientEventFacts, renderEventCli, renderGrepActivitiesView, renderPresenceAnchor, renderWatchAlreadyActive, renderWatchReplaced, renderWatchStatus, renderUnreadSummary, takeoverRecoveryLines, withPathOutput, truncateChars, } from './presentation.js';
5
+ import { formatDuration, formatRelativeTime, formatTimestamp } from './time.js';
6
6
  import { style } from './tty-style.js';
7
7
  function listDisplay(value) {
8
8
  const truncated = truncateChars(value, 159);
@@ -53,7 +53,7 @@ export function renderJoinResult(data, owner, surface = 'cli') {
53
53
  now: after.now, preview: 200, perception: event.perception,
54
54
  })).filter(Boolean).join('\n\n');
55
55
  const fallback = after.deliveryAvailable ? ['', '· when someone calls you, you’ll hear them here'] : [
56
- '', surface === 'tool' ? formatToolAction('perceive', { location: displayPath(after.location), as: name, idle: 1800000 }) : `${participantCommandPrefix(after.location, name, owner)} perceive --idle 30m`,
56
+ '', surface === 'tool' ? formatToolAction('perceive', { location: displayPath(after.location), as: name, idle: '30m' }) : `${participantCommandPrefix(after.location, name, owner)} perceive --idle 30m`,
57
57
  ' · stay within earshot — keep this perceive open for new activity',
58
58
  ];
59
59
  const entryLine = data.kind === 'joined' ? '● you stepped into the square'
@@ -101,14 +101,14 @@ export function renderExpression(squarePath, data, owner, surface = 'cli') {
101
101
  return withPathOutput(projection.location ?? squarePath, confirmation + (data.hint ? `\n${style('dim', `· ${data.hint}`)}` : '') + replyNotice + unmatchedNotice + pending, { participantCount: projection.standingCount });
102
102
  }
103
103
  function continuationCommand(squarePath, name, options, owner) {
104
- const args = ['--now'];
104
+ const args = [];
105
105
  if (options.from?.length)
106
106
  args.push('--from', options.from.join(','));
107
107
  if (options.mention)
108
108
  args.push('--mention');
109
109
  if (options.limit !== undefined)
110
110
  args.push('--limit', String(options.limit));
111
- return `${participantCommandPrefix(squarePath, name, owner)} perceive ${args.join(' ')}`;
111
+ return [participantCommandPrefix(squarePath, name, owner), 'perceive', ...args].join(' ');
112
112
  }
113
113
  /** Render settled perceive facts; no selection, terminal decisions, receipts or wait machinery. */
114
114
  export function renderPerceiveOutcome(squarePath, data, options = {}, owner, surface = 'cli') {
@@ -141,16 +141,16 @@ export function renderPerceiveOutcome(squarePath, data, options = {}, owner, sur
141
141
  ...(stop === 'idle' && options.idle !== undefined ? { idleMs: options.idle } : {}),
142
142
  });
143
143
  const fallback = stop === undefined && !projection.deliveryAvailable && data.remaining === 0
144
- ? `${surface === 'tool' ? formatToolAction('perceive', { location: displayPath(location), as: name, idle: 1800000 }) : `${participantCommandPrefix(location, name, owner)} perceive --idle 30m`}\n stay available for new activity` : '';
144
+ ? `${surface === 'tool' ? formatToolAction('perceive', { location: displayPath(location), as: name, idle: '30m' }) : `${participantCommandPrefix(location, name, owner)} perceive --idle 30m`}\n stay available for new activity` : '';
145
145
  const hint = data.hint === undefined ? '' : style('dim', `· ${data.hint}`);
146
146
  return {
147
147
  stdout: withPathOutput(location, [terminal, rendered, hint, remaining, fallback].filter(Boolean).join('\n\n'), header),
148
148
  exitCode: stop === 'capped' ? 1 : 0,
149
149
  };
150
150
  }
151
- function renderHistoryProjection(projection, visible, noTruncate, squarePath, surface) {
151
+ function renderHistoryProjection(projection, visible, full, squarePath, surface) {
152
152
  const shown = visible;
153
- const preview = noTruncate || shown.length <= 1 ? undefined : 200;
153
+ const preview = full || shown.length <= 1 ? undefined : 200;
154
154
  const chunks = [];
155
155
  // Presence anchors collect into one closing line instead of interrupting the page.
156
156
  const anchored = [];
@@ -167,7 +167,7 @@ function renderHistoryProjection(projection, visible, noTruncate, squarePath, su
167
167
  return '○ no activity matches this history query';
168
168
  if (preview !== undefined && shown.some((activity) => activity.kind === 'say' && (activity.body?.length ?? 0) > preview)) {
169
169
  const ids = shown.map((activity) => formatActivityId(activity.index));
170
- chunks.push(surface === 'tool' ? formatToolAction('history', { location: displayPath(squarePath), at: ids, noTruncate: true }) : `${commandPrefix(squarePath)} history --at ${ids.join(',')} --no-truncate`);
170
+ chunks.push(surface === 'tool' ? formatToolAction('history', { location: displayPath(squarePath), at: ids, full: true }) : `${commandPrefix(squarePath)} history --at ${ids.join(',')} --full`);
171
171
  }
172
172
  if (anchored.length > 0)
173
173
  chunks.push(renderPresenceAnchor(anchored));
@@ -185,14 +185,15 @@ function historyQueryArgs(query) {
185
185
  args.push('--since', formatTimestamp(query.since));
186
186
  if (query.at?.length)
187
187
  args.push('--at', query.at.join(','));
188
- if (query.contextBefore !== undefined)
189
- args.push('-B', String(query.contextBefore));
190
- if (query.contextAfter !== undefined)
191
- args.push('-A', String(query.contextAfter));
188
+ if (query.context !== undefined)
189
+ args.push('-C', String(query.context));
192
190
  if (query.mention !== undefined)
193
191
  args.push('--mention', query.mention);
194
- if (query.search !== undefined)
195
- args.push(query.search.mode === 'regex' ? '--grep' : '--fixed', query.search.text);
192
+ if (query.search !== undefined) {
193
+ args.push('--search', query.search.text);
194
+ if (query.search.mode === 'regex')
195
+ args.push('--regex');
196
+ }
196
197
  if (query.order !== undefined)
197
198
  args.push('--order', query.order);
198
199
  return args;
@@ -202,14 +203,14 @@ export function renderHistoryResult(squarePath, data, options = {}) {
202
203
  if (projection === undefined)
203
204
  return undefined;
204
205
  const query = options.query ?? {};
205
- const noTruncate = options.noTruncate === true;
206
+ const full = options.full === true;
206
207
  const search = query.search;
207
208
  const output = search === undefined
208
- ? renderHistoryProjection(projection, projection.visibleActivities, noTruncate, squarePath, options.surface ?? 'cli')
209
- : renderGrepActivitiesView(projection.visibleActivities, projection.totalMatches, noTruncate, squarePath, search.text, search.mode === 'literal', () => 'full', options.surface);
209
+ ? renderHistoryProjection(projection, projection.visibleActivities, full, squarePath, options.surface ?? 'cli')
210
+ : renderGrepActivitiesView(projection.visibleActivities, projection.totalMatches, full, squarePath, search.text, search.mode === 'literal', () => 'full', options.surface);
210
211
  const next = projection.continuation;
211
- const base = options.continuationArgs ?? historyQueryArgs(query);
212
- const continuation = next === undefined ? '' : `\n\n${options.surface === 'tool' ? formatToolAction('history', { location: displayPath(squarePath), ...(query.from?.length ? { from: query.from } : {}), ...(query.since !== undefined ? { since: formatTimestamp(query.since) } : {}), ...(query.at?.length ? { at: query.at } : {}), ...(query.contextBefore !== undefined && query.contextBefore === query.contextAfter ? { context: query.contextBefore } : { ...(query.contextBefore !== undefined ? { contextBefore: query.contextBefore } : {}), ...(query.contextAfter !== undefined ? { contextAfter: query.contextAfter } : {}) }), ...(query.mention !== undefined ? { mention: query.mention } : {}), ...(query.search !== undefined ? (query.search.mode === 'regex' ? { grep: query.search.text } : { fixed: query.search.text }) : {}), ...(query.order !== undefined ? { order: query.order } : {}), ...(noTruncate ? { noTruncate: true } : {}), [next.direction]: next.cursor, limit: next.limit }) : historyContinuationCommand(squarePath, [...base, `--${next.direction}`, next.cursor, '--limit', String(next.limit)])}`;
212
+ const base = options.continuationArgs ?? [...historyQueryArgs(query), ...(full ? ['--full'] : [])];
213
+ const continuation = next === undefined ? '' : `\n\n${options.surface === 'tool' ? formatToolAction('history', { location: displayPath(squarePath), ...(query.from?.length ? { from: query.from } : {}), ...(query.since !== undefined ? { since: formatTimestamp(query.since) } : {}), ...(query.at?.length ? { at: query.at } : {}), ...(query.context !== undefined ? { context: query.context } : {}), ...(query.mention !== undefined ? { mention: query.mention } : {}), ...(query.search !== undefined ? { search: query.search.text, ...(query.search.mode === 'regex' ? { regex: true } : {}) } : {}), ...(query.order !== undefined ? { order: query.order } : {}), ...(full ? { full: true } : {}), [next.direction]: next.cursor, limit: next.limit }) : historyContinuationCommand(squarePath, [...base, `--${next.direction}`, next.cursor, '--limit', String(next.limit)])}`;
213
214
  return withPathOutput(squarePath, output + continuation, { participantCount: projection.standingCount });
214
215
  }
215
216
  export function renderStatusResult(squarePath, data, options = {}) {
@@ -276,7 +277,7 @@ export function renderStatusResult(squarePath, data, options = {}) {
276
277
  if (presentation.joinCount > 3)
277
278
  latest.push(style('dim', ` → … ${presentation.joinCount - 3} more stepped in`));
278
279
  if (visible.bodyClipped && data.latestActivity !== undefined) {
279
- latest.push(options.surface === 'tool' ? formatToolAction('history', { location: displayPath(squarePath), at: [data.latestActivity.id], context: 2, noTruncate: true }) : `${commandPrefix(squarePath)} history --at ${data.latestActivity.id} -C 2 --no-truncate`);
280
+ latest.push(options.surface === 'tool' ? formatToolAction('history', { location: displayPath(squarePath), at: [data.latestActivity.id], context: 2, full: true }) : `${commandPrefix(squarePath)} history --at ${data.latestActivity.id} -C 2 --full`);
280
281
  }
281
282
  const counts = [
282
283
  `${orderedHere.length} here`,
@@ -296,15 +297,6 @@ export function renderStatusResult(squarePath, data, options = {}) {
296
297
  ].join('\n');
297
298
  return withPathOutput(squarePath, output, { participantCount: presentation.standingCount });
298
299
  }
299
- export function renderListeningResult(squarePath, data) {
300
- const projection = data.observation;
301
- if (projection?.participant === undefined)
302
- return undefined;
303
- const body = data.listening.length === 0
304
- ? `○ ${participantIdentity(projection.participant)} is not turned toward anyone`
305
- : ['listening', ...data.listening.map((target) => ` · ${participantIdentity(target)}`)].join('\n');
306
- return withPathOutput(squarePath, body, { participantCount: projection.standingCount });
307
- }
308
300
  export function renderListenerChange(squarePath, verb, data) {
309
301
  const projection = data.observation;
310
302
  if (projection?.participant === undefined)
@@ -330,15 +322,49 @@ export function renderLifecycleResult(squarePath, data) {
330
322
  participantCount: projection.standingCount,
331
323
  });
332
324
  }
325
+ /** Express gates are physics, not mistakes: one scene for every surface, then that surface's next action. */
326
+ export function isExpressGate(code) {
327
+ return code === 'behind' || code === 'capped' || code === 'throttled' || code === 'bell_quota';
328
+ }
329
+ function expressGateLines(failure, options) {
330
+ if (!isExpressGate(failure.code))
331
+ return undefined;
332
+ const { squarePath, name, owner } = options;
333
+ const facts = failure.facts;
334
+ const tool = options.surface === 'tool';
335
+ const scene = failure.code === 'behind'
336
+ ? ['✕ your words stay unsent — someone spoke while you were away', ...renderUnreadSummary(facts?.activitySummaries ?? [])]
337
+ : failure.code === 'capped'
338
+ ? [`✕ you’ve reached your speaking cap${facts?.spoken !== undefined && facts.hardCap !== undefined ? ` — ${facts.spoken}/${facts.hardCap} spoken` : ''}`]
339
+ : failure.code === 'throttled'
340
+ ? ['✕ the square is packed — shoulder to shoulder', ` · a lull opens in ${formatDuration(facts?.retryAfterMs ?? 1)}`]
341
+ : ['✕ the bell stays quiet for now', ` · you can ring it again in ${formatDuration(facts?.retryAfterMs ?? 1)}`];
342
+ const lines = [...scene, ...(options.draftPath === undefined ? [] : [style('dim', `· draft kept: ${options.draftPath}`)])];
343
+ if (squarePath === undefined || name === undefined)
344
+ return lines;
345
+ const action = (verb) => tool
346
+ ? formatToolAction(verb, { location: displayPath(squarePath), as: name })
347
+ : `${participantCommandPrefix(squarePath, name, owner)} ${verb}`;
348
+ if (failure.code === 'behind')
349
+ lines.push(...(tool ? ['Take it in, then express again:', action('perceive')] : [action('perceive'), ' · take it in, then retry:']));
350
+ if (failure.code === 'capped')
351
+ lines.push(' · your words stay unsent; done only steps out', action('done'));
352
+ if (failure.code === 'bell_quota' && !tool)
353
+ lines.push(' · retry when the bell is ready:');
354
+ if (failure.code !== 'capped' && options.retry !== undefined)
355
+ lines.push(options.retry);
356
+ return lines;
357
+ }
333
358
  /** Refusal lines with surface-specific recovery actions. */
334
359
  export function renderFailureLines(failure, options = {}) {
335
360
  const { squarePath, name, owner } = options;
336
361
  const facts = failure.facts;
337
362
  const reason = facts?.reason;
363
+ const gate = expressGateLines(failure, options);
364
+ if (gate !== undefined)
365
+ return gate;
338
366
  const marked = reason === 'never_joined' || reason === 'not_standing';
339
367
  const lines = marked ? failure.message.split('\n').map((line) => `✕ ${line}`) : [failure.message];
340
- if (failure.code === 'behind' && options.surface === 'tool')
341
- lines[0] = `✕ your words stay unsent — ${failure.message}`;
342
368
  if (reason === 'bell_mention_conflict' || reason === 'invalid_reply') {
343
369
  lines[0] = reason === 'bell_mention_conflict' ? '✕ a bell cannot be combined with a mention'
344
370
  : `Invalid ${options.surface === 'tool' ? 'reply' : '--reply'}: ${facts?.activityExists === false ? `${facts.activityId ?? options.reply ?? 'that activity'} is not in this square's history` : 'expected an activity id like act/12'}`;
@@ -1,6 +1,6 @@
1
1
  import { DeliveryError } from './errors.js';
2
- import type { OpenCodeConnectOptions, ClaudeConnectOptions, PiConnectOptions, PaseoConnectOptions, CodexConnectOptions, CodexAppServerConnectOptions, CodexCliConnectOptions } from './types.js';
3
- export type { OpenCodeConnectOptions, ClaudeConnectOptions, PiConnectOptions, PaseoConnectOptions, CodexConnectOptions, CodexAppServerConnectOptions, CodexCliConnectOptions } from './types.js';
2
+ import type { OpenCodeConnectOptions, PiConnectOptions, PaseoConnectOptions, CodexConnectOptions, CodexAppServerConnectOptions, CodexCliConnectOptions } from './types.js';
3
+ export type { OpenCodeConnectOptions, PiConnectOptions, PaseoConnectOptions, CodexConnectOptions, CodexAppServerConnectOptions, CodexCliConnectOptions } from './types.js';
4
4
  export interface SendOptions {
5
5
  readonly timeoutMs?: number;
6
6
  readonly signal?: AbortSignal;
@@ -10,7 +10,7 @@ export interface KeyedSendOptions extends SendOptions {
10
10
  }
11
11
  export interface Receipt {
12
12
  readonly id: string;
13
- readonly proof: 'written' | 'admitted' | 'observed';
13
+ readonly proof: 'admitted' | 'observed';
14
14
  }
15
15
  export interface Steerable<O = SendOptions> {
16
16
  steer(text: string, options?: O): Promise<Receipt>;
@@ -22,10 +22,6 @@ export type OpenCodeAgent = Steerable<KeyedSendOptions> & Queueable<KeyedSendOpt
22
22
  readonly harness: 'opencode';
23
23
  readonly sessionId: string;
24
24
  };
25
- export type ClaudeAgent = Steerable & {
26
- readonly harness: 'claude';
27
- readonly sessionId: string;
28
- };
29
25
  export type PiAgent = Steerable & Queueable & {
30
26
  readonly harness: 'pi';
31
27
  readonly sessionId: string;
@@ -47,9 +43,8 @@ export type CodexCliAgent = Queueable & {
47
43
  readonly sessionId: string;
48
44
  };
49
45
  export type CodexAgent = CodexAppServerAgent | CodexCliAgent;
50
- export type Agent = OpenCodeAgent | ClaudeAgent | PiAgent | PaseoAgent | CodexAgent;
46
+ export type Agent = OpenCodeAgent | PiAgent | PaseoAgent | CodexAgent;
51
47
  export declare function connect(options: OpenCodeConnectOptions): Promise<OpenCodeAgent>;
52
- export declare function connect(options: ClaudeConnectOptions): Promise<ClaudeAgent>;
53
48
  export declare function connect(options: PiConnectOptions): Promise<PiAgent>;
54
49
  export declare function connect(options: PaseoConnectOptions): Promise<PaseoAgent>;
55
50
  export declare function connect(options: CodexCliConnectOptions): Promise<CodexCliAgent>;
@@ -58,15 +58,6 @@ const harnesses = {
58
58
  return { coordinate: target.sessionId, send: (text, value) => sendText(target, text, value) };
59
59
  },
60
60
  },
61
- claude: {
62
- harness: 'claude', proof: 'written', accepted: 'written', coordinate: 'sessionId', keyed: false, queue: false,
63
- id: (result) => result.messageId,
64
- open: async (options) => {
65
- const { connectExisting, sendText } = await import('./claude.js');
66
- const target = await connectExisting(options);
67
- return { coordinate: target.sessionId, send: (text, value) => sendText(target, text, value) };
68
- },
69
- },
70
61
  pi: {
71
62
  harness: 'pi', proof: 'observed', accepted: 'observed', coordinate: 'sessionId', keyed: false, queue: true,
72
63
  id: (result) => result.inputId,
@@ -1,20 +1,12 @@
1
1
  import net from 'node:net';
2
2
  export interface LocalEndpoint {
3
- readonly kind: 'unix' | 'pipe';
4
- /** What the socket connects to. */
5
3
  readonly path: string;
6
- /** What the native receiver fingerprints; also the auth key file digest input. */
7
- readonly canonical: string;
8
4
  }
9
- /**
10
- * A local endpoint is either a Windows named pipe or an absolute Unix socket
11
- * path. There is no `stat().isSocket()` check: connecting is the existence check.
12
- */
5
+ /** An absolute Unix socket path; connecting is the existence check. */
13
6
  export declare function parseLocalEndpoint(raw: unknown): LocalEndpoint;
14
7
  export declare class LocalEndpointError extends Error {
15
8
  readonly code: 'unavailable' | 'aborted' | 'timeout' | 'transport';
16
- readonly maybeDelivered: boolean;
17
- constructor(code: LocalEndpointError['code'], maybeDelivered?: boolean);
9
+ constructor(code: LocalEndpointError['code']);
18
10
  }
19
11
  export interface LocalConnectScope {
20
12
  readonly signal?: AbortSignal;
@@ -22,5 +14,3 @@ export interface LocalConnectScope {
22
14
  }
23
15
  /** Connect with bounded waiting. A connect failure is `unavailable`: nothing was written. */
24
16
  export declare function connectLocal(endpoint: LocalEndpoint, scope?: LocalConnectScope): Promise<net.Socket>;
25
- /** LF-delimited JSON frames. Any failure here is past the uncertainty boundary. */
26
- export declare function writeFrames(socket: net.Socket, frames: object[]): Promise<void>;
@@ -1,35 +1,20 @@
1
1
  import net from 'node:net';
2
2
  import { resolve } from 'node:path';
3
- /** Claude's own pipe spelling: `\\.\pipe\<lowercased name>`. */
4
- const PIPE = /^[\\/]{2}[.?][\\/]pipe[\\/](?:(LOCAL)[\\/])?([^\\/]+)$/i;
5
- /**
6
- * A local endpoint is either a Windows named pipe or an absolute Unix socket
7
- * path. There is no `stat().isSocket()` check: connecting is the existence check.
8
- */
3
+ /** An absolute Unix socket path; connecting is the existence check. */
9
4
  export function parseLocalEndpoint(raw) {
10
- if (typeof raw !== 'string' || raw.includes('\0'))
11
- throw new Error('Invalid local endpoint.');
12
- const pipe = PIPE.exec(raw);
13
- if (pipe) {
14
- const canonical = `\\\\.\\pipe\\${pipe[2].toLowerCase()}`;
15
- return { kind: 'pipe', path: canonical, canonical };
16
- }
17
- if (!(process.platform === 'win32' ? /^[A-Za-z]:[\\/]/.test(raw) : raw.startsWith('/')))
5
+ if (typeof raw !== 'string' || raw.includes('\0') || !raw.startsWith('/'))
18
6
  throw new Error('Invalid local endpoint.');
19
7
  const limit = process.platform === 'darwin' ? 103 : process.platform === 'linux' ? 107 : undefined;
20
8
  if (limit !== undefined && Buffer.byteLength(raw) > limit)
21
9
  throw new Error('Invalid local endpoint.');
22
- const canonical = resolve(raw);
23
- return { kind: 'unix', path: canonical, canonical };
10
+ return { path: resolve(raw) };
24
11
  }
25
12
  export class LocalEndpointError extends Error {
26
13
  code;
27
- maybeDelivered;
28
- constructor(code, maybeDelivered = false) {
14
+ constructor(code) {
29
15
  super(code);
30
16
  this.name = 'LocalEndpointError';
31
17
  this.code = code;
32
- this.maybeDelivered = maybeDelivered;
33
18
  }
34
19
  }
35
20
  function errnoCode(error) {
@@ -83,32 +68,3 @@ export function connectLocal(endpoint, scope = {}) {
83
68
  }
84
69
  });
85
70
  }
86
- /** LF-delimited JSON frames. Any failure here is past the uncertainty boundary. */
87
- export function writeFrames(socket, frames) {
88
- const payload = frames.map((frame) => JSON.stringify(frame)).join('\n') + '\n';
89
- return new Promise((resolveWrite, reject) => {
90
- let settled = false;
91
- // Error/close handlers stay attached past settling, so a later I/O failure is
92
- // swallowed here instead of surfacing as an unhandled socket event.
93
- const finish = (error) => {
94
- if (settled)
95
- return;
96
- settled = true;
97
- if (error) {
98
- reject(error);
99
- return;
100
- }
101
- resolveWrite();
102
- };
103
- const failed = (error) => finish(new LocalEndpointError(errnoCode(error), true));
104
- socket.once('error', failed);
105
- socket.once('close', () => finish(new LocalEndpointError('transport', true)));
106
- socket.end(payload, 'utf8', (error) => {
107
- if (error) {
108
- failed(error);
109
- return;
110
- }
111
- finish();
112
- });
113
- });
114
- }
@@ -55,8 +55,6 @@ export async function connectPi(options) {
55
55
  }
56
56
  if (process.platform !== 'darwin')
57
57
  throw new ConnectionError('unsupported_platform');
58
- if (endpoint.kind !== 'unix')
59
- throw new ConnectionError('invalid_arguments');
60
58
  const answer = await request(endpoint, { protocol: VERSION, harness: 'pi', op: 'hello', sessionId: options.sessionId }, options.timeoutMs, options.signal);
61
59
  if (answer.code !== undefined)
62
60
  throw new ConnectionError(answer.code === 'transport' ? 'service_unavailable' : answer.code);
@@ -5,11 +5,6 @@ export interface OpenCodeTarget {
5
5
  readonly sessionId: string;
6
6
  readonly [targetBrand]: true;
7
7
  }
8
- export interface ClaudeTarget {
9
- readonly harness: 'claude';
10
- readonly sessionId: string;
11
- readonly [targetBrand]: true;
12
- }
13
8
  export interface PiTarget {
14
9
  readonly harness: 'pi';
15
10
  readonly sessionId: string;
@@ -25,7 +20,7 @@ export interface CodexTarget {
25
20
  readonly sessionId: string;
26
21
  readonly [targetBrand]: true;
27
22
  }
28
- export type Target = OpenCodeTarget | ClaudeTarget | PiTarget | PaseoTarget | CodexTarget;
23
+ export type Target = OpenCodeTarget | PiTarget | PaseoTarget | CodexTarget;
29
24
  export type Delivery = 'steer' | 'queue';
30
25
  export interface OpenCodeSendTextOptions {
31
26
  readonly delivery?: Delivery;
@@ -33,12 +28,6 @@ export interface OpenCodeSendTextOptions {
33
28
  readonly timeoutMs?: number;
34
29
  readonly signal?: AbortSignal;
35
30
  }
36
- export interface ClaudeSendTextOptions {
37
- readonly delivery?: 'steer';
38
- readonly inputId?: never;
39
- readonly timeoutMs?: number;
40
- readonly signal?: AbortSignal;
41
- }
42
31
  export interface PiSendTextOptions {
43
32
  readonly delivery?: Delivery;
44
33
  readonly inputId?: never;
@@ -58,7 +47,7 @@ export interface CodexSendTextOptions {
58
47
  readonly timeoutMs?: number;
59
48
  readonly signal?: AbortSignal;
60
49
  }
61
- export type SendTextOptions = OpenCodeSendTextOptions | ClaudeSendTextOptions | PiSendTextOptions | PaseoSendTextOptions | CodexSendTextOptions;
50
+ export type SendTextOptions = OpenCodeSendTextOptions | PiSendTextOptions | PaseoSendTextOptions | CodexSendTextOptions;
62
51
  export interface OpenCodeConnectOptions {
63
52
  readonly harness: 'opencode';
64
53
  readonly sessionId: string;
@@ -74,15 +63,6 @@ export interface OpenCodeConnectOptions {
74
63
  readonly timeoutMs?: number;
75
64
  readonly signal?: AbortSignal;
76
65
  }
77
- export interface ClaudeConnectOptions {
78
- readonly harness: 'claude';
79
- readonly sessionId: string;
80
- readonly endpoint: string;
81
- readonly token?: string;
82
- readonly claudeHome?: string;
83
- readonly timeoutMs?: number;
84
- readonly signal?: AbortSignal;
85
- }
86
66
  export interface PiConnectOptions {
87
67
  readonly harness: 'pi';
88
68
  readonly sessionId: string;
@@ -147,20 +127,6 @@ export type OpenCodeDeliveryResult = (OpenCodeAttempt & {
147
127
  readonly state: 'unavailable';
148
128
  readonly code: 'aborted' | 'timeout';
149
129
  });
150
- interface ClaudeAttempt {
151
- readonly harness: 'claude';
152
- readonly sessionId: string;
153
- }
154
- export type ClaudeDeliveryResult = (ClaudeAttempt & {
155
- readonly state: 'written';
156
- readonly messageId: string;
157
- }) | (ClaudeAttempt & {
158
- readonly state: 'unknown';
159
- readonly code: 'timeout' | 'aborted' | 'transport';
160
- }) | (ClaudeAttempt & {
161
- readonly state: 'unavailable';
162
- readonly code: 'aborted' | 'timeout' | 'endpoint_unavailable' | 'authentication_failed';
163
- });
164
130
  interface PiAttempt {
165
131
  readonly harness: 'pi';
166
132
  readonly sessionId: string;
@@ -214,5 +180,5 @@ export type CodexDeliveryResult = (CodexAttempt & {
214
180
  readonly state: 'rejected';
215
181
  readonly code: 'not_found' | 'refused' | 'unsupported_version';
216
182
  });
217
- export type DeliveryResult = OpenCodeDeliveryResult | ClaudeDeliveryResult | PiDeliveryResult | PaseoDeliveryResult | CodexDeliveryResult;
183
+ export type DeliveryResult = OpenCodeDeliveryResult | PiDeliveryResult | PaseoDeliveryResult | CodexDeliveryResult;
218
184
  export {};
@@ -0,0 +1,6 @@
1
+ import type { CardPresentation } from "./card-presentation.ts";
2
+ export declare function reachLabel(reach?: CardPresentation["reach"]): string | undefined;
3
+ /** Calendar days, rather than elapsed hours, keep yesterday correct across DST. */
4
+ export declare function timeLabel(at: number, now?: number, compact?: boolean): string;
5
+ /** Only adjacent references from the same origin can form a range. */
6
+ export declare function cardReferences(items: readonly CardPresentation[], originLabel?: (origin: string) => string): string;