@marifold/core 0.60.0 → 0.64.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 (79) hide show
  1. package/dist/agent/AgentEvents.d.ts +7 -0
  2. package/dist/agent/AgentEvents.d.ts.map +1 -1
  3. package/dist/agent/AgentRunner.d.ts +4 -1
  4. package/dist/agent/AgentRunner.d.ts.map +1 -1
  5. package/dist/agent/AgentRunner.js +108 -20
  6. package/dist/agent/AgentRunner.js.map +1 -1
  7. package/dist/agent/AttachmentResources.d.ts +40 -0
  8. package/dist/agent/AttachmentResources.d.ts.map +1 -0
  9. package/dist/agent/AttachmentResources.js +192 -0
  10. package/dist/agent/AttachmentResources.js.map +1 -0
  11. package/dist/agent/RunArtifacts.d.ts +18 -0
  12. package/dist/agent/RunArtifacts.d.ts.map +1 -0
  13. package/dist/agent/RunArtifacts.js +137 -0
  14. package/dist/agent/RunArtifacts.js.map +1 -0
  15. package/dist/agent/tools/InspectAttachmentTool.d.ts.map +1 -1
  16. package/dist/agent/tools/InspectAttachmentTool.js +4 -69
  17. package/dist/agent/tools/InspectAttachmentTool.js.map +1 -1
  18. package/dist/agent/tools/ReadAttachmentTool.d.ts +34 -0
  19. package/dist/agent/tools/ReadAttachmentTool.d.ts.map +1 -0
  20. package/dist/agent/tools/ReadAttachmentTool.js +84 -0
  21. package/dist/agent/tools/ReadAttachmentTool.js.map +1 -0
  22. package/dist/agent/tools/SearchAttachmentTool.d.ts +33 -0
  23. package/dist/agent/tools/SearchAttachmentTool.d.ts.map +1 -0
  24. package/dist/agent/tools/SearchAttachmentTool.js +76 -0
  25. package/dist/agent/tools/SearchAttachmentTool.js.map +1 -0
  26. package/dist/agent/tools/SkillManagementTool.d.ts +75 -0
  27. package/dist/agent/tools/SkillManagementTool.d.ts.map +1 -0
  28. package/dist/agent/tools/SkillManagementTool.js +312 -0
  29. package/dist/agent/tools/SkillManagementTool.js.map +1 -0
  30. package/dist/config/ConfigManager.d.ts +9 -0
  31. package/dist/config/ConfigManager.d.ts.map +1 -1
  32. package/dist/config/ConfigManager.js +43 -0
  33. package/dist/config/ConfigManager.js.map +1 -1
  34. package/dist/config/ConfigSchema.d.ts +4 -4
  35. package/dist/config/ConfigSchema.d.ts.map +1 -1
  36. package/dist/config/MarifoldOpenAICompatProvider.d.ts +3 -0
  37. package/dist/config/MarifoldOpenAICompatProvider.d.ts.map +1 -1
  38. package/dist/config/MarifoldOpenAICompatProvider.js +35 -3
  39. package/dist/config/MarifoldOpenAICompatProvider.js.map +1 -1
  40. package/dist/config/ProviderFactory.d.ts +4 -0
  41. package/dist/config/ProviderFactory.d.ts.map +1 -1
  42. package/dist/config/ProviderFactory.js +7 -0
  43. package/dist/config/ProviderFactory.js.map +1 -1
  44. package/dist/errors/MarifoldError.d.ts +2 -1
  45. package/dist/errors/MarifoldError.d.ts.map +1 -1
  46. package/dist/errors/MarifoldError.js +3 -0
  47. package/dist/errors/MarifoldError.js.map +1 -1
  48. package/dist/index.d.ts +10 -2
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +26 -3
  51. package/dist/index.js.map +1 -1
  52. package/dist/runs/RunRegistry.d.ts +4 -0
  53. package/dist/runs/RunRegistry.d.ts.map +1 -1
  54. package/dist/runs/RunRegistry.js +22 -1
  55. package/dist/runs/RunRegistry.js.map +1 -1
  56. package/dist/runtime/MarifoldRuntime.d.ts +9 -5
  57. package/dist/runtime/MarifoldRuntime.d.ts.map +1 -1
  58. package/dist/runtime/MarifoldRuntime.js +140 -35
  59. package/dist/runtime/MarifoldRuntime.js.map +1 -1
  60. package/dist/runtime/MarifoldTypes.d.ts +8 -1
  61. package/dist/runtime/MarifoldTypes.d.ts.map +1 -1
  62. package/dist/skill/BuiltInSkillManager.d.ts.map +1 -1
  63. package/dist/skill/BuiltInSkillManager.js +2 -1
  64. package/dist/skill/BuiltInSkillManager.js.map +1 -1
  65. package/dist/skill/BuiltInSkills.d.ts +6 -0
  66. package/dist/skill/BuiltInSkills.d.ts.map +1 -0
  67. package/dist/skill/BuiltInSkills.js +91 -0
  68. package/dist/skill/BuiltInSkills.js.map +1 -0
  69. package/dist/skill/SkillSchema.d.ts +2 -2
  70. package/dist/skill/SkillSchema.d.ts.map +1 -1
  71. package/dist/skill/SkillStore.d.ts +9 -0
  72. package/dist/skill/SkillStore.d.ts.map +1 -1
  73. package/dist/skill/SkillStore.js +87 -14
  74. package/dist/skill/SkillStore.js.map +1 -1
  75. package/dist/skill/index.d.ts +1 -0
  76. package/dist/skill/index.d.ts.map +1 -1
  77. package/dist/skill/index.js +5 -1
  78. package/dist/skill/index.js.map +1 -1
  79. package/package.json +1 -1
