@agent-wire/terminal 1.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 (80) hide show
  1. package/README.md +353 -0
  2. package/dist/api.d.ts +660 -0
  3. package/dist/api.js +1157 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/background-worker.d.ts +6 -0
  6. package/dist/background-worker.js +101 -0
  7. package/dist/background-worker.js.map +1 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +940 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.d.ts +17 -0
  12. package/dist/config.js +36 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/help-pointer.d.ts +11 -0
  15. package/dist/help-pointer.js +10 -0
  16. package/dist/help-pointer.js.map +1 -0
  17. package/dist/identity.d.ts +40 -0
  18. package/dist/identity.js +193 -0
  19. package/dist/identity.js.map +1 -0
  20. package/dist/index.d.ts +5 -0
  21. package/dist/index.js +11 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/local-pull.d.ts +45 -0
  24. package/dist/local-pull.js +173 -0
  25. package/dist/local-pull.js.map +1 -0
  26. package/dist/lockfile.d.ts +16 -0
  27. package/dist/lockfile.js +78 -0
  28. package/dist/lockfile.js.map +1 -0
  29. package/dist/mcp-server.d.ts +43 -0
  30. package/dist/mcp-server.js +3159 -0
  31. package/dist/mcp-server.js.map +1 -0
  32. package/dist/response-shaper.d.ts +60 -0
  33. package/dist/response-shaper.js +893 -0
  34. package/dist/response-shaper.js.map +1 -0
  35. package/dist/slots.d.ts +65 -0
  36. package/dist/slots.js +128 -0
  37. package/dist/slots.js.map +1 -0
  38. package/dist/sync/diff.d.ts +17 -0
  39. package/dist/sync/diff.js +152 -0
  40. package/dist/sync/diff.js.map +1 -0
  41. package/dist/sync/hash.d.ts +11 -0
  42. package/dist/sync/hash.js +18 -0
  43. package/dist/sync/hash.js.map +1 -0
  44. package/dist/sync/index.d.ts +24 -0
  45. package/dist/sync/index.js +22 -0
  46. package/dist/sync/index.js.map +1 -0
  47. package/dist/sync/manifest.d.ts +29 -0
  48. package/dist/sync/manifest.js +59 -0
  49. package/dist/sync/manifest.js.map +1 -0
  50. package/dist/sync/match.d.ts +29 -0
  51. package/dist/sync/match.js +153 -0
  52. package/dist/sync/match.js.map +1 -0
  53. package/dist/sync/paginate.d.ts +16 -0
  54. package/dist/sync/paginate.js +34 -0
  55. package/dist/sync/paginate.js.map +1 -0
  56. package/dist/sync/preview.d.ts +16 -0
  57. package/dist/sync/preview.js +179 -0
  58. package/dist/sync/preview.js.map +1 -0
  59. package/dist/sync/pull.d.ts +23 -0
  60. package/dist/sync/pull.js +126 -0
  61. package/dist/sync/pull.js.map +1 -0
  62. package/dist/sync/push.d.ts +27 -0
  63. package/dist/sync/push.js +116 -0
  64. package/dist/sync/push.js.map +1 -0
  65. package/dist/sync/resolve.d.ts +19 -0
  66. package/dist/sync/resolve.js +42 -0
  67. package/dist/sync/resolve.js.map +1 -0
  68. package/dist/sync/types.d.ts +70 -0
  69. package/dist/sync/types.js +6 -0
  70. package/dist/sync/types.js.map +1 -0
  71. package/dist/sync/walk.d.ts +12 -0
  72. package/dist/sync/walk.js +155 -0
  73. package/dist/sync/walk.js.map +1 -0
  74. package/dist/wait-cli.d.ts +46 -0
  75. package/dist/wait-cli.js +280 -0
  76. package/dist/wait-cli.js.map +1 -0
  77. package/dist/worker.d.ts +14 -0
  78. package/dist/worker.js +252 -0
  79. package/dist/worker.js.map +1 -0
  80. package/package.json +58 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Push local files to Wire.
