@nuvin/nuvin-core 1.7.2 → 1.9.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.
package/dist/VERSION CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.7.2",
3
- "commit": "9570da1"
2
+ "version": "1.9.0",
3
+ "commit": "66edafd"
4
4
  }
package/dist/index.d.ts CHANGED
@@ -393,6 +393,7 @@ type TodoWriteMetadata = {
393
393
  type AssignTaskMetadata = DelegationMetadata;
394
394
  type ToolErrorMetadata = {
395
395
  errorReason?: ErrorReason;
396
+ editInstruction?: string;
396
397
  path?: string;
397
398
  agentId?: string;
398
399
  code?: string | number;
@@ -418,6 +419,7 @@ type ToolCall = {
418
419
  name: string;
419
420
  arguments: string;
420
421
  };
422
+ editInstruction?: string;
421
423
  };
422
424
  type TextContentPart = {
423
425
  type: 'text';
@@ -586,46 +588,57 @@ type ToolInvocation = {
586
588
  id: string;
587
589
  name: 'bash_tool';
588
590
  parameters: BashToolArgs;
591
+ editInstruction?: string;
589
592
  } | {
590
593
  id: string;
591
594
  name: 'file_read';
592
595
  parameters: FileReadArgs;
596
+ editInstruction?: string;
593
597
  } | {
594
598
  id: string;
595
599
  name: 'file_edit';
596
600
  parameters: FileEditArgs;
601
+ editInstruction?: string;
597
602
  } | {
598
603
  id: string;
599
604
  name: 'file_new';
600
605
  parameters: FileNewArgs;
606
+ editInstruction?: string;
601
607
  } | {
602
608
  id: string;
603
609
  name: 'dir_ls';
604
610
  parameters: DirLsArgs;
611
+ editInstruction?: string;
605
612
  } | {
606
613
  id: string;
607
614
  name: 'web_search';
608
615
  parameters: WebSearchArgs;
616
+ editInstruction?: string;
609
617
  } | {
610
618
  id: string;
611
619
  name: 'web_fetch';
612
620
  parameters: WebFetchArgs;
621
+ editInstruction?: string;
613
622
  } | {
614
623
  id: string;
615
624
  name: 'todo_write';
616
625
  parameters: TodoWriteArgs;
626
+ editInstruction?: string;
617
627
  } | {
618
628
  id: string;
619
629
  name: 'assign_task';
620
630
  parameters: AssignTaskArgs;
631
+ editInstruction?: string;
621
632
  } | {
622
633
  id: string;
623
634
  name: string;
624
635
  parameters: Record<string, unknown>;
636
+ editInstruction?: string;
625
637
  };
626
638
  declare enum ErrorReason {
627
639
  Aborted = "aborted",
628
640
  Denied = "denied",
641
+ Edited = "edited",
629
642
  Timeout = "timeout",
630
643
  NotFound = "not_found",
631
644
  PermissionDenied = "permission_denied",
@@ -841,7 +854,7 @@ declare const AgentEventTypes: {
841
854
  readonly SubAgentCompleted: "sub_agent_completed";
842
855
  readonly SubAgentMetrics: "sub_agent_metrics";
843
856
  };
844
- type ToolApprovalDecision = 'approve' | 'deny' | 'approve_all';
857
+ type ToolApprovalDecision = 'approve' | 'deny' | 'approve_all' | 'edit';
845
858
  type AgentEvent = {
846
859
  type: typeof AgentEventTypes.MessageStarted;
847
860
  conversationId: string;
@@ -868,6 +881,7 @@ type AgentEvent = {
868
881
  approvalId: string;
869
882
  decision: ToolApprovalDecision;
870
883
  approvedCalls?: ToolCall[];
884
+ editInstruction?: string;
871
885
  } | {
872
886
  type: typeof AgentEventTypes.ToolResult;
873
887
  conversationId: string;
@@ -1034,7 +1048,7 @@ declare class AgentOrchestrator {
1034
1048
  private processToolApproval;
1035
1049
  send(content: UserMessagePayload, opts?: SendMessageOptions): Promise<MessageResponse>;
1036
1050
  private waitForToolApproval;
1037
- handleToolApproval(approvalId: string, decision: ToolApprovalDecision, approvedCalls?: ToolCall[]): void;
1051
+ handleToolApproval(approvalId: string, decision: ToolApprovalDecision, approvedCalls?: ToolCall[], editInstruction?: string): void;
1038
1052
  private toInvocations;
1039
1053
  }
1040
1054
 
@@ -1905,6 +1919,54 @@ declare function okJson<T extends Record<string, unknown> | unknown[], M extends
1905
1919
  };
1906
1920
  declare function err(result: string, metadata?: Record<string, unknown>, errorReason?: ErrorReason): ExecResultError;
1907
1921
 
1922
+ type CommandSource = 'global' | 'profile' | 'local';
1923
+ interface CustomCommandTemplate {
1924
+ id: string;
1925
+ description: string;
1926
+ prompt: string;
1927
+ enabled?: boolean;
1928
+ source: CommandSource;
1929
+ filePath?: string;
1930
+ }
1931
+ interface CompleteCustomCommand extends CustomCommandTemplate {
1932
+ id: string;
1933
+ description: string;
1934
+ prompt: string;
1935
+ enabled: boolean;
1936
+ source: CommandSource;
1937
+ filePath: string;
1938
+ shadowedBy?: CommandSource;
1939
+ }
1940
+ interface CustomCommandFrontmatter {
1941
+ description: string;
1942
+ enabled?: boolean;
1943
+ }
1944
+ declare function isValidCommandId(id: string): boolean;
1945
+ declare function sanitizeCommandId(name: string): string;
1946
+
1947
+ interface CommandFilePersistenceOptions {
1948
+ globalDir: string;
1949
+ profileDir?: string;
1950
+ localDir: string;
1951
+ }
1952
+ declare class CommandFilePersistence {
1953
+ private globalDir;
1954
+ private profileDir?;
1955
+ private localDir;
1956
+ constructor(options: CommandFilePersistenceOptions);
1957
+ setProfileDir(profileDir: string | undefined): void;
1958
+ getDir(source: CommandSource): string;
1959
+ private ensureDir;
1960
+ loadAll(): Promise<CustomCommandTemplate[]>;
1961
+ private loadFromDir;
1962
+ load(filename: string, source: CommandSource): Promise<CustomCommandTemplate | null>;
1963
+ save(command: CustomCommandTemplate): Promise<void>;
1964
+ delete(commandId: string, source: CommandSource): Promise<void>;
1965
+ exists(commandId: string, source: CommandSource): boolean;
1966
+ private parseFrontmatter;
1967
+ private buildMarkdown;
1968
+ }
1969
+
1908
1970
  /**
1909
1971
  * Sub-agent related types
1910
1972
  * These types track the state and execution of delegated specialist agents
@@ -2255,4 +2317,4 @@ declare function resolveBackspaces(s: string): string;
2255
2317
  declare function stripAnsiAndControls(s: string): string;
2256
2318
  declare function canonicalizeTerminalPaste(raw: string): string;
2257
2319
 
2258
- export { AGENT_CREATOR_SYSTEM_PROMPT, AbortError, type AgentAwareToolPort, type AgentCatalog, type AgentConfig, type AgentEvent, AgentEventTypes, AgentFilePersistence, AgentManager, AgentManagerCommandRunner, AgentOrchestrator, AgentRegistry, type AgentTemplate, AnthropicAISDKLLM, type AssignErrorResult, type AssignParams, type AssignResult, type AssignSuccessResult$1 as AssignSuccessResult, type AssignTaskArgs, type AssignTaskMetadata, type BaseLLMOptions, type BashErrorResult, type BashParams, type BashResult, type BashSuccessResult$1 as BashSuccessResult, BashTool, type BashToolArgs, type BashToolMetadata, type CommandMetadata, type CompleteAgent, CompositeToolPort, type Conversation, ConversationContext, type ConversationMetadata, type ConversationSnapshot, ConversationStore, CoreMCPClient, DEFAULT_RETRY_CONFIG, DefaultDelegationPolicy, DefaultDelegationResultFormatter, DefaultDelegationService, DefaultSpecialistAgentFactory, type DelegationMetadata, type DelegationService, type DelegationServiceConfig, DelegationServiceFactory, type DirEntry, type DirLsArgs, type DirLsMetadata, type DirLsParams, type DirLsResult, type DirLsSuccessResult$1 as DirLsSuccessResult, type ErrorMetadata, ErrorReason, type ExecResult, type ExecResultError, type ExecResultSuccess, type FileEditArgs, type FileEditMetadata, type FileEditResult, type FileEditSuccessResult$1 as FileEditSuccessResult, type FileMetadata, type FileNewArgs, type FileNewMetadata, type FileNewParams, type FileNewResult, type FileNewSuccessResult$1 as FileNewSuccessResult, type FileReadArgs, type FileReadErrorResult, type FileReadMetadata, type FileReadParams, type FileReadResult, type FileReadSuccessResult$1 as FileReadSuccessResult, type FolderTreeOptions, type FunctionTool, GithubLLM, InMemoryMemory, InMemoryMetadata, InMemoryMetricsPort, JsonFileMemoryPersistence, type LLMConfig, LLMError, type LLMFactory, type LLMOptions, type LLMPort, LLMResolver, type LineRangeMetadata, type MCPConfig, type MCPServerConfig, MCPToolPort, type MemoryPort, MemoryPortMetadataAdapter, type Message, type MessageContent, type MessageContentPart, type MetadataPort, type MetricsChangeHandler, type MetricsPort, type MetricsSnapshot, type ModelInfo, type ModelLimits, NoopMetricsPort, NoopReminders, type OrchestratorAwareToolPort, type ParseResult, PersistedMemory, PersistingConsoleEventPort, type RetryConfig, RetryTransport, RuntimeEnv, type SendMessageOptions, SimpleContextBuilder, SimpleCost, SimpleId, type SpecialistAgentConfig, type SpecialistAgentResult, type SubAgentState, type SubAgentToolCall, SystemClock, type TodoWriteArgs, type TodoWriteMetadata, type TodoWriteResult, type TodoWriteSuccessResult$1 as TodoWriteSuccessResult, type ToolApprovalDecision, type ToolArguments, type ToolCall, type ToolCallValidation, type ToolErrorMetadata, type ToolExecutionContext, type ToolExecutionResult, type ToolMetadataMap, type ToolName, type ToolParameterMap, type ToolPort, ToolRegistry, type ToolValidator, type TypedToolInvocation, type UsageData, type UserAttachment, type UserMessagePayload, type ValidationResult, type WebFetchArgs, type WebFetchMetadata, type WebFetchParams, type WebFetchResult, type WebFetchSuccessResult$1 as WebFetchSuccessResult, type WebSearchArgs, type WebSearchMetadata, type WebSearchParams, type WebSearchResult, type WebSearchSuccessResult$1 as WebSearchSuccessResult, type WebSearchToolResult, buildAgentCreationPrompt, buildInjectedSystem, canonicalizeTerminalPaste, convertToolCall, convertToolCalls, createEmptySnapshot, createLLM, deduplicateModels, err, generateFolderTree, getAvailableProviders, getFallbackLimits, getProviderLabel, isAssignResult, isAssignSuccess, isAssignTaskArgs, isBashResult, isBashSuccess, isBashToolArgs, isDirLsArgs, isDirLsResult, isDirLsSuccess, isError, isFileEditArgs, isFileEditResult, isFileEditSuccess, isFileNewArgs, isFileNewResult, isFileNewSuccess, isFileReadArgs, isFileReadResult, isFileReadSuccess, isJsonResult, isRetryableError, isRetryableStatusCode, isSuccess, isSuccessJson, isSuccessText, isTextResult, isTodoWriteArgs, isTodoWriteResult, isTodoWriteSuccess, isWebFetchArgs, isWebFetchResult, isWebFetchSuccess, isWebSearchArgs, isWebSearchResult, isWebSearchSuccess, normalizeModelInfo, normalizeModelLimits, normalizeNewlines, okJson, okText, parseJSON, parseSubAgentToolCallArguments, parseToolArguments, renderTemplate, resolveBackspaces, resolveCarriageReturns, stripAnsiAndControls, supportsGetModels, toolValidators };
2320
+ export { AGENT_CREATOR_SYSTEM_PROMPT, AbortError, type AgentAwareToolPort, type AgentCatalog, type AgentConfig, type AgentEvent, AgentEventTypes, AgentFilePersistence, AgentManager, AgentManagerCommandRunner, AgentOrchestrator, AgentRegistry, type AgentTemplate, AnthropicAISDKLLM, type AssignErrorResult, type AssignParams, type AssignResult, type AssignSuccessResult$1 as AssignSuccessResult, type AssignTaskArgs, type AssignTaskMetadata, type BaseLLMOptions, type BashErrorResult, type BashParams, type BashResult, type BashSuccessResult$1 as BashSuccessResult, BashTool, type BashToolArgs, type BashToolMetadata, CommandFilePersistence, type CommandMetadata, type CommandSource, type CompleteAgent, type CompleteCustomCommand, CompositeToolPort, type Conversation, ConversationContext, type ConversationMetadata, type ConversationSnapshot, ConversationStore, CoreMCPClient, type CustomCommandFrontmatter, type CustomCommandTemplate, DEFAULT_RETRY_CONFIG, DefaultDelegationPolicy, DefaultDelegationResultFormatter, DefaultDelegationService, DefaultSpecialistAgentFactory, type DelegationMetadata, type DelegationService, type DelegationServiceConfig, DelegationServiceFactory, type DirEntry, type DirLsArgs, type DirLsMetadata, type DirLsParams, type DirLsResult, type DirLsSuccessResult$1 as DirLsSuccessResult, type ErrorMetadata, ErrorReason, type ExecResult, type ExecResultError, type ExecResultSuccess, type FileEditArgs, type FileEditMetadata, type FileEditResult, type FileEditSuccessResult$1 as FileEditSuccessResult, type FileMetadata, type FileNewArgs, type FileNewMetadata, type FileNewParams, type FileNewResult, type FileNewSuccessResult$1 as FileNewSuccessResult, type FileReadArgs, type FileReadErrorResult, type FileReadMetadata, type FileReadParams, type FileReadResult, type FileReadSuccessResult$1 as FileReadSuccessResult, type FolderTreeOptions, type FunctionTool, GithubLLM, InMemoryMemory, InMemoryMetadata, InMemoryMetricsPort, JsonFileMemoryPersistence, type LLMConfig, LLMError, type LLMFactory, type LLMOptions, type LLMPort, LLMResolver, type LineRangeMetadata, type MCPConfig, type MCPServerConfig, MCPToolPort, type MemoryPort, MemoryPortMetadataAdapter, type Message, type MessageContent, type MessageContentPart, type MetadataPort, type MetricsChangeHandler, type MetricsPort, type MetricsSnapshot, type ModelInfo, type ModelLimits, NoopMetricsPort, NoopReminders, type OrchestratorAwareToolPort, type ParseResult, PersistedMemory, PersistingConsoleEventPort, type RetryConfig, RetryTransport, RuntimeEnv, type SendMessageOptions, SimpleContextBuilder, SimpleCost, SimpleId, type SpecialistAgentConfig, type SpecialistAgentResult, type SubAgentState, type SubAgentToolCall, SystemClock, type TodoWriteArgs, type TodoWriteMetadata, type TodoWriteResult, type TodoWriteSuccessResult$1 as TodoWriteSuccessResult, type ToolApprovalDecision, type ToolArguments, type ToolCall, type ToolCallValidation, type ToolErrorMetadata, type ToolExecutionContext, type ToolExecutionResult, type ToolMetadataMap, type ToolName, type ToolParameterMap, type ToolPort, ToolRegistry, type ToolValidator, type TypedToolInvocation, type UsageData, type UserAttachment, type UserMessagePayload, type ValidationResult, type WebFetchArgs, type WebFetchMetadata, type WebFetchParams, type WebFetchResult, type WebFetchSuccessResult$1 as WebFetchSuccessResult, type WebSearchArgs, type WebSearchMetadata, type WebSearchParams, type WebSearchResult, type WebSearchSuccessResult$1 as WebSearchSuccessResult, type WebSearchToolResult, buildAgentCreationPrompt, buildInjectedSystem, canonicalizeTerminalPaste, convertToolCall, convertToolCalls, createEmptySnapshot, createLLM, deduplicateModels, err, generateFolderTree, getAvailableProviders, getFallbackLimits, getProviderLabel, isAssignResult, isAssignSuccess, isAssignTaskArgs, isBashResult, isBashSuccess, isBashToolArgs, isDirLsArgs, isDirLsResult, isDirLsSuccess, isError, isFileEditArgs, isFileEditResult, isFileEditSuccess, isFileNewArgs, isFileNewResult, isFileNewSuccess, isFileReadArgs, isFileReadResult, isFileReadSuccess, isJsonResult, isRetryableError, isRetryableStatusCode, isSuccess, isSuccessJson, isSuccessText, isTextResult, isTodoWriteArgs, isTodoWriteResult, isTodoWriteSuccess, isValidCommandId, isWebFetchArgs, isWebFetchResult, isWebFetchSuccess, isWebSearchArgs, isWebSearchResult, isWebSearchSuccess, normalizeModelInfo, normalizeModelLimits, normalizeNewlines, okJson, okText, parseJSON, parseSubAgentToolCallArguments, parseToolArguments, renderTemplate, resolveBackspaces, resolveCarriageReturns, sanitizeCommandId, stripAnsiAndControls, supportsGetModels, toolValidators };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  var ErrorReason = /* @__PURE__ */ ((ErrorReason2) => {
3
3
  ErrorReason2["Aborted"] = "aborted";
4
4
  ErrorReason2["Denied"] = "denied";
5
+ ErrorReason2["Edited"] = "edited";
5
6
  ErrorReason2["Timeout"] = "timeout";
6
7
  ErrorReason2["NotFound"] = "not_found";
7
8
  ErrorReason2["PermissionDenied"] = "permission_denied";
@@ -268,9 +269,9 @@ var JsonFileMemoryPersistence = class {
268
269
  }
269
270
  async load() {
270
271
  try {
271
- const fs9 = await import("fs");
272
- if (!fs9.existsSync(this.filename)) return {};
273
- const text = fs9.readFileSync(this.filename, "utf-8");
272
+ const fs10 = await import("fs");
273
+ if (!fs10.existsSync(this.filename)) return {};
274
+ const text = fs10.readFileSync(this.filename, "utf-8");
274
275
  const data = JSON.parse(text);
275
276
  return typeof data === "object" && data ? data : {};
276
277
  } catch {
@@ -280,13 +281,13 @@ var JsonFileMemoryPersistence = class {
280
281
  }
281
282
  async save(snapshot) {
282
283
  try {
283
- const fs9 = await import("fs");
284
- const path8 = await import("path");
285
- const dir = path8.dirname(this.filename);
286
- if (dir && dir !== "." && !fs9.existsSync(dir)) {
287
- fs9.mkdirSync(dir, { recursive: true });
284
+ const fs10 = await import("fs");
285
+ const path9 = await import("path");
286
+ const dir = path9.dirname(this.filename);
287
+ if (dir && dir !== "." && !fs10.existsSync(dir)) {
288
+ fs10.mkdirSync(dir, { recursive: true });
288
289
  }
289
- fs9.writeFileSync(this.filename, JSON.stringify(snapshot, null, 2), "utf-8");
290
+ fs10.writeFileSync(this.filename, JSON.stringify(snapshot, null, 2), "utf-8");
290
291
  } catch (err2) {
291
292
  console.warn(`Failed to save memory to ${this.filename}`, err2);
292
293
  }
@@ -734,7 +735,8 @@ function convertToolCall(toolCall, options = {}) {
734
735
  invocation: {
735
736
  id: toolCall.id,
736
737
  name: toolCall.function.name,
737
- parameters
738
+ parameters,
739
+ editInstruction: toolCall.editInstruction
738
740
  }
739
741
  };
740
742
  }
@@ -752,7 +754,8 @@ function convertToolCalls(toolCalls, options = {}) {
752
754
  invocations.push({
753
755
  id: result.callId,
754
756
  name: result.toolName,
755
- parameters: {}
757
+ parameters: {},
758
+ editInstruction: tc.editInstruction
756
759
  });
757
760
  } else {
758
761
  invocations.push(result.invocation);
@@ -998,8 +1001,16 @@ var AgentOrchestrator = class {
998
1001
  return { approvedCalls: callsToAutoApprove, wasDenied: false };
999
1002
  }
1000
1003
  try {
1001
- const manuallyApproved = await this.waitForToolApproval(callsNeedingApproval, conversationId, messageId);
1002
- return { approvedCalls: [...manuallyApproved, ...callsToAutoApprove], wasDenied: false };
1004
+ const result = await this.waitForToolApproval(callsNeedingApproval, conversationId, messageId);
1005
+ if ("editInstruction" in result) {
1006
+ const editInstruction = result.editInstruction;
1007
+ const editedCalls = toolCalls.map((call) => ({
1008
+ ...call,
1009
+ editInstruction
1010
+ }));
1011
+ return { approvedCalls: editedCalls, wasDenied: false };
1012
+ }
1013
+ return { approvedCalls: [...result, ...callsToAutoApprove], wasDenied: false };
1003
1014
  } catch (err2) {
1004
1015
  const errorMsg = err2 instanceof Error ? err2.message : "Tool approval failed";
1005
1016
  const denialMessage = `Tool execution was not approved: ${errorMsg}`;
@@ -1372,7 +1383,7 @@ var AgentOrchestrator = class {
1372
1383
  });
1373
1384
  });
1374
1385
  }
1375
- handleToolApproval(approvalId, decision, approvedCalls) {
1386
+ handleToolApproval(approvalId, decision, approvedCalls, editInstruction) {
1376
1387
  const approval = this.pendingApprovals.get(approvalId);
1377
1388
  if (!approval) {
1378
1389
  console.warn(`[Orchestrator] Received approval for unknown or already processed ID: ${approvalId}`);
@@ -1381,6 +1392,8 @@ var AgentOrchestrator = class {
1381
1392
  this.pendingApprovals.delete(approvalId);
1382
1393
  if (decision === "deny") {
1383
1394
  approval.reject(new Error("Tool execution denied by user"));
1395
+ } else if (decision === "edit" && editInstruction) {
1396
+ approval.resolve({ editInstruction });
1384
1397
  } else if (decision === "approve_all" || decision === "approve") {
1385
1398
  approval.resolve(approvedCalls || []);
1386
1399
  } else {
@@ -4223,6 +4236,22 @@ var ToolRegistry = class {
4223
4236
  durationMs: 0
4224
4237
  };
4225
4238
  }
4239
+ if (c.editInstruction) {
4240
+ const editResult = `${c.editInstruction}
4241
+ <system-reminder>
4242
+ This is not a result from the tool call. The user wants something else. Please follow the user's instruction.
4243
+ DO NOT mention this explicitly to the user.
4244
+ </system-reminder>`;
4245
+ return {
4246
+ id: c.id,
4247
+ name: c.name,
4248
+ status: "error",
4249
+ type: "text",
4250
+ result: editResult,
4251
+ metadata: { errorReason: "edited" /* Edited */, editInstruction: c.editInstruction },
4252
+ durationMs: 0
4253
+ };
4254
+ }
4226
4255
  const startTime = performance.now();
4227
4256
  const impl = this.tools.get(c.name);
4228
4257
  if (!impl) {
@@ -4581,6 +4610,175 @@ var AgentFilePersistence = class {
4581
4610
  }
4582
4611
  };
4583
4612
 
4613
+ // src/command-file-persistence.ts
4614
+ import * as fs9 from "fs";
4615
+ import * as path8 from "path";
4616
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
4617
+
4618
+ // src/command-types.ts
4619
+ function isValidCommandId(id) {
4620
+ return /^[a-z][a-z0-9-]*$/.test(id);
4621
+ }
4622
+ function sanitizeCommandId(name) {
4623
+ return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
4624
+ }
4625
+
4626
+ // src/command-file-persistence.ts
4627
+ var CommandFilePersistence = class {
4628
+ globalDir;
4629
+ profileDir;
4630
+ localDir;
4631
+ constructor(options) {
4632
+ this.globalDir = options.globalDir;
4633
+ this.profileDir = options.profileDir;
4634
+ this.localDir = options.localDir;
4635
+ }
4636
+ setProfileDir(profileDir) {
4637
+ this.profileDir = profileDir;
4638
+ }
4639
+ getDir(source) {
4640
+ switch (source) {
4641
+ case "global":
4642
+ return this.globalDir;
4643
+ case "profile":
4644
+ if (!this.profileDir) {
4645
+ throw new Error("Profile directory not set");
4646
+ }
4647
+ return this.profileDir;
4648
+ case "local":
4649
+ return this.localDir;
4650
+ }
4651
+ }
4652
+ ensureDir(dir) {
4653
+ if (!fs9.existsSync(dir)) {
4654
+ fs9.mkdirSync(dir, { recursive: true });
4655
+ }
4656
+ }
4657
+ async loadAll() {
4658
+ const commands = [];
4659
+ const sources = ["global", "local"];
4660
+ if (this.profileDir) {
4661
+ sources.splice(1, 0, "profile");
4662
+ }
4663
+ for (const source of sources) {
4664
+ try {
4665
+ const dir = this.getDir(source);
4666
+ const loaded = await this.loadFromDir(dir, source);
4667
+ commands.push(...loaded);
4668
+ } catch {
4669
+ }
4670
+ }
4671
+ return commands;
4672
+ }
4673
+ async loadFromDir(dir, source) {
4674
+ const commands = [];
4675
+ if (!fs9.existsSync(dir)) {
4676
+ return commands;
4677
+ }
4678
+ const files = fs9.readdirSync(dir);
4679
+ const mdFiles = files.filter((f) => f.endsWith(".md"));
4680
+ for (const file of mdFiles) {
4681
+ try {
4682
+ const command = await this.load(file, source);
4683
+ if (command) {
4684
+ commands.push(command);
4685
+ }
4686
+ } catch (error) {
4687
+ console.warn(`Failed to load command from ${file}:`, error);
4688
+ }
4689
+ }
4690
+ return commands;
4691
+ }
4692
+ async load(filename, source) {
4693
+ try {
4694
+ const dir = this.getDir(source);
4695
+ const filePath = path8.join(dir, filename);
4696
+ const content = fs9.readFileSync(filePath, "utf8");
4697
+ const { frontmatter, body } = this.parseFrontmatter(content);
4698
+ if (!frontmatter.description) {
4699
+ console.warn(`Invalid command template in ${filename}: missing description`);
4700
+ return null;
4701
+ }
4702
+ const id = path8.basename(filename, ".md");
4703
+ return {
4704
+ id,
4705
+ description: frontmatter.description,
4706
+ prompt: body.trim(),
4707
+ enabled: frontmatter.enabled ?? true,
4708
+ source,
4709
+ filePath
4710
+ };
4711
+ } catch (error) {
4712
+ console.warn(`Failed to load command from ${filename}:`, error);
4713
+ return null;
4714
+ }
4715
+ }
4716
+ async save(command) {
4717
+ const dir = this.getDir(command.source);
4718
+ this.ensureDir(dir);
4719
+ const id = sanitizeCommandId(command.id);
4720
+ const filename = `${id}.md`;
4721
+ const filePath = path8.join(dir, filename);
4722
+ const frontmatter = {
4723
+ description: command.description
4724
+ };
4725
+ if (command.enabled === false) {
4726
+ frontmatter.enabled = false;
4727
+ }
4728
+ const content = this.buildMarkdown(frontmatter, command.prompt);
4729
+ fs9.writeFileSync(filePath, content, "utf8");
4730
+ }
4731
+ async delete(commandId, source) {
4732
+ const dir = this.getDir(source);
4733
+ const filename = `${sanitizeCommandId(commandId)}.md`;
4734
+ const filePath = path8.join(dir, filename);
4735
+ if (fs9.existsSync(filePath)) {
4736
+ fs9.unlinkSync(filePath);
4737
+ }
4738
+ }
4739
+ exists(commandId, source) {
4740
+ try {
4741
+ const dir = this.getDir(source);
4742
+ const filename = `${sanitizeCommandId(commandId)}.md`;
4743
+ const filePath = path8.join(dir, filename);
4744
+ return fs9.existsSync(filePath);
4745
+ } catch {
4746
+ return false;
4747
+ }
4748
+ }
4749
+ parseFrontmatter(content) {
4750
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
4751
+ const match = content.match(frontmatterRegex);
4752
+ if (!match) {
4753
+ return {
4754
+ frontmatter: {},
4755
+ body: content
4756
+ };
4757
+ }
4758
+ try {
4759
+ const frontmatter = parseYaml(match[1] || "");
4760
+ return {
4761
+ frontmatter: frontmatter || {},
4762
+ body: match[2] || ""
4763
+ };
4764
+ } catch {
4765
+ return {
4766
+ frontmatter: {},
4767
+ body: content
4768
+ };
4769
+ }
4770
+ }
4771
+ buildMarkdown(frontmatter, body) {
4772
+ const yamlContent = stringifyYaml(frontmatter, { lineWidth: 0 }).trim();
4773
+ return `---
4774
+ ${yamlContent}
4775
+ ---
4776
+
4777
+ ${body}
4778
+ `;
4779
+ }
4780
+ };
4781
+
4584
4782
  // src/sub-agent-types.ts
4585
4783
  function parseSubAgentToolCallArguments(argsString) {
4586
4784
  if (!argsString) return {};
@@ -4917,21 +5115,21 @@ var NetworkLogger = class {
4917
5115
  async appendToLogFile(entry) {
4918
5116
  if (!this.opts.persistFile) return;
4919
5117
  try {
4920
- const fs9 = await import("fs/promises");
4921
- const path8 = await import("path");
5118
+ const fs10 = await import("fs/promises");
5119
+ const path9 = await import("path");
4922
5120
  const file = this.opts.persistFile;
4923
- const dir = path8.dirname(file);
5121
+ const dir = path9.dirname(file);
4924
5122
  if (dir && dir !== ".") {
4925
5123
  try {
4926
- await fs9.mkdir(dir, { recursive: true });
5124
+ await fs10.mkdir(dir, { recursive: true });
4927
5125
  } catch {
4928
5126
  }
4929
5127
  }
4930
5128
  const logLine = this.formatLogEntry(entry);
4931
- await fs9.appendFile(file, `${logLine}
5129
+ await fs10.appendFile(file, `${logLine}
4932
5130
  `, "utf-8");
4933
5131
  if (this.opts.maxFileSize) {
4934
- const stats = await fs9.stat(file);
5132
+ const stats = await fs10.stat(file);
4935
5133
  if (stats.size > this.opts.maxFileSize) {
4936
5134
  await this.rotateLogFile(file);
4937
5135
  }
@@ -4951,9 +5149,9 @@ var NetworkLogger = class {
4951
5149
  }
4952
5150
  async rotateLogFile(file) {
4953
5151
  try {
4954
- const fs9 = await import("fs/promises");
5152
+ const fs10 = await import("fs/promises");
4955
5153
  const rotatedFile = `${file}.${Date.now()}`;
4956
- await fs9.rename(file, rotatedFile);
5154
+ await fs10.rename(file, rotatedFile);
4957
5155
  } catch {
4958
5156
  }
4959
5157
  }
@@ -5180,12 +5378,12 @@ var GithubAuthTransport = class {
5180
5378
  this.dynamicApiUrl = data.endpoints.api;
5181
5379
  }
5182
5380
  }
5183
- buildFullUrl(path8) {
5184
- if (path8.startsWith("/")) {
5381
+ buildFullUrl(path9) {
5382
+ if (path9.startsWith("/")) {
5185
5383
  const apiUrl = this.dynamicApiUrl ?? this.baseUrl;
5186
- return `${apiUrl}${path8}`;
5384
+ return `${apiUrl}${path9}`;
5187
5385
  }
5188
- return path8;
5386
+ return path9;
5189
5387
  }
5190
5388
  hasVisionPayload(body) {
5191
5389
  if (!body || typeof body !== "object") return false;
@@ -5539,11 +5737,11 @@ var AnthropicAuthTransport = class {
5539
5737
  this.refreshPromise = null;
5540
5738
  }
5541
5739
  }
5542
- buildFullUrl(path8) {
5543
- if (path8.startsWith("/")) {
5544
- return `${this.baseUrl}${path8}`;
5740
+ buildFullUrl(path9) {
5741
+ if (path9.startsWith("/")) {
5742
+ return `${this.baseUrl}${path9}`;
5545
5743
  }
5546
- return path8;
5744
+ return path9;
5547
5745
  }
5548
5746
  makeAuthHeaders(headers) {
5549
5747
  const base = {
@@ -5650,11 +5848,11 @@ var BaseBearerAuthTransport = class {
5650
5848
  this.version = version;
5651
5849
  this.customHeaders = customHeaders;
5652
5850
  }
5653
- buildFullUrl(path8) {
5654
- if (path8.startsWith("/")) {
5655
- return `${this.baseUrl}${path8}`;
5851
+ buildFullUrl(path9) {
5852
+ if (path9.startsWith("/")) {
5853
+ return `${this.baseUrl}${path9}`;
5656
5854
  }
5657
- return path8;
5855
+ return path9;
5658
5856
  }
5659
5857
  makeAuthHeaders(headers) {
5660
5858
  const base = headers ? { ...headers } : {};
@@ -6707,6 +6905,22 @@ var MCPToolPort = class {
6707
6905
  result: "Tool execution aborted by user"
6708
6906
  };
6709
6907
  }
6908
+ if (c.editInstruction) {
6909
+ const editResult = `${c.editInstruction}
6910
+ <system-reminder>
6911
+ This is not a result from the tool call. The user wants something else. Please follow the user's instruction.
6912
+ DO NOT mention this explicitly to the user.
6913
+ </system-reminder>`;
6914
+ return {
6915
+ id: c.id,
6916
+ name: c.name,
6917
+ status: "error",
6918
+ type: "text",
6919
+ result: editResult,
6920
+ metadata: { errorReason: "edited" /* Edited */, editInstruction: c.editInstruction },
6921
+ durationMs: 0
6922
+ };
6923
+ }
6710
6924
  const original = this.map.get(c.name);
6711
6925
  if (!original) {
6712
6926
  return { id: c.id, name: c.name, status: "error", type: "text", result: `Unknown MCP tool: ${c.name}` };
@@ -6741,6 +6955,7 @@ export {
6741
6955
  AgentRegistry,
6742
6956
  AnthropicAISDKLLM,
6743
6957
  BashTool,
6958
+ CommandFilePersistence,
6744
6959
  CompositeToolPort,
6745
6960
  ConversationContext,
6746
6961
  ConversationStore,
@@ -6814,6 +7029,7 @@ export {
6814
7029
  isTodoWriteArgs,
6815
7030
  isTodoWriteResult,
6816
7031
  isTodoWriteSuccess,
7032
+ isValidCommandId,
6817
7033
  isWebFetchArgs,
6818
7034
  isWebFetchResult,
6819
7035
  isWebFetchSuccess,
@@ -6831,6 +7047,7 @@ export {
6831
7047
  renderTemplate,
6832
7048
  resolveBackspaces,
6833
7049
  resolveCarriageReturns,
7050
+ sanitizeCommandId,
6834
7051
  stripAnsiAndControls,
6835
7052
  supportsGetModels,
6836
7053
  toolValidators
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuvin/nuvin-core",
3
- "version": "1.7.2",
3
+ "version": "1.9.0",
4
4
  "description": "",
5
5
  "private": false,
6
6
  "main": "dist/index.js",