@@ -0,0 +1,33 @@
1
+ import type { JSONValue } from '@priest-ai/core';
2
+ import { AgentTool, ToolExecutionContext, ToolExecutionResult, ToolRiskAssessment } from '../ToolRegistry';
3
+ export declare class SearchAttachmentTool implements AgentTool {
4
+ readonly kind: 'read';
5
+ readonly definition: {
6
+ name: string;
7
+ description: string;
8
+ parameters: {
9
+ type: string;
10
+ properties: {
11
+ attachment_id: {
12
+ type: string;
13
+ description: string;
14
+ };
15
+ query: {
16
+ type: string;
17
+ description: string;
18
+ };
19
+ max_results: {
20
+ type: string;
21
+ minimum: number;
22
+ maximum: number;
23
+ description: string;
24
+ };
25
+ };
26
+ required: string[];
27
+ };
28
+ };
29
+ summarizeCall(input: Record<string, JSONValue>): string;
30
+ assessRisk(): ToolRiskAssessment;
31
+ execute(input: Record<string, JSONValue>, ctx: ToolExecutionContext): Promise<ToolExecutionResult>;
32
+ }
33
+ //# sourceMappingURL=SearchAttachmentTool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchAttachmentTool.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/SearchAttachmentTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOjD,OAAO,EACL,SAAS,EAET,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAEzB,qBAAa,oBAAqB,YAAW,SAAS;IACpD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,UAAU;;;;;;;oBAUI,IAAI;oBAAY,WAAW;;;oBACnC,IAAI;oBAAY,WAAW;;;;;;;;;;;MAUxC;IAEF,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,CAItD;IAED,UAAU,IAAI,kBAAkB,CAE/B;IAEK,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgCvG;CACF"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SearchAttachmentTool = void 0;
4
+ const AttachmentResources_1 = require("../AttachmentResources");
5
+ const ToolRegistry_1 = require("../ToolRegistry");
6
+ class SearchAttachmentTool {
7
+ kind = 'read';
8
+ definition = {
9
+ name: 'search_attachment',
10
+ description: [
11
+ 'Search the derived readable view of one uploaded attachment and return bounded line matches.',
12
+ 'When to use: locate a heading, identifier, name, table label, or passage without loading the complete document into model context.',
13
+ 'When NOT to use: transform a file, search an arbitrary filesystem path, or repeatedly enumerate an entire document. Use a local format-specific tool for complete-file processing.',
14
+ ].join(' '),
15
+ parameters: {
16
+ type: 'object',
17
+ properties: {
18
+ attachment_id: { type: 'string', description: 'Opaque attachment ID from the current run manifest.' },
19
+ query: { type: 'string', description: 'Case-insensitive literal text to find.' },
20
+ max_results: {
21
+ type: 'integer',
22
+ minimum: 1,
23
+ maximum: AttachmentResources_1.MAX_ATTACHMENT_SEARCH_RESULTS,
24
+ description: `Maximum matches to return. Defaults to ${AttachmentResources_1.DEFAULT_ATTACHMENT_SEARCH_RESULTS}.`,
25
+ },
26
+ },
27
+ required: ['attachment_id', 'query'],
28
+ },
29
+ };
30
+ summarizeCall(input) {
31
+ const id = typeof input.attachment_id === 'string' ? input.attachment_id : '<missing attachment>';
32
+ const query = typeof input.query === 'string' ? input.query : '<missing query>';
33
+ return `search ${id} for ${JSON.stringify(query)}`;
34
+ }
35
+ assessRisk() {
36
+ return { escalate: false, trusted: true };
37
+ }
38
+ async execute(input, ctx) {
39
+ const id = (0, ToolRegistry_1.requireStringInput)(input, 'attachment_id', 'search_attachment');
40
+ const query = (0, ToolRegistry_1.requireStringInput)(input, 'query', 'search_attachment');
41
+ const attachment = ctx.workspace?.attachments.find(candidate => candidate.id === id);
42
+ if (!attachment) {
43
+ const available = ctx.workspace?.attachments.map(candidate => candidate.id).join(', ') || '(none)';
44
+ return {
45
+ content: `Attachment '${id}' is not available in this run. Available attachment IDs: ${available}.`,
46
+ summary: `attachment ${id} not found`,
47
+ isError: true,
48
+ };
49
+ }
50
+ const maxResults = integerInput(input.max_results, AttachmentResources_1.DEFAULT_ATTACHMENT_SEARCH_RESULTS);
51
+ if (maxResults < 1 || maxResults > AttachmentResources_1.MAX_ATTACHMENT_SEARCH_RESULTS) {
52
+ return {
53
+ content: `search_attachment requires max_results between 1 and ${AttachmentResources_1.MAX_ATTACHMENT_SEARCH_RESULTS}.`,
54
+ summary: `invalid search limit for ${attachment.name}`,
55
+ isError: true,
56
+ };
57
+ }
58
+ const result = new AttachmentResources_1.AttachmentResource(attachment).search(query, maxResults);
59
+ if (!result) {
60
+ return {
61
+ content: `No built-in searchable view is available for ${attachment.name}. Use a format-specific local tool against ${attachment.path ?? 'its staged run path'}.`,
62
+ summary: `no searchable view for ${attachment.name}`,
63
+ isError: true,
64
+ };
65
+ }
66
+ return {
67
+ content: (0, AttachmentResources_1.formatAttachmentSearch)(result, query),
68
+ summary: `found ${result.matches.length} match${result.matches.length === 1 ? '' : 'es'} in ${attachment.name}`,
69
+ };
70
+ }
71
+ }
72
+ exports.SearchAttachmentTool = SearchAttachmentTool;
73
+ function integerInput(value, fallback) {
74
+ return typeof value === 'number' && Number.isInteger(value) ? value : fallback;
75
+ }
76
+ //# sourceMappingURL=SearchAttachmentTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchAttachmentTool.js","sourceRoot":"","sources":["../../../src/agent/tools/SearchAttachmentTool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import type { JSONValue } from '@priest-ai/core';
2
+ import { SkillStore } from '../../skill/SkillStore';
3
+ import { AgentTool, ToolExecutionContext, ToolExecutionResult, ToolRiskAssessment } from '../ToolRegistry';
4
+ export interface SkillManagementToolOptions {
5
+ store: SkillStore;
6
+ profile: string;
7
+ globalDir: string;
8
+ profileDir: string;
9
+ }
10
+ /** Validated mutation boundary used by Marifold's protected management skills. */
11
+ export declare class SkillManagementTool implements AgentTool {
12
+ private readonly options;
13
+ readonly kind: 'write';
14
+ readonly definition: {
15
+ name: string;
16
+ description: string;
17
+ parameters: {
18
+ type: string;
19
+ properties: {
20
+ action: {
21
+ type: string;
22
+ enum: string[];
23
+ description: string;
24
+ };
25
+ scope: {
26
+ type: string;
27
+ enum: string[];
28
+ description: string;
29
+ };
30
+ name: {
31
+ type: string;
32
+ description: string;
33
+ };
34
+ source: {
35
+ type: string;
36
+ description: string;
37
+ };
38
+ content: {
39
+ type: string;
40
+ description: string;
41
+ };
42
+ files: {
43
+ type: string;
44
+ description: string;
45
+ items: {
46
+ type: string;
47
+ properties: {
48
+ path: {
49
+ type: string;
50
+ };
51
+ content: {
52
+ type: string;
53
+ };
54
+ };
55
+ required: string[];
56
+ };
57
+ };
58
+ };
59
+ required: string[];
60
+ };
61
+ };
62
+ constructor(options: SkillManagementToolOptions);
63
+ summarizeCall(input: Record<string, JSONValue>): string;
64
+ assessRisk(input: Record<string, JSONValue>): ToolRiskAssessment;
65
+ execute(input: Record<string, JSONValue>, ctx: ToolExecutionContext): Promise<ToolExecutionResult>;
66
+ private create;
67
+ private install;
68
+ private update;
69
+ private remove;
70
+ private exactSkill;
71
+ private verify;
72
+ private dirForScope;
73
+ private scopeLabel;
74
+ }
75
+ //# sourceMappingURL=SkillManagementTool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillManagementTool.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/SkillManagementTool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAA+B,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGjF,OAAO,EACL,SAAS,EAET,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAOzB,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,kFAAkF;AAClF,qBAAa,mBAAoB,YAAW,SAAS;IAoDvC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAnDpC,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,QAAQ,CAAC,UAAU;QACjB,IAAI;QACJ,WAAW;QAMX,UAAU;YACR,IAAI;YACJ,UAAU;gBACR,MAAM;oBACJ,IAAI;oBACJ,IAAI;oBACJ,WAAW;;gBAEb,KAAK;oBACH,IAAI;oBACJ,IAAI;oBACJ,WAAW;;gBAEb,IAAI;oBACF,IAAI;oBACJ,WAAW;;gBAEb,MAAM;oBACJ,IAAI;oBACJ,WAAW;;gBAEb,OAAO;oBACL,IAAI;oBACJ,WAAW;;gBAEb,KAAK;oBACH,IAAI;oBACJ,WAAW;oBACX,KAAK;wBACH,IAAI;wBACJ,UAAU;4BACR,IAAI;gCAAI,IAAI;;4BACZ,OAAO;gCAAI,IAAI;;;wBAEjB,QAAQ;;;;YAId,QAAQ;;MAEV;IAEF,YAA6B,OAAO,EAAE,0BAA0B,EAAI;IAEpE,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,CAStD;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,kBAAkB,CAa/D;IAEK,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA2BvG;IAED,OAAO,CAAC,MAAM;IAgCd,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,MAAM;IAwBd,OAAO,CAAC,MAAM;IAkBd,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;CAGnB"}
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SkillManagementTool = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const MarifoldError_1 = require("../../errors/MarifoldError");
40
+ const BuiltInSkills_1 = require("../../skill/BuiltInSkills");
41
+ const SkillStore_1 = require("../../skill/SkillStore");
42
+ const SkillValidator_1 = require("../../skill/SkillValidator");
43
+ const WorkspacePaths_1 = require("../../workspace/WorkspacePaths");
44
+ const ToolRegistry_1 = require("../ToolRegistry");
45
+ /** Validated mutation boundary used by Marifold's protected management skills. */
46
+ class SkillManagementTool {
47
+ options;
48
+ kind = 'write';
49
+ definition = {
50
+ name: 'manage_skill',
51
+ description: [
52
+ 'Create, install, update, or remove a user-managed Marifold skill in the active profile or configured global skill directory.',
53
+ 'When to use: Marifold skill management after the user invokes a protected management skill or explicitly asks the agent to change a skill.',
54
+ 'When NOT to use: running a skill, editing unrelated files, managing protected built-ins, fetching network sources, or changing both scopes at once.',
55
+ 'Profile scope is the default user-facing scope; pass the exact intended scope on every call.',
56
+ ].join(' '),
57
+ parameters: {
58
+ type: 'object',
59
+ properties: {
60
+ action: {
61
+ type: 'string',
62
+ enum: ['create', 'install', 'update', 'remove'],
63
+ description: 'The validated skill mutation to perform.',
64
+ },
65
+ scope: {
66
+ type: 'string',
67
+ enum: ['profile', 'global'],
68
+ description: 'Exact destination scope. Use profile unless the user explicitly requested global.',
69
+ },
70
+ name: {
71
+ type: 'string',
72
+ description: 'Required for create, update, and remove. Must match the SKILL.md name for create/update.',
73
+ },
74
+ source: {
75
+ type: 'string',
76
+ description: 'Local Markdown file or folder containing SKILL.md. Required for install and update.',
77
+ },
78
+ content: {
79
+ type: 'string',
80
+ description: 'Complete SKILL.md text. Required for create.',
81
+ },
82
+ files: {
83
+ type: 'array',
84
+ description: 'Optional bundled text files for create, using safe paths relative to the new skill folder.',
85
+ items: {
86
+ type: 'object',
87
+ properties: {
88
+ path: { type: 'string' },
89
+ content: { type: 'string' },
90
+ },
91
+ required: ['path', 'content'],
92
+ },
93
+ },
94
+ },
95
+ required: ['action', 'scope'],
96
+ },
97
+ };
98
+ constructor(options) {
99
+ this.options = options;
100
+ }
101
+ summarizeCall(input) {
102
+ const action = typeof input.action === 'string' ? input.action : '<missing action>';
103
+ const scope = typeof input.scope === 'string' ? input.scope : 'profile';
104
+ const target = typeof input.name === 'string'
105
+ ? `$${input.name}`
106
+ : typeof input.source === 'string'
107
+ ? input.source
108
+ : '<missing skill>';
109
+ return `${action} ${scope} skill ${target}`;
110
+ }
111
+ assessRisk(input) {
112
+ const scope = input.scope === 'global' ? 'global' : 'profile';
113
+ const dir = this.dirForScope(scope);
114
+ const suppliedName = typeof input.name === 'string' && /^[a-z0-9][a-z0-9_-]*$/.test(input.name)
115
+ ? input.name
116
+ : undefined;
117
+ const target = suppliedName ? path.join(dir, suppliedName) : dir;
118
+ return {
119
+ escalate: true,
120
+ persistable: false,
121
+ reason: `modifying the ${scope} Marifold skill directory`,
122
+ targetPath: target,
123
+ };
124
+ }
125
+ async execute(input, ctx) {
126
+ try {
127
+ const action = (0, ToolRegistry_1.requireStringInput)(input, 'action', 'manage_skill');
128
+ const scope = skillScope(input.scope);
129
+ switch (action) {
130
+ case 'create':
131
+ return this.create(input, scope);
132
+ case 'install':
133
+ return this.install(input, scope, ctx);
134
+ case 'update':
135
+ return this.update(input, scope, ctx);
136
+ case 'remove':
137
+ return this.remove(input, scope);
138
+ default:
139
+ throw MarifoldError_1.MarifoldError.agentToolInvalid(`Tool 'manage_skill' received unsupported action '${action}'.`, 'manage_skill');
140
+ }
141
+ }
142
+ catch (error) {
143
+ const message = error instanceof Error ? error.message : String(error);
144
+ return {
145
+ content: `Skill management failed: ${message}`,
146
+ summary: 'skill management failed',
147
+ isError: true,
148
+ };
149
+ }
150
+ }
151
+ create(input, scope) {
152
+ const name = requireMutableName(input, 'name');
153
+ const content = (0, ToolRegistry_1.requireStringInput)(input, 'content', 'manage_skill');
154
+ const skill = (0, SkillValidator_1.parseSkill)(content);
155
+ if (skill.name !== name) {
156
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Requested name '${name}' does not match SKILL.md name '${skill.name}'.`);
157
+ }
158
+ if (this.exactSkill(name, scope)) {
159
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Skill '${name}' already exists in ${scope} scope. Choose another name or update it separately.`);
160
+ }
161
+ const files = bundledTextFiles(input.files);
162
+ const installed = this.options.store.installFromText(content, scope);
163
+ const skillDir = path.dirname(installed.source);
164
+ try {
165
+ for (const file of files) {
166
+ const target = path.join(skillDir, file.path);
167
+ fs.mkdirSync(path.dirname(target), { recursive: true });
168
+ fs.writeFileSync(target, file.content);
169
+ }
170
+ this.verify(name, scope);
171
+ }
172
+ catch (error) {
173
+ this.options.store.remove(name, scope);
174
+ throw error;
175
+ }
176
+ return {
177
+ content: `Created $${name} in ${this.scopeLabel(scope)} at ${skillDir}. Invoke it with $${name}.`,
178
+ summary: `created ${scope} skill $${name}`,
179
+ };
180
+ }
181
+ install(input, scope, ctx) {
182
+ const source = localSource(input, ctx);
183
+ const preview = (0, SkillStore_1.readSkillSource)(source);
184
+ if ((0, BuiltInSkills_1.isBuiltInSkillName)(preview.skill.name)) {
185
+ throw protectedBuiltIn(preview.skill.name);
186
+ }
187
+ const existed = Boolean(this.exactSkill(preview.skill.name, scope));
188
+ const installed = this.options.store.installFromFile(source, scope);
189
+ this.verify(installed.name, scope);
190
+ const verb = existed ? 'Updated' : 'Installed';
191
+ return {
192
+ content: `${verb} $${installed.name} in ${this.scopeLabel(scope)} at ${path.dirname(installed.source)}.`,
193
+ summary: `${verb.toLowerCase()} ${scope} skill $${installed.name}`,
194
+ };
195
+ }
196
+ update(input, scope, ctx) {
197
+ const name = requireMutableName(input, 'name');
198
+ if (!this.exactSkill(name, scope)) {
199
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Skill '${name}' does not exist in ${scope} scope.`);
200
+ }
201
+ const source = localSource(input, ctx);
202
+ const preview = (0, SkillStore_1.readSkillSource)(source);
203
+ if (preview.skill.name !== name) {
204
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Update source name '${preview.skill.name}' does not match requested skill '${name}'.`);
205
+ }
206
+ const installed = this.options.store.installFromFile(source, scope);
207
+ this.verify(name, scope);
208
+ return {
209
+ content: `Updated $${name} in ${this.scopeLabel(scope)} at ${path.dirname(installed.source)}.`,
210
+ summary: `updated ${scope} skill $${name}`,
211
+ };
212
+ }
213
+ remove(input, scope) {
214
+ const name = requireMutableName(input, 'name');
215
+ const existing = this.exactSkill(name, scope);
216
+ if (!existing) {
217
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Skill '${name}' does not exist in ${scope} scope.`);
218
+ }
219
+ const removedDir = path.dirname(existing.source);
220
+ this.options.store.remove(name, scope);
221
+ const effective = this.options.store.get(name);
222
+ const fallback = effective
223
+ ? ` The ${effective.scope} copy at ${path.dirname(effective.source)} is now effective.`
224
+ : ' No user-managed copy remains effective.';
225
+ return {
226
+ content: `Removed $${name} from ${this.scopeLabel(scope)} at ${removedDir}.${fallback}`,
227
+ summary: `removed ${scope} skill $${name}`,
228
+ };
229
+ }
230
+ exactSkill(name, scope) {
231
+ return this.options.store.list(scope).find(skill => skill.name === name);
232
+ }
233
+ verify(name, scope) {
234
+ if (!this.exactSkill(name, scope)) {
235
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Could not verify '${name}' after writing ${scope} scope.`);
236
+ }
237
+ }
238
+ dirForScope(scope) {
239
+ return scope === 'global' ? this.options.globalDir : this.options.profileDir;
240
+ }
241
+ scopeLabel(scope) {
242
+ return scope === 'global' ? 'global scope' : `profile '${this.options.profile}'`;
243
+ }
244
+ }
245
+ exports.SkillManagementTool = SkillManagementTool;
246
+ function skillScope(value) {
247
+ if (value === 'profile' || value === 'global')
248
+ return value;
249
+ throw MarifoldError_1.MarifoldError.agentToolInvalid("Tool 'manage_skill' requires scope 'profile' or 'global'.", 'manage_skill');
250
+ }
251
+ function requireMutableName(input, key) {
252
+ const name = (0, ToolRegistry_1.requireStringInput)(input, key, 'manage_skill');
253
+ if (!/^[a-z0-9][a-z0-9_-]*$/.test(name)) {
254
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Invalid skill name '${name}'. Use lowercase letters, numbers, underscores, or hyphens (starting alphanumeric).`);
255
+ }
256
+ if ((0, BuiltInSkills_1.isBuiltInSkillName)(name))
257
+ throw protectedBuiltIn(name);
258
+ return name;
259
+ }
260
+ function protectedBuiltIn(name) {
261
+ return MarifoldError_1.MarifoldError.skillInvalid(`Skill '${name}' is a protected Marifold built-in and cannot be installed, updated, or removed.`);
262
+ }
263
+ function localSource(input, ctx) {
264
+ const source = (0, WorkspacePaths_1.expandHome)((0, ToolRegistry_1.requireStringInput)(input, 'source', 'manage_skill'));
265
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(source)) {
266
+ throw MarifoldError_1.MarifoldError.skillInvalid('Skill sources must be local files or folders; network URLs are not supported.');
267
+ }
268
+ return path.resolve(ctx.cwd, source);
269
+ }
270
+ function bundledTextFiles(value) {
271
+ if (value === undefined)
272
+ return [];
273
+ if (!Array.isArray(value)) {
274
+ throw MarifoldError_1.MarifoldError.agentToolInvalid("Tool 'manage_skill' expects 'files' to be an array.", 'manage_skill');
275
+ }
276
+ const seen = new Set();
277
+ return value.map((entry, index) => {
278
+ if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
279
+ throw MarifoldError_1.MarifoldError.agentToolInvalid(`Tool 'manage_skill' expects files[${index}] to be an object.`, 'manage_skill');
280
+ }
281
+ const file = entry;
282
+ if (typeof file.content !== 'string') {
283
+ throw MarifoldError_1.MarifoldError.agentToolInvalid(`Tool 'manage_skill' requires files[${index}].content to be a string.`, 'manage_skill');
284
+ }
285
+ const relative = safeBundledPath((0, ToolRegistry_1.requireStringInput)(file, 'path', 'manage_skill'));
286
+ if (seen.has(relative)) {
287
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Duplicate bundled file path '${relative}'.`);
288
+ }
289
+ seen.add(relative);
290
+ return {
291
+ path: relative,
292
+ content: file.content,
293
+ };
294
+ });
295
+ }
296
+ function safeBundledPath(value) {
297
+ if (value.includes('\0')) {
298
+ throw MarifoldError_1.MarifoldError.skillInvalid('Bundled file paths cannot contain null bytes.');
299
+ }
300
+ const portable = value.replace(/\\/g, '/');
301
+ const parts = portable.split('/');
302
+ if (portable.startsWith('/')
303
+ || /^[a-z]:\//i.test(portable)
304
+ || parts.some(part => part === '' || part === '.' || part === '..')) {
305
+ throw MarifoldError_1.MarifoldError.skillInvalid(`Unsafe bundled file path '${value}'.`);
306
+ }
307
+ if (portable === 'SKILL.md') {
308
+ throw MarifoldError_1.MarifoldError.skillInvalid("Bundled files cannot replace the skill's SKILL.md.");
309
+ }
310
+ return parts.join(path.sep);
311
+ }
312
+ //# sourceMappingURL=SkillManagementTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillManagementTool.js","sourceRoot":"","sources":["../../../src/agent/tools/SkillManagementTool.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,11 @@ export interface ConfigRemoveProviderResult extends ConfigSetResult {
12
12
  removed: boolean;
