@maintainer-pro/ai-cli 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Logger } from 'pino';
2
+ export { Logger } from 'pino';
1
3
  import { z } from 'zod';
2
4
 
3
5
  type AiCliProviderId = "claude" | "cursor" | "antigravity" | (string & {});
@@ -54,8 +56,15 @@ interface CallAiOptions {
54
56
  * Injected into the prompt for the model to use when relevant.
55
57
  */
56
58
  priorConversationsContext?: string;
59
+ /**
60
+ * Explicit reply-to parent chain (oldest → newest ancestor of the current
61
+ * user message). Injected so the model anchors on the thread being answered.
62
+ */
63
+ parentChainContext?: string;
57
64
  /** Extra / override providers (e.g. future HTTP model backends). */
58
65
  providers?: AiProvider[];
66
+ /** When true, skip the end-user chat footer so the agent can return structured output. */
67
+ technical?: boolean;
59
68
  }
60
69
  interface AiProvider {
61
70
  id: string;
@@ -82,18 +91,97 @@ declare function providerLabel(providerId: string): string;
82
91
  /** Extract ```json ... ``` tool blocks and strip them from assistant text. */
83
92
  declare function parseAiResponse(raw: string, provider: AiCliProviderId): AiResponse;
84
93
 
94
+ /** Stable delimiters so models can weight sections distinctly. */
95
+ declare const PROMPT_SECTION: {
96
+ readonly system: {
97
+ readonly begin: "<<<SYSTEM_BEGIN>>>";
98
+ readonly end: "<<<SYSTEM_END>>>";
99
+ };
100
+ readonly clientContext: {
101
+ readonly begin: "<<<CLIENT_CONTEXT_BEGIN>>>";
102
+ readonly end: "<<<CLIENT_CONTEXT_END>>>";
103
+ };
104
+ readonly priorConversations: {
105
+ readonly begin: "<<<PRIOR_CONVERSATIONS_BEGIN>>>";
106
+ readonly end: "<<<PRIOR_CONVERSATIONS_END>>>";
107
+ };
108
+ readonly parentChain: {
109
+ readonly begin: "<<<PARENT_CHAIN_BEGIN>>>";
110
+ readonly end: "<<<PARENT_CHAIN_END>>>";
111
+ };
112
+ readonly history: {
113
+ readonly begin: "<<<CONVERSATION_HISTORY_BEGIN>>>";
114
+ readonly end: "<<<CONVERSATION_HISTORY_END>>>";
115
+ };
116
+ readonly attachments: {
117
+ readonly begin: "<<<ATTACHMENTS_BEGIN>>>";
118
+ readonly end: "<<<ATTACHMENTS_END>>>";
119
+ };
120
+ readonly currentRequest: {
121
+ readonly begin: "<<<CURRENT_REQUEST_BEGIN>>>";
122
+ readonly end: "<<<CURRENT_REQUEST_END>>>";
123
+ };
124
+ };
85
125
  declare function buildConversationPrompt(messages: ChatMessage[]): string;
86
126
  declare function formatClientContext(context?: ClientContext): string;
87
127
  /** Full prompt for providers without a native --system-prompt flag (Cursor). */
88
- declare function buildCursorPrompt(systemPrompt: string, messages: ChatMessage[], context?: ClientContext, attachmentPaths?: string[], priorConversationsContext?: string): string;
128
+ declare function buildCursorPrompt(systemPrompt: string, messages: ChatMessage[], context?: ClientContext, attachmentPaths?: string[], priorConversationsContext?: string, technical?: boolean, parentChainContext?: string): string;
89
129
  /** Conversation + context for Claude (system prompt passed separately). */
90
- declare function buildClaudeUserPrompt(messages: ChatMessage[], context?: ClientContext, attachmentPaths?: string[], priorConversationsContext?: string): string;
130
+ declare function buildClaudeUserPrompt(messages: ChatMessage[], context?: ClientContext, attachmentPaths?: string[], priorConversationsContext?: string, technical?: boolean, parentChainContext?: string): string;
131
+
132
+ /** Stored row fields needed to walk reply-to links. */
133
+ type ParentChainSource = {
134
+ id: string;
135
+ role: string;
136
+ content: string;
137
+ parentMessageId?: string | null;
138
+ senderName?: string | null;
139
+ provider?: string | null;
140
+ };
141
+ type ParentChainEntry = {
142
+ id: string;
143
+ role: "user" | "assistant" | "system";
144
+ content: string;
145
+ senderName?: string;
146
+ };
147
+ /**
148
+ * Walk `parentMessageId` from `startId` up to the root (oldest first).
149
+ * Skips empty / working placeholders.
150
+ */
151
+ declare function collectParentChain(rows: ParentChainSource[], startId: string | null | undefined): ParentChainEntry[];
152
+ /**
153
+ * Resolve the reply-to id for the current user turn, then walk ancestors.
154
+ * `currentMessageId` is the user message being answered this turn.
155
+ */
156
+ declare function parentChainForTurn(rows: ParentChainSource[], currentMessageId: string | null | undefined, fallbackParentId?: string | null): ParentChainEntry[];
157
+ /** Prompt block so the model treats the chain as the reply target. */
158
+ declare function formatParentChainContext(chain: ParentChainEntry[]): string;
91
159
 
92
160
  declare function createDefaultSystemPrompt(input: {
93
161
  productDescription: string;
94
162
  relevantFilesHint?: string;
95
163
  runtimeToolsHint?: string;
164
+ /** Relative ignore globs (already merged with defaults). */
165
+ ignorePaths?: string[];
166
+ }): string;
167
+
168
+ /** Always blocked relative to the project folder (secrets / credentials). */
169
+ declare const DEFAULT_AI_IGNORE_PATHS: readonly [".env", ".env.*", "**/.env", "**/.env.*"];
170
+ declare function parseIgnorePathsEnv(raw: string | undefined | null): string[];
171
+ declare function normalizeIgnorePaths(paths: string[]): string[];
172
+ /** Partner paths plus built-in secret ignores (deduped). */
173
+ declare function resolveIgnorePaths(partnerPaths: string[]): string[];
174
+ declare function isInsideWorkspace(workspaceDir: string, targetPath: string): boolean;
175
+ declare function isIgnoredRelative(relativePath: string, patterns: string[]): boolean;
176
+ declare function isPathAllowed(workspaceDir: string, targetPath: string, ignorePaths: string[]): boolean;
177
+ declare function formatAccessPolicyPromptSection(input: {
178
+ ignorePaths: string[];
96
179
  }): string;
180
+ /** Marker block written into .cursorignore (and similar) by the bridge. */
181
+ declare const ACCESS_IGNORE_BEGIN = "# maintainer-pro:access-begin";
182
+ declare const ACCESS_IGNORE_END = "# maintainer-pro:access-end";
183
+ declare function renderManagedIgnoreBlock(ignorePaths: string[]): string;
184
+ declare function upsertManagedIgnoreFile(existing: string, ignorePaths: string[]): string;
97
185
 
98
186
  declare function createClaudeProvider(): AiProvider;
99
187
 
@@ -101,6 +189,29 @@ declare function createCursorProvider(): AiProvider;
101
189
 
102
190
  declare function createAntigravityProvider(): AiProvider;
103
191
 
192
+ /** True when NODE_ENV / AI_ENV is development (or AI_DEV=1). */
193
+ declare function isDevMode(): boolean;
194
+ /**
195
+ * Resolve log level from env.
196
+ * Defaults to `debug` in development, otherwise `info`.
197
+ * Override anytime with LOG_LEVEL / AI_LOG_LEVEL.
198
+ */
199
+ declare function resolveLogLevel(): string;
200
+ /**
201
+ * Shared logger for Maintainer Pro Node packages.
202
+ *
203
+ * Levels: fatal | error | warn | info | debug | trace | silent
204
+ * - Dev (`NODE_ENV=development` or unset on local sidecars): default `debug`
205
+ * - Production: default `info`
206
+ * - Override: `LOG_LEVEL=debug` / `AI_LOG_LEVEL`
207
+ * - Pretty TTY output (disable with `LOG_PRETTY=0`)
208
+ */
209
+ declare function createLogger(name: string): Logger;
210
+ /** Adapter for older `(msg) => void` callbacks — logs at info. */
211
+ declare function createInfoLogger(name: string): (msg: string) => void;
212
+ /** Short preview for debug logs (never dump huge prompts). */
213
+ declare function previewText(text: string | undefined | null, max?: number): string;
214
+
104
215
  type ToolSchemaMap = Record<string, z.ZodTypeAny>;
105
216
  declare function createToolValidator(schemas: ToolSchemaMap): (toolCall: ToolCall) => {
106
217
  valid: true;
@@ -118,13 +229,27 @@ interface ChatStoreLike {
118
229
  ensureConversation(id: string): Promise<void>;
119
230
  saveMessage(input: {
120
231
  conversationId: string;
232
+ id?: string;
121
233
  role: "user" | "assistant" | "system";
122
234
  content: string;
123
235
  provider?: string;
124
236
  attachmentPaths?: string[];
125
237
  senderType?: "client" | "developer" | "ai";
126
238
  senderName?: string;
127
- }): Promise<unknown>;
239
+ /** Reply chain: assistant/working rows point at the user message. */
240
+ parentMessageId?: string | null;
241
+ /** queue = persist only; run = this user turn starts the AI. */
242
+ intent?: "queue" | "run";
243
+ queueStatus?: "working" | "queued" | null;
244
+ }): Promise<{
245
+ id: string;
246
+ queueStatus?: string | null;
247
+ queuePosition?: number | null;
248
+ nextQueued?: {
249
+ id: string;
250
+ content: string;
251
+ } | null;
252
+ } | unknown>;
128
253
  listMessages?(conversationId: string): Promise<Array<{
129
254
  id: string;
130
255
  role: string;
@@ -134,9 +259,29 @@ interface ChatStoreLike {
134
259
  attachmentPaths?: string[];
135
260
  senderType?: "client" | "developer" | "ai" | null;
136
261
  senderName?: string | null;
262
+ parentMessageId?: string | null;
263
+ queueStatus?: string | null;
264
+ queuePosition?: number | null;
137
265
  }>>;
138
266
  /** Remove in-progress working placeholders (at most one per conversation). */
139
267
  clearWorkingMessages?(conversationId: string): Promise<void>;
268
+ /** Clear the working user turn and promote the oldest queued message. */
269
+ releaseWorkingTurn?(conversationId: string, parentMessageId?: string | null): Promise<{
270
+ nextQueued?: {
271
+ id: string;
272
+ content: string;
273
+ } | null;
274
+ } | void>;
275
+ /** Unstick working/queued turns after crashes or raced promotes. */
276
+ recoverQueue?(conversationId: string): Promise<{
277
+ action: string;
278
+ workingId?: string | null;
279
+ promotedId?: string | null;
280
+ nextQueued?: {
281
+ id: string;
282
+ content: string;
283
+ } | null;
284
+ } | void>;
140
285
  /** All conversations under the store (for prior-chat context). */
141
286
  listConversations?(): Promise<Array<{
142
287
  id: string;
@@ -171,6 +316,7 @@ interface ChatHandlerOptions {
171
316
  db?: ChatStoreLike;
172
317
  conversationId?: string | ((request: Request) => string | undefined);
173
318
  onToolCalls?: (toolCalls: ToolCall[], context?: ClientContext) => void | Promise<void>;
319
+ logger?: Logger;
174
320
  }
175
321
  interface ChatHandlers {
176
322
  GET: (request: Request) => Promise<Response>;
@@ -195,6 +341,9 @@ interface LocalStoredMessage {
195
341
  attachmentPaths?: string[];
196
342
  senderType?: "client" | "developer" | "ai" | null;
197
343
  senderName?: string | null;
344
+ parentMessageId?: string | null;
345
+ queueStatus?: string | null;
346
+ queuePosition?: number | null;
198
347
  }
199
348
  /**
200
349
  * Persist conversations as JSON files under a local directory.
@@ -205,12 +354,61 @@ declare function createLocalDirectoryStore(baseDir: string): ChatStoreLike & {
205
354
  listConversations: NonNullable<ChatStoreLike["listConversations"]>;
206
355
  };
207
356
 
357
+ type CachedChatMessage = NonNullable<Awaited<ReturnType<NonNullable<ChatStoreLike["listMessages"]>>>>[number];
358
+ type CachedConversation = {
359
+ id: string;
360
+ updatedAt: string;
361
+ messages: CachedChatMessage[];
362
+ };
363
+ type SyncedStoreStats = {
364
+ conversations: number;
365
+ messages: number;
366
+ };
367
+ type SyncedChatStore = ChatStoreLike & {
368
+ uploadAttachments?: NonNullable<ChatStoreLike["uploadAttachments"]>;
369
+ ready: Promise<SyncedStoreStats>;
370
+ stop: () => void;
371
+ };
372
+ type RemoteStore = ChatStoreLike & {
373
+ uploadAttachments?: NonNullable<ChatStoreLike["uploadAttachments"]>;
374
+ listSnapshot?: () => Promise<CachedConversation[]>;
375
+ };
376
+ type WorkingTurnEvent = {
377
+ conversationId: string;
378
+ message: CachedChatMessage;
379
+ };
380
+ type SyncedChatStoreOptions = {
381
+ remote: RemoteStore;
382
+ maintainerProUrl: string;
383
+ apiKey: string;
384
+ /** Pino logger. Prefer this over `log`. */
385
+ logger?: Logger;
386
+ /** @deprecated Prefer `logger`. Info-level string messages only. */
387
+ log?: (msg: string) => void;
388
+ onWorkingTurn?: (event: WorkingTurnEvent) => void;
389
+ };
390
+ /**
391
+ * In-memory message cache in front of a remote Maintainer Pro store.
392
+ * Hydrates a full snapshot on start, writes through on local changes,
393
+ * and applies live WebSocket events from the other party.
394
+ */
395
+ declare function createSyncedChatStore(options: SyncedChatStoreOptions): SyncedChatStore;
396
+
208
397
  interface MaintainerProStoreOptions {
209
398
  baseUrl: string;
210
399
  apiKey: string;
211
400
  /** Directory for temporary local copies of images for CLI providers. */
212
401
  tempDir?: string;
213
402
  fetchImpl?: typeof fetch;
403
+ /**
404
+ * Keep a local message cache and live-sync over WebSocket.
405
+ * Default true. Set false for HTTP-only (tests / one-shot scripts).
406
+ */
407
+ sync?: boolean;
408
+ logger?: Logger;
409
+ /** @deprecated Prefer `logger`. */
410
+ log?: (msg: string) => void;
411
+ onWorkingTurn?: (event: WorkingTurnEvent) => void;
214
412
  }
215
413
  type UploadResult = {
216
414
  /** Refs persisted on messages (maintainer-pro://uuid). */
@@ -222,11 +420,16 @@ type UploadResult = {
222
420
  /**
223
421
  * Persist chat data via Maintainer Pro HTTP API (no local .maintainer-pro writes).
224
422
  */
225
- declare function createMaintainerProStore(options: MaintainerProStoreOptions): ChatStoreLike & {
423
+ declare function createMaintainerProStore(options: MaintainerProStoreOptions): SyncedChatStore & {
226
424
  uploadAttachments: (conversationId: string, attachments: ChatAttachment[] | undefined) => Promise<UploadResult>;
227
425
  };
228
426
  /** Build a Maintainer Pro store from env when configured. */
229
- declare function createMaintainerProStoreFromEnv(): ReturnType<typeof createMaintainerProStore> | null;
427
+ declare function createMaintainerProStoreFromEnv(options?: {
428
+ logger?: Logger;
429
+ log?: (msg: string) => void;
430
+ sync?: boolean;
431
+ onWorkingTurn?: (event: WorkingTurnEvent) => void;
432
+ }): ReturnType<typeof createMaintainerProStore> | null;
230
433
 
231
434
  interface PriorConversationOptions {
232
435
  excludeConversationId?: string;
@@ -241,4 +444,39 @@ interface PriorConversationOptions {
241
444
  */
242
445
  declare function buildPriorConversationsContext(db: ChatStoreLike, options: PriorConversationOptions): Promise<string>;
243
446
 
244
- export { type AiCliProviderId, type AiProvider, type AiResponse, type CallAiOptions, type ChatAttachment, type ChatHandlerOptions, type ChatHandlers, type ChatMessage, type ChatSenderType, type ChatStoreLike, type ChatUser, type ClientContext, type LocalStoredMessage, type MaintainerProStoreOptions, type PriorConversationOptions, type ProviderPreference, type ToolCall, type ToolSchemaMap, WORKING_PROVIDER, buildClaudeUserPrompt, buildConversationPrompt, buildCursorPrompt, buildPriorConversationsContext, callAi, commandExists, createAntigravityProvider, createBuiltinProviders, createChatHandler, createClaudeProvider, createCursorProvider, createDefaultSystemPrompt, createLocalDirectoryStore, createMaintainerProStore, createMaintainerProStoreFromEnv, createToolValidator, formatClientContext, getProviderPreference, parseAiResponse, providerLabel, resolveCliBinary, resolveProvider, saveChatAttachments, toNextRoute };
447
+ type WorkspaceKind = "next" | "vite" | "html" | "empty" | "other";
448
+ interface WorkspaceInspectInput {
449
+ workspaceDir: string;
450
+ appName?: string;
451
+ /** When set, the agent diagnoses and tries to fix this failure. */
452
+ problem?: string;
453
+ extraContext?: string;
454
+ }
455
+ interface WorkspaceInspectResult {
456
+ kind: WorkspaceKind;
457
+ name: string;
458
+ summary: string;
459
+ scripts: {
460
+ ui?: string;
461
+ backend?: string;
462
+ app?: string;
463
+ };
464
+ ports: {
465
+ ui?: number;
466
+ backend?: number;
467
+ app?: number;
468
+ };
469
+ issues: string[];
470
+ fixes: string[];
471
+ ready: boolean;
472
+ provider: string;
473
+ rawText: string;
474
+ }
475
+ /**
476
+ * Ask the coding-agent CLI (via callAi) to inspect a workspace and optionally
477
+ * repair setup issues. Used by ai-bridge so host-process planning uses the
478
+ * same provider resolution as chat.
479
+ */
480
+ declare function inspectAndRepairWorkspace(input: WorkspaceInspectInput): Promise<WorkspaceInspectResult>;
481
+
482
+ export { ACCESS_IGNORE_BEGIN, ACCESS_IGNORE_END, type AiCliProviderId, type AiProvider, type AiResponse, type CachedChatMessage, type CachedConversation, type CallAiOptions, type ChatAttachment, type ChatHandlerOptions, type ChatHandlers, type ChatMessage, type ChatSenderType, type ChatStoreLike, type ChatUser, type ClientContext, DEFAULT_AI_IGNORE_PATHS, type LocalStoredMessage, type MaintainerProStoreOptions, PROMPT_SECTION, type ParentChainEntry, type ParentChainSource, type PriorConversationOptions, type ProviderPreference, type SyncedChatStore, type SyncedChatStoreOptions, type SyncedStoreStats, type ToolCall, type ToolSchemaMap, WORKING_PROVIDER, type WorkingTurnEvent, type WorkspaceInspectInput, type WorkspaceInspectResult, type WorkspaceKind, buildClaudeUserPrompt, buildConversationPrompt, buildCursorPrompt, buildPriorConversationsContext, callAi, collectParentChain, commandExists, createAntigravityProvider, createBuiltinProviders, createChatHandler, createClaudeProvider, createCursorProvider, createDefaultSystemPrompt, createInfoLogger, createLocalDirectoryStore, createLogger, createMaintainerProStore, createMaintainerProStoreFromEnv, createSyncedChatStore, createToolValidator, formatAccessPolicyPromptSection, formatClientContext, formatParentChainContext, getProviderPreference, inspectAndRepairWorkspace, isDevMode, isIgnoredRelative, isInsideWorkspace, isPathAllowed, normalizeIgnorePaths, parentChainForTurn, parseAiResponse, parseIgnorePathsEnv, previewText, providerLabel, renderManagedIgnoreBlock, resolveCliBinary, resolveIgnorePaths, resolveLogLevel, resolveProvider, saveChatAttachments, toNextRoute, upsertManagedIgnoreFile };