@maintainer-pro/ai-cli 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # @maintainer-pro/ai-cli
2
2
 
3
- Server SDK for Maintainer Pro. It talks to coding agents — Cursor (`agent`), Claude (`claude`), or Antigravity (`agy`) — and exposes chat HTTP handlers for your Node app.
3
+ Server SDK for Maintainer Pro. It talks to coding agents — Cursor (`agent`), Claude (`claude`), or Antigravity (`agy`) — and exposes chat HTTP handlers.
4
4
 
5
- Use this package when you already have a server (Next, Express, Fastify). To get a port with no custom `server.mjs`, use [`@maintainer-pro/ai-server`](https://www.npmjs.com/package/@maintainer-pro/ai-server).
5
+ **Local development:** prefer [`@maintainer-pro/ai-server`](https://www.npmjs.com/package/@maintainer-pro/ai-server) as a sidecar (a separate Node chat server beside the host app). Do not add chat routes to the host.
6
+
7
+ **Production:** use this SDK on a machine that can run a coding-agent CLI, or pass a custom `AiProvider`. HTTP model backends are out of scope for the default providers. The embed widget (`ai-ui.iife.js`) must be served as a static file in production — `localhost` sidecar URLs will not load.
6
8
 
7
9
  ## Install
8
10
 
@@ -10,7 +12,7 @@ Use this package when you already have a server (Next, Express, Fastify). To get
10
12
  npm install @maintainer-pro/ai-cli
11
13
  ```
12
14
 
13
- Requires **Node.js 22+** and one authenticated coding-agent CLI on the machine that runs chat.
15
+ Requires **Node.js 22+** and one authenticated coding-agent CLI on the machine that runs chat (unless you supply `providers`).
14
16
 
15
17
  ## Quick start
16
18
 
@@ -38,7 +40,7 @@ export const GET = handlers.GET;
38
40
  export const POST = handlers.POST;
39
41
  ```
40
42
 
41
- Chat history is stored in Maintainer Pro admin. Do not put API keys in the browser bundle — serve the client key from `/embed-config.js` (or Next `/api/embed-config`).
43
+ Chat history is stored in Maintainer Pro admin. Do not put API keys in the browser — serve the client key from `/embed-config.js`.
42
44
 
43
45
  ## Environment
44
46
 
@@ -54,8 +56,8 @@ Chat history is stored in Maintainer Pro admin. Do not put API keys in the brows
54
56
 
55
57
  | Package | Role |
56
58
  |---------|------|
57
- | [`@maintainer-pro/ai-server`](https://www.npmjs.com/package/@maintainer-pro/ai-server) | `npx` Node server that uses this SDK |
58
- | [`@maintainer-pro/ai-ui`](https://www.npmjs.com/package/@maintainer-pro/ai-ui) | React chat UI and embed script |
59
+ | [`@maintainer-pro/ai-server`](https://www.npmjs.com/package/@maintainer-pro/ai-server) | Local Node chat server (sidecar) that uses this SDK |
60
+ | [`@maintainer-pro/ai-ui`](https://www.npmjs.com/package/@maintainer-pro/ai-ui) | Embed widget (`ai-ui.iife.js`) sidecar in dev, static file in prod |
59
61
  | [`@maintainer-pro/setup`](https://www.npmjs.com/package/@maintainer-pro/setup) | Download the sandbox setup guide |
60
62
 
61
63
  Optional SQL persistence lives on `@maintainer-pro/ai-cli/db` (install `better-sqlite3`, `postgres`, or `mysql2`).
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ WORKING_PROVIDER: () => WORKING_PROVIDER,
33
34
  buildClaudeUserPrompt: () => buildClaudeUserPrompt,
34
35
  buildConversationPrompt: () => buildConversationPrompt,
35
36
  buildCursorPrompt: () => buildCursorPrompt,
@@ -592,7 +593,9 @@ async function buildPriorConversationsContext(db, options) {
592
593
  ).slice(0, maxConversations) : ranked;
593
594
  const blocks = selected.map((c) => {
594
595
  const slice = c.messages.length > maxMessages ? c.messages.slice(-maxMessages) : c.messages;
595
- const lines = slice.filter((m) => m.role === "user" || m.role === "assistant").map(
596
+ const lines = slice.filter(
597
+ (m) => (m.role === "user" || m.role === "assistant") && m.provider !== "working" && Boolean(m.content?.trim())
598
+ ).map(
596
599
  (m) => `${m.role === "user" ? "Human" : "Assistant"}: ${truncate(m.content)}`
597
600
  );
598
601
  const when = c.updatedAt ? ` (updated ${c.updatedAt.slice(0, 10)})` : "";
@@ -625,6 +628,18 @@ function createToolValidator(schemas) {
625
628
  }
626
629
 
627
630
  // src/http/handler.ts
631
+ var WORKING_PROVIDER = "working";
632
+ async function setWorkingMessage(db, conversationId) {
633
+ await db.ensureConversation(conversationId);
634
+ await db.clearWorkingMessages?.(conversationId);
635
+ await db.saveMessage({
636
+ conversationId,
637
+ role: "assistant",
638
+ content: "",
639
+ provider: WORKING_PROVIDER,
640
+ senderType: "ai"
641
+ });
642
+ }
628
643
  var SHARED_CONVERSATION_ID = "shared";
629
644
  var conversationTurnSeq = /* @__PURE__ */ new Map();
630
645
  function beginConversationTurn(conversationId) {
@@ -697,6 +712,8 @@ function createChatHandler(options) {
697
712
  }
698
713
  },
699
714
  async POST(request) {
715
+ let trackedConversationId;
716
+ let trackedTurn = 0;
700
717
  try {
701
718
  const body = await request.json();
702
719
  const conversationId = await resolveSharedConversationId(
@@ -704,21 +721,16 @@ function createChatHandler(options) {
704
721
  options,
705
722
  body.conversationId
706
723
  );
707
- if (body.type === "status") {
708
- const content = body.content?.trim();
709
- if (!conversationId || !content) {
724
+ trackedConversationId = conversationId;
725
+ if (body.type === "working-clear") {
726
+ if (!conversationId) {
710
727
  return Response.json(
711
- { error: "conversationId and content are required" },
728
+ { error: "conversationId is required" },
712
729
  { status: 400 }
713
730
  );
714
731
  }
715
- if (options.db) {
716
- await options.db.ensureConversation(conversationId);
717
- await options.db.saveMessage({
718
- conversationId,
719
- role: "assistant",
720
- content
721
- });
732
+ if (options.db?.clearWorkingMessages) {
733
+ await options.db.clearWorkingMessages(conversationId);
722
734
  }
723
735
  return Response.json({ ok: true, conversationId });
724
736
  }
@@ -766,7 +778,8 @@ function createChatHandler(options) {
766
778
  );
767
779
  persistAttachmentPaths = attachmentPaths;
768
780
  }
769
- const turn = beginConversationTurn(conversationId);
781
+ const turn = beginConversationTurn(conversationId ?? SHARED_CONVERSATION_ID);
782
+ trackedTurn = turn;
770
783
  const signal = request.signal;
771
784
  if (options.db && conversationId) {
772
785
  const latest = messages[messages.length - 1];
@@ -782,13 +795,26 @@ function createChatHandler(options) {
782
795
  senderName: body.senderName?.trim() || void 0
783
796
  });
784
797
  }
798
+ await setWorkingMessage(options.db, conversationId);
785
799
  }
786
800
  const latestUser = [...messages].reverse().find((m) => m.role === "user");
787
801
  const priorConversationsContext = options.db ? await buildPriorConversationsContext(options.db, {
788
802
  excludeConversationId: conversationId,
789
803
  currentRequest: latestUser?.content ?? ""
790
804
  }) : "";
791
- if (signal.aborted || !isActiveConversationTurn(conversationId, turn)) {
805
+ if (!isActiveConversationTurn(
806
+ conversationId ?? SHARED_CONVERSATION_ID,
807
+ turn
808
+ )) {
809
+ return Response.json({
810
+ superseded: true,
811
+ conversationId: conversationId ?? null
812
+ });
813
+ }
814
+ if (signal.aborted) {
815
+ if (options.db?.clearWorkingMessages && conversationId) {
816
+ await options.db.clearWorkingMessages(conversationId);
817
+ }
792
818
  return Response.json({
793
819
  superseded: true,
794
820
  conversationId: conversationId ?? null
@@ -799,7 +825,10 @@ function createChatHandler(options) {
799
825
  attachmentPaths,
800
826
  priorConversationsContext: priorConversationsContext || void 0
801
827
  });
802
- if (!isActiveConversationTurn(conversationId, turn)) {
828
+ if (!isActiveConversationTurn(
829
+ conversationId ?? SHARED_CONVERSATION_ID,
830
+ turn
831
+ )) {
803
832
  return Response.json({
804
833
  superseded: true,
805
834
  conversationId: conversationId ?? null
@@ -811,6 +840,7 @@ function createChatHandler(options) {
811
840
  }
812
841
  if (options.db && conversationId) {
813
842
  await options.db.ensureConversation(conversationId);
843
+ await options.db.clearWorkingMessages?.(conversationId);
814
844
  await options.db.saveMessage({
815
845
  conversationId,
816
846
  role: "assistant",
@@ -834,6 +864,11 @@ function createChatHandler(options) {
834
864
  });
835
865
  } catch (err) {
836
866
  console.error("Chat API error:", err);
867
+ if (trackedConversationId && options.db?.clearWorkingMessages && isActiveConversationTurn(trackedConversationId, trackedTurn)) {
868
+ await options.db.clearWorkingMessages(trackedConversationId).catch(
869
+ () => void 0
870
+ );
871
+ }
837
872
  return Response.json(
838
873
  {
839
874
  error: "Sorry about that \u2014 I couldn't finish this right now. Happy to jump on a quick call if you'd like help \u2014 just let us know when works."
@@ -903,6 +938,16 @@ function createLocalDirectoryStore(baseDir) {
903
938
  await writeConversation(filePath, existing);
904
939
  return message;
905
940
  },
941
+ async clearWorkingMessages(conversationId) {
942
+ const filePath = fileFor(conversationId);
943
+ const existing = await readConversation(filePath);
944
+ if (!existing) return;
945
+ const next = existing.messages.filter((m) => m.provider !== "working");
946
+ if (next.length === existing.messages.length) return;
947
+ existing.messages = next;
948
+ existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
949
+ await writeConversation(filePath, existing);
950
+ },
906
951
  async listMessages(conversationId) {
907
952
  const existing = await readConversation(fileFor(conversationId));
908
953
  return existing?.messages ?? [];
@@ -1009,6 +1054,15 @@ function createMaintainerProStore(options) {
1009
1054
  );
1010
1055
  return data.message;
1011
1056
  },
1057
+ async clearWorkingMessages(conversationId) {
1058
+ await mpFetch(
1059
+ baseUrl,
1060
+ apiKey,
1061
+ `/api/v1/store/conversations/${encodeURIComponent(conversationId)}/messages?provider=working`,
1062
+ { method: "DELETE" },
1063
+ fetchImpl
1064
+ );
1065
+ },
1012
1066
  async listMessages(conversationId) {
1013
1067
  const data = await mpFetch(
1014
1068
  baseUrl,
@@ -1090,6 +1144,7 @@ function createMaintainerProStoreFromEnv() {
1090
1144
  }
1091
1145
  // Annotate the CommonJS export names for ESM import in node:
1092
1146
  0 && (module.exports = {
1147
+ WORKING_PROVIDER,
1093
1148
  buildClaudeUserPrompt,
1094
1149
  buildConversationPrompt,
1095
1150
  buildCursorPrompt,
package/dist/index.d.cts CHANGED
@@ -111,6 +111,8 @@ declare function createToolValidator(schemas: ToolSchemaMap): (toolCall: ToolCal
111
111
  error: string;
112
112
  };
113
113
 
114
+ /** Stored on assistant rows while a single in-flight AI turn is running. */
115
+ declare const WORKING_PROVIDER = "working";
114
116
  /** Minimal persistence contract (file store, SQL, or Maintainer Pro). */
115
117
  interface ChatStoreLike {
116
118
  ensureConversation(id: string): Promise<void>;
@@ -133,6 +135,8 @@ interface ChatStoreLike {
133
135
  senderType?: "client" | "developer" | "ai" | null;
134
136
  senderName?: string | null;
135
137
  }>>;
138
+ /** Remove in-progress working placeholders (at most one per conversation). */
139
+ clearWorkingMessages?(conversationId: string): Promise<void>;
136
140
  /** All conversations under the store (for prior-chat context). */
137
141
  listConversations?(): Promise<Array<{
138
142
  id: string;
@@ -141,6 +145,7 @@ interface ChatStoreLike {
141
145
  role: string;
142
146
  content: string;
143
147
  createdAt?: string | Date;
148
+ provider?: string | null;
144
149
  }>;
145
150
  }>>;
146
151
  saveToolEvents?(conversationId: string, events: Array<{
@@ -236,4 +241,4 @@ interface PriorConversationOptions {
236
241
  */
237
242
  declare function buildPriorConversationsContext(db: ChatStoreLike, options: PriorConversationOptions): Promise<string>;
238
243
 
239
- 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, buildClaudeUserPrompt, buildConversationPrompt, buildCursorPrompt, buildPriorConversationsContext, callAi, commandExists, createAntigravityProvider, createBuiltinProviders, createChatHandler, createClaudeProvider, createCursorProvider, createDefaultSystemPrompt, createLocalDirectoryStore, createMaintainerProStore, createMaintainerProStoreFromEnv, createToolValidator, formatClientContext, getProviderPreference, parseAiResponse, providerLabel, resolveCliBinary, resolveProvider, saveChatAttachments, toNextRoute };
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 };
package/dist/index.d.ts CHANGED
@@ -111,6 +111,8 @@ declare function createToolValidator(schemas: ToolSchemaMap): (toolCall: ToolCal
111
111
  error: string;
112
112
  };
113
113
 
114
+ /** Stored on assistant rows while a single in-flight AI turn is running. */
115
+ declare const WORKING_PROVIDER = "working";
114
116
  /** Minimal persistence contract (file store, SQL, or Maintainer Pro). */
115
117
  interface ChatStoreLike {
116
118
  ensureConversation(id: string): Promise<void>;
@@ -133,6 +135,8 @@ interface ChatStoreLike {
133
135
  senderType?: "client" | "developer" | "ai" | null;
134
136
  senderName?: string | null;
135
137
  }>>;
138
+ /** Remove in-progress working placeholders (at most one per conversation). */
139
+ clearWorkingMessages?(conversationId: string): Promise<void>;
136
140
  /** All conversations under the store (for prior-chat context). */
137
141
  listConversations?(): Promise<Array<{
138
142
  id: string;
@@ -141,6 +145,7 @@ interface ChatStoreLike {
141
145
  role: string;
142
146
  content: string;
143
147
  createdAt?: string | Date;
148
+ provider?: string | null;
144
149
  }>;
145
150
  }>>;
146
151
  saveToolEvents?(conversationId: string, events: Array<{
@@ -236,4 +241,4 @@ interface PriorConversationOptions {
236
241
  */
237
242
  declare function buildPriorConversationsContext(db: ChatStoreLike, options: PriorConversationOptions): Promise<string>;
238
243
 
239
- 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, buildClaudeUserPrompt, buildConversationPrompt, buildCursorPrompt, buildPriorConversationsContext, callAi, commandExists, createAntigravityProvider, createBuiltinProviders, createChatHandler, createClaudeProvider, createCursorProvider, createDefaultSystemPrompt, createLocalDirectoryStore, createMaintainerProStore, createMaintainerProStoreFromEnv, createToolValidator, formatClientContext, getProviderPreference, parseAiResponse, providerLabel, resolveCliBinary, resolveProvider, saveChatAttachments, toNextRoute };
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 };
package/dist/index.js CHANGED
@@ -533,7 +533,9 @@ async function buildPriorConversationsContext(db, options) {
533
533
  ).slice(0, maxConversations) : ranked;
534
534
  const blocks = selected.map((c) => {
535
535
  const slice = c.messages.length > maxMessages ? c.messages.slice(-maxMessages) : c.messages;
536
- const lines = slice.filter((m) => m.role === "user" || m.role === "assistant").map(
536
+ const lines = slice.filter(
537
+ (m) => (m.role === "user" || m.role === "assistant") && m.provider !== "working" && Boolean(m.content?.trim())
538
+ ).map(
537
539
  (m) => `${m.role === "user" ? "Human" : "Assistant"}: ${truncate(m.content)}`
538
540
  );
539
541
  const when = c.updatedAt ? ` (updated ${c.updatedAt.slice(0, 10)})` : "";
@@ -566,6 +568,18 @@ function createToolValidator(schemas) {
566
568
  }
567
569
 
568
570
  // src/http/handler.ts
571
+ var WORKING_PROVIDER = "working";
572
+ async function setWorkingMessage(db, conversationId) {
573
+ await db.ensureConversation(conversationId);
574
+ await db.clearWorkingMessages?.(conversationId);
575
+ await db.saveMessage({
576
+ conversationId,
577
+ role: "assistant",
578
+ content: "",
579
+ provider: WORKING_PROVIDER,
580
+ senderType: "ai"
581
+ });
582
+ }
569
583
  var SHARED_CONVERSATION_ID = "shared";
570
584
  var conversationTurnSeq = /* @__PURE__ */ new Map();
571
585
  function beginConversationTurn(conversationId) {
@@ -638,6 +652,8 @@ function createChatHandler(options) {
638
652
  }
639
653
  },
640
654
  async POST(request) {
655
+ let trackedConversationId;
656
+ let trackedTurn = 0;
641
657
  try {
642
658
  const body = await request.json();
643
659
  const conversationId = await resolveSharedConversationId(
@@ -645,21 +661,16 @@ function createChatHandler(options) {
645
661
  options,
646
662
  body.conversationId
647
663
  );
648
- if (body.type === "status") {
649
- const content = body.content?.trim();
650
- if (!conversationId || !content) {
664
+ trackedConversationId = conversationId;
665
+ if (body.type === "working-clear") {
666
+ if (!conversationId) {
651
667
  return Response.json(
652
- { error: "conversationId and content are required" },
668
+ { error: "conversationId is required" },
653
669
  { status: 400 }
654
670
  );
655
671
  }
656
- if (options.db) {
657
- await options.db.ensureConversation(conversationId);
658
- await options.db.saveMessage({
659
- conversationId,
660
- role: "assistant",
661
- content
662
- });
672
+ if (options.db?.clearWorkingMessages) {
673
+ await options.db.clearWorkingMessages(conversationId);
663
674
  }
664
675
  return Response.json({ ok: true, conversationId });
665
676
  }
@@ -707,7 +718,8 @@ function createChatHandler(options) {
707
718
  );
708
719
  persistAttachmentPaths = attachmentPaths;
709
720
  }
710
- const turn = beginConversationTurn(conversationId);
721
+ const turn = beginConversationTurn(conversationId ?? SHARED_CONVERSATION_ID);
722
+ trackedTurn = turn;
711
723
  const signal = request.signal;
712
724
  if (options.db && conversationId) {
713
725
  const latest = messages[messages.length - 1];
@@ -723,13 +735,26 @@ function createChatHandler(options) {
723
735
  senderName: body.senderName?.trim() || void 0
724
736
  });
725
737
  }
738
+ await setWorkingMessage(options.db, conversationId);
726
739
  }
727
740
  const latestUser = [...messages].reverse().find((m) => m.role === "user");
728
741
  const priorConversationsContext = options.db ? await buildPriorConversationsContext(options.db, {
729
742
  excludeConversationId: conversationId,
730
743
  currentRequest: latestUser?.content ?? ""
731
744
  }) : "";
732
- if (signal.aborted || !isActiveConversationTurn(conversationId, turn)) {
745
+ if (!isActiveConversationTurn(
746
+ conversationId ?? SHARED_CONVERSATION_ID,
747
+ turn
748
+ )) {
749
+ return Response.json({
750
+ superseded: true,
751
+ conversationId: conversationId ?? null
752
+ });
753
+ }
754
+ if (signal.aborted) {
755
+ if (options.db?.clearWorkingMessages && conversationId) {
756
+ await options.db.clearWorkingMessages(conversationId);
757
+ }
733
758
  return Response.json({
734
759
  superseded: true,
735
760
  conversationId: conversationId ?? null
@@ -740,7 +765,10 @@ function createChatHandler(options) {
740
765
  attachmentPaths,
741
766
  priorConversationsContext: priorConversationsContext || void 0
742
767
  });
743
- if (!isActiveConversationTurn(conversationId, turn)) {
768
+ if (!isActiveConversationTurn(
769
+ conversationId ?? SHARED_CONVERSATION_ID,
770
+ turn
771
+ )) {
744
772
  return Response.json({
745
773
  superseded: true,
746
774
  conversationId: conversationId ?? null
@@ -752,6 +780,7 @@ function createChatHandler(options) {
752
780
  }
753
781
  if (options.db && conversationId) {
754
782
  await options.db.ensureConversation(conversationId);
783
+ await options.db.clearWorkingMessages?.(conversationId);
755
784
  await options.db.saveMessage({
756
785
  conversationId,
757
786
  role: "assistant",
@@ -775,6 +804,11 @@ function createChatHandler(options) {
775
804
  });
776
805
  } catch (err) {
777
806
  console.error("Chat API error:", err);
807
+ if (trackedConversationId && options.db?.clearWorkingMessages && isActiveConversationTurn(trackedConversationId, trackedTurn)) {
808
+ await options.db.clearWorkingMessages(trackedConversationId).catch(
809
+ () => void 0
810
+ );
811
+ }
778
812
  return Response.json(
779
813
  {
780
814
  error: "Sorry about that \u2014 I couldn't finish this right now. Happy to jump on a quick call if you'd like help \u2014 just let us know when works."
@@ -844,6 +878,16 @@ function createLocalDirectoryStore(baseDir) {
844
878
  await writeConversation(filePath, existing);
845
879
  return message;
846
880
  },
881
+ async clearWorkingMessages(conversationId) {
882
+ const filePath = fileFor(conversationId);
883
+ const existing = await readConversation(filePath);
884
+ if (!existing) return;
885
+ const next = existing.messages.filter((m) => m.provider !== "working");
886
+ if (next.length === existing.messages.length) return;
887
+ existing.messages = next;
888
+ existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
889
+ await writeConversation(filePath, existing);
890
+ },
847
891
  async listMessages(conversationId) {
848
892
  const existing = await readConversation(fileFor(conversationId));
849
893
  return existing?.messages ?? [];
@@ -950,6 +994,15 @@ function createMaintainerProStore(options) {
950
994
  );
951
995
  return data.message;
952
996
  },
997
+ async clearWorkingMessages(conversationId) {
998
+ await mpFetch(
999
+ baseUrl,
1000
+ apiKey,
1001
+ `/api/v1/store/conversations/${encodeURIComponent(conversationId)}/messages?provider=working`,
1002
+ { method: "DELETE" },
1003
+ fetchImpl
1004
+ );
1005
+ },
953
1006
  async listMessages(conversationId) {
954
1007
  const data = await mpFetch(
955
1008
  baseUrl,
@@ -1030,6 +1083,7 @@ function createMaintainerProStoreFromEnv() {
1030
1083
  return createMaintainerProStore({ baseUrl, apiKey });
1031
1084
  }
1032
1085
  export {
1086
+ WORKING_PROVIDER,
1033
1087
  buildClaudeUserPrompt,
1034
1088
  buildConversationPrompt,
1035
1089
  buildCursorPrompt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maintainer-pro/ai-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Maintainer Pro server SDK: Claude/Cursor CLI, chat HTTP handlers, and optional SQL persistence",
5
5
  "keywords": [
6
6
  "maintainer-pro",