13
13
  removedModels: string[];
14
14
  }
15
+ export interface ConfigAddProviderOptions {
16
+ baseUrl?: string;
17
+ apiKeyEnv?: string;
18
+ proxy?: string;
19
+ }
15
20
  export declare class ConfigManager {
16
21
  private readonly loadedConfig;
17
22
  constructor(loadedConfig: LoadedMarifoldConfig);
@@ -29,6 +34,10 @@ export declare class ConfigManager {
29
34
  private readValue;
30
35
  setDefaultModel(model: string, provider?: string): ConfigSetResult;
31
36
  addModel(provider: string, model: string, options?: Partial<MarifoldProviderConfig>): ConfigSetResult;
37
+ /** Add or reconfigure one provider using the same registry defaults as the
38
+ * CLI picker and Web catalog. Credentials remain untouched and raw secrets
39
+ * are deliberately outside this input surface. */
40
+ addProvider(provider: string, options?: ConfigAddProviderOptions): ConfigSetResult;
32
41
  /** Merge changes into the [web_search] section (undefined keys are left as-is)
33
42
  * and persist. Used by `marifold config search`. */
34
43
  updateWebSearch(partial: Partial<MarifoldWebSearchConfig>): ConfigSetResult;
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigManager.d.ts","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EAGxB,MAAM,gBAAgB,CAAC;AAOxB,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,0BAA2B,SAAQ,eAAe;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,YAAY;IAAzC,YAA6B,YAAY,EAAE,oBAAoB,EAAI;IAEnE,IAAI,MAAM,IAAI,cAAc,CAE3B;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,IAAI,MAAM,CAIb;IAED,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CA0BpD;IAED;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMxC;IAED,OAAO,CAAC,SAAS;IA2FjB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CAWjE;IAED,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAAG,eAAe,CAsBxG;IAED;wDACoD;IACpD,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,eAAe,CAO1E;IAED,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,CA0BpE;IAED;mFAC+E;IAC/E,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CA+B3D;IAED,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOjF;IAED,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAKlD;IAED,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,YAAY;IAyBpB,OAAO,CAAC,cAAc;IAatB;;0EAEsE;IACtE,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,gBAAgB;IAiCxB,OAAO,CAAC,cAAc;CAQvB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAsGnE"}
1
+ {"version":3,"file":"ConfigManager.d.ts","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EAGxB,MAAM,gBAAgB,CAAC;AAOxB,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,0BAA2B,SAAQ,eAAe;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,YAAY;IAAzC,YAA6B,YAAY,EAAE,oBAAoB,EAAI;IAEnE,IAAI,MAAM,IAAI,cAAc,CAE3B;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,IAAI,MAAM,CAIb;IAED,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CA0BpD;IAED;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMxC;IAED,OAAO,CAAC,SAAS;IA2FjB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CAWjE;IAED,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAAG,eAAe,CAsBxG;IAED;;sDAEkD;IAClD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,wBAA6B,GAAG,eAAe,CAiCrF;IAED;wDACoD;IACpD,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,eAAe,CAO1E;IAED,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,CA0BpE;IAED;mFAC+E;IAC/E,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CA+B3D;IAED,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOjF;IAED,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAKlD;IAED,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,YAAY;IAyBpB,OAAO,CAAC,cAAc;IAatB;;0EAEsE;IACtE,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,gBAAgB;IAiCxB,OAAO,CAAC,cAAc;CAQvB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAsGnE"}
@@ -246,6 +246,49 @@ class ConfigManager {
246
246
  this.save();
247
247
  return { configPath: this.configPath, key: 'models.options', value: `${provider}/${model}` };
248
248
  }
249
+ /** Add or reconfigure one provider using the same registry defaults as the
250
+ * CLI picker and Web catalog. Credentials remain untouched and raw secrets
251
+ * are deliberately outside this input surface. */
252
+ addProvider(provider, options = {}) {
253
+ if (!provider)
254
+ throw MarifoldError_1.MarifoldError.configInvalid('Provider cannot be empty.');
255
+ const existing = this.config.providers[provider];
256
+ const registry = (0, ProviderRegistry_1.getProviderRegistryEntry)(provider);
257
+ if (!registry && !existing)
258
+ throw MarifoldError_1.MarifoldError.configInvalid(`Unknown provider: ${provider}`);
259
+ const type = existing?.type ?? registry?.type ?? 'openai-compatible';
260
+ const baseUrl = options.baseUrl === undefined
261
+ ? existing?.baseUrl ?? registry?.defaultBaseUrl
262
+ : options.baseUrl.trim();
263
+ const apiKeyEnv = options.apiKeyEnv === undefined
264
+ ? existing?.apiKeyEnv ?? registry?.apiKeyEnv
265
+ : options.apiKeyEnv.trim();
266
+ if ((type === 'ollama' || type === 'openai-compatible') && !baseUrl) {
267
+ throw MarifoldError_1.MarifoldError.configInvalid(`Provider '${provider}' requires a server URL.`);
268
+ }
269
+ if (registry?.kind === 'api' && !apiKeyEnv) {
270
+ throw MarifoldError_1.MarifoldError.configInvalid(`Provider '${provider}' requires an API key environment variable name.`);
271
+ }
272
+ const config = { ...(existing ?? {}), type };
273
+ if (baseUrl)
274
+ config.baseUrl = baseUrl.replace(/\/+$/, '');
275
+ else
276
+ delete config.baseUrl;
277
+ if (apiKeyEnv)
278
+ config.apiKeyEnv = apiKeyEnv;
279
+ else
280
+ delete config.apiKeyEnv;
281
+ if (options.proxy !== undefined) {
282
+ const proxy = options.proxy.trim();
283
+ if (proxy)
284
+ config.proxy = proxy;
285
+ else
286
+ delete config.proxy;
287
+ }
288
+ this.config.providers[provider] = config;
289
+ this.save();
290
+ return { configPath: this.configPath, key: `providers.${provider}`, value: provider };
291
+ }
249
292
  /** Merge changes into the [web_search] section (undefined keys are left as-is)
250
293
  * and persist. Used by `marifold config search`. */
251
294
  updateWebSearch(partial) {