@skillsmith/core 0.11.5 → 0.11.6
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/CHANGELOG.md +47 -0
- package/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.js +5 -0
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/client.test.js +39 -0
- package/dist/src/api/client.test.js.map +1 -1
- package/dist/src/compatibility/slugs.d.ts +7 -3
- package/dist/src/compatibility/slugs.d.ts.map +1 -1
- package/dist/src/compatibility/slugs.js +11 -4
- package/dist/src/compatibility/slugs.js.map +1 -1
- package/dist/src/db/drivers/sqljsDriver.d.ts +8 -0
- package/dist/src/db/drivers/sqljsDriver.d.ts.map +1 -1
- package/dist/src/db/drivers/sqljsDriver.js +24 -2
- package/dist/src/db/drivers/sqljsDriver.js.map +1 -1
- package/dist/src/db/migration-runner.d.ts.map +1 -1
- package/dist/src/db/migration-runner.js +23 -2
- package/dist/src/db/migration-runner.js.map +1 -1
- package/dist/src/db/schema.d.ts.map +1 -1
- package/dist/src/db/schema.js +29 -3
- package/dist/src/db/schema.js.map +1 -1
- package/dist/src/exports/services.d.ts +1 -0
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +5 -0
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/install/index.d.ts +2 -2
- package/dist/src/install/index.d.ts.map +1 -1
- package/dist/src/install/index.js +1 -1
- package/dist/src/install/index.js.map +1 -1
- package/dist/src/install/paths.d.ts +155 -1
- package/dist/src/install/paths.d.ts.map +1 -1
- package/dist/src/install/paths.js +235 -1
- package/dist/src/install/paths.js.map +1 -1
- package/dist/src/install/paths.test.js +174 -2
- package/dist/src/install/paths.test.js.map +1 -1
- package/dist/src/services/context-words.d.ts +40 -0
- package/dist/src/services/context-words.d.ts.map +1 -0
- package/dist/src/services/context-words.js +178 -0
- package/dist/src/services/context-words.js.map +1 -0
- package/dist/src/services/context-words.test.d.ts +2 -0
- package/dist/src/services/context-words.test.d.ts.map +1 -0
- package/dist/src/services/context-words.test.js +94 -0
- package/dist/src/services/context-words.test.js.map +1 -0
- package/dist/src/services/skill-installation.content.d.ts +8 -0
- package/dist/src/services/skill-installation.content.d.ts.map +1 -1
- package/dist/src/services/skill-installation.content.js +2 -2
- package/dist/src/services/skill-installation.content.js.map +1 -1
- package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
- package/dist/src/services/skill-installation.helpers.js +24 -2
- package/dist/src/services/skill-installation.helpers.js.map +1 -1
- package/dist/src/services/skill-installation.helpers.test.js +76 -2
- package/dist/src/services/skill-installation.helpers.test.js.map +1 -1
- package/dist/src/services/skill-installation.io.d.ts +22 -1
- package/dist/src/services/skill-installation.io.d.ts.map +1 -1
- package/dist/src/services/skill-installation.io.js +36 -5
- package/dist/src/services/skill-installation.io.js.map +1 -1
- package/dist/src/services/skill-installation.service.d.ts +2 -0
- package/dist/src/services/skill-installation.service.d.ts.map +1 -1
- package/dist/src/services/skill-installation.service.js +4 -1
- package/dist/src/services/skill-installation.service.js.map +1 -1
- package/dist/src/services/skill-manifest.d.ts +21 -0
- package/dist/src/services/skill-manifest.d.ts.map +1 -1
- package/dist/src/services/skill-manifest.js +51 -6
- package/dist/src/services/skill-manifest.js.map +1 -1
- package/dist/src/services/skill-manifest.test.d.ts +2 -0
- package/dist/src/services/skill-manifest.test.d.ts.map +1 -0
- package/dist/src/services/skill-manifest.test.js +202 -0
- package/dist/src/services/skill-manifest.test.js.map +1 -0
- package/dist/src/types/skill.d.ts +10 -0
- package/dist/src/types/skill.d.ts.map +1 -1
- package/dist/src/types.d.ts +9 -5
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tests/db/migration-runner-race.test.d.ts +2 -0
- package/dist/tests/db/migration-runner-race.test.d.ts.map +1 -0
- package/dist/tests/db/migration-runner-race.test.js +75 -0
- package/dist/tests/db/migration-runner-race.test.js.map +1 -0
- package/dist/tests/db/schema-async.test.js +37 -1
- package/dist/tests/db/schema-async.test.js.map +1 -1
- package/dist/tests/db/sqljsDriver.test.js +63 -1
- package/dist/tests/db/sqljsDriver.test.js.map +1 -1
- package/dist/tests/schema.test.js +43 -1
- package/dist/tests/schema.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.d.ts +34 -0
- package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js +246 -0
- package/dist/tests/unit/services/skill-installation.io.client-agent-path.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.d.ts +17 -0
- package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.js +112 -0
- package/dist/tests/unit/services/skill-installation.service.companion-basedir.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* pythonIncremental.hardening.test.ts (SMI-4315/4316).
|
|
8
8
|
*/
|
|
9
9
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
10
12
|
// vi.hoisted runs before vi.mock factories so we can share the spy instance.
|
|
11
13
|
const { existsSyncSpy } = vi.hoisted(() => ({
|
|
12
14
|
existsSyncSpy: vi.fn(() => false),
|
|
@@ -15,7 +17,7 @@ vi.mock('node:fs', async () => {
|
|
|
15
17
|
const actual = await vi.importActual('node:fs');
|
|
16
18
|
return { ...actual, existsSync: (p) => existsSyncSpy(p) };
|
|
17
19
|
});
|
|
18
|
-
import { CLIENT_IDS, CLIENT_NATIVE_PATHS, enumerateHarnessPresence } from './paths.js';
|
|
20
|
+
import { CANONICAL_CLIENT, CLIENT_IDS, CLIENT_NATIVE_PATHS, COMPANION_AGENT_TARGETS, enumerateHarnessPresence, getCompanionAgentTarget, resolveCompanionAgentDir, resolveCompanionAgentPath, } from './paths.js';
|
|
19
21
|
describe('enumerateHarnessPresence (SMI-5390)', () => {
|
|
20
22
|
beforeEach(() => {
|
|
21
23
|
existsSyncSpy.mockReset();
|
|
@@ -39,6 +41,7 @@ describe('enumerateHarnessPresence (SMI-5390)', () => {
|
|
|
39
41
|
expect(result.find((r) => r.harness === 'opencode')?.present).toBe(false);
|
|
40
42
|
expect(result.find((r) => r.harness === 'hermes')?.present).toBe(false);
|
|
41
43
|
expect(result.find((r) => r.harness === 'grok')?.present).toBe(false);
|
|
44
|
+
expect(result.find((r) => r.harness === 'antigravity')?.present).toBe(false);
|
|
42
45
|
});
|
|
43
46
|
it('reports all harnesses absent when existsSync returns false for every path', () => {
|
|
44
47
|
existsSyncSpy.mockReturnValue(false);
|
|
@@ -76,10 +79,179 @@ describe('opencode + hermes ClientIds (SMI-5456 Wave 1 Step 5)', () => {
|
|
|
76
79
|
describe('grok ClientId (SMI-5697)', () => {
|
|
77
80
|
it('CLIENT_IDS includes grok', () => {
|
|
78
81
|
expect(CLIENT_IDS).toContain('grok');
|
|
79
|
-
expect(CLIENT_IDS).toHaveLength(8);
|
|
80
82
|
});
|
|
81
83
|
it('grok resolves to ~/.grok/skills', () => {
|
|
82
84
|
expect(CLIENT_NATIVE_PATHS.grok.endsWith('/.grok/skills')).toBe(true);
|
|
83
85
|
});
|
|
84
86
|
});
|
|
87
|
+
describe('antigravity ClientId (SMI-5982 Wave 6)', () => {
|
|
88
|
+
it('CLIENT_IDS includes antigravity, 9 total', () => {
|
|
89
|
+
expect(CLIENT_IDS).toContain('antigravity');
|
|
90
|
+
expect(CLIENT_IDS).toHaveLength(9);
|
|
91
|
+
});
|
|
92
|
+
it('antigravity resolves to ~/.gemini/config/skills (corrects SMI-5179 stale ~/.gemini/antigravity/skills claim)', () => {
|
|
93
|
+
expect(CLIENT_NATIVE_PATHS.antigravity).toBe(join(homedir(), '.gemini', 'config', 'skills'));
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* SMI-5980 (Wave 3): COMPANION_AGENT_TARGETS is a regression guard by
|
|
98
|
+
* design — every existing ClientId's companion-subagent output path must be
|
|
99
|
+
* EXACTLY unchanged from the pre-Wave-3 hardcoded
|
|
100
|
+
* `path.join(os.homedir(), '.claude', 'agents')` default, except copilot and
|
|
101
|
+
* opencode, which get an independently-evidenced directory value cited from
|
|
102
|
+
* AGENT_SHIM_TARGETS (agent-harness-targets.ts) for the SAME underlying
|
|
103
|
+
* tool — not a new invented value.
|
|
104
|
+
*/
|
|
105
|
+
describe('COMPANION_AGENT_TARGETS (SMI-5980 Wave 3)', () => {
|
|
106
|
+
it('has exactly one entry per ClientId in CLIENT_IDS', () => {
|
|
107
|
+
for (const id of CLIENT_IDS) {
|
|
108
|
+
expect(COMPANION_AGENT_TARGETS[id]).toBeDefined();
|
|
109
|
+
}
|
|
110
|
+
expect(Object.keys(COMPANION_AGENT_TARGETS)).toHaveLength(CLIENT_IDS.length);
|
|
111
|
+
});
|
|
112
|
+
it('every entry but antigravity uses flat file mode; every flat entry but copilot uses the shared {name}-specialist.md pattern', () => {
|
|
113
|
+
// SMI-5982 (Wave 6): antigravity is the first 'directory-package' entry —
|
|
114
|
+
// see the dedicated 'antigravity directory-package entry' test below.
|
|
115
|
+
for (const id of CLIENT_IDS) {
|
|
116
|
+
if (id === 'antigravity')
|
|
117
|
+
continue;
|
|
118
|
+
expect(COMPANION_AGENT_TARGETS[id].fileMode).toBe('flat');
|
|
119
|
+
if (id === 'copilot')
|
|
120
|
+
continue;
|
|
121
|
+
expect(COMPANION_AGENT_TARGETS[id].filenamePattern).toBe('{name}-specialist.md');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
it('copilot uses {name}.agent.md — its own independently-evidenced filename, not the shared -specialist.md suffix (PR-review finding, BLOCKING)', () => {
|
|
125
|
+
// AGENT_SHIM_TARGETS.copilot (agent-harness-targets.ts) and shims.ts's
|
|
126
|
+
// own doc comment both independently confirm Copilot's real
|
|
127
|
+
// companion-agent format is `.agent.md` -- a plain `-specialist.md`
|
|
128
|
+
// suffix risked producing a file Copilot's own surfaces never discover.
|
|
129
|
+
expect(COMPANION_AGENT_TARGETS.copilot.filenamePattern).toBe('{name}.agent.md');
|
|
130
|
+
});
|
|
131
|
+
it('claude-code matches the pre-Wave-3 hardcoded default exactly', () => {
|
|
132
|
+
// Pre-Wave-3: path.join(os.homedir(), '.claude', 'agents') — the exact
|
|
133
|
+
// literal skill-installation.io.ts and author/utils.ts both hardcoded.
|
|
134
|
+
expect(COMPANION_AGENT_TARGETS['claude-code'].dir).toBe(join(homedir(), '.claude', 'agents'));
|
|
135
|
+
});
|
|
136
|
+
it.each(['cursor', 'windsurf', 'agents', 'hermes', 'grok'])('%s has no independent AGENT_SHIM_TARGETS evidence — defaults to the claude-code value', (client) => {
|
|
137
|
+
expect(COMPANION_AGENT_TARGETS[client].dir).toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
138
|
+
});
|
|
139
|
+
it('copilot uses its own independently-evidenced directory, not the claude-code default', () => {
|
|
140
|
+
expect(COMPANION_AGENT_TARGETS.copilot.dir.endsWith('/.copilot/agents')).toBe(true);
|
|
141
|
+
expect(COMPANION_AGENT_TARGETS.copilot.dir).not.toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
142
|
+
});
|
|
143
|
+
it('opencode uses its own independently-evidenced directory, not the claude-code default', () => {
|
|
144
|
+
expect(COMPANION_AGENT_TARGETS.opencode.dir.endsWith('/.config/opencode/agents')).toBe(true);
|
|
145
|
+
expect(COMPANION_AGENT_TARGETS.opencode.dir).not.toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
146
|
+
});
|
|
147
|
+
it('antigravity directory-package entry: its own dir, directory-package mode, fixed agent.md filename (SMI-5982 Wave 6)', () => {
|
|
148
|
+
// Project-scoped relative dir (Step 1 of the SMI-5982 plan: no existing
|
|
149
|
+
// global-vs-project distinction anywhere in this CLI to hook into) — NOT
|
|
150
|
+
// homedir()-anchored like every other client's dir.
|
|
151
|
+
expect(COMPANION_AGENT_TARGETS.antigravity.dir).toBe(join('.agents', 'agents'));
|
|
152
|
+
expect(COMPANION_AGENT_TARGETS.antigravity.dir).not.toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
153
|
+
expect(COMPANION_AGENT_TARGETS.antigravity.fileMode).toBe('directory-package');
|
|
154
|
+
// No {name} token — the skill name lives in the directory segment, not the filename.
|
|
155
|
+
expect(COMPANION_AGENT_TARGETS.antigravity.filenamePattern).toBe('agent.md');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe('getCompanionAgentTarget / resolveCompanionAgentDir / resolveCompanionAgentPath (SMI-5980 Wave 3)', () => {
|
|
159
|
+
it('getCompanionAgentTarget defaults to CANONICAL_CLIENT when no client is passed', () => {
|
|
160
|
+
expect(getCompanionAgentTarget()).toEqual(COMPANION_AGENT_TARGETS[CANONICAL_CLIENT]);
|
|
161
|
+
});
|
|
162
|
+
it('getCompanionAgentTarget returns the exact per-client entry', () => {
|
|
163
|
+
for (const id of CLIENT_IDS) {
|
|
164
|
+
expect(getCompanionAgentTarget(id)).toEqual(COMPANION_AGENT_TARGETS[id]);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
it('resolveCompanionAgentDir defaults to the canonical (claude-code) dir', () => {
|
|
168
|
+
expect(resolveCompanionAgentDir()).toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
169
|
+
});
|
|
170
|
+
it.each(CLIENT_IDS.filter((id) => id !== 'copilot' && id !== 'antigravity'))('resolveCompanionAgentPath(%s) matches dir + <skillName>-specialist.md for every flat client but copilot', (client) => {
|
|
171
|
+
const result = resolveCompanionAgentPath('my-skill', client);
|
|
172
|
+
expect(result).toBe(join(COMPANION_AGENT_TARGETS[client].dir, 'my-skill-specialist.md'));
|
|
173
|
+
});
|
|
174
|
+
it('resolveCompanionAgentPath(copilot) matches dir + <skillName>.agent.md', () => {
|
|
175
|
+
const result = resolveCompanionAgentPath('my-skill', 'copilot');
|
|
176
|
+
expect(result).toBe(join(COMPANION_AGENT_TARGETS.copilot.dir, 'my-skill.agent.md'));
|
|
177
|
+
});
|
|
178
|
+
it('resolveCompanionAgentPath(antigravity) matches dir/<skillName>/agent.md — directory-package mode (SMI-5982 Wave 6)', () => {
|
|
179
|
+
// SMI-5982 code-review fix #1: antigravity's `dir` is RELATIVE, so the
|
|
180
|
+
// 3rd `baseDir` param is resolved against it explicitly, producing an
|
|
181
|
+
// ABSOLUTE path. PR-review follow-up: `baseDir` is now REQUIRED for
|
|
182
|
+
// directory-package mode (no `process.cwd()` default) — see the
|
|
183
|
+
// dedicated 'resolveCompanionAgentPath baseDir resolution' describe
|
|
184
|
+
// block below for the required-baseDir + traversal-guard coverage.
|
|
185
|
+
const result = resolveCompanionAgentPath('my-skill', 'antigravity', process.cwd());
|
|
186
|
+
expect(result).toBe(join(process.cwd(), COMPANION_AGENT_TARGETS.antigravity.dir, 'my-skill', 'agent.md'));
|
|
187
|
+
expect(result).toBe(join(process.cwd(), '.agents', 'agents', 'my-skill', 'agent.md'));
|
|
188
|
+
});
|
|
189
|
+
it('resolveCompanionAgentPath defaults to canonical client when omitted (regression: unchanged)', () => {
|
|
190
|
+
const result = resolveCompanionAgentPath('my-skill');
|
|
191
|
+
expect(result).toBe(join(COMPANION_AGENT_TARGETS['claude-code'].dir, 'my-skill-specialist.md'));
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
/**
|
|
195
|
+
* SMI-5982 code-review fix #1 (BLOCKING, cwd-dependent resolution): the
|
|
196
|
+
* `baseDir` param makes the resolution root explicit instead of an implicit
|
|
197
|
+
* `process.cwd()` lookup at whatever moment an `fs` call eventually consumes
|
|
198
|
+
* the returned path — critical for the long-running MCP server, whose cwd is
|
|
199
|
+
* fixed at launch and generally does not track the calling editor/agent's
|
|
200
|
+
* actual project.
|
|
201
|
+
*
|
|
202
|
+
* PR-review follow-up (BLOCKING): the original `baseDir: string =
|
|
203
|
+
* process.cwd()` default only closed the bug for callers whose own cwd
|
|
204
|
+
* happens to be the caller's real project — it silently did nothing for
|
|
205
|
+
* every OTHER production call site (e.g. the MCP private-registry install
|
|
206
|
+
* action, which has no per-call cwd input at all). `baseDir` is now
|
|
207
|
+
* **required** (no default) for every `directory-package`-mode client —
|
|
208
|
+
* omitting it throws instead of silently resolving against this process's
|
|
209
|
+
* ambient cwd, closing the bug class by construction for every current and
|
|
210
|
+
* future caller.
|
|
211
|
+
*/
|
|
212
|
+
describe('resolveCompanionAgentPath baseDir resolution (SMI-5982 code-review fix #1)', () => {
|
|
213
|
+
it('resolves a directory-package (antigravity) relative dir against an explicit baseDir', () => {
|
|
214
|
+
const result = resolveCompanionAgentPath('my-skill', 'antigravity', '/some/explicit/root');
|
|
215
|
+
expect(result).toBe('/some/explicit/root/.agents/agents/my-skill/agent.md');
|
|
216
|
+
});
|
|
217
|
+
it('omitting baseDir for a directory-package client (antigravity) now throws instead of defaulting to process.cwd() (PR-review follow-up)', () => {
|
|
218
|
+
expect(() => resolveCompanionAgentPath('my-skill', 'antigravity')).toThrow(/directory-package mode.*explicit baseDir is required/s);
|
|
219
|
+
});
|
|
220
|
+
it('explicit baseDir still succeeds for antigravity (regression guard)', () => {
|
|
221
|
+
expect(() => resolveCompanionAgentPath('my-skill', 'antigravity', process.cwd())).not.toThrow();
|
|
222
|
+
const result = resolveCompanionAgentPath('my-skill', 'antigravity', process.cwd());
|
|
223
|
+
expect(result).toBe(join(process.cwd(), '.agents', 'agents', 'my-skill', 'agent.md'));
|
|
224
|
+
});
|
|
225
|
+
it('flat-mode clients (e.g. claude-code) are unaffected by the required-baseDir guard — omitting baseDir still resolves correctly (regression guard)', () => {
|
|
226
|
+
const withBaseDir = resolveCompanionAgentPath('my-skill', 'claude-code', '/some/explicit/root');
|
|
227
|
+
const withoutBaseDir = resolveCompanionAgentPath('my-skill', 'claude-code');
|
|
228
|
+
expect(withBaseDir).toBe(withoutBaseDir);
|
|
229
|
+
expect(withBaseDir).toBe(join(COMPANION_AGENT_TARGETS['claude-code'].dir, 'my-skill-specialist.md'));
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
/**
|
|
233
|
+
* SMI-5982 code-review fix #2 (BLOCKING, path traversal): `skillName` becomes
|
|
234
|
+
* its own path segment in directory-package mode, so an unsanitized value
|
|
235
|
+
* like '..' would escape the intended companion-agent namespace. Every
|
|
236
|
+
* current caller already sanitizes skillName upstream, but this function is
|
|
237
|
+
* exported and reusable, so it validates independently (same "last line of
|
|
238
|
+
* defense" principle as `skillNameFromSkillId()` in
|
|
239
|
+
* skill-installation.content.ts).
|
|
240
|
+
*/
|
|
241
|
+
describe('resolveCompanionAgentPath directory-package skillName validation (SMI-5982 code-review fix #2)', () => {
|
|
242
|
+
// baseDir is passed explicitly throughout this block so these cases exercise the skillName
|
|
243
|
+
// validation specifically, not the required-baseDir guard (fix #1, PR-review follow-up) — that
|
|
244
|
+
// guard runs first and would otherwise mask the skillName check being tested here.
|
|
245
|
+
it.each(['..', '.', '', 'foo/bar', 'foo\\bar'])('throws for unsafe skillName %j in directory-package mode (antigravity)', (unsafeName) => {
|
|
246
|
+
expect(() => resolveCompanionAgentPath(unsafeName, 'antigravity', process.cwd())).toThrow(/Unsafe skill name for directory-package companion path/);
|
|
247
|
+
});
|
|
248
|
+
it('still succeeds for a normal skillName (regression guard)', () => {
|
|
249
|
+
expect(() => resolveCompanionAgentPath('my-skill', 'antigravity', process.cwd())).not.toThrow();
|
|
250
|
+
});
|
|
251
|
+
it.each(['..', '.', '', 'foo/bar', 'foo\\bar'])('flat-mode clients are unaffected by the directory-package validation — %j still resolves for claude-code', (name) => {
|
|
252
|
+
expect(() => resolveCompanionAgentPath(name, 'claude-code')).not.toThrow();
|
|
253
|
+
const result = resolveCompanionAgentPath(name, 'claude-code');
|
|
254
|
+
expect(result).toBe(join(COMPANION_AGENT_TARGETS['claude-code'].dir, `${name}-specialist.md`));
|
|
255
|
+
});
|
|
256
|
+
});
|
|
85
257
|
//# sourceMappingURL=paths.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.test.js","sourceRoot":"","sources":["../../../src/install/paths.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"paths.test.js","sourceRoot":"","sources":["../../../src/install/paths.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared context-word extraction for skill recommendations.
|
|
3
|
+
* @module @skillsmith/core/services/context-words
|
|
4
|
+
* @see SMI-5986: CLI `recommend --context` (`recommend.ts:76`) and MCP
|
|
5
|
+
* `skill_recommend`'s `project_context` (`recommend.ts:127`) each derived a
|
|
6
|
+
* "context words" slice for the recommendation stack via
|
|
7
|
+
* `.filter((w) => w.length > 3)` — a bare length threshold that silently
|
|
8
|
+
* dropped real 2-3 character technical terms ("git", "ci", "aws", "sql")
|
|
9
|
+
* that happen to be short. When a caller's context consisted only of such
|
|
10
|
+
* terms, the resulting derived stack was empty and the SMI-5896
|
|
11
|
+
* empty-stack guard (`buildEmptyStackGuidance`, this module's sibling)
|
|
12
|
+
* fired even though the caller *did* supply usable context.
|
|
13
|
+
*
|
|
14
|
+
* Shared here (not duplicated per-twin) so CLI and MCP can't independently
|
|
15
|
+
* drift on what counts as noise vs. a real short technical term — the same
|
|
16
|
+
* class of duplication risk `buildEmptyStackGuidance` above already closed
|
|
17
|
+
* for the empty-stack message itself (plan-review correction, SMI-5984
|
|
18
|
+
* Wave 1: a bare length threshold "admits noise words" and leaves the two
|
|
19
|
+
* twins free to drift apart again independently).
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Extract up to `maxWords` usable technical terms from free-text project
|
|
23
|
+
* context for the recommendation stack.
|
|
24
|
+
*
|
|
25
|
+
* Replaces the old `.filter((w) => w.length > 3)` threshold: real technical
|
|
26
|
+
* terms of 2-3 characters ("git", "ci", "aws", "sql") are now kept, while
|
|
27
|
+
* single-character tokens, punctuation-only tokens (including one that
|
|
28
|
+
* survives edge-stripping because it's made entirely of `+`/`#`, e.g. "++"
|
|
29
|
+
* or "+#" — PR review round 3, SMI-5986), and short English function words
|
|
30
|
+
* ("a", "the", "is", ...) are still dropped as noise. Words of 4+
|
|
31
|
+
* characters are unaffected — this only changes the outcome for the short
|
|
32
|
+
* end of the spectrum the length threshold got wrong.
|
|
33
|
+
*
|
|
34
|
+
* @param projectContext - Free-text project/context description. `null`/
|
|
35
|
+
* `undefined`/empty returns `[]`, mirroring both callers' pre-existing
|
|
36
|
+
* `if (project_context)` guard.
|
|
37
|
+
* @param maxWords - Maximum number of words to return (default 5).
|
|
38
|
+
*/
|
|
39
|
+
export declare function extractContextWords(projectContext: string | undefined | null, maxWords?: number): string[];
|
|
40
|
+
//# sourceMappingURL=context-words.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-words.d.ts","sourceRoot":"","sources":["../../../src/services/context-words.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAmIH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACzC,QAAQ,GAAE,MAA0B,GACnC,MAAM,EAAE,CAcV"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared context-word extraction for skill recommendations.
|
|
3
|
+
* @module @skillsmith/core/services/context-words
|
|
4
|
+
* @see SMI-5986: CLI `recommend --context` (`recommend.ts:76`) and MCP
|
|
5
|
+
* `skill_recommend`'s `project_context` (`recommend.ts:127`) each derived a
|
|
6
|
+
* "context words" slice for the recommendation stack via
|
|
7
|
+
* `.filter((w) => w.length > 3)` — a bare length threshold that silently
|
|
8
|
+
* dropped real 2-3 character technical terms ("git", "ci", "aws", "sql")
|
|
9
|
+
* that happen to be short. When a caller's context consisted only of such
|
|
10
|
+
* terms, the resulting derived stack was empty and the SMI-5896
|
|
11
|
+
* empty-stack guard (`buildEmptyStackGuidance`, this module's sibling)
|
|
12
|
+
* fired even though the caller *did* supply usable context.
|
|
13
|
+
*
|
|
14
|
+
* Shared here (not duplicated per-twin) so CLI and MCP can't independently
|
|
15
|
+
* drift on what counts as noise vs. a real short technical term — the same
|
|
16
|
+
* class of duplication risk `buildEmptyStackGuidance` above already closed
|
|
17
|
+
* for the empty-stack message itself (plan-review correction, SMI-5984
|
|
18
|
+
* Wave 1: a bare length threshold "admits noise words" and leaves the two
|
|
19
|
+
* twins free to drift apart again independently).
|
|
20
|
+
*/
|
|
21
|
+
/** Maximum context words carried into the recommendation stack (matches both callers' pre-existing `.slice(0, 5)`). */
|
|
22
|
+
const MAX_CONTEXT_WORDS = 5;
|
|
23
|
+
/**
|
|
24
|
+
* Common short English function words that would otherwise pass a
|
|
25
|
+
* length-based filter and pollute the recommendation stack as noise. Kept
|
|
26
|
+
* intentionally short and grammar-only — no 2-3 letter technical acronym
|
|
27
|
+
* ("ci", "ai", "ml", "db", "os", "ui", "js", "go", "git", "aws", "sql",
|
|
28
|
+
* "cli", "api", "sdk", "css") appears here, since those are exactly the real
|
|
29
|
+
* terms this fix exists to stop dropping.
|
|
30
|
+
*/
|
|
31
|
+
const CONTEXT_STOPWORDS = new Set([
|
|
32
|
+
// 2-letter
|
|
33
|
+
'an',
|
|
34
|
+
'is',
|
|
35
|
+
'it',
|
|
36
|
+
'be',
|
|
37
|
+
'to',
|
|
38
|
+
'of',
|
|
39
|
+
'in',
|
|
40
|
+
'on',
|
|
41
|
+
'at',
|
|
42
|
+
'as',
|
|
43
|
+
'or',
|
|
44
|
+
'if',
|
|
45
|
+
'so',
|
|
46
|
+
'no',
|
|
47
|
+
'do',
|
|
48
|
+
'am',
|
|
49
|
+
'we',
|
|
50
|
+
'us',
|
|
51
|
+
'he',
|
|
52
|
+
'my',
|
|
53
|
+
'up',
|
|
54
|
+
// 3-letter
|
|
55
|
+
'the',
|
|
56
|
+
'and',
|
|
57
|
+
'but',
|
|
58
|
+
'not',
|
|
59
|
+
'did',
|
|
60
|
+
'has',
|
|
61
|
+
'had',
|
|
62
|
+
'she',
|
|
63
|
+
'him',
|
|
64
|
+
'her',
|
|
65
|
+
'its',
|
|
66
|
+
'our',
|
|
67
|
+
'all',
|
|
68
|
+
'few',
|
|
69
|
+
'out',
|
|
70
|
+
'off',
|
|
71
|
+
'via',
|
|
72
|
+
'per',
|
|
73
|
+
'own',
|
|
74
|
+
'too',
|
|
75
|
+
'yet',
|
|
76
|
+
'nor',
|
|
77
|
+
'you',
|
|
78
|
+
'are',
|
|
79
|
+
'was',
|
|
80
|
+
'for',
|
|
81
|
+
'may',
|
|
82
|
+
'who',
|
|
83
|
+
'why',
|
|
84
|
+
'how',
|
|
85
|
+
// Code-review correction (SMI-5986): "any" (TS/SQL keyword), "let"
|
|
86
|
+
// (JS/Rust keyword), and "can" (CAN-bus acronym) were removed from this
|
|
87
|
+
// set — each is a real technical term this fix exists to stop dropping,
|
|
88
|
+
// same class as "git"/"ci"/"aws"/"sql". Leaving them in would have
|
|
89
|
+
// contradicted this list's own documented promise above.
|
|
90
|
+
]);
|
|
91
|
+
/**
|
|
92
|
+
* Whether a single character counts as "keep" (not strippable edge
|
|
93
|
+
* punctuation) — see `stripEdgePunctuation`. Plain character-code range
|
|
94
|
+
* checks, not a regex — this is the actual "no regex" implementation (PR
|
|
95
|
+
* review round 3, SMI-5986): round 2's fix still called `.test()` against a
|
|
96
|
+
* single-character-class regex, which isn't the polynomial-backtracking
|
|
97
|
+
* shape CodeQL flags, but didn't match its own doc comment's "manual
|
|
98
|
+
* index-scan rather than a regex" claim either.
|
|
99
|
+
*/
|
|
100
|
+
function isKeepChar(ch) {
|
|
101
|
+
return (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch === '+' || ch === '#';
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Whether a word contains at least one alphanumeric character — used to
|
|
105
|
+
* reject punctuation-only tokens ("++", "##", "+#") that `isKeepChar` alone
|
|
106
|
+
* would let through, since `+`/`#` count as "keep" but aren't themselves
|
|
107
|
+
* usable content (PR review round 3, SMI-5986: `extractContextWords('++ ##
|
|
108
|
+
* +#')` was returning `['++', '##', '+#']` — all three passed the length
|
|
109
|
+
* filter with no alphanumeric substance at all).
|
|
110
|
+
*/
|
|
111
|
+
function hasAlphaNumeric(word) {
|
|
112
|
+
for (let i = 0; i < word.length; i++) {
|
|
113
|
+
const ch = word[i];
|
|
114
|
+
if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Strip leading/trailing punctuation from an already-lowercased token
|
|
121
|
+
* without touching interior characters — "k8s" is untouched, but "git," ->
|
|
122
|
+
* "git" and "(sql)" -> "sql". Real-world context strings aren't always
|
|
123
|
+
* clean whitespace-delimited tokens (trailing commas, wrapping parens),
|
|
124
|
+
* and a stray comma would otherwise make "git," fail to match the real
|
|
125
|
+
* "git" term downstream.
|
|
126
|
+
*
|
|
127
|
+
* `+` and `#` count as "keep" characters (code-review correction, SMI-5986)
|
|
128
|
+
* — they're meaningful trailing characters in real technical terms ("c++",
|
|
129
|
+
* "c#"), not punctuation noise; stripping them turned both into the single
|
|
130
|
+
* character "c", which the length filter then discarded entirely. A
|
|
131
|
+
* punctuation-only token surviving this step (e.g. "++") is rejected
|
|
132
|
+
* downstream by `hasAlphaNumeric`, not here — this function only trims
|
|
133
|
+
* edges, it doesn't judge the result's usability.
|
|
134
|
+
*
|
|
135
|
+
* O(n), two linear index scans, no regex anywhere in the call chain
|
|
136
|
+
* (CodeQL js/polynomial-redos, SMI-5986 PR review round 2 — verified
|
|
137
|
+
* empirically, a 200k-character adversarial input runs in under 1ms).
|
|
138
|
+
*/
|
|
139
|
+
function stripEdgePunctuation(word) {
|
|
140
|
+
let start = 0;
|
|
141
|
+
while (start < word.length && !isKeepChar(word[start]))
|
|
142
|
+
start++;
|
|
143
|
+
let end = word.length;
|
|
144
|
+
while (end > start && !isKeepChar(word[end - 1]))
|
|
145
|
+
end--;
|
|
146
|
+
return word.slice(start, end);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Extract up to `maxWords` usable technical terms from free-text project
|
|
150
|
+
* context for the recommendation stack.
|
|
151
|
+
*
|
|
152
|
+
* Replaces the old `.filter((w) => w.length > 3)` threshold: real technical
|
|
153
|
+
* terms of 2-3 characters ("git", "ci", "aws", "sql") are now kept, while
|
|
154
|
+
* single-character tokens, punctuation-only tokens (including one that
|
|
155
|
+
* survives edge-stripping because it's made entirely of `+`/`#`, e.g. "++"
|
|
156
|
+
* or "+#" — PR review round 3, SMI-5986), and short English function words
|
|
157
|
+
* ("a", "the", "is", ...) are still dropped as noise. Words of 4+
|
|
158
|
+
* characters are unaffected — this only changes the outcome for the short
|
|
159
|
+
* end of the spectrum the length threshold got wrong.
|
|
160
|
+
*
|
|
161
|
+
* @param projectContext - Free-text project/context description. `null`/
|
|
162
|
+
* `undefined`/empty returns `[]`, mirroring both callers' pre-existing
|
|
163
|
+
* `if (project_context)` guard.
|
|
164
|
+
* @param maxWords - Maximum number of words to return (default 5).
|
|
165
|
+
*/
|
|
166
|
+
export function extractContextWords(projectContext, maxWords = MAX_CONTEXT_WORDS) {
|
|
167
|
+
if (!projectContext)
|
|
168
|
+
return [];
|
|
169
|
+
return projectContext
|
|
170
|
+
.toLowerCase()
|
|
171
|
+
.split(/\s+/)
|
|
172
|
+
.map(stripEdgePunctuation)
|
|
173
|
+
.filter((word) => word.length >= 2 &&
|
|
174
|
+
hasAlphaNumeric(word) &&
|
|
175
|
+
!(word.length <= 3 && CONTEXT_STOPWORDS.has(word)))
|
|
176
|
+
.slice(0, maxWords);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=context-words.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-words.js","sourceRoot":"","sources":["../../../src/services/context-words.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-words.test.d.ts","sourceRoot":"","sources":["../../../src/services/context-words.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Unit tests for the shared context-word extraction helper
|
|
3
|
+
* (SMI-5986). Both CLI `recommend --context` and MCP `skill_recommend`'s
|
|
4
|
+
* `project_context` now call this instead of duplicating
|
|
5
|
+
* `.filter((w) => w.length > 3)`, so their behavior can't drift apart.
|
|
6
|
+
* @module @skillsmith/core/services/context-words.test
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { extractContextWords } from './context-words.js';
|
|
10
|
+
describe('extractContextWords (SMI-5986)', () => {
|
|
11
|
+
it('keeps real short technical terms that the old length>3 threshold dropped', () => {
|
|
12
|
+
const words = extractContextWords('git ci aws sql k8s');
|
|
13
|
+
expect(words).toEqual(['git', 'ci', 'aws', 'sql', 'k8s']);
|
|
14
|
+
});
|
|
15
|
+
it('does not derive an empty stack from a context of only short technical terms', () => {
|
|
16
|
+
// SMI-5986 regression: this exact shape used to filter to [], which then
|
|
17
|
+
// tripped the SMI-5896 empty-stack guard even though the caller supplied
|
|
18
|
+
// usable context.
|
|
19
|
+
expect(extractContextWords('git').length).toBeGreaterThan(0);
|
|
20
|
+
expect(extractContextWords('ci').length).toBeGreaterThan(0);
|
|
21
|
+
});
|
|
22
|
+
it('drops single-character tokens as noise', () => {
|
|
23
|
+
expect(extractContextWords('a i x')).toEqual([]);
|
|
24
|
+
});
|
|
25
|
+
it('drops short English stopwords but keeps a real term in the same input', () => {
|
|
26
|
+
const words = extractContextWords('a be api testing');
|
|
27
|
+
expect(words).not.toContain('a');
|
|
28
|
+
expect(words).not.toContain('be');
|
|
29
|
+
expect(words).toContain('api');
|
|
30
|
+
expect(words).toContain('testing');
|
|
31
|
+
});
|
|
32
|
+
it('drops punctuation-only tokens', () => {
|
|
33
|
+
expect(extractContextWords('... -- !!')).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
it('drops tokens made entirely of + and #, not just other punctuation', () => {
|
|
36
|
+
// PR review round 3 (SMI-5986): + and # count as "keep" characters for
|
|
37
|
+
// stripEdgePunctuation (so "c++"/"c#" survive), but a token with no
|
|
38
|
+
// alphanumeric content at all ("++", "##", "+#") must still be rejected
|
|
39
|
+
// as noise — it isn't a real technical term just because it contains a
|
|
40
|
+
// "keep" character.
|
|
41
|
+
expect(extractContextWords('++ ## +#')).toEqual([]);
|
|
42
|
+
expect(extractContextWords('++')).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
it('drops a token that is leading-punctuation-only after stripping ("+++x" keeps content, "+++" alone does not)', () => {
|
|
45
|
+
expect(extractContextWords('+++')).toEqual([]);
|
|
46
|
+
expect(extractContextWords('+++git')).toEqual(['+++git']);
|
|
47
|
+
});
|
|
48
|
+
it('strips edge punctuation without mangling the term ("git," -> "git")', () => {
|
|
49
|
+
expect(extractContextWords('git,')).toEqual(['git']);
|
|
50
|
+
expect(extractContextWords('(sql)')).toEqual(['sql']);
|
|
51
|
+
});
|
|
52
|
+
it('is case-insensitive ("Git" -> "git")', () => {
|
|
53
|
+
expect(extractContextWords('Git')).toEqual(['git']);
|
|
54
|
+
expect(extractContextWords('AWS SQL')).toEqual(['aws', 'sql']);
|
|
55
|
+
});
|
|
56
|
+
it('preserves + and # as meaningful trailing characters, not strippable punctuation', () => {
|
|
57
|
+
// Code-review regression (SMI-5986): edge-punctuation stripping used to
|
|
58
|
+
// treat "+" and "#" as noise, turning "c++"/"c#" into the single
|
|
59
|
+
// character "c", which the length filter then discarded entirely.
|
|
60
|
+
expect(extractContextWords('c++')).toEqual(['c++']);
|
|
61
|
+
expect(extractContextWords('c#')).toEqual(['c#']);
|
|
62
|
+
expect(extractContextWords('c++,')).toEqual(['c++']);
|
|
63
|
+
expect(extractContextWords('(c#)')).toEqual(['c#']);
|
|
64
|
+
});
|
|
65
|
+
it('does not filter real technical terms that are also common English words', () => {
|
|
66
|
+
// Code-review regression (SMI-5986): "any" (TS/SQL keyword), "let"
|
|
67
|
+
// (JS/Rust keyword), and "can" (CAN-bus acronym) were previously in the
|
|
68
|
+
// stopword set, contradicting its own documented promise.
|
|
69
|
+
expect(extractContextWords('any')).toEqual(['any']);
|
|
70
|
+
expect(extractContextWords('let')).toEqual(['let']);
|
|
71
|
+
expect(extractContextWords('can')).toEqual(['can']);
|
|
72
|
+
});
|
|
73
|
+
it('leaves 4+ character words unaffected (pre-existing behavior preserved)', () => {
|
|
74
|
+
const words = extractContextWords('testing utilities framework');
|
|
75
|
+
expect(words).toEqual(['testing', 'utilities', 'framework']);
|
|
76
|
+
});
|
|
77
|
+
it('slices to the max word count (default 5)', () => {
|
|
78
|
+
const words = extractContextWords('one two three four five six seven');
|
|
79
|
+
expect(words).toHaveLength(5);
|
|
80
|
+
});
|
|
81
|
+
it('respects a custom maxWords argument', () => {
|
|
82
|
+
const words = extractContextWords('git ci aws sql k8s docker', 3);
|
|
83
|
+
expect(words).toEqual(['git', 'ci', 'aws']);
|
|
84
|
+
});
|
|
85
|
+
it('returns [] for undefined, null, or empty input', () => {
|
|
86
|
+
expect(extractContextWords(undefined)).toEqual([]);
|
|
87
|
+
expect(extractContextWords(null)).toEqual([]);
|
|
88
|
+
expect(extractContextWords('')).toEqual([]);
|
|
89
|
+
});
|
|
90
|
+
it('returns [] for whitespace-only input', () => {
|
|
91
|
+
expect(extractContextWords(' ')).toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=context-words.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-words.test.js","sourceRoot":"","sources":["../../../src/services/context-words.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -78,6 +78,14 @@ export interface InstallFromContentParams extends InstallFromContentOptions {
|
|
|
78
78
|
manifest: ManifestManager;
|
|
79
79
|
client: ClientId;
|
|
80
80
|
onProgress: ProgressCallback;
|
|
81
|
+
/**
|
|
82
|
+
* SMI-5982 code-review fix #1: base dir for resolving a relative companion-agent
|
|
83
|
+
* target (Antigravity only) — see writeInstallFiles()'s own doc comment.
|
|
84
|
+
* PR-review follow-up: optional (not required) — an omitted value must flow
|
|
85
|
+
* through to `resolveCompanionAgentPath()`'s own required-`baseDir` guard as
|
|
86
|
+
* `undefined`, not be silently defaulted anywhere in this chain.
|
|
87
|
+
*/
|
|
88
|
+
companionBaseDir?: string;
|
|
81
89
|
}
|
|
82
90
|
/**
|
|
83
91
|
* Install an already-resolved private-registry skill's content to disk.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-installation.content.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,KAAK,EACV,gBAAgB,EAChB,yBAAyB,EACzB,aAAa,EACd,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AA8C1D;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,WAAW,EAAE,MAAM,GAClB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAgCnD;AA8DD;;yCAEyC;AACzC,MAAM,WAAW,wBAAyB,SAAQ,yBAAyB;IACzE,EAAE,EAAE,QAAQ,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,eAAe,CAAA;IACzB,MAAM,EAAE,QAAQ,CAAA;IAChB,UAAU,EAAE,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"skill-installation.content.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,KAAK,EACV,gBAAgB,EAChB,yBAAyB,EACzB,aAAa,EACd,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AA8C1D;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,WAAW,EAAE,MAAM,GAClB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAgCnD;AA8DD;;yCAEyC;AACzC,MAAM,WAAW,wBAAyB,SAAQ,yBAAyB;IACzE,EAAE,EAAE,QAAQ,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,eAAe,CAAA;IACzB,MAAM,EAAE,QAAQ,CAAA;IAChB,UAAU,EAAE,gBAAgB,CAAA;IAC5B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC,CAqKjG"}
|
|
@@ -187,7 +187,7 @@ function skillNameFromSkillId(skillId) {
|
|
|
187
187
|
* See this file's header doc comment for the full scope trim vs. `install()`.
|
|
188
188
|
*/
|
|
189
189
|
export async function installFromContent(params) {
|
|
190
|
-
const { db, skillsDir, manifest, client, onProgress, skillId, version, content, force = false, } = params;
|
|
190
|
+
const { db, skillsDir, manifest, client, onProgress, skillId, version, content, force = false, companionBaseDir, } = params;
|
|
191
191
|
const skillName = skillNameFromSkillId(skillId);
|
|
192
192
|
const trustTier = CONTENT_INSTALL_TRUST_TIER;
|
|
193
193
|
if (skillName === null) {
|
|
@@ -273,7 +273,7 @@ export async function installFromContent(params) {
|
|
|
273
273
|
.map(([filename, fileContent]) => ({ filename, content: fileContent }));
|
|
274
274
|
const generatedNoCollision = subSkillFiles.filter((generated) => !teamAuthoredSubFiles.some((team) => team.filename === generated.filename));
|
|
275
275
|
onProgress('write', 'Writing skill files');
|
|
276
|
-
const writeResult = await writeInstallFiles(installPath, skillsDir, skillName, finalSkillContent, [...generatedNoCollision, ...teamAuthoredSubFiles], subagentContent);
|
|
276
|
+
const writeResult = await writeInstallFiles(installPath, skillsDir, skillName, finalSkillContent, [...generatedNoCollision, ...teamAuthoredSubFiles], subagentContent, client, companionBaseDir);
|
|
277
277
|
if (writeResult.subagentPath) {
|
|
278
278
|
optimizationInfo.subagentPath = writeResult.subagentPath;
|
|
279
279
|
}
|