@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
|
@@ -5,8 +5,29 @@
|
|
|
5
5
|
* and isSqlJsAvailable. The better-sqlite3 mock is scoped with vi.isolateModules()
|
|
6
6
|
* to prevent contaminating betterSqlite3Driver.test.ts.
|
|
7
7
|
*/
|
|
8
|
-
import { describe, it, expect, afterEach } from 'vitest';
|
|
8
|
+
import { describe, it, expect, afterEach, beforeEach, vi } from 'vitest';
|
|
9
|
+
import { existsSync, readFileSync, mkdtempSync, rmSync } from 'node:fs';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
9
12
|
import { createSqlJsDatabase, SqlJsDatabaseAdapter, isSqlJsAvailable, } from '../../src/db/drivers/sqljsDriver.js';
|
|
13
|
+
// SMI-5997: sqljsDriver.ts imports writeFileSync from 'node:fs' as a live ESM
|
|
14
|
+
// binding, which vi.spyOn cannot redefine ("Module namespace is not
|
|
15
|
+
// configurable in ESM"). vi.mock + importOriginal is the supported way to
|
|
16
|
+
// intercept a single named export while passing everything else through.
|
|
17
|
+
const failNextWrite = vi.hoisted(() => ({ value: false }));
|
|
18
|
+
vi.mock('node:fs', async (importOriginal) => {
|
|
19
|
+
const actual = await importOriginal();
|
|
20
|
+
return {
|
|
21
|
+
...actual,
|
|
22
|
+
writeFileSync: (...args) => {
|
|
23
|
+
if (failNextWrite.value) {
|
|
24
|
+
failNextWrite.value = false;
|
|
25
|
+
throw new Error('simulated crash mid-write');
|
|
26
|
+
}
|
|
27
|
+
return actual.writeFileSync(...args);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
});
|
|
10
31
|
describe('sqljsDriver — edge cases', () => {
|
|
11
32
|
describe('isSqlJsAvailable', () => {
|
|
12
33
|
it('returns true when fts5-sql-bundle is resolvable', () => {
|
|
@@ -71,5 +92,46 @@ describe('sqljsDriver — edge cases', () => {
|
|
|
71
92
|
await expect(createSqlJsDatabase(nonExistentPath, { fileMustExist: true })).rejects.toThrow(/SQLITE_CANTOPEN/);
|
|
72
93
|
});
|
|
73
94
|
});
|
|
95
|
+
describe('persist() — atomic write (SMI-5997)', () => {
|
|
96
|
+
let dir;
|
|
97
|
+
let dbPath;
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
dir = mkdtempSync(join(tmpdir(), 'sqljs-persist-'));
|
|
100
|
+
dbPath = join(dir, 'test.db');
|
|
101
|
+
});
|
|
102
|
+
afterEach(() => {
|
|
103
|
+
failNextWrite.value = false;
|
|
104
|
+
rmSync(dir, { recursive: true, force: true });
|
|
105
|
+
});
|
|
106
|
+
it('writes via temp file + rename, leaving no leftover .tmp file', async () => {
|
|
107
|
+
const db = await createSqlJsDatabase(dbPath);
|
|
108
|
+
db.exec('CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)');
|
|
109
|
+
db.exec("INSERT INTO t (name) VALUES ('alpha')");
|
|
110
|
+
db.persist();
|
|
111
|
+
expect(existsSync(dbPath)).toBe(true);
|
|
112
|
+
expect(existsSync(`${dbPath}.tmp`)).toBe(false);
|
|
113
|
+
expect(readFileSync(dbPath).length).toBeGreaterThan(0);
|
|
114
|
+
db.close();
|
|
115
|
+
});
|
|
116
|
+
it('leaves the original file byte-for-byte untouched if the write is interrupted', async () => {
|
|
117
|
+
const db = await createSqlJsDatabase(dbPath);
|
|
118
|
+
db.exec('CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)');
|
|
119
|
+
db.exec("INSERT INTO t (name) VALUES ('alpha')");
|
|
120
|
+
db.persist();
|
|
121
|
+
const originalContent = readFileSync(dbPath);
|
|
122
|
+
expect(originalContent.length).toBeGreaterThan(0);
|
|
123
|
+
db.exec("INSERT INTO t (name) VALUES ('beta')");
|
|
124
|
+
// Simulate a crash/kill mid-write: writeFileSync (to the temp file)
|
|
125
|
+
// throws before rename() ever runs.
|
|
126
|
+
failNextWrite.value = true;
|
|
127
|
+
expect(() => db.persist()).toThrow('simulated crash mid-write');
|
|
128
|
+
// Reproduces the SMI-5997 incident check in reverse: the real file
|
|
129
|
+
// must never be truncated by a failed write, only ever replaced
|
|
130
|
+
// wholesale by a successful rename().
|
|
131
|
+
expect(readFileSync(dbPath)).toEqual(originalContent);
|
|
132
|
+
expect(existsSync(`${dbPath}.tmp`)).toBe(false);
|
|
133
|
+
db.close();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
74
136
|
});
|
|
75
137
|
//# sourceMappingURL=sqljsDriver.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqljsDriver.test.js","sourceRoot":"","sources":["../../../tests/db/sqljsDriver.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"sqljsDriver.test.js","sourceRoot":"","sources":["../../../tests/db/sqljsDriver.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
* SMI-577: Database Schema Tests
|
|
3
3
|
*/
|
|
4
4
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
5
|
-
import {
|
|
5
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { createDatabase, openDatabase, closeDatabase, getSchemaVersion, runMigrations, SCHEMA_VERSION, } from '../src/db/schema.js';
|
|
9
|
+
import { isBetterSqlite3Available } from '../src/db/drivers/betterSqlite3Driver.js';
|
|
6
10
|
describe('Database Schema', () => {
|
|
7
11
|
let db;
|
|
8
12
|
beforeEach(() => {
|
|
@@ -163,6 +167,44 @@ describe('Database Schema', () => {
|
|
|
163
167
|
expect(indexNames).toContain('idx_skills_quality_score');
|
|
164
168
|
});
|
|
165
169
|
});
|
|
170
|
+
describe('openDatabase — empty/corrupt database detection (SMI-5997)', () => {
|
|
171
|
+
let dir;
|
|
172
|
+
beforeEach(() => {
|
|
173
|
+
dir = mkdtempSync(join(tmpdir(), 'schema-open-sync-'));
|
|
174
|
+
});
|
|
175
|
+
afterEach(() => {
|
|
176
|
+
rmSync(dir, { recursive: true, force: true });
|
|
177
|
+
});
|
|
178
|
+
it('throws an actionable error for a 0-byte file (no tables, no schema_version)', () => {
|
|
179
|
+
if (!isBetterSqlite3Available()) {
|
|
180
|
+
console.log('Skipping test: no SQLite driver available');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const testPath = join(dir, 'empty-corrupt.db');
|
|
184
|
+
// Reproduces the SMI-5997 incident via the deprecated sync path
|
|
185
|
+
// (packages/cli/src/commands/merge.ts still calls openDatabase()
|
|
186
|
+
// directly) — SQLite treats a 0-byte file as a valid, openable, empty
|
|
187
|
+
// database, so this must be caught by the zero-table check rather
|
|
188
|
+
// than a native SQLITE_CANTOPEN/corruption error.
|
|
189
|
+
writeFileSync(testPath, Buffer.alloc(0));
|
|
190
|
+
expect(() => openDatabase(testPath)).toThrow(/empty or corrupt/);
|
|
191
|
+
});
|
|
192
|
+
it('still treats a file with real tables but no schema_version as a legacy import', () => {
|
|
193
|
+
if (!isBetterSqlite3Available()) {
|
|
194
|
+
console.log('Skipping test: no SQLite driver available');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const testPath = join(dir, 'legacy-import.db');
|
|
198
|
+
const seedDb = createDatabase(testPath);
|
|
199
|
+
seedDb.exec('DROP TABLE schema_version');
|
|
200
|
+
closeDatabase(seedDb);
|
|
201
|
+
const reopened = openDatabase(testPath);
|
|
202
|
+
expect(reopened.open).toBe(true);
|
|
203
|
+
const version = getSchemaVersion(reopened);
|
|
204
|
+
expect(version).toBe(SCHEMA_VERSION);
|
|
205
|
+
closeDatabase(reopened);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
166
208
|
describe('closeDatabase (SMI-4640)', () => {
|
|
167
209
|
it('tolerates undefined without throwing', () => {
|
|
168
210
|
expect(() => closeDatabase(undefined)).not.toThrow();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../tests/schema.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../tests/schema.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5980 (Wave 3): writeInstallFiles must route the companion-subagent
|
|
3
|
+
* write through COMPANION_AGENT_TARGETS (install/paths.ts) for the caller's
|
|
4
|
+
* `client`, not a hardcoded `path.join(os.homedir(), '.claude', 'agents')`
|
|
5
|
+
* literal.
|
|
6
|
+
*
|
|
7
|
+
* `homedir()` is mocked to a controlled tmp directory BEFORE `paths.ts` is
|
|
8
|
+
* first imported — COMPANION_AGENT_TARGETS is a module-level constant
|
|
9
|
+
* computed once at import time from `homedir()`, so every assertion below
|
|
10
|
+
* compares against that SAME already-resolved map rather than a second,
|
|
11
|
+
* independently-hardcoded expectation. This also keeps the test from ever
|
|
12
|
+
* writing to a real developer/CI machine's actual home directory.
|
|
13
|
+
*
|
|
14
|
+
* SMI-5982 (Wave 6): antigravity's `COMPANION_AGENT_TARGETS` entry uses a
|
|
15
|
+
* RELATIVE `dir` (resolved against `process.cwd()`, not `homedir()`) — its
|
|
16
|
+
* own dedicated describe block below chdir's into an isolated tmp directory
|
|
17
|
+
* per test (never TEST_HOME, never the real repo checkout) rather than
|
|
18
|
+
* relying on the homedir() mock every other client's assertions use.
|
|
19
|
+
*
|
|
20
|
+
* SMI-5982 code-review fix #1 (BLOCKING, cwd-dependent resolution):
|
|
21
|
+
* `writeInstallFiles()` now resolves antigravity's relative `dir` via
|
|
22
|
+
* `resolveCompanionAgentPath()`'s explicit `baseDir` param (defaulting to
|
|
23
|
+
* `process.cwd()` at the call site, not deferred to whatever `fs` call
|
|
24
|
+
* eventually consumes the path) — so `result.subagentPath` is now an
|
|
25
|
+
* ABSOLUTE path even for antigravity, not the raw relative string. The
|
|
26
|
+
* `it.each` below covers both the omitted-`companionBaseDir` (falls back to
|
|
27
|
+
* `process.cwd()`, which this describe block's chdir controls) and an
|
|
28
|
+
* explicit `companionBaseDir` override.
|
|
29
|
+
*
|
|
30
|
+
* Split out of skill-installation.io.test.ts to stay under the 500-line
|
|
31
|
+
* CI gate (same rationale as skill-installation.io.symlink.test.ts).
|
|
32
|
+
*/
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=skill-installation.io.client-agent-path.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.io.client-agent-path.test.d.ts","sourceRoot":"","sources":["../../../../tests/unit/services/skill-installation.io.client-agent-path.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5980 (Wave 3): writeInstallFiles must route the companion-subagent
|
|
3
|
+
* write through COMPANION_AGENT_TARGETS (install/paths.ts) for the caller's
|
|
4
|
+
* `client`, not a hardcoded `path.join(os.homedir(), '.claude', 'agents')`
|
|
5
|
+
* literal.
|
|
6
|
+
*
|
|
7
|
+
* `homedir()` is mocked to a controlled tmp directory BEFORE `paths.ts` is
|
|
8
|
+
* first imported — COMPANION_AGENT_TARGETS is a module-level constant
|
|
9
|
+
* computed once at import time from `homedir()`, so every assertion below
|
|
10
|
+
* compares against that SAME already-resolved map rather than a second,
|
|
11
|
+
* independently-hardcoded expectation. This also keeps the test from ever
|
|
12
|
+
* writing to a real developer/CI machine's actual home directory.
|
|
13
|
+
*
|
|
14
|
+
* SMI-5982 (Wave 6): antigravity's `COMPANION_AGENT_TARGETS` entry uses a
|
|
15
|
+
* RELATIVE `dir` (resolved against `process.cwd()`, not `homedir()`) — its
|
|
16
|
+
* own dedicated describe block below chdir's into an isolated tmp directory
|
|
17
|
+
* per test (never TEST_HOME, never the real repo checkout) rather than
|
|
18
|
+
* relying on the homedir() mock every other client's assertions use.
|
|
19
|
+
*
|
|
20
|
+
* SMI-5982 code-review fix #1 (BLOCKING, cwd-dependent resolution):
|
|
21
|
+
* `writeInstallFiles()` now resolves antigravity's relative `dir` via
|
|
22
|
+
* `resolveCompanionAgentPath()`'s explicit `baseDir` param (defaulting to
|
|
23
|
+
* `process.cwd()` at the call site, not deferred to whatever `fs` call
|
|
24
|
+
* eventually consumes the path) — so `result.subagentPath` is now an
|
|
25
|
+
* ABSOLUTE path even for antigravity, not the raw relative string. The
|
|
26
|
+
* `it.each` below covers both the omitted-`companionBaseDir` (falls back to
|
|
27
|
+
* `process.cwd()`, which this describe block's chdir controls) and an
|
|
28
|
+
* explicit `companionBaseDir` override.
|
|
29
|
+
*
|
|
30
|
+
* Split out of skill-installation.io.test.ts to stay under the 500-line
|
|
31
|
+
* CI gate (same rationale as skill-installation.io.symlink.test.ts).
|
|
32
|
+
*/
|
|
33
|
+
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
34
|
+
import * as fs from 'fs/promises';
|
|
35
|
+
import * as path from 'path';
|
|
36
|
+
import * as os from 'node:os';
|
|
37
|
+
const { TEST_HOME, homedirMock } = vi.hoisted(() => {
|
|
38
|
+
const home = '/tmp/skillsmith-wif-client-agent-path-test-' + process.pid;
|
|
39
|
+
return { TEST_HOME: home, homedirMock: vi.fn(() => home) };
|
|
40
|
+
});
|
|
41
|
+
vi.mock('node:os', async (importOriginal) => {
|
|
42
|
+
const actual = await importOriginal();
|
|
43
|
+
return { ...actual, homedir: homedirMock };
|
|
44
|
+
});
|
|
45
|
+
import { writeInstallFiles } from '../../../src/services/skill-installation.io.js';
|
|
46
|
+
import { CLIENT_IDS, COMPANION_AGENT_TARGETS } from '../../../src/install/paths.js';
|
|
47
|
+
afterAll(async () => {
|
|
48
|
+
await fs.rm(TEST_HOME, { recursive: true, force: true }).catch(() => { });
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Fresh skillsDir/installPath per test so parallel `it.each` iterations
|
|
52
|
+
* (all sharing TEST_HOME) never collide with each other.
|
|
53
|
+
*/
|
|
54
|
+
async function freshInstallPath(label) {
|
|
55
|
+
const skillsDir = path.join(TEST_HOME, 'src', label, 'skills');
|
|
56
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
57
|
+
return { skillsDir, installPath: path.join(skillsDir, 'my-skill') };
|
|
58
|
+
}
|
|
59
|
+
describe('writeInstallFiles companion-subagent path per client (SMI-5980 regression)', () => {
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
homedirMock.mockReturnValue(TEST_HOME);
|
|
62
|
+
});
|
|
63
|
+
// SMI-5982 (Wave 6): antigravity is excluded from this generic 'flat'
|
|
64
|
+
// it.each — its dir is a RELATIVE path (resolved against process.cwd(),
|
|
65
|
+
// NOT the mocked homedir()), so writing it here would land outside
|
|
66
|
+
// TEST_HOME, pollute the real working tree, and never get cleaned up by
|
|
67
|
+
// this file's afterAll. It gets its own cwd-isolated describe block below.
|
|
68
|
+
it.each(CLIENT_IDS.filter((id) => id !== 'antigravity'))('writes the companion subagent for client=%s at exactly COMPANION_AGENT_TARGETS[client]', async (client) => {
|
|
69
|
+
const { skillsDir, installPath } = await freshInstallPath(client);
|
|
70
|
+
const result = await writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], '---\nname: my-skill-specialist\n---\nbody', client);
|
|
71
|
+
// Every remaining client uses 'flat' mode (copilot's own
|
|
72
|
+
// '{name}.agent.md' pattern, SMI-5980 PR-review finding, included).
|
|
73
|
+
const target = COMPANION_AGENT_TARGETS[client];
|
|
74
|
+
const expectedPath = path.join(target.dir, target.filenamePattern.replace('{name}', 'my-skill'));
|
|
75
|
+
expect(result.subagentPath).toBe(expectedPath);
|
|
76
|
+
expect(await fs.readFile(expectedPath, 'utf8')).toBe('---\nname: my-skill-specialist\n---\nbody');
|
|
77
|
+
});
|
|
78
|
+
it('defaults to the canonical (claude-code) target when client is omitted (regression: unchanged)', async () => {
|
|
79
|
+
const { skillsDir, installPath } = await freshInstallPath('default-client');
|
|
80
|
+
const result = await writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], 'subagent body'
|
|
81
|
+
// client omitted — must resolve exactly like the old hardcoded default.
|
|
82
|
+
);
|
|
83
|
+
const expectedPath = path.join(COMPANION_AGENT_TARGETS['claude-code'].dir, 'my-skill-specialist.md');
|
|
84
|
+
expect(result.subagentPath).toBe(expectedPath);
|
|
85
|
+
expect(await fs.readFile(expectedPath, 'utf8')).toBe('subagent body');
|
|
86
|
+
});
|
|
87
|
+
it('claude-code and cursor land in the SAME directory (both default, no independent evidence for cursor)', async () => {
|
|
88
|
+
const claudeCode = await freshInstallPath('cc-vs-cursor-claude');
|
|
89
|
+
const cursor = await freshInstallPath('cc-vs-cursor-cursor');
|
|
90
|
+
const claudeResult = await writeInstallFiles(claudeCode.installPath, claudeCode.skillsDir, 'my-skill', '# hello', [], 'body', 'claude-code');
|
|
91
|
+
const cursorResult = await writeInstallFiles(cursor.installPath, cursor.skillsDir, 'my-skill', '# hello', [], 'body', 'cursor');
|
|
92
|
+
expect(path.dirname(cursorResult.subagentPath ?? '')).toBe(path.dirname(claudeResult.subagentPath ?? ''));
|
|
93
|
+
});
|
|
94
|
+
it('copilot and opencode land at their own real, literal directories (code-review finding: not just "different from claude-code")', async () => {
|
|
95
|
+
const copilot = await freshInstallPath('copilot-diff');
|
|
96
|
+
const opencode = await freshInstallPath('opencode-diff');
|
|
97
|
+
const copilotResult = await writeInstallFiles(copilot.installPath, copilot.skillsDir, 'my-skill', '# hello', [], 'body', 'copilot');
|
|
98
|
+
const opencodeResult = await writeInstallFiles(opencode.installPath, opencode.skillsDir, 'my-skill', '# hello', [], 'body', 'opencode');
|
|
99
|
+
// Independently-constructed literal expected paths (via the SAME mocked
|
|
100
|
+
// TEST_HOME this file's own homedir() mock uses, but NOT derived from
|
|
101
|
+
// COMPANION_AGENT_TARGETS itself) — a code-review pass on an earlier
|
|
102
|
+
// version of this test caught that comparing only against
|
|
103
|
+
// COMPANION_AGENT_TARGETS['claude-code'].dir proves "different from
|
|
104
|
+
// claude-code," not "equals the actual intended copilot/opencode value";
|
|
105
|
+
// a typo in the map (e.g. singular '.copilot/agent') would have still
|
|
106
|
+
// passed the old assertion.
|
|
107
|
+
expect(path.dirname(copilotResult.subagentPath ?? '')).toBe(path.join(TEST_HOME, '.copilot', 'agents'));
|
|
108
|
+
expect(path.dirname(opencodeResult.subagentPath ?? '')).toBe(path.join(TEST_HOME, '.config', 'opencode', 'agents'));
|
|
109
|
+
// Belt-and-suspenders: still confirm both differ from claude-code's dir.
|
|
110
|
+
expect(path.dirname(copilotResult.subagentPath ?? '')).not.toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
111
|
+
expect(path.dirname(opencodeResult.subagentPath ?? '')).not.toBe(COMPANION_AGENT_TARGETS['claude-code'].dir);
|
|
112
|
+
});
|
|
113
|
+
it('does not write any companion-subagent file when subagentContent is undefined, regardless of client', async () => {
|
|
114
|
+
const { skillsDir, installPath } = await freshInstallPath('no-subagent');
|
|
115
|
+
const result = await writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], undefined, 'copilot');
|
|
116
|
+
expect(result.subagentPath).toBeUndefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
/**
|
|
120
|
+
* SMI-5982 (Wave 6): antigravity's companion-agent dir is a RELATIVE path
|
|
121
|
+
* (`.agents/agents`, project-scoped per the plan's Step 1 — no existing
|
|
122
|
+
* global-vs-project distinction to hook into) resolved against
|
|
123
|
+
* `process.cwd()`, unlike every other client's `homedir()`-anchored
|
|
124
|
+
* absolute dir. This describe block is isolated from the rest of the file:
|
|
125
|
+
* each test chdir's into its own fresh tmp directory (never TEST_HOME, and
|
|
126
|
+
* never the real repo checkout) and restores the original cwd in
|
|
127
|
+
* `afterEach` even on assertion failure, so a broken assertion can never
|
|
128
|
+
* leave the whole test PROCESS's cwd corrupted for later tests/files.
|
|
129
|
+
*/
|
|
130
|
+
describe('writeInstallFiles companion-subagent path for antigravity (directory-package, SMI-5982 Wave 6)', () => {
|
|
131
|
+
let originalCwd;
|
|
132
|
+
let projectDir;
|
|
133
|
+
beforeEach(async () => {
|
|
134
|
+
originalCwd = process.cwd();
|
|
135
|
+
projectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'skillsmith-antigravity-cwd-'));
|
|
136
|
+
process.chdir(projectDir);
|
|
137
|
+
});
|
|
138
|
+
afterEach(async () => {
|
|
139
|
+
process.chdir(originalCwd);
|
|
140
|
+
await fs.rm(projectDir, { recursive: true, force: true }).catch(() => { });
|
|
141
|
+
});
|
|
142
|
+
it('writes agent.md inside a skill-named subdirectory when companionBaseDir is passed explicitly (SMI-5982 code-review fix #1)', async () => {
|
|
143
|
+
const { skillsDir, installPath } = await freshInstallPath('antigravity-write');
|
|
144
|
+
const result = await writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], '---\nname: my-skill-specialist\n---\nbody', 'antigravity',
|
|
145
|
+
// PR-review follow-up: writeInstallFiles() no longer falls back to
|
|
146
|
+
// process.cwd() itself when companionBaseDir is omitted — an explicit
|
|
147
|
+
// value (here, this describe block's chdir target) is required for
|
|
148
|
+
// directory-package clients. See the dedicated "omitted
|
|
149
|
+
// companionBaseDir" test below for the fail-closed case.
|
|
150
|
+
projectDir);
|
|
151
|
+
// SMI-5982 code-review fix #1: resolveCompanionAgentPath() resolves
|
|
152
|
+
// antigravity's relative dir against the explicit baseDir BEFORE
|
|
153
|
+
// returning — so subagentPath is ABSOLUTE, not the raw relative string.
|
|
154
|
+
// Independently verify the REAL file via an absolute path built from the
|
|
155
|
+
// known projectDir (not derived from result.subagentPath, so a bug that
|
|
156
|
+
// silently mis-resolved the value would still be caught).
|
|
157
|
+
const expectedRelativePath = path.join('.agents', 'agents', 'my-skill', 'agent.md');
|
|
158
|
+
const expectedAbsolutePath = path.join(projectDir, expectedRelativePath);
|
|
159
|
+
expect(result.subagentPath).toBe(expectedAbsolutePath);
|
|
160
|
+
expect(await fs.readFile(expectedAbsolutePath, 'utf8')).toBe('---\nname: my-skill-specialist\n---\nbody');
|
|
161
|
+
// Directory-package structure: agent.md lives INSIDE a subdirectory
|
|
162
|
+
// named after the skill, not directly inside the agents dir.
|
|
163
|
+
expect(path.basename(path.dirname(expectedAbsolutePath))).toBe('my-skill');
|
|
164
|
+
});
|
|
165
|
+
it('omitting companionBaseDir for antigravity now rejects the install instead of silently defaulting to process.cwd() (PR-review follow-up)', async () => {
|
|
166
|
+
const { skillsDir, installPath } = await freshInstallPath('antigravity-omitted-basedir');
|
|
167
|
+
await expect(writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], '---\nname: my-skill-specialist\n---\nbody', 'antigravity'
|
|
168
|
+
// companionBaseDir omitted — must now throw (fail closed), not
|
|
169
|
+
// resolve against process.cwd(). SKILL.md IS written before this
|
|
170
|
+
// point (the companion-agent step runs last), but writeInstallFiles'
|
|
171
|
+
// existing rollback-on-failure logic unwinds installPath entirely on
|
|
172
|
+
// any thrown error — so nothing survives on disk after the throw.
|
|
173
|
+
)).rejects.toThrow(/directory-package mode.*explicit baseDir is required/s);
|
|
174
|
+
await expect(fs.access(installPath)).rejects.toThrow();
|
|
175
|
+
});
|
|
176
|
+
it('writes agent.md resolved against an explicit companionBaseDir, not process.cwd() (SMI-5982 code-review fix #1)', async () => {
|
|
177
|
+
// Deliberately DIFFERENT from projectDir (this block's chdir target) to
|
|
178
|
+
// prove companionBaseDir — not the ambient cwd — drives resolution. This
|
|
179
|
+
// is exactly the MCP-server scenario the fix targets: a long-running
|
|
180
|
+
// process whose own cwd does not track the caller's real project.
|
|
181
|
+
const explicitBaseDir = await fs.mkdtemp(path.join(os.tmpdir(), 'skillsmith-antigravity-explicit-basedir-'));
|
|
182
|
+
try {
|
|
183
|
+
const { skillsDir, installPath } = await freshInstallPath('antigravity-explicit-basedir');
|
|
184
|
+
const result = await writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], '---\nname: my-skill-specialist\n---\nbody', 'antigravity', explicitBaseDir);
|
|
185
|
+
const expectedAbsolutePath = path.join(explicitBaseDir, '.agents', 'agents', 'my-skill', 'agent.md');
|
|
186
|
+
expect(result.subagentPath).toBe(expectedAbsolutePath);
|
|
187
|
+
expect(result.subagentPath?.startsWith(projectDir)).toBe(false);
|
|
188
|
+
expect(await fs.readFile(expectedAbsolutePath, 'utf8')).toBe('---\nname: my-skill-specialist\n---\nbody');
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
await fs.rm(explicitBaseDir, { recursive: true, force: true }).catch(() => { });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
it('a safeWriteFile failure on the companion-agent path does not crash, and never force-removes a non-empty per-skill directory', async () => {
|
|
195
|
+
// Reachable, non-mocked failure mode for the LAST step in
|
|
196
|
+
// writeInstallFiles's try block (companion-agent write): a symlink
|
|
197
|
+
// already sitting at the exact target path. safeWriteFile's O_NOFOLLOW
|
|
198
|
+
// open() refuses it (SymlinkError), so the rollback branch added in
|
|
199
|
+
// SMI-5982 runs with subagentPath already assigned. The per-skill
|
|
200
|
+
// directory is NOT empty (the symlink itself is still inside it), so
|
|
201
|
+
// the rollback's rmdir() must be a safe no-op here, never a force-delete
|
|
202
|
+
// — this proves the fix degrades safely rather than that it always
|
|
203
|
+
// reclaims disk space (an EMPTY orphaned directory can only arise from a
|
|
204
|
+
// transient I/O failure between mkdir and the write, not reproducible
|
|
205
|
+
// deterministically without mocking fs internals).
|
|
206
|
+
const { skillsDir, installPath } = await freshInstallPath('antigravity-symlink');
|
|
207
|
+
const agentSkillDir = path.join(projectDir, '.agents', 'agents', 'my-skill');
|
|
208
|
+
await fs.mkdir(agentSkillDir, { recursive: true });
|
|
209
|
+
await fs.symlink('/nonexistent-target', path.join(agentSkillDir, 'agent.md'));
|
|
210
|
+
await expect(writeInstallFiles(installPath, skillsDir, 'my-skill', '# hello', [], '---\nname: my-skill-specialist\n---\nbody', 'antigravity',
|
|
211
|
+
// PR-review follow-up: explicit now that writeInstallFiles() no
|
|
212
|
+
// longer defaults a missing companionBaseDir to process.cwd() —
|
|
213
|
+
// required so this test still reaches the symlink failure it is
|
|
214
|
+
// actually exercising, rather than the (also-now-thrown)
|
|
215
|
+
// required-baseDir guard.
|
|
216
|
+
projectDir)).rejects.toThrow(/symlink/i);
|
|
217
|
+
// The directory (and its symlink) must still exist — rollback did not
|
|
218
|
+
// blindly force-delete non-empty content.
|
|
219
|
+
const stats = await fs.lstat(agentSkillDir);
|
|
220
|
+
expect(stats.isDirectory()).toBe(true);
|
|
221
|
+
});
|
|
222
|
+
it('rejects a path-traversal skillName ("..") for the companion-agent path and rolls back the already-written SKILL.md (SMI-5982 code-review fix #2)', async () => {
|
|
223
|
+
// resolveCompanionAgentPath()'s own directory-package validation (fix #2)
|
|
224
|
+
// is the last line of defense here: this test passes a malicious
|
|
225
|
+
// skillName distinct from what installPath was built from, exactly the
|
|
226
|
+
// "a future caller bypasses upstream sanitization" scenario the fix's
|
|
227
|
+
// doc comment calls out.
|
|
228
|
+
const { skillsDir, installPath } = await freshInstallPath('antigravity-traversal');
|
|
229
|
+
await expect(writeInstallFiles(installPath, skillsDir, '..', '# hello', [], '---\nname: specialist\n---\nbody', 'antigravity',
|
|
230
|
+
// PR-review follow-up: explicit now that writeInstallFiles() no
|
|
231
|
+
// longer defaults a missing companionBaseDir to process.cwd() —
|
|
232
|
+
// required so this test still reaches the skillName traversal
|
|
233
|
+
// guard it is actually exercising, rather than the
|
|
234
|
+
// (also-now-thrown) required-baseDir guard.
|
|
235
|
+
projectDir)).rejects.toThrow(/Unsafe skill name for directory-package companion path/);
|
|
236
|
+
// Rollback: the existing catch block in writeInstallFiles() already
|
|
237
|
+
// covers this — SKILL.md was written before the throw (subagentPath is
|
|
238
|
+
// resolved last), so it (and installPath itself) must be gone. Nothing
|
|
239
|
+
// was ever created under the companion-agent dir, since the throw
|
|
240
|
+
// happens BEFORE any fs.mkdir/write for that path.
|
|
241
|
+
await expect(fs.access(installPath)).rejects.toThrow();
|
|
242
|
+
const agentsParentDir = path.join(projectDir, '.agents');
|
|
243
|
+
await expect(fs.access(agentsParentDir)).rejects.toThrow();
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
//# sourceMappingURL=skill-installation.io.client-agent-path.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.io.client-agent-path.test.js","sourceRoot":"","sources":["../../../../tests/unit/services/skill-installation.io.client-agent-path.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5982 code-review fix #1 (BLOCKING, cwd-dependent resolution):
|
|
3
|
+
* `SkillInstallationService`'s `companionBaseDir` constructor param must
|
|
4
|
+
* thread all the way through `install()` -> `writeInstallFiles()` ->
|
|
5
|
+
* `resolveCompanionAgentPath()` so the Antigravity companion-agent file
|
|
6
|
+
* lands under an explicitly-passed root, not whatever `process.cwd()`
|
|
7
|
+
* happens to be at the moment the write actually runs — the exact hazard
|
|
8
|
+
* for a long-running MCP server whose cwd is fixed at launch and does not
|
|
9
|
+
* track the calling editor/agent's real project.
|
|
10
|
+
*
|
|
11
|
+
* `applyOptimization` (skill-installation.helpers.ts) is mocked to force a
|
|
12
|
+
* deterministic `subagentContent` without depending on the real
|
|
13
|
+
* TransformationService's content-shape heuristics — this test is about
|
|
14
|
+
* PATH WIRING, not optimization behavior, which is covered elsewhere.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=skill-installation.service.companion-basedir.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.service.companion-basedir.test.d.ts","sourceRoot":"","sources":["../../../../tests/unit/services/skill-installation.service.companion-basedir.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|