3
+ * Requires WireAPI client — uses HTTP calls, not fs.
4
+ *
5
+ * Strategy:
6
+ * - push_new: POST to create document with source_path set
7
+ * - push_update (draft): PATCH to update body directly
8
+ * - push_update (published): call createDocumentVersion RPC to atomically create a new version
9
+ */
10
+ /**
11
+ * Push local files to the Wire corpus.
12
+ *
13
+ * @param apiClient - Authenticated WireAPI instance
14
+ * @param corpusSlug - The corpus slug to push to
15
+ * @param entries - DiffEntry items to push (push_new or push_update)
16
+ * @param publish - Whether to publish immediately (default: false, creates as draft)
17
+ * @returns Array of push results per file
18
+ */
19
+ export async function pushFiles(apiClient, corpusSlug, entries, publish = false) {
20
+ const results = [];
21
+ for (const entry of entries) {
22
+ try {
23
+ if (!entry.localFile) {
24
+ results.push({
25
+ relativePath: entry.relativePath,
26
+ documentId: '',
27
+ success: false,
28
+ error: 'No local file content available',
29
+ });
30
+ continue;
31
+ }
32
+ const { localFile, remoteDoc } = entry;
33
+ // Derive title from filename (strip extension, convert hyphens to spaces)
34
+ const filename = localFile.relativePath.split('/').pop() || localFile.relativePath;
35
+ const title = filename
36
+ .replace(/\.(md|txt|html)$/i, '')
37
+ .replace(/[-_]/g, ' ')
38
+ .replace(/\b\w/g, c => c.toUpperCase());
39
+ if (entry.state === 'local_only') {
40
+ // New document — POST to corpus
41
+ const response = await apiClient.request('POST', `/wire/corpora/${encodeURIComponent(corpusSlug)}/documents`, {
42
+ title,
43
+ body: localFile.content,
44
+ format: detectFormat(localFile.relativePath),
45
+ source_path: localFile.relativePath,
46
+ status: publish ? 'published' : 'draft',
47
+ });
48
+ results.push({
49
+ relativePath: entry.relativePath,
50
+ documentId: response.id,
51
+ success: true,
52
+ });
53
+ }
54
+ else if (entry.state === 'local_ahead' && remoteDoc) {
55
+ // Existing document — update strategy depends on status
56
+ if (remoteDoc.status === 'published') {
57
+ // Published: create new version via atomic RPC
58
+ const newId = await apiClient.createDocumentVersion(remoteDoc.id, remoteDoc.corpus_id, title, localFile.content, detectFormat(localFile.relativePath), localFile.relativePath);
59
+ results.push({
60
+ relativePath: entry.relativePath,
61
+ documentId: newId,
62
+ success: true,
63
+ });
64
+ }
65
+ else {
66
+ // Draft: PATCH directly
67
+ await apiClient.request('PATCH', `/wire/documents/${remoteDoc.id}`, {
68
+ title,
69
+ body: localFile.content,
70
+ source_path: localFile.relativePath,
71
+ });
72
+ results.push({
73
+ relativePath: entry.relativePath,
74
+ documentId: remoteDoc.id,
75
+ success: true,
76
+ });
77
+ }
78
+ }
79
+ else {
80
+ results.push({
81
+ relativePath: entry.relativePath,
82
+ documentId: remoteDoc?.id || '',
83
+ success: false,
84
+ error: `Unexpected state: ${entry.state}`,
85
+ });
86
+ }
87
+ }
88
+ catch (err) {
89
+ results.push({
90
+ relativePath: entry.relativePath,
91
+ documentId: entry.remoteDoc?.id || '',
92
+ success: false,
93
+ error: err instanceof Error ? err.message : String(err),
94
+ });
95
+ }
96
+ }
97
+ return results;
98
+ }
99
+ /**
100
+ * Detect document format from file extension.
101
+ */
102
+ function detectFormat(filePath) {
103
+ const ext = filePath.split('.').pop()?.toLowerCase();
104
+ switch (ext) {
105
+ case 'md':
106
+ return 'text/markdown';
107
+ case 'html':
108
+ case 'htm':
109
+ return 'text/html';
110
+ case 'txt':
111
+ return 'text/plain';
112
+ default:
113
+ return 'text/markdown';
114
+ }
115
+ }
116
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Conflict resolution helpers.
3
+ * Isomorphic — no Node.js dependencies.
4
+ */
5
+ import type { DiffEntry } from './types.js';
6
+ export type ConflictResolution = 'local_wins' | 'remote_wins' | 'skip';
7
+ /**
8
+ * Apply conflict resolutions to a set of conflicting entries.
9
+ * Returns categorized arrays for downstream processing.
10
+ *
11
+ * - local_wins: entry goes to push (local overwrites remote)
12
+ * - remote_wins: entry goes to pull (remote overwrites local)
13
+ * - skip: entry is skipped (no action taken)
14
+ */
15
+ export declare function resolveConflicts(conflicts: DiffEntry[], resolutions: Map<string, ConflictResolution>): {
16
+ toPush: DiffEntry[];
17
+ toPull: DiffEntry[];
18
+ skipped: DiffEntry[];
19
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Conflict resolution helpers.
3
+ * Isomorphic — no Node.js dependencies.
4
+ */
5
+ /**
6
+ * Apply conflict resolutions to a set of conflicting entries.
7
+ * Returns categorized arrays for downstream processing.
8
+ *
9
+ * - local_wins: entry goes to push (local overwrites remote)
10
+ * - remote_wins: entry goes to pull (remote overwrites local)
11
+ * - skip: entry is skipped (no action taken)
12
+ */
13
+ export function resolveConflicts(conflicts, resolutions) {
14
+ const toPush = [];
15
+ const toPull = [];
16
+ const skipped = [];
17
+ for (const entry of conflicts) {
18
+ const resolution = resolutions.get(entry.relativePath);
19
+ if (!resolution || resolution === 'skip') {
20
+ skipped.push(entry);
21
+ continue;
22
+ }
23
+ switch (resolution) {
24
+ case 'local_wins':
25
+ toPush.push({
26
+ ...entry,
27
+ state: 'local_ahead',
28
+ warnings: [...entry.warnings, 'Conflict resolved: local wins'],
29
+ });
30
+ break;
31
+ case 'remote_wins':
32
+ toPull.push({
33
+ ...entry,
34
+ state: 'remote_ahead',
35
+ warnings: [...entry.warnings, 'Conflict resolved: remote wins'],
36
+ });
37
+ break;
38
+ }
39
+ }
40
+ return { toPush, toPull, skipped };
41
+ }
42
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/sync/resolve.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAsB,EACtB,WAA4C;IAE5C,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAgB,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAEvD,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,YAAY;gBACf,MAAM,CAAC,IAAI,CAAC;oBACV,GAAG,KAAK;oBACR,KAAK,EAAE,aAAa;oBACpB,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,+BAA+B,CAAC;iBAC/D,CAAC,CAAC;gBACH,MAAM;YACR,KAAK,aAAa;gBAChB,MAAM,CAAC,IAAI,CAAC;oBACV,GAAG,KAAK;oBACR,KAAK,EAAE,cAAc;oBACrB,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,gCAAgC,CAAC;iBAChE,CAAC,CAAC;gBACH,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Type definitions for the Wire Corpus Sync Engine.
3
+ * Isomorphic — no Node.js dependencies.
4
+ */
5
+ export type SyncState = 'in_sync' | 'local_ahead' | 'remote_ahead' | 'conflict' | 'local_only' | 'remote_only';
6
+ export interface SyncFileEntry {
7
+ document_id: string;
8
+ local_hash: string;
9
+ remote_hash: string;
10
+ remote_status: 'draft' | 'published' | 'retracted';
11
+ remote_anchored: boolean;
12
+ remote_version_number: number;
13
+ remote_word_count: number;
14
+ last_synced_at: string;
15
+ status: SyncState;
16
+ }
17
+ export interface SyncManifest {
18
+ corpus_slug: string;
19
+ corpus_id: string;
20
+ last_sync: string;
21
+ files: Record<string, SyncFileEntry>;
22
+ }
23
+ export interface LocalFile {
24
+ absolutePath: string;
25
+ relativePath: string;
26
+ hash: string;
27
+ sizeBytes: number;
28
+ content: string;
29
+ }
30
+ export interface RemoteDocument {
31
+ id: string;
32
+ corpus_id: string;
33
+ title: string;
34
+ body_hash: string;
35
+ source_path: string | null;
36
+ status: string;
37
+ anchored: boolean;
38
+ version_number: number;
39
+ word_count: number;
40
+ family_id: string | null;
41
+ }
42
+ export interface DiffEntry {
43
+ relativePath: string;
44
+ localFile?: LocalFile;
45
+ remoteDoc?: RemoteDocument;
46
+ state: SyncState;
47
+ sizeInfo?: string;
48
+ warnings: string[];
49
+ }
50
+ export interface DiffResult {
51
+ push_new: DiffEntry[];
52
+ push_update: DiffEntry[];
53
+ pull_new: DiffEntry[];
54
+ pull_update: DiffEntry[];
55
+ in_sync: DiffEntry[];
56
+ conflicts: DiffEntry[];
57
+ }
58
+ export interface PreviewOutput {
59
+ corpus_slug: string;
60
+ local_dir: string;
61
+ diff: DiffResult;
62
+ summary: {
63
+ push_new: number;
64
+ push_update: number;
65
+ pull_new: number;
66
+ pull_update: number;
67
+ in_sync: number;
68
+ conflicts: number;
69
+ };
70
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Type definitions for the Wire Corpus Sync Engine.
3
+ * Isomorphic — no Node.js dependencies.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Recursive directory walker for local corpus files.
3
+ * Node.js only — uses fs/promises.
4
+ *
5
+ * Supports .wireignore files (gitignore-style patterns).
6
+ */
7
+ import type { LocalFile } from './types.js';
8
+ /**
9
+ * Walk a directory recursively, computing hashes for all non-ignored files.
10
+ * Returns a Map of relativePath → LocalFile.
11
+ */
12
+ export declare function walkDirectory(dir: string, ignorePatterns?: string[]): Promise<Map<string, LocalFile>>;
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Recursive directory walker for local corpus files.
3
+ * Node.js only — uses fs/promises.
4
+ *
5
+ * Supports .wireignore files (gitignore-style patterns).
6
+ */
7
+ import { readdir, readFile, stat } from 'fs/promises';
8
+ import { join, relative, resolve } from 'path';
9
+ import { computeHash } from './hash.js';
10
+ const MAX_FILES = 10_000;
11
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
12
+ const MAX_TOTAL_SIZE = 500 * 1024 * 1024; // 500 MB
13
+ const DEFAULT_IGNORE_PATTERNS = [
14
+ '.wire-sync.json',
15
+ '.git/',
16
+ 'node_modules/',
17
+ '.DS_Store',
18
+ '*.lock',
19
+ '*.png',
20
+ '*.jpg',
21
+ '*.jpeg',
22
+ '*.gif',
23
+ '*.svg',
24
+ '*.pdf',
25
+ '*.zip',
26
+ '*.tar.gz',
27
+ ];
28
+ /**
29
+ * Convert a gitignore-style pattern to a RegExp.
30
+ * Supports: *, **, ?, directory trailing slash.
31
+ */
32
+ function patternToRegex(pattern) {
33
+ // Directory pattern (trailing slash): match anything under that dir
34
+ const isDir = pattern.endsWith('/');
35
+ let p = pattern;
36
+ if (isDir) {
37
+ p = p.slice(0, -1);
38
+ }
39
+ // Escape regex special chars except * and ?
40
+ let regex = p.replace(/[.+^${}()|[\]\\]/g, '\\$&');
41
+ // Handle ** (matches any path segment, including /)
42
+ regex = regex.replace(/\*\*/g, '<<<GLOBSTAR>>>');
43
+ // Handle * (matches anything except /)
44
+ regex = regex.replace(/\*/g, '[^/]*');
45
+ // Handle ?
46
+ regex = regex.replace(/\?/g, '[^/]');
47
+ // Restore globstar
48
+ regex = regex.replace(/<<<GLOBSTAR>>>/g, '.*');
49
+ if (isDir) {
50
+ // Match the directory name or anything inside it
51
+ return new RegExp(`(^|/)${regex}(/|$)`);
52
+ }
53
+ // Match as full path segment or exact filename
54
+ return new RegExp(`(^|/)${regex}$`);
55
+ }
56
+ /**
57
+ * Check if a relative path matches any of the ignore patterns.
58
+ */
59
+ function isIgnored(relativePath, patterns) {
60
+ return patterns.some(re => re.test(relativePath));
61
+ }
62
+ /**
63
+ * Load .wireignore from directory if it exists.
64
+ * Returns parsed patterns (non-empty, non-comment lines).
65
+ */
66
+ async function loadWireignore(dir) {
67
+ try {
68
+ const content = await readFile(join(dir, '.wireignore'), 'utf-8');
69
+ return content
70
+ .split('\n')
71
+ .map(line => line.trim())
72
+ .filter(line => line.length > 0 && !line.startsWith('#'));
73
+ }
74
+ catch {
75
+ return [];
76
+ }
77
+ }
78
+ /**
79
+ * Walk a directory recursively, computing hashes for all non-ignored files.
80
+ * Returns a Map of relativePath → LocalFile.
81
+ */
82
+ export async function walkDirectory(dir, ignorePatterns) {
83
+ const rootDir = resolve(dir);
84
+ const results = new Map();
85
+ // Merge default + custom + .wireignore patterns
86
+ const wireignorePatterns = await loadWireignore(rootDir);
87
+ const allPatternStrings = [
88
+ ...DEFAULT_IGNORE_PATTERNS,
89
+ ...(ignorePatterns || []),
90
+ ...wireignorePatterns,
91
+ ];
92
+ const compiledPatterns = allPatternStrings.map(patternToRegex);
93
+ let totalBytes = 0;
94
+ let limitHit = false;
95
+ async function walk(currentDir) {
96
+ if (limitHit)
97
+ return;
98
+ const entries = await readdir(currentDir, { withFileTypes: true });
99
+ for (const entry of entries) {
100
+ if (limitHit)
101
+ return;
102
+ const fullPath = join(currentDir, entry.name);
103
+ // Normalize backslashes to forward slashes for cross-platform sync
104
+ const relPath = relative(rootDir, fullPath).replace(/\\/g, '/');
105
+ if (isIgnored(relPath, compiledPatterns)) {
106
+ continue;
107
+ }
108
+ if (entry.isDirectory()) {
109
+ // Also check directory ignore (with trailing slash behavior)
110
+ if (isIgnored(relPath + '/', compiledPatterns)) {
111
+ continue;
112
+ }
113
+ await walk(fullPath);
114
+ }
115
+ else if (entry.isFile()) {
116
+ // Guard: max files
117
+ if (results.size >= MAX_FILES) {
118
+ console.warn(`[wire-sync] MAX_FILES limit reached (${MAX_FILES}). Stopping walk.`);
119
+ limitHit = true;
120
+ return;
121
+ }
122
+ try {
123
+ const fileStat = await stat(fullPath);
124
+ // Guard: skip oversized files
125
+ if (fileStat.size > MAX_FILE_SIZE) {
126
+ console.error(`[wire-sync] Skipping ${relPath}: file size ${fileStat.size} exceeds MAX_FILE_SIZE (${MAX_FILE_SIZE})`);
127
+ continue;
128
+ }
129
+ // Guard: max total size
130
+ if (totalBytes + fileStat.size > MAX_TOTAL_SIZE) {
131
+ console.warn(`[wire-sync] MAX_TOTAL_SIZE limit reached (${MAX_TOTAL_SIZE}). Stopping walk.`);
132
+ limitHit = true;
133
+ return;
134
+ }
135
+ const content = await readFile(fullPath, 'utf-8');
136
+ const hash = await computeHash(content);
137
+ totalBytes += fileStat.size;
138
+ results.set(relPath, {
139
+ absolutePath: fullPath,
140
+ relativePath: relPath,
141
+ hash,
142
+ sizeBytes: fileStat.size,
143
+ content,
144
+ });
145
+ }
146
+ catch {
147
+ // Skip files that can't be read as UTF-8 (binary files)
148
+ }
149
+ }
150
+ }
151
+ }
152
+ await walk(rootDir);
153
+ return results;
154
+ }
155
+ //# sourceMappingURL=walk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk.js","sourceRoot":"","sources":["../../src/sync/walk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { type WireEventStreamMessage } from './api.js';
2
+ import { type WireNodeConfig } from './config.js';
3
+ import { type AgentIdentity } from './identity.js';
4
+ export interface WaitCliOptions {
5
+ triggers?: string[];
6
+ cursor?: string;
7
+ filters: Record<string, string>;
8
+ timeoutSeconds: number;
9
+ limit: number;
10
+ name?: string;
11
+ }
12
+ export interface WaitCliIo {
13
+ stdout: Pick<NodeJS.WriteStream, 'write'>;
14
+ stderr: Pick<NodeJS.WriteStream, 'write'>;
15
+ }
16
+ export interface WaitCliApi {
17
+ streamEvents(params?: {
18
+ triggers?: string[];
19
+ filters?: Record<string, unknown>;
20
+ cursor?: string;
21
+ limit?: number;
22
+ }, options?: {
23
+ signal?: AbortSignal;
24
+ }): AsyncGenerator<WireEventStreamMessage>;
25
+ }
26
+ export interface WaitCliDeps {
27
+ loadIdentity?: (name?: string) => AgentIdentity;
28
+ createApi?: (config: WireNodeConfig, identity: AgentIdentity) => WaitCliApi;
29
+ processTarget?: Pick<NodeJS.Process, 'once' | 'off' | 'removeListener'>;
30
+ }
31
+ export declare class WaitCliUsageError extends Error {
32
+ constructor(message: string);
33
+ }
34
+ export declare class WaitCliHelp extends Error {
35
+ constructor();
36
+ }
37
+ export declare function parseWaitArgs(argv: string[]): WaitCliOptions;
38
+ export declare function resolveWaitIdentity(name?: string): AgentIdentity;
39
+ export declare function installWaitSignalHandlers(controller: AbortController, processTarget?: Pick<NodeJS.Process, 'once' | 'off' | 'removeListener'>): () => void;
40
+ export declare function waitForMatchingEvents(api: WaitCliApi, options: WaitCliOptions, signal: AbortSignal): Promise<{
41
+ status: 'matched' | 'timeout' | 'aborted';
42
+ events: Record<string, unknown>[];
43
+ nextCursor: string;
44
+ }>;
45
+ export declare function waitUsage(): string;
46
+ export declare function runWaitCommand(argv: string[], io?: WaitCliIo, deps?: WaitCliDeps): Promise<number>;