@skaile/workspaces 0.44.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/dist/{asset-feeds-EGSG4FUB.js → asset-feeds-AOZLZMDV.js} +2 -2
- package/dist/{asset-feeds-EGSG4FUB.js.map → asset-feeds-AOZLZMDV.js.map} +1 -1
- package/dist/asset-manager/index.js +1 -1
- package/dist/asset-manager/src/index.d.ts +47 -0
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/{chunk-NHLXS2CH.js → chunk-JUZGLINM.js} +2 -2
- package/dist/{chunk-NHLXS2CH.js.map → chunk-JUZGLINM.js.map} +1 -1
- package/dist/{chunk-JUZLVRI4.js → chunk-L6BKSTAX.js} +71 -4
- package/dist/chunk-L6BKSTAX.js.map +1 -0
- package/dist/{chunk-7NQXVBCQ.js → chunk-LHUCCPH4.js} +2 -2
- package/dist/{chunk-7NQXVBCQ.js.map → chunk-LHUCCPH4.js.map} +1 -1
- package/dist/{chunk-5LHPKVGR.js → chunk-N2KV5RK3.js} +121 -4
- package/dist/chunk-N2KV5RK3.js.map +1 -0
- package/dist/cli/index.js +841 -553
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/catalog.d.ts +9 -3
- package/dist/cli/src/commands/catalog.d.ts.map +1 -1
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/skailify-lib.d.ts +108 -0
- package/dist/cli/src/commands/skailify-lib.d.ts.map +1 -0
- package/dist/core/index.js +1 -1
- package/dist/core/src/index.d.ts +1 -1
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/run-flow.js +1 -1
- package/dist/factory-assets/skaile.manifest.yaml +3 -0
- package/dist/factory-assets/skills/skailify/SKILL.md +84 -0
- package/dist/{plugin-store-RBCDBO7K.js → plugin-store-2X2YXJVG.js} +2 -2
- package/dist/{plugin-store-RBCDBO7K.js.map → plugin-store-2X2YXJVG.js.map} +1 -1
- package/dist/runner/index.js +2 -2
- package/dist/runner/src/file-changed-coalescer.d.ts +48 -0
- package/dist/runner/src/file-changed-coalescer.d.ts.map +1 -0
- package/dist/runner/src/resources.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +1 -1
- package/dist/sdk/core.js +1 -1
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/runner.js +2 -2
- package/dist/tui/index.js +2 -2
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5LHPKVGR.js.map +0 -1
- package/dist/chunk-JUZLVRI4.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -9,11 +9,11 @@ import '../chunk-5FVJXQDP.js';
|
|
|
9
9
|
import '../chunk-JXT46QFC.js';
|
|
10
10
|
import '../chunk-UKJMQZV6.js';
|
|
11
11
|
import '../chunk-R7FOF242.js';
|
|
12
|
-
import { runFlow, resumeFlow } from '../chunk-
|
|
12
|
+
import { runFlow, resumeFlow } from '../chunk-LHUCCPH4.js';
|
|
13
13
|
import '../chunk-4R6DROGN.js';
|
|
14
14
|
import { validateFlowVersions, parseSkillFrontmatter } from '../chunk-GXC3TYMQ.js';
|
|
15
|
-
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-
|
|
16
|
-
import { buildClaudePluginFiles } from '../chunk-
|
|
15
|
+
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-N2KV5RK3.js';
|
|
16
|
+
import { buildClaudePluginFiles } from '../chunk-JUZGLINM.js';
|
|
17
17
|
import '../chunk-X5YPJV4N.js';
|
|
18
18
|
import '../chunk-O7SG5PC2.js';
|
|
19
19
|
import '../chunk-7QBNJTTQ.js';
|
|
@@ -36,15 +36,15 @@ import '../chunk-6E6PKKAD.js';
|
|
|
36
36
|
import { loadFlow, loadAllFlows } from '../chunk-X46FY45B.js';
|
|
37
37
|
import '../chunk-DEYYRFQU.js';
|
|
38
38
|
import '../chunk-IFGTRL2I.js';
|
|
39
|
-
import { AssetManager, NON_DEPLOYABLE_KINDS } from '../chunk-
|
|
39
|
+
import { AssetManager, NON_DEPLOYABLE_KINDS, MissingManifestError } from '../chunk-L6BKSTAX.js';
|
|
40
40
|
import '../chunk-CVWA4RIK.js';
|
|
41
41
|
import { readLock, resolveSettings, globalSettingsPath, projectSettingsPath, loadSettings, saveSettings, portableSpawn, portableSpawnSync, WorkspaceYamlEditor } from '../chunk-BLGHFVXE.js';
|
|
42
42
|
import { assetSearchDirs, detectDomains } from '../chunk-ZAP2BDHG.js';
|
|
43
43
|
import '../chunk-VPXV2Z5E.js';
|
|
44
44
|
import { globalCacheRoot, getGlobalCacheDir, resolveAgentDir, findWorkspaceRoot, workspaceConfigFilename, resolveSkWorkspaceConfig } from '../chunk-COSTF7QW.js';
|
|
45
|
-
import { SKAILE_MANIFEST_FILENAME, decodeSkaileManifest } from '../chunk-DZCK7GRW.js';
|
|
45
|
+
import { SKAILE_MANIFEST_FILENAME, decodeSkaileManifest, loadSkPublishManifest, saveSkPublishManifest } from '../chunk-DZCK7GRW.js';
|
|
46
46
|
import { parseFrontmatter } from '../chunk-6IDBWPK2.js';
|
|
47
|
-
import { parseAssetRef, ASSET_KINDS, isValidAssetName, ASSET_NAME_HINT, assetRefToStr } from '../chunk-GEEW6SY2.js';
|
|
47
|
+
import { parseAssetRef, ASSET_KINDS, isValidAssetName, slugifyAssetName, ASSET_NAME_HINT, assetRefToStr } from '../chunk-GEEW6SY2.js';
|
|
48
48
|
import '../chunk-XGCXFX7X.js';
|
|
49
49
|
import { SUPPORTED_DRIVER_TARGETS } from '../chunk-O4JH3KUE.js';
|
|
50
50
|
import { DRIVER_DEFAULTS } from '../chunk-K5GBV4SA.js';
|
|
@@ -55,32 +55,483 @@ import '../chunk-XUXVH3JK.js';
|
|
|
55
55
|
import '../chunk-RGPBEGP2.js';
|
|
56
56
|
import '../chunk-CGYEHQOX.js';
|
|
57
57
|
import '../chunk-NSBPE2FW.js';
|
|
58
|
-
import * as
|
|
59
|
-
import
|
|
60
|
-
import * as
|
|
61
|
-
import
|
|
58
|
+
import * as fs12 from 'fs';
|
|
59
|
+
import fs12__default, { readFileSync, existsSync, writeFileSync, lstatSync, rmSync, readdirSync, statSync } from 'fs';
|
|
60
|
+
import * as path14 from 'path';
|
|
61
|
+
import path14__default, { resolve, join } from 'path';
|
|
62
62
|
import { fileURLToPath } from 'url';
|
|
63
63
|
import { Help, Command, Option } from 'commander';
|
|
64
|
-
import { homedir } from 'os';
|
|
65
64
|
import * as p6 from '@clack/prompts';
|
|
66
65
|
import pc5 from 'picocolors';
|
|
66
|
+
import * as os from 'os';
|
|
67
|
+
import { homedir } from 'os';
|
|
68
|
+
import { parse, stringify } from 'yaml';
|
|
67
69
|
import * as readline from 'readline';
|
|
68
70
|
import { createInterface } from 'readline';
|
|
69
|
-
import
|
|
70
|
-
import { parse as parse$1, stringify } from 'smol-toml';
|
|
71
|
+
import fs6 from 'fs/promises';
|
|
72
|
+
import { parse as parse$1, stringify as stringify$1 } from 'smol-toml';
|
|
71
73
|
import { execSync, spawnSync } from 'child_process';
|
|
72
74
|
import { createTRPCUntypedClient, httpLink, httpSubscriptionLink } from '@trpc/client';
|
|
73
|
-
import { parse } from 'yaml';
|
|
74
75
|
|
|
76
|
+
async function runSearch(kind, query, opts) {
|
|
77
|
+
if (kind?.includes(":")) {
|
|
78
|
+
query = kind;
|
|
79
|
+
kind = void 0;
|
|
80
|
+
}
|
|
81
|
+
const showLocal = !opts.store;
|
|
82
|
+
const showStore = !opts.local;
|
|
83
|
+
if (showLocal) {
|
|
84
|
+
searchLocal(query, kind, opts, showStore);
|
|
85
|
+
}
|
|
86
|
+
if (showStore) {
|
|
87
|
+
await searchStore(query, kind, opts);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function searchLocal(query, kind, opts, showStore) {
|
|
91
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
92
|
+
const entries = am2.search(query, kind);
|
|
93
|
+
if (entries.length === 0) {
|
|
94
|
+
if (!showStore) {
|
|
95
|
+
logInfo(
|
|
96
|
+
query ? `No entries matching "${query}".` : "No assets found. Run `skaile source sync` first."
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (showStore) {
|
|
102
|
+
console.log(`
|
|
103
|
+
${S.heading("Local:")}`);
|
|
104
|
+
}
|
|
105
|
+
printLocalEntries(entries);
|
|
106
|
+
}
|
|
107
|
+
function printLocalEntries(entries) {
|
|
108
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
109
|
+
for (const e of entries) {
|
|
110
|
+
if (!byKind.has(e.kind)) byKind.set(e.kind, []);
|
|
111
|
+
byKind.get(e.kind).push(e);
|
|
112
|
+
}
|
|
113
|
+
for (const [k, items] of byKind) {
|
|
114
|
+
const nameW = Math.max(4, ...items.map((e) => e.name.length));
|
|
115
|
+
console.log();
|
|
116
|
+
console.log(
|
|
117
|
+
` ${kindColor(k)} ${S.heading(`${k.toUpperCase()}S`)} ${S.dim(`(${items.length})`)}`
|
|
118
|
+
);
|
|
119
|
+
console.log(` ${S.rule(nameW + 62)}`);
|
|
120
|
+
for (const e of items) {
|
|
121
|
+
const ver = e.version ? S.dim(` v${e.version}`) : "";
|
|
122
|
+
console.log(` ${S.cmd(e.name.padEnd(nameW))} ${e.description.slice(0, 60)}${ver}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log(`
|
|
126
|
+
${S.dim(`${entries.length} total`)}
|
|
127
|
+
`);
|
|
128
|
+
}
|
|
129
|
+
async function searchStore(query, kind, opts) {
|
|
130
|
+
try {
|
|
131
|
+
const { getStoreConfig: getStoreConfig2, storeFetch: storeFetch2 } = await import('../store-client-XFZFKY3W.js');
|
|
132
|
+
const config = getStoreConfig2();
|
|
133
|
+
const params = {};
|
|
134
|
+
if (query) params.q = query;
|
|
135
|
+
if (kind) params.kind = kind;
|
|
136
|
+
const storeRes = await storeFetch2(config, "/api/assets", { params });
|
|
137
|
+
if (storeRes.results.length > 0) {
|
|
138
|
+
console.log(`
|
|
139
|
+
${S.heading("Store:")}`);
|
|
140
|
+
for (const asset of storeRes.results) {
|
|
141
|
+
const ref = `${asset.kind}:@${asset.publisher}/${asset.slug}`;
|
|
142
|
+
console.log(
|
|
143
|
+
` \u2B21 ${kindColorPad(asset.kind)} ${colorRef(ref).padEnd(40)} ${S.dim(asset.description?.slice(0, 50) || "")} ${S.dim(`\u2193${asset.downloads}`)}`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
} else if (opts.store) {
|
|
147
|
+
logInfo("No results in store");
|
|
148
|
+
}
|
|
149
|
+
} catch (e) {
|
|
150
|
+
if (opts.store) {
|
|
151
|
+
logErr(`Store search failed: ${e.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function makeSearchCommand() {
|
|
156
|
+
return new Command("search").description("Search across all repos").argument("[kind]", "Filter by asset kind").argument("[query]", "Search query").option("--project-dir <path>", "Project directory", process.cwd()).option("--store", "Search only the store").option("--local", "Search only local repos").action(async (kind, query, opts) => {
|
|
157
|
+
await runSearch(kind, query, opts);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function makeAddCommand() {
|
|
161
|
+
return new Command("add").description("Add to skaile.yaml + deploy").argument("<ref>", "Asset reference (kind:name[@repo])").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Deploy to global dir (~/.claude)").option("--target <agent>", "Driver target", "claude-code").action(async (ref, opts) => {
|
|
162
|
+
const am2 = new AssetManager({
|
|
163
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
164
|
+
global: opts.global,
|
|
165
|
+
driverTarget: opts.target
|
|
166
|
+
});
|
|
167
|
+
const spinner5 = p6.spinner();
|
|
168
|
+
spinner5.start(`Adding ${ref}`);
|
|
169
|
+
try {
|
|
170
|
+
const added = await am2.add(ref);
|
|
171
|
+
spinner5.stop("Done");
|
|
172
|
+
if (added.length === 0) {
|
|
173
|
+
const kind = parseAssetRef(ref).kind;
|
|
174
|
+
if (NON_DEPLOYABLE_KINDS.has(kind))
|
|
175
|
+
logInfo(
|
|
176
|
+
`Recorded in skaile.yaml. ${kind} assets are not deployed into the driver target \u2014 they are wired when skaile runs the agent.`
|
|
177
|
+
);
|
|
178
|
+
else logInfo("Nothing to deploy (already up to date).");
|
|
179
|
+
} else for (const a of added) logOk(a);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
spinner5.stop("Failed");
|
|
182
|
+
logErr(String(err));
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function makeRemoveCommand() {
|
|
188
|
+
return new Command("remove").description("Remove from skaile.yaml + undeploy").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Remove from global dir").option("--target <agent>", "Driver target", "claude-code").action((ref, opts) => {
|
|
189
|
+
const am2 = new AssetManager({
|
|
190
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
191
|
+
global: opts.global,
|
|
192
|
+
driverTarget: opts.target
|
|
193
|
+
});
|
|
194
|
+
const ok = am2.remove(ref);
|
|
195
|
+
if (ok) logOk(`Removed ${ref}`);
|
|
196
|
+
else logErr(`Not deployed: ${ref}`);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function stateLabel(s) {
|
|
200
|
+
if (s === "installed") return S.ok(s);
|
|
201
|
+
if (s === "drift") return S.warn(s);
|
|
202
|
+
if (s === "invalid") return S.err(s);
|
|
203
|
+
return S.dim(s);
|
|
204
|
+
}
|
|
205
|
+
function makeListCommand() {
|
|
206
|
+
return new Command("list").description("List declared dependencies from skaile.yaml with state").argument("[kind]", "Filter by asset kind").option("--project-dir <path>", "Project directory", process.cwd()).option("-g, --global", "Inspect the global deployment dir for state").option("--json", "Output as JSON").addOption(
|
|
207
|
+
new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
|
|
208
|
+
).action((kind, opts) => {
|
|
209
|
+
const am2 = new AssetManager({
|
|
210
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
211
|
+
global: opts.global,
|
|
212
|
+
driverTarget: opts.target
|
|
213
|
+
});
|
|
214
|
+
let declared;
|
|
215
|
+
try {
|
|
216
|
+
declared = am2.listDeclared(kind);
|
|
217
|
+
} catch (err) {
|
|
218
|
+
if (err instanceof MissingManifestError)
|
|
219
|
+
logErr(`No ${S.cmd("skaile.yaml")} found. Run ${S.cmd("skaile init")} to create one.`);
|
|
220
|
+
else logErr(err instanceof Error ? err.message : String(err));
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
if (opts.json) {
|
|
224
|
+
console.log(JSON.stringify(declared, null, 2));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (declared.length === 0) {
|
|
228
|
+
logInfo("No dependencies declared in skaile.yaml.");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const kindW = Math.max(4, ...declared.map((e) => e.kind.length));
|
|
232
|
+
const nameW = Math.max(4, ...declared.map((e) => e.name.length));
|
|
233
|
+
console.log();
|
|
234
|
+
console.log(
|
|
235
|
+
` ${S.dim("KIND".padEnd(kindW))} ${S.dim("NAME".padEnd(nameW))} ${S.dim("STATE")}`
|
|
236
|
+
);
|
|
237
|
+
console.log(` ${S.rule(kindW + nameW + 4 + "installed".length)}`);
|
|
238
|
+
for (const e of declared) {
|
|
239
|
+
console.log(
|
|
240
|
+
` ${kindColorPad(e.kind, kindW)} ${e.name.padEnd(nameW)} ${stateLabel(e.state)}`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
console.log(`
|
|
244
|
+
${S.dim(`${declared.length} declared`)}`);
|
|
245
|
+
const drift = declared.filter((e) => e.state === "drift").length;
|
|
246
|
+
if (drift > 0)
|
|
247
|
+
logInfo(`${drift} with drift \u2014 run ${S.cmd("skaile install")} to materialize.`);
|
|
248
|
+
const invalid = declared.filter((e) => e.state === "invalid").length;
|
|
249
|
+
if (invalid > 0)
|
|
250
|
+
logInfo(`${invalid} invalid \u2014 fix the ${S.cmd("skaile.yaml")} dependencies entry.`);
|
|
251
|
+
console.log();
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
function makeInfoCommand() {
|
|
255
|
+
return new Command("info").description("Show asset metadata, deps, deploy status").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
256
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
257
|
+
const entry = am2.info(ref);
|
|
258
|
+
if (!entry) {
|
|
259
|
+
logErr(
|
|
260
|
+
`'${ref}' not found. Run ${S.cmd("skaile source sync")} then ${S.cmd("skaile search")}.`
|
|
261
|
+
);
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
console.log();
|
|
265
|
+
console.log(` ${S.heading(entry.name)}`);
|
|
266
|
+
console.log(` ${S.rule(40)}`);
|
|
267
|
+
console.log(` kind: ${kindColor(entry.kind)}`);
|
|
268
|
+
if (entry.version) console.log(` version: ${entry.version}`);
|
|
269
|
+
if (entry.description) console.log(` description: ${entry.description}`);
|
|
270
|
+
if (entry.publisher) console.log(` repository: ${S.dim(entry.publisher)}`);
|
|
271
|
+
console.log(` source: ${S.dim(entry.source)}`);
|
|
272
|
+
if (entry.requires.length) {
|
|
273
|
+
console.log(` requires:`);
|
|
274
|
+
for (const d of entry.requires)
|
|
275
|
+
console.log(` ${S.dim("\xB7")} ${kindColor(d.kind)}:${d.name}`);
|
|
276
|
+
}
|
|
277
|
+
if (entry.dependencies.length) {
|
|
278
|
+
console.log(` dependencies:`);
|
|
279
|
+
for (const s of entry.dependencies) console.log(` ${S.dim("\xB7")} ${colorRef(s)}`);
|
|
280
|
+
}
|
|
281
|
+
console.log();
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
function makeCreateCommand() {
|
|
285
|
+
return new Command("create").description("Scaffold a new asset").argument("<name>", "Asset name").addOption(
|
|
286
|
+
new Option("-k, --kind <kind>", "Asset kind").default("skill").choices([...ASSET_KINDS])
|
|
287
|
+
).option("-d, --dir <dir>", "Target directory (default: cwd)").action((name, opts) => {
|
|
288
|
+
const am2 = new AssetManager({ projectDir: process.cwd() });
|
|
289
|
+
const destDir = opts.dir ? path14__default.resolve(opts.dir) : process.cwd();
|
|
290
|
+
const result = am2.create(name, opts.kind, destDir);
|
|
291
|
+
if (result.ok) logOk(`Created ${kindColor(opts.kind)}: ${pc5.dim(result.path)}`);
|
|
292
|
+
else {
|
|
293
|
+
logErr(result.path);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function makeDoctorCommand() {
|
|
299
|
+
return new Command("doctor").description("Scan for missing dependency chains").argument("[name]", "Check a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((name, opts) => {
|
|
300
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
301
|
+
const issues = am2.doctor();
|
|
302
|
+
if (issues.length === 0) {
|
|
303
|
+
logOk("No missing dependencies.");
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const assetW = Math.max(5, ...issues.map((i) => `${i.assetKind}:${i.assetName}`.length));
|
|
307
|
+
const depW = Math.max(11, ...issues.map((i) => `${i.depKind}:${i.depName}`.length));
|
|
308
|
+
console.log();
|
|
309
|
+
console.log(
|
|
310
|
+
` ${S.dim("ASSET".padEnd(assetW))} ${S.dim("MISSING DEP".padEnd(depW))} ${S.dim("IN REPOS")}`
|
|
311
|
+
);
|
|
312
|
+
console.log(` ${S.rule(assetW + depW + 15)}`);
|
|
313
|
+
for (const i of issues) {
|
|
314
|
+
const asset = `${i.assetKind}:${i.assetName}`;
|
|
315
|
+
const dep = `${i.depKind}:${i.depName}`;
|
|
316
|
+
const status4 = i.inRepos ? S.warn("fixable") : S.err("not found");
|
|
317
|
+
console.log(` ${asset.padEnd(assetW)} ${dep.padEnd(depW)} ${status4}`);
|
|
318
|
+
}
|
|
319
|
+
console.log();
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
var DEFAULT_IMPORT_VERSION = "0.1.0";
|
|
323
|
+
var DEFAULT_IMPORT_STAGE = "alpha";
|
|
324
|
+
function claudeSkillRoots() {
|
|
325
|
+
const roots = [];
|
|
326
|
+
const override = process.env.SKAILE_CLAUDE_SKILLS_DIR;
|
|
327
|
+
if (override) roots.push(override);
|
|
328
|
+
roots.push(path14.join(os.homedir(), ".claude", "skills"));
|
|
329
|
+
return roots;
|
|
330
|
+
}
|
|
331
|
+
function resolveImportSource(nameOrPath) {
|
|
332
|
+
const asPath = path14.resolve(nameOrPath);
|
|
333
|
+
if (fs12.existsSync(asPath)) {
|
|
334
|
+
const dir = fs12.statSync(asPath).isDirectory() ? asPath : path14.dirname(asPath);
|
|
335
|
+
const skillFile = path14.join(dir, "SKILL.md");
|
|
336
|
+
if (fs12.existsSync(skillFile)) return { dir, skillFile, via: "path" };
|
|
337
|
+
}
|
|
338
|
+
if (!nameOrPath.includes(path14.sep) && !nameOrPath.startsWith(".")) {
|
|
339
|
+
for (const root of claudeSkillRoots()) {
|
|
340
|
+
const dir = path14.join(root, nameOrPath);
|
|
341
|
+
const skillFile = path14.join(dir, "SKILL.md");
|
|
342
|
+
if (fs12.existsSync(skillFile)) return { dir, skillFile, via: "claude-skills" };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
function normalizeSkillContent(raw, opts = {}) {
|
|
348
|
+
const notes = [];
|
|
349
|
+
const { data, body } = parseFrontmatter(raw);
|
|
350
|
+
const rawName = typeof data.name === "string" && data.name.trim() ? data.name.trim() : void 0;
|
|
351
|
+
const sourceName = rawName ?? opts.fallbackName ?? "";
|
|
352
|
+
let name = sourceName;
|
|
353
|
+
let originalName;
|
|
354
|
+
if (!sourceName) {
|
|
355
|
+
throw new Error("skill has no `name` in frontmatter and no fallback was provided");
|
|
356
|
+
}
|
|
357
|
+
if (!isValidAssetName(sourceName)) {
|
|
358
|
+
name = slugifyAssetName(sourceName);
|
|
359
|
+
originalName = sourceName;
|
|
360
|
+
notes.push(`renamed "${sourceName}" \u2192 "${name}" (canonical kebab-case)`);
|
|
361
|
+
}
|
|
362
|
+
const existingMeta = data.metadata && typeof data.metadata === "object" && !Array.isArray(data.metadata) ? { ...data.metadata } : {};
|
|
363
|
+
if (existingMeta.version == null) {
|
|
364
|
+
existingMeta.version = opts.version ?? DEFAULT_IMPORT_VERSION;
|
|
365
|
+
notes.push(`stamped metadata.version: ${existingMeta.version}`);
|
|
366
|
+
}
|
|
367
|
+
if (existingMeta.stage == null) {
|
|
368
|
+
existingMeta.stage = opts.stage ?? DEFAULT_IMPORT_STAGE;
|
|
369
|
+
notes.push(`stamped metadata.stage: ${existingMeta.stage}`);
|
|
370
|
+
}
|
|
371
|
+
if (existingMeta.tags == null) {
|
|
372
|
+
const keywords = Array.isArray(data.keywords) ? data.keywords : [];
|
|
373
|
+
existingMeta.tags = keywords.filter((k) => typeof k === "string");
|
|
374
|
+
if (existingMeta.tags.length > 0) {
|
|
375
|
+
notes.push("promoted top-level keywords \u2192 metadata.tags");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const ordered = { name };
|
|
379
|
+
if (data.description != null) ordered.description = data.description;
|
|
380
|
+
ordered.metadata = existingMeta;
|
|
381
|
+
for (const [k, v] of Object.entries(data)) {
|
|
382
|
+
if (k === "name" || k === "description" || k === "metadata" || k === "keywords") continue;
|
|
383
|
+
ordered[k] = v;
|
|
384
|
+
}
|
|
385
|
+
const fm = stringify(ordered).trimEnd();
|
|
386
|
+
const content = `---
|
|
387
|
+
${fm}
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
${body}
|
|
391
|
+
`;
|
|
392
|
+
const changed = notes.length > 0;
|
|
393
|
+
return { content, name, originalName, changed, notes };
|
|
394
|
+
}
|
|
395
|
+
var DOMAIN_TEMPLATE = (name, publisher, description) => {
|
|
396
|
+
const fm = stringify({ name, publisher, description }).trimEnd();
|
|
397
|
+
return `---
|
|
398
|
+
${fm}
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
# ${name}
|
|
402
|
+
|
|
403
|
+
${description}
|
|
404
|
+
`;
|
|
405
|
+
};
|
|
406
|
+
function ensureDomain(libraryPath, domain, opts = {}) {
|
|
407
|
+
const dir = path14.join(libraryPath, domain);
|
|
408
|
+
const domainFile = path14.join(dir, "DOMAIN.md");
|
|
409
|
+
const publisher = opts.publisher ?? slugifyAssetName(domain);
|
|
410
|
+
if (fs12.existsSync(domainFile)) {
|
|
411
|
+
return { dir, publisher, created: false };
|
|
412
|
+
}
|
|
413
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
414
|
+
const description = opts.description ?? `The ${domain} domain.`;
|
|
415
|
+
fs12.writeFileSync(domainFile, DOMAIN_TEMPLATE(domain, publisher, description), "utf8");
|
|
416
|
+
return { dir, publisher, created: true };
|
|
417
|
+
}
|
|
418
|
+
function listDomains(libraryPath) {
|
|
419
|
+
if (!fs12.existsSync(libraryPath)) return [];
|
|
420
|
+
return fs12.readdirSync(libraryPath, { withFileTypes: true }).filter((e) => e.isDirectory() && fs12.existsSync(path14.join(libraryPath, e.name, "DOMAIN.md"))).map((e) => e.name).sort();
|
|
421
|
+
}
|
|
422
|
+
function upsertManifestAsset(libraryPath, input) {
|
|
423
|
+
const manifest = loadSkPublishManifest(libraryPath) ?? { assets: [] };
|
|
424
|
+
const assets = Array.isArray(manifest.assets) ? [...manifest.assets] : [];
|
|
425
|
+
const entry = { kind: input.kind, name: input.name, root: input.root };
|
|
426
|
+
if (input.version) entry.version = input.version;
|
|
427
|
+
if (input.publisher) entry.publisher = input.publisher;
|
|
428
|
+
if (input.description) entry.description = input.description;
|
|
429
|
+
if (input.keywords && input.keywords.length > 0) entry.keywords = input.keywords;
|
|
430
|
+
const idx = assets.findIndex((a) => a.kind === input.kind && a.name === input.name);
|
|
431
|
+
const added = idx < 0;
|
|
432
|
+
if (added) {
|
|
433
|
+
assets.push(entry);
|
|
434
|
+
} else {
|
|
435
|
+
assets[idx] = { ...assets[idx], ...entry };
|
|
436
|
+
}
|
|
437
|
+
const manifestPath = saveSkPublishManifest(libraryPath, { ...manifest, assets });
|
|
438
|
+
return { manifestPath, added };
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// cli/src/commands/asset-cmd.ts
|
|
75
442
|
function makeAssetCommand() {
|
|
76
443
|
const cmd = new Command("asset").description("Author and install AI assets");
|
|
444
|
+
cmd.command("import <name-or-path>").description("Import + skailify an existing coding-agent skill into a library").option("--to <library>", "Target library (default: auto / personal)").option("--domain <name>", "Place under this domain's skills/ (created if missing)").option("--version <semver>", "Version to stamp when the skill ships none").option("--stage <stage>", "Lifecycle stage to stamp (default: alpha)").option("--no-normalize", "Copy verbatim \u2014 skip frontmatter normalization").option("--commit", "Auto-commit in git-backed libraries", false).action(
|
|
445
|
+
async (nameOrPath, opts) => {
|
|
446
|
+
const src = resolveImportSource(nameOrPath);
|
|
447
|
+
if (!src) {
|
|
448
|
+
logErr(
|
|
449
|
+
`No skill found for "${nameOrPath}". Pass a path to a SKILL.md dir, or a bare name present under ~/.claude/skills/.`
|
|
450
|
+
);
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|
|
453
|
+
logInfo(`Source: ${S.dim(src.dir)} (${src.via})`);
|
|
454
|
+
const { manager, close } = await openLibraryManager();
|
|
455
|
+
try {
|
|
456
|
+
let target;
|
|
457
|
+
if (opts.to) {
|
|
458
|
+
target = await manager.requireLibrary(opts.to);
|
|
459
|
+
} else {
|
|
460
|
+
const all = await manager.listLibraries();
|
|
461
|
+
const def = all.find(
|
|
462
|
+
(l) => l.isDefault && (l.ownership === "owner" || l.ownership === "contributor")
|
|
463
|
+
);
|
|
464
|
+
target = def ?? (await manager.ensurePersonalLibrary(resolveLibraryDir())).library;
|
|
465
|
+
}
|
|
466
|
+
if (target.ownership === "reader") {
|
|
467
|
+
logErr(`Library "${target.name}" is read-only (ownership=reader). Choose --to.`);
|
|
468
|
+
process.exit(1);
|
|
469
|
+
}
|
|
470
|
+
const rawSkill = fs12.readFileSync(src.skillFile, "utf8");
|
|
471
|
+
const norm = opts.normalize ? normalizeSkillContent(rawSkill, {
|
|
472
|
+
fallbackName: path14.basename(src.dir),
|
|
473
|
+
version: opts.version,
|
|
474
|
+
stage: opts.stage
|
|
475
|
+
}) : { content: rawSkill, name: path14.basename(src.dir), changed: false, notes: [] };
|
|
476
|
+
if (!opts.normalize && !isValidAssetName(norm.name)) {
|
|
477
|
+
logWarn(
|
|
478
|
+
`Name "${norm.name}" is not canonical (kebab-case); \`skaile validate\` will reject this manifest entry. Drop --no-normalize to slugify it.`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
let destParent = target.path;
|
|
482
|
+
let publisher;
|
|
483
|
+
if (opts.domain) {
|
|
484
|
+
const dom = ensureDomain(target.path, opts.domain);
|
|
485
|
+
if (dom.created) logOk(`Scaffolded domain ${S.cmd(opts.domain)} \u2192 ${dom.dir}`);
|
|
486
|
+
destParent = path14.join(dom.dir, "skills");
|
|
487
|
+
publisher = dom.publisher;
|
|
488
|
+
}
|
|
489
|
+
fs12.mkdirSync(destParent, { recursive: true });
|
|
490
|
+
const destDir = path14.join(destParent, norm.name);
|
|
491
|
+
if (fs12.existsSync(destDir)) {
|
|
492
|
+
logErr(`Destination already exists: ${destDir}`);
|
|
493
|
+
process.exit(1);
|
|
494
|
+
}
|
|
495
|
+
fs12.cpSync(src.dir, destDir, { recursive: true });
|
|
496
|
+
fs12.writeFileSync(path14.join(destDir, "SKILL.md"), norm.content, "utf8");
|
|
497
|
+
for (const note of norm.notes) logInfo(` \u2022 ${note}`);
|
|
498
|
+
const descRaw = parseFrontmatter(norm.content).data.description;
|
|
499
|
+
const description = typeof descRaw === "string" ? descRaw.trim() : void 0;
|
|
500
|
+
const root = path14.relative(target.path, destDir);
|
|
501
|
+
const up = upsertManifestAsset(target.path, {
|
|
502
|
+
kind: "skill",
|
|
503
|
+
name: norm.name,
|
|
504
|
+
root,
|
|
505
|
+
version: opts.version,
|
|
506
|
+
publisher,
|
|
507
|
+
description
|
|
508
|
+
});
|
|
509
|
+
logOk(`${up.added ? "Added" : "Updated"} manifest entry skill:${norm.name}`);
|
|
510
|
+
if (target.backend === "git" && opts.commit) {
|
|
511
|
+
const { spawnSync: spawnSync2 } = await import('child_process');
|
|
512
|
+
spawnSync2("git", ["add", "--", destDir], { cwd: target.path, stdio: "inherit" });
|
|
513
|
+
const r = spawnSync2("git", ["commit", "-m", `skaile: import ${norm.name}`], {
|
|
514
|
+
cwd: target.path,
|
|
515
|
+
stdio: "inherit"
|
|
516
|
+
});
|
|
517
|
+
if (r.status !== 0) {
|
|
518
|
+
logWarn("Nothing committed (working tree clean or commit aborted).");
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
logOk(`Imported ${S.cmd(norm.name)} \u2192 ${target.name}`);
|
|
522
|
+
logInfo(`Verify: ${S.cmd(`skaile validate ${target.path}`)}`);
|
|
523
|
+
} finally {
|
|
524
|
+
close();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
);
|
|
77
528
|
cmd.command("migrate <path>").description("Move/copy/link a workspace asset into a library").option("--to <library>", "Target library (default: auto)").option("--domain <name>", "Place inside this domain (domain-structured libs)").option("--mode <mode>", "copy | move | link", "copy").option("--commit", "Auto-commit in git-backed libraries", false).action(
|
|
78
529
|
async (srcPath, opts) => {
|
|
79
530
|
if (!["copy", "move", "link"].includes(opts.mode)) {
|
|
80
531
|
logErr(`Invalid --mode "${opts.mode}". Expected: copy | move | link.`);
|
|
81
532
|
process.exit(1);
|
|
82
533
|
}
|
|
83
|
-
if (!
|
|
534
|
+
if (!fs12.existsSync(srcPath)) {
|
|
84
535
|
logErr(`Source path does not exist: ${srcPath}`);
|
|
85
536
|
process.exit(1);
|
|
86
537
|
}
|
|
@@ -107,32 +558,35 @@ function makeAssetCommand() {
|
|
|
107
558
|
);
|
|
108
559
|
process.exit(1);
|
|
109
560
|
}
|
|
110
|
-
const basename2 =
|
|
111
|
-
const destDir = target.structure === "domain" && opts.domain ?
|
|
112
|
-
|
|
113
|
-
const destPath =
|
|
114
|
-
if (
|
|
561
|
+
const basename2 = path14.basename(srcPath);
|
|
562
|
+
const destDir = target.structure === "domain" && opts.domain ? path14.join(target.path, opts.domain) : target.path;
|
|
563
|
+
fs12.mkdirSync(destDir, { recursive: true });
|
|
564
|
+
const destPath = path14.join(destDir, basename2);
|
|
565
|
+
if (fs12.existsSync(destPath)) {
|
|
115
566
|
logErr(`Destination already exists: ${destPath}`);
|
|
116
567
|
process.exit(1);
|
|
117
568
|
}
|
|
118
569
|
switch (opts.mode) {
|
|
119
570
|
case "copy":
|
|
120
|
-
|
|
571
|
+
fs12.cpSync(srcPath, destPath, { recursive: true });
|
|
121
572
|
break;
|
|
122
573
|
case "move":
|
|
123
|
-
|
|
574
|
+
fs12.renameSync(srcPath, destPath);
|
|
124
575
|
break;
|
|
125
576
|
case "link":
|
|
126
|
-
|
|
577
|
+
fs12.symlinkSync(path14.resolve(srcPath), destPath);
|
|
127
578
|
break;
|
|
128
579
|
}
|
|
129
580
|
if (target.backend === "git" && opts.commit) {
|
|
130
581
|
const { spawnSync: spawnSync2 } = await import('child_process');
|
|
131
|
-
spawnSync2("git", ["add", "
|
|
132
|
-
spawnSync2("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
|
|
582
|
+
spawnSync2("git", ["add", "--", destPath], { cwd: target.path, stdio: "inherit" });
|
|
583
|
+
const r = spawnSync2("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
|
|
133
584
|
cwd: target.path,
|
|
134
|
-
stdio: "
|
|
585
|
+
stdio: "inherit"
|
|
135
586
|
});
|
|
587
|
+
if (r.status !== 0) {
|
|
588
|
+
logWarn("Nothing committed (working tree clean or commit aborted).");
|
|
589
|
+
}
|
|
136
590
|
}
|
|
137
591
|
logOk(`Migrated ${basename2} \u2192 ${target.name} (${opts.mode})`);
|
|
138
592
|
if (opts.mode === "move") {
|
|
@@ -157,7 +611,7 @@ function makeAssetCommand() {
|
|
|
157
611
|
try {
|
|
158
612
|
const def = await library.getAssetDef(ref);
|
|
159
613
|
if (!def) {
|
|
160
|
-
logErr(`No asset found for ref "${ref}". Try \`skaile
|
|
614
|
+
logErr(`No asset found for ref "${ref}". Try \`skaile search\`.`);
|
|
161
615
|
process.exit(1);
|
|
162
616
|
}
|
|
163
617
|
const target = opts.target ?? process.cwd();
|
|
@@ -171,17 +625,17 @@ function makeAssetCommand() {
|
|
|
171
625
|
}
|
|
172
626
|
const manifestPath = def.manifest.path;
|
|
173
627
|
const candidateSubpath = typeof manifestPath === "string" && manifestPath.length > 0 ? manifestPath : def.name;
|
|
174
|
-
const srcPath =
|
|
175
|
-
if (!
|
|
628
|
+
const srcPath = path14.join(lib.path, candidateSubpath);
|
|
629
|
+
if (!fs12.existsSync(srcPath)) {
|
|
176
630
|
logErr(`Asset path not found: ${srcPath}`);
|
|
177
631
|
process.exit(1);
|
|
178
632
|
}
|
|
179
|
-
const destPath =
|
|
180
|
-
|
|
633
|
+
const destPath = path14.join(target, candidateSubpath);
|
|
634
|
+
fs12.mkdirSync(path14.dirname(destPath), { recursive: true });
|
|
181
635
|
if (opts.mode === "copy") {
|
|
182
|
-
|
|
636
|
+
fs12.cpSync(srcPath, destPath, { recursive: true });
|
|
183
637
|
} else {
|
|
184
|
-
|
|
638
|
+
fs12.symlinkSync(path14.resolve(srcPath), destPath);
|
|
185
639
|
}
|
|
186
640
|
logOk(`Installed ${ref} \u2192 ${destPath} (${opts.mode})`);
|
|
187
641
|
} finally {
|
|
@@ -189,29 +643,7 @@ function makeAssetCommand() {
|
|
|
189
643
|
}
|
|
190
644
|
}
|
|
191
645
|
);
|
|
192
|
-
cmd.
|
|
193
|
-
const { manager, library, close } = await openLibraryManager();
|
|
194
|
-
try {
|
|
195
|
-
let defs = await library.listAssetDefs(opts.kind ? { kind: opts.kind } : void 0);
|
|
196
|
-
if (opts.library) {
|
|
197
|
-
const lib = await manager.requireLibrary(opts.library);
|
|
198
|
-
defs = defs.filter((d) => d.libraryId === lib.id);
|
|
199
|
-
}
|
|
200
|
-
if (opts.json) return console.log(JSON.stringify(defs, null, 2));
|
|
201
|
-
if (defs.length === 0) {
|
|
202
|
-
logInfo("No assets cached. Run `skaile library sync <name>` first.");
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
for (const d of defs) {
|
|
206
|
-
console.log(` ${S.cmd(d.id.padEnd(40))} ${d.kind.padEnd(10)} ${d.description ?? ""}`);
|
|
207
|
-
}
|
|
208
|
-
console.log(`
|
|
209
|
-
${S.dim(`${defs.length} asset(s)`)}
|
|
210
|
-
`);
|
|
211
|
-
} finally {
|
|
212
|
-
close();
|
|
213
|
-
}
|
|
214
|
-
});
|
|
646
|
+
cmd.addCommand(makeListCommand());
|
|
215
647
|
cmd.command("show <ref>").description("Show details for an asset by canonical ref").action(async (ref) => {
|
|
216
648
|
const { library, close } = await openLibraryManager();
|
|
217
649
|
try {
|
|
@@ -268,14 +700,14 @@ function makeAuthCommand() {
|
|
|
268
700
|
}
|
|
269
701
|
function collectCacheTargets(scope) {
|
|
270
702
|
const out = [];
|
|
271
|
-
out.push(
|
|
272
|
-
out.push(
|
|
273
|
-
out.push(
|
|
703
|
+
out.push(path14__default.join(scope.projectDir, ".skaile", "cache"));
|
|
704
|
+
out.push(path14__default.join(scope.projectDir, ".skaile", "store-cache"));
|
|
705
|
+
out.push(path14__default.join(scope.projectDir, ".skaile", "repos"));
|
|
274
706
|
if (scope.global) {
|
|
275
707
|
out.push(globalCacheRoot());
|
|
276
|
-
const home = process.env.SKAILE_HOME ??
|
|
277
|
-
out.push(
|
|
278
|
-
out.push(
|
|
708
|
+
const home = process.env.SKAILE_HOME ?? path14__default.join(homedir(), ".skaile");
|
|
709
|
+
out.push(path14__default.join(home, "repos"));
|
|
710
|
+
out.push(path14__default.join(home, "catalog-cache"));
|
|
279
711
|
}
|
|
280
712
|
return out;
|
|
281
713
|
}
|
|
@@ -289,7 +721,7 @@ function dirSize(target) {
|
|
|
289
721
|
function dirSizeOfDir(dir) {
|
|
290
722
|
let total = 0;
|
|
291
723
|
for (const ent of readdirSync(dir, { withFileTypes: true })) {
|
|
292
|
-
const child =
|
|
724
|
+
const child = path14__default.join(dir, ent.name);
|
|
293
725
|
if (ent.isSymbolicLink()) continue;
|
|
294
726
|
if (ent.isDirectory()) total += dirSizeOfDir(child);
|
|
295
727
|
else if (ent.isFile()) total += statSync(child).size;
|
|
@@ -315,7 +747,7 @@ function makeCacheCommand() {
|
|
|
315
747
|
const cmd = new Command("cache").description("Inspect and reclaim the re-derivable cache");
|
|
316
748
|
cmd.command("clean").description("Remove the project cache (.skaile/cache); --global also clears ~/.skaile/cache").option("--global", "Also clear the global cache (sources + catalog) and legacy dirs").option("--dry-run", "Show what would be removed without doing it").option("-y, --yes", "Skip confirmation prompt").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
317
749
|
const targets = collectCacheTargets({
|
|
318
|
-
projectDir:
|
|
750
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
319
751
|
global: opts.global
|
|
320
752
|
}).filter((t) => existsSync(t));
|
|
321
753
|
if (targets.length === 0) {
|
|
@@ -345,12 +777,12 @@ function makeCacheCommand() {
|
|
|
345
777
|
for (const r of removed) logOk(`Removed ${r}`);
|
|
346
778
|
});
|
|
347
779
|
cmd.command("dir").description("Print the resolved cache roots").option("--global", "Include the global cache root").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
348
|
-
console.log(
|
|
780
|
+
console.log(path14__default.join(path14__default.resolve(opts.projectDir), ".skaile", "cache"));
|
|
349
781
|
if (opts.global) console.log(globalCacheRoot());
|
|
350
782
|
});
|
|
351
783
|
cmd.command("size").description("Show cache disk usage per directory").option("--global", "Include the global cache").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
352
784
|
const targets = collectCacheTargets({
|
|
353
|
-
projectDir:
|
|
785
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
354
786
|
global: opts.global
|
|
355
787
|
});
|
|
356
788
|
console.log();
|
|
@@ -362,229 +794,11 @@ function makeCacheCommand() {
|
|
|
362
794
|
});
|
|
363
795
|
return cmd;
|
|
364
796
|
}
|
|
365
|
-
async function runSearch(kind, query, opts) {
|
|
366
|
-
if (kind?.includes(":")) {
|
|
367
|
-
query = kind;
|
|
368
|
-
kind = void 0;
|
|
369
|
-
}
|
|
370
|
-
const showLocal = !opts.store;
|
|
371
|
-
const showStore = !opts.local;
|
|
372
|
-
if (showLocal) {
|
|
373
|
-
searchLocal(query, kind, opts, showStore);
|
|
374
|
-
}
|
|
375
|
-
if (showStore) {
|
|
376
|
-
await searchStore(query, kind, opts);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function searchLocal(query, kind, opts, showStore) {
|
|
380
|
-
const am2 = new AssetManager({ projectDir: path13__default.resolve(opts.projectDir) });
|
|
381
|
-
const entries = am2.search(query, kind);
|
|
382
|
-
if (entries.length === 0) {
|
|
383
|
-
if (!showStore) {
|
|
384
|
-
logInfo(
|
|
385
|
-
query ? `No entries matching "${query}".` : "No assets found. Run `skaile source sync` first."
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
if (showStore) {
|
|
391
|
-
console.log(`
|
|
392
|
-
${S.heading("Local:")}`);
|
|
393
|
-
}
|
|
394
|
-
printLocalEntries(entries);
|
|
395
|
-
}
|
|
396
|
-
function printLocalEntries(entries) {
|
|
397
|
-
const byKind = /* @__PURE__ */ new Map();
|
|
398
|
-
for (const e of entries) {
|
|
399
|
-
if (!byKind.has(e.kind)) byKind.set(e.kind, []);
|
|
400
|
-
byKind.get(e.kind).push(e);
|
|
401
|
-
}
|
|
402
|
-
for (const [k, items] of byKind) {
|
|
403
|
-
const nameW = Math.max(4, ...items.map((e) => e.name.length));
|
|
404
|
-
console.log();
|
|
405
|
-
console.log(
|
|
406
|
-
` ${kindColor(k)} ${S.heading(`${k.toUpperCase()}S`)} ${S.dim(`(${items.length})`)}`
|
|
407
|
-
);
|
|
408
|
-
console.log(` ${S.rule(nameW + 62)}`);
|
|
409
|
-
for (const e of items) {
|
|
410
|
-
const ver = e.version ? S.dim(` v${e.version}`) : "";
|
|
411
|
-
console.log(` ${S.cmd(e.name.padEnd(nameW))} ${e.description.slice(0, 60)}${ver}`);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
console.log(`
|
|
415
|
-
${S.dim(`${entries.length} total`)}
|
|
416
|
-
`);
|
|
417
|
-
}
|
|
418
|
-
async function searchStore(query, kind, opts) {
|
|
419
|
-
try {
|
|
420
|
-
const { getStoreConfig: getStoreConfig2, storeFetch: storeFetch2 } = await import('../store-client-XFZFKY3W.js');
|
|
421
|
-
const config = getStoreConfig2();
|
|
422
|
-
const params = {};
|
|
423
|
-
if (query) params.q = query;
|
|
424
|
-
if (kind) params.kind = kind;
|
|
425
|
-
const storeRes = await storeFetch2(config, "/api/assets", { params });
|
|
426
|
-
if (storeRes.results.length > 0) {
|
|
427
|
-
console.log(`
|
|
428
|
-
${S.heading("Store:")}`);
|
|
429
|
-
for (const asset of storeRes.results) {
|
|
430
|
-
const ref = `${asset.kind}:@${asset.publisher}/${asset.slug}`;
|
|
431
|
-
console.log(
|
|
432
|
-
` \u2B21 ${kindColorPad(asset.kind)} ${colorRef(ref).padEnd(40)} ${S.dim(asset.description?.slice(0, 50) || "")} ${S.dim(`\u2193${asset.downloads}`)}`
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
} else if (opts.store) {
|
|
436
|
-
logInfo("No results in store");
|
|
437
|
-
}
|
|
438
|
-
} catch (e) {
|
|
439
|
-
if (opts.store) {
|
|
440
|
-
logErr(`Store search failed: ${e.message}`);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
function makeSearchCommand() {
|
|
445
|
-
return new Command("search").description("Search across all repos").argument("[kind]", "Filter by asset kind").argument("[query]", "Search query").option("--project-dir <path>", "Project directory", process.cwd()).option("--store", "Search only the store").option("--local", "Search only local repos").action(async (kind, query, opts) => {
|
|
446
|
-
await runSearch(kind, query, opts);
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
function makeAddCommand() {
|
|
450
|
-
return new Command("add").description("Add to skaile.yaml + deploy").argument("<ref>", "Asset reference (kind:name[@repo])").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Deploy to global dir (~/.claude)").option("--target <agent>", "Driver target", "claude-code").action(async (ref, opts) => {
|
|
451
|
-
const am2 = new AssetManager({
|
|
452
|
-
projectDir: path13__default.resolve(opts.projectDir),
|
|
453
|
-
global: opts.global,
|
|
454
|
-
driverTarget: opts.target
|
|
455
|
-
});
|
|
456
|
-
const spinner5 = p6.spinner();
|
|
457
|
-
spinner5.start(`Adding ${ref}`);
|
|
458
|
-
try {
|
|
459
|
-
const added = await am2.add(ref);
|
|
460
|
-
spinner5.stop("Done");
|
|
461
|
-
if (added.length === 0) {
|
|
462
|
-
const kind = parseAssetRef(ref).kind;
|
|
463
|
-
if (NON_DEPLOYABLE_KINDS.has(kind))
|
|
464
|
-
logInfo(
|
|
465
|
-
`Recorded in skaile.yaml. ${kind} assets are not deployed into the driver target \u2014 they are wired when skaile runs the agent.`
|
|
466
|
-
);
|
|
467
|
-
else logInfo("Nothing to deploy (already up to date).");
|
|
468
|
-
} else for (const a of added) logOk(a);
|
|
469
|
-
} catch (err) {
|
|
470
|
-
spinner5.stop("Failed");
|
|
471
|
-
logErr(String(err));
|
|
472
|
-
process.exit(1);
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
function makeRemoveCommand() {
|
|
477
|
-
return new Command("remove").description("Remove from skaile.yaml + undeploy").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Remove from global dir").option("--target <agent>", "Driver target", "claude-code").action((ref, opts) => {
|
|
478
|
-
const am2 = new AssetManager({
|
|
479
|
-
projectDir: path13__default.resolve(opts.projectDir),
|
|
480
|
-
global: opts.global,
|
|
481
|
-
driverTarget: opts.target
|
|
482
|
-
});
|
|
483
|
-
const ok = am2.remove(ref);
|
|
484
|
-
if (ok) logOk(`Removed ${ref}`);
|
|
485
|
-
else logErr(`Not deployed: ${ref}`);
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
function makeListCommand() {
|
|
489
|
-
return new Command("list").description("List deployed assets").argument("[kind]", "Filter by asset kind").option("--project-dir <path>", "Project directory", process.cwd()).option("-g, --global", "List global deployment").addOption(
|
|
490
|
-
new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
|
|
491
|
-
).action((kind, opts) => {
|
|
492
|
-
const am2 = new AssetManager({
|
|
493
|
-
projectDir: path13__default.resolve(opts.projectDir),
|
|
494
|
-
global: opts.global,
|
|
495
|
-
driverTarget: opts.target
|
|
496
|
-
});
|
|
497
|
-
const deployed = am2.listDeployed(kind);
|
|
498
|
-
if (deployed.length === 0) {
|
|
499
|
-
logInfo("Nothing deployed.");
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
const kindW = Math.max(5, ...deployed.map((e) => e.kind.length));
|
|
503
|
-
const nameW = Math.max(4, ...deployed.map((e) => e.name.length));
|
|
504
|
-
console.log();
|
|
505
|
-
console.log(` ${S.dim("KIND".padEnd(kindW))} ${S.dim("NAME".padEnd(nameW))}`);
|
|
506
|
-
console.log(` ${S.rule(kindW + nameW + 4)}`);
|
|
507
|
-
for (const e of deployed) {
|
|
508
|
-
console.log(` ${kindColorPad(e.kind, kindW)} ${e.name.padEnd(nameW)}`);
|
|
509
|
-
}
|
|
510
|
-
console.log(`
|
|
511
|
-
${S.dim(`${deployed.length} deployed`)}
|
|
512
|
-
`);
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
function makeInfoCommand() {
|
|
516
|
-
return new Command("info").description("Show asset metadata, deps, deploy status").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
517
|
-
const am2 = new AssetManager({ projectDir: path13__default.resolve(opts.projectDir) });
|
|
518
|
-
const entry = am2.info(ref);
|
|
519
|
-
if (!entry) {
|
|
520
|
-
logErr(
|
|
521
|
-
`'${ref}' not found. Run ${S.cmd("skaile source sync")} then ${S.cmd("skaile search")}.`
|
|
522
|
-
);
|
|
523
|
-
process.exit(1);
|
|
524
|
-
}
|
|
525
|
-
console.log();
|
|
526
|
-
console.log(` ${S.heading(entry.name)}`);
|
|
527
|
-
console.log(` ${S.rule(40)}`);
|
|
528
|
-
console.log(` kind: ${kindColor(entry.kind)}`);
|
|
529
|
-
if (entry.version) console.log(` version: ${entry.version}`);
|
|
530
|
-
if (entry.description) console.log(` description: ${entry.description}`);
|
|
531
|
-
if (entry.publisher) console.log(` repository: ${S.dim(entry.publisher)}`);
|
|
532
|
-
console.log(` source: ${S.dim(entry.source)}`);
|
|
533
|
-
if (entry.requires.length) {
|
|
534
|
-
console.log(` requires:`);
|
|
535
|
-
for (const d of entry.requires)
|
|
536
|
-
console.log(` ${S.dim("\xB7")} ${kindColor(d.kind)}:${d.name}`);
|
|
537
|
-
}
|
|
538
|
-
if (entry.dependencies.length) {
|
|
539
|
-
console.log(` dependencies:`);
|
|
540
|
-
for (const s of entry.dependencies) console.log(` ${S.dim("\xB7")} ${colorRef(s)}`);
|
|
541
|
-
}
|
|
542
|
-
console.log();
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
function makeCreateCommand() {
|
|
546
|
-
return new Command("create").description("Scaffold a new asset").argument("<name>", "Asset name").addOption(
|
|
547
|
-
new Option("-k, --kind <kind>", "Asset kind").default("skill").choices([...ASSET_KINDS])
|
|
548
|
-
).option("-d, --dir <dir>", "Target directory (default: cwd)").action((name, opts) => {
|
|
549
|
-
const am2 = new AssetManager({ projectDir: process.cwd() });
|
|
550
|
-
const destDir = opts.dir ? path13__default.resolve(opts.dir) : process.cwd();
|
|
551
|
-
const result = am2.create(name, opts.kind, destDir);
|
|
552
|
-
if (result.ok) logOk(`Created ${kindColor(opts.kind)}: ${pc5.dim(result.path)}`);
|
|
553
|
-
else {
|
|
554
|
-
logErr(result.path);
|
|
555
|
-
process.exit(1);
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
function makeDoctorCommand() {
|
|
560
|
-
return new Command("doctor").description("Scan for missing dependency chains").argument("[name]", "Check a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((name, opts) => {
|
|
561
|
-
const am2 = new AssetManager({ projectDir: path13__default.resolve(opts.projectDir) });
|
|
562
|
-
const issues = am2.doctor();
|
|
563
|
-
if (issues.length === 0) {
|
|
564
|
-
logOk("No missing dependencies.");
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
const assetW = Math.max(5, ...issues.map((i) => `${i.assetKind}:${i.assetName}`.length));
|
|
568
|
-
const depW = Math.max(11, ...issues.map((i) => `${i.depKind}:${i.depName}`.length));
|
|
569
|
-
console.log();
|
|
570
|
-
console.log(
|
|
571
|
-
` ${S.dim("ASSET".padEnd(assetW))} ${S.dim("MISSING DEP".padEnd(depW))} ${S.dim("IN REPOS")}`
|
|
572
|
-
);
|
|
573
|
-
console.log(` ${S.rule(assetW + depW + 15)}`);
|
|
574
|
-
for (const i of issues) {
|
|
575
|
-
const asset = `${i.assetKind}:${i.assetName}`;
|
|
576
|
-
const dep = `${i.depKind}:${i.depName}`;
|
|
577
|
-
const status4 = i.inRepos ? S.warn("fixable") : S.err("not found");
|
|
578
|
-
console.log(` ${asset.padEnd(assetW)} ${dep.padEnd(depW)} ${status4}`);
|
|
579
|
-
}
|
|
580
|
-
console.log();
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
797
|
function makeCatalogCommand() {
|
|
584
798
|
const catalog = new Command("catalog").description("Catalog source health and configuration");
|
|
585
799
|
catalog.command("test").description("Probe the configured catalog source and report status").option("--project-dir <path>", "Project directory (for project-level config overlay)").option("--url <url>", "Override the catalog URL for this probe").option("--force", "Probe the network even in air-gapped mode (cache_ttl: 0)").action(async (opts) => {
|
|
586
800
|
const { resolveConfig, isLocalCatalogUrl, trpcGetUrl } = await import('../library/index.js');
|
|
587
|
-
const projectDir = opts.projectDir ?
|
|
801
|
+
const projectDir = opts.projectDir ? path14__default.resolve(opts.projectDir) : void 0;
|
|
588
802
|
const cfg = resolveConfig({ projectDir });
|
|
589
803
|
const baseUrl = opts.url ?? cfg.catalog.url;
|
|
590
804
|
if (isLocalCatalogUrl(baseUrl)) {
|
|
@@ -602,7 +816,7 @@ function makeCatalogCommand() {
|
|
|
602
816
|
});
|
|
603
817
|
catalog.command("info").description("Print the resolved catalog configuration (url, framing, cacheTtlMs)").option("--project-dir <path>", "Project directory (for project-level config overlay)").action(async (opts) => {
|
|
604
818
|
const { resolveConfig } = await import('../library/index.js');
|
|
605
|
-
const projectDir = opts.projectDir ?
|
|
819
|
+
const projectDir = opts.projectDir ? path14__default.resolve(opts.projectDir) : void 0;
|
|
606
820
|
const cfg = resolveConfig({ projectDir });
|
|
607
821
|
console.log(`url: ${cfg.catalog.url}`);
|
|
608
822
|
console.log(`framing: ${cfg.catalog.framing}`);
|
|
@@ -744,8 +958,8 @@ function findFlowFile(flowId, priorityRoots = []) {
|
|
|
744
958
|
for (const root of [...priorityRoots, ...aiResourceRoots()]) {
|
|
745
959
|
for (const { dir } of assetSearchDirs(root, "flows")) {
|
|
746
960
|
for (const ext of [".flow.yaml", ".flow.json", ".json"]) {
|
|
747
|
-
const candidate =
|
|
748
|
-
if (
|
|
961
|
+
const candidate = path14__default.join(dir, `${flowId}${ext}`);
|
|
962
|
+
if (fs12__default.existsSync(candidate)) return candidate;
|
|
749
963
|
}
|
|
750
964
|
}
|
|
751
965
|
}
|
|
@@ -755,7 +969,7 @@ function findSkills(domain) {
|
|
|
755
969
|
const found = [];
|
|
756
970
|
for (const root of aiResourceRoots()) {
|
|
757
971
|
for (const { dir, domain: dirDomain } of assetSearchDirs(root, "skills")) {
|
|
758
|
-
if (
|
|
972
|
+
if (fs12__default.existsSync(dir)) walkSkills(dir, dirDomain, found);
|
|
759
973
|
}
|
|
760
974
|
}
|
|
761
975
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -768,11 +982,11 @@ function findSkills(domain) {
|
|
|
768
982
|
return deduped;
|
|
769
983
|
}
|
|
770
984
|
function walkSkills(dir, domain, out) {
|
|
771
|
-
for (const entry of
|
|
772
|
-
const full =
|
|
985
|
+
for (const entry of fs12__default.readdirSync(dir, { withFileTypes: true })) {
|
|
986
|
+
const full = path14__default.join(dir, entry.name);
|
|
773
987
|
if (entry.isDirectory()) {
|
|
774
|
-
const skillMd =
|
|
775
|
-
if (
|
|
988
|
+
const skillMd = path14__default.join(full, "SKILL.md");
|
|
989
|
+
if (fs12__default.existsSync(skillMd)) {
|
|
776
990
|
out.push({ name: entry.name, path: full, skillPath: skillMd, domain });
|
|
777
991
|
} else {
|
|
778
992
|
walkSkills(full, domain, out);
|
|
@@ -800,10 +1014,10 @@ function resolveFlowIds() {
|
|
|
800
1014
|
}
|
|
801
1015
|
}
|
|
802
1016
|
function resolveSessionIds(projectDir) {
|
|
803
|
-
const sessionsDir =
|
|
804
|
-
if (!
|
|
1017
|
+
const sessionsDir = path14__default.join(projectDir, ".skaile", "sessions");
|
|
1018
|
+
if (!fs12__default.existsSync(sessionsDir)) return [];
|
|
805
1019
|
try {
|
|
806
|
-
return
|
|
1020
|
+
return fs12__default.readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
|
|
807
1021
|
} catch {
|
|
808
1022
|
return [];
|
|
809
1023
|
}
|
|
@@ -919,7 +1133,7 @@ function printResolvedPathsSection(config) {
|
|
|
919
1133
|
console.log(` ${S.label("prompts:".padEnd(16))} ${config.promptsDir ?? paths.promptsDir}`);
|
|
920
1134
|
}
|
|
921
1135
|
async function showConfig(opts) {
|
|
922
|
-
const projectDir = opts.projectDir ?
|
|
1136
|
+
const projectDir = opts.projectDir ? path14__default.resolve(opts.projectDir) : process.cwd();
|
|
923
1137
|
const config = await resolveSettings(projectDir);
|
|
924
1138
|
const wsDefaults = collectWorkspaceDefaults(projectDir);
|
|
925
1139
|
printEffectiveSection(config);
|
|
@@ -932,13 +1146,13 @@ function makeConfigCommand() {
|
|
|
932
1146
|
const cmd = new Command("config").description("Manage personal config (.skaile/settings.json)");
|
|
933
1147
|
cmd.command("show").description("Show effective config with sources").option("--project-dir <path>", "Project directory").action((opts) => showConfig(opts));
|
|
934
1148
|
cmd.command("get <key>").description("Get an effective config value").option("--project-dir <path>", "Project directory").action(async (key, opts) => {
|
|
935
|
-
const projectDir = opts.projectDir ?
|
|
1149
|
+
const projectDir = opts.projectDir ? path14__default.resolve(opts.projectDir) : process.cwd();
|
|
936
1150
|
const config = await resolveSettings(projectDir);
|
|
937
1151
|
const value = config[key];
|
|
938
1152
|
console.log(value ?? S.dim("(not set)"));
|
|
939
1153
|
});
|
|
940
1154
|
cmd.command("set <key> <value>").description("Set a personal config value (driver, model, provider, apiKey.<provider>)").option("--project-dir <path>", "Project directory").option("--global", "Write to ~/.skaile/settings.json instead of project-local").action(async (key, value, opts) => {
|
|
941
|
-
const projectDir = opts.projectDir ?
|
|
1155
|
+
const projectDir = opts.projectDir ? path14__default.resolve(opts.projectDir) : process.cwd();
|
|
942
1156
|
const isApiKey = key.startsWith(API_KEY_PREFIX);
|
|
943
1157
|
if (!PERSONAL_KEYS.has(key) && !isApiKey) {
|
|
944
1158
|
logErr(
|
|
@@ -1053,11 +1267,11 @@ function makeConnectCommand() {
|
|
|
1053
1267
|
process.exitCode = 1;
|
|
1054
1268
|
return;
|
|
1055
1269
|
}
|
|
1056
|
-
await new Promise((
|
|
1270
|
+
await new Promise((resolve5) => {
|
|
1057
1271
|
client.onMessage((event) => {
|
|
1058
1272
|
console.log(formatEvent(event));
|
|
1059
1273
|
if (event.type === "finished" || event.type === "debug_result") {
|
|
1060
|
-
|
|
1274
|
+
resolve5();
|
|
1061
1275
|
}
|
|
1062
1276
|
});
|
|
1063
1277
|
client.send(parsed);
|
|
@@ -1101,12 +1315,12 @@ function makeConnectCommand() {
|
|
|
1101
1315
|
client.send(cmd);
|
|
1102
1316
|
rl.prompt();
|
|
1103
1317
|
});
|
|
1104
|
-
await new Promise((
|
|
1105
|
-
rl.on("close",
|
|
1318
|
+
await new Promise((resolve5) => {
|
|
1319
|
+
rl.on("close", resolve5);
|
|
1106
1320
|
client.onDisconnect(() => {
|
|
1107
1321
|
logErr("Server disconnected");
|
|
1108
1322
|
rl.close();
|
|
1109
|
-
|
|
1323
|
+
resolve5();
|
|
1110
1324
|
});
|
|
1111
1325
|
});
|
|
1112
1326
|
await client.disconnect();
|
|
@@ -1188,15 +1402,15 @@ function parseOpArgs(args) {
|
|
|
1188
1402
|
async function promptText(label, defaultVal) {
|
|
1189
1403
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1190
1404
|
const hint = defaultVal ? ` [${defaultVal}]` : "";
|
|
1191
|
-
return new Promise((
|
|
1405
|
+
return new Promise((resolve5) => {
|
|
1192
1406
|
rl.question(` ${label}${hint}: `, (answer) => {
|
|
1193
1407
|
rl.close();
|
|
1194
|
-
|
|
1408
|
+
resolve5(answer.trim() || defaultVal || "");
|
|
1195
1409
|
});
|
|
1196
1410
|
});
|
|
1197
1411
|
}
|
|
1198
1412
|
async function promptSecret(label) {
|
|
1199
|
-
return new Promise((
|
|
1413
|
+
return new Promise((resolve5) => {
|
|
1200
1414
|
process.stdout.write(` ${label} (hidden): `);
|
|
1201
1415
|
const stdin = process.stdin;
|
|
1202
1416
|
stdin.setRawMode?.(true);
|
|
@@ -1209,7 +1423,7 @@ async function promptSecret(label) {
|
|
|
1209
1423
|
stdin.pause();
|
|
1210
1424
|
stdin.removeListener("data", onData);
|
|
1211
1425
|
process.stdout.write("\n");
|
|
1212
|
-
|
|
1426
|
+
resolve5(value);
|
|
1213
1427
|
} else if (char === "") {
|
|
1214
1428
|
process.exit(1);
|
|
1215
1429
|
} else if (char === "\x7F") {
|
|
@@ -1256,8 +1470,8 @@ function makeConnectorCommand() {
|
|
|
1256
1470
|
async (driver, opts) => {
|
|
1257
1471
|
const { installNpmPackages } = await import('../connectors/index.js');
|
|
1258
1472
|
const { scanDirectory, factoryAssetRoots, WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
1259
|
-
const projectDir =
|
|
1260
|
-
const yamlPath =
|
|
1473
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1474
|
+
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
1261
1475
|
if (!existsSync(yamlPath)) {
|
|
1262
1476
|
logErr("No skaile.yaml found in current directory. Run 'skaile init' first.");
|
|
1263
1477
|
process.exit(1);
|
|
@@ -1317,8 +1531,8 @@ ${installResult.output}`);
|
|
|
1317
1531
|
);
|
|
1318
1532
|
cmd.command("remove <id>").option("--project-dir <path>", "Workspace directory", process.cwd()).description("Remove a connector from skaile.yaml by its instance ID").action(async (id, opts) => {
|
|
1319
1533
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
1320
|
-
const projectDir =
|
|
1321
|
-
const yamlPath =
|
|
1534
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1535
|
+
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
1322
1536
|
if (!existsSync(yamlPath)) {
|
|
1323
1537
|
logErr("No skaile.yaml found in current directory.");
|
|
1324
1538
|
process.exit(1);
|
|
@@ -1335,7 +1549,7 @@ ${installResult.output}`);
|
|
|
1335
1549
|
cmd.command("status [id]").option("--project-dir <path>", "Workspace directory", process.cwd()).description("Connect and report health status for one or all connectors").action(async (id, opts) => {
|
|
1336
1550
|
const res = await import('../connectors/index.js');
|
|
1337
1551
|
res.registerBuiltinConnectors();
|
|
1338
|
-
const projectDir =
|
|
1552
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1339
1553
|
const declarations = res.loadConnectorDeclarations(projectDir);
|
|
1340
1554
|
if (declarations.length === 0) {
|
|
1341
1555
|
console.log("No connectors configured in skaile.yaml.");
|
|
@@ -1359,7 +1573,7 @@ ${installResult.output}`);
|
|
|
1359
1573
|
await manager.disconnectAll();
|
|
1360
1574
|
});
|
|
1361
1575
|
cmd.command("list").description("List all configured connectors").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
1362
|
-
const projectDir =
|
|
1576
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1363
1577
|
const manager = await connectConnectors(projectDir);
|
|
1364
1578
|
try {
|
|
1365
1579
|
console.log(JSON.stringify(manager.listConnectors(), null, 2));
|
|
@@ -1368,7 +1582,7 @@ ${installResult.output}`);
|
|
|
1368
1582
|
}
|
|
1369
1583
|
});
|
|
1370
1584
|
cmd.command("sync [id]").description("Re-sync a filesystem-face connector or all of them (git pull, S3 refresh, etc.)").option("--all", "Sync all connectors").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, opts) => {
|
|
1371
|
-
const projectDir =
|
|
1585
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1372
1586
|
const manager = await connectConnectors(projectDir);
|
|
1373
1587
|
try {
|
|
1374
1588
|
if (opts.all) {
|
|
@@ -1392,7 +1606,7 @@ ${installResult.output}`);
|
|
|
1392
1606
|
}
|
|
1393
1607
|
});
|
|
1394
1608
|
cmd.command("ops <id>").description("List available operations for a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, opts) => {
|
|
1395
|
-
const projectDir =
|
|
1609
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1396
1610
|
const manager = await connectConnectors(projectDir);
|
|
1397
1611
|
try {
|
|
1398
1612
|
if (!manager.has(id)) {
|
|
@@ -1407,7 +1621,7 @@ ${installResult.output}`);
|
|
|
1407
1621
|
}
|
|
1408
1622
|
});
|
|
1409
1623
|
cmd.command("read <id> <resource-path>").description("Read content from a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, resourcePath, opts) => {
|
|
1410
|
-
const projectDir =
|
|
1624
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1411
1625
|
const manager = await connectConnectors(projectDir);
|
|
1412
1626
|
try {
|
|
1413
1627
|
const content = await manager.read(id, resourcePath);
|
|
@@ -1417,7 +1631,7 @@ ${installResult.output}`);
|
|
|
1417
1631
|
}
|
|
1418
1632
|
});
|
|
1419
1633
|
cmd.command("write <id> <resource-path> <content>").description("Write content to a connector at a path").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, resourcePath, content, opts) => {
|
|
1420
|
-
const projectDir =
|
|
1634
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1421
1635
|
const manager = await connectConnectors(projectDir);
|
|
1422
1636
|
try {
|
|
1423
1637
|
await manager.write(id, resourcePath, { data: content });
|
|
@@ -1427,7 +1641,7 @@ ${installResult.output}`);
|
|
|
1427
1641
|
}
|
|
1428
1642
|
});
|
|
1429
1643
|
cmd.command("entries <id> [resource-path]").description("List entries in a connector (files, keys, rows, etc)").option("--project-dir <path>", "Workspace directory", process.cwd()).option("--recursive", "Include nested entries").option("--limit <n>", "Maximum entries to return", parsePositiveIntOption).action(async (id, resourcePath, opts) => {
|
|
1430
|
-
const projectDir =
|
|
1644
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1431
1645
|
const manager = await connectConnectors(projectDir);
|
|
1432
1646
|
try {
|
|
1433
1647
|
const entries = await manager.list(id, resourcePath, {
|
|
@@ -1440,7 +1654,7 @@ ${installResult.output}`);
|
|
|
1440
1654
|
}
|
|
1441
1655
|
});
|
|
1442
1656
|
cmd.command("search <id> <query>").description("Search within a connector for matching content").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, query, opts) => {
|
|
1443
|
-
const projectDir =
|
|
1657
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1444
1658
|
const manager = await connectConnectors(projectDir);
|
|
1445
1659
|
try {
|
|
1446
1660
|
const results = await manager.search(id, query);
|
|
@@ -1450,7 +1664,7 @@ ${installResult.output}`);
|
|
|
1450
1664
|
}
|
|
1451
1665
|
});
|
|
1452
1666
|
cmd.command("delete <id> <resource-path>").description("Delete an entry from a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, resourcePath, opts) => {
|
|
1453
|
-
const projectDir =
|
|
1667
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1454
1668
|
const manager = await connectConnectors(projectDir);
|
|
1455
1669
|
try {
|
|
1456
1670
|
const ok = await manager.delete(id, resourcePath);
|
|
@@ -1460,7 +1674,7 @@ ${installResult.output}`);
|
|
|
1460
1674
|
}
|
|
1461
1675
|
});
|
|
1462
1676
|
cmd.command("run <id> <op> [args...]").description("Run a custom adapter operation (e.g. git log, sqlite query)").option("--project-dir <path>", "Workspace directory", process.cwd()).allowUnknownOption().action(async (id, op, args, opts) => {
|
|
1463
|
-
const projectDir =
|
|
1677
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1464
1678
|
const manager = await connectConnectors(projectDir);
|
|
1465
1679
|
try {
|
|
1466
1680
|
if (!manager.has(id)) {
|
|
@@ -1495,17 +1709,17 @@ async function runDebugQuery(query, parentOpts, args) {
|
|
|
1495
1709
|
process.exitCode = 1;
|
|
1496
1710
|
return;
|
|
1497
1711
|
}
|
|
1498
|
-
await new Promise((
|
|
1712
|
+
await new Promise((resolve5) => {
|
|
1499
1713
|
const timeout = setTimeout(() => {
|
|
1500
1714
|
logErr("Timeout: no debug_result received within 5s");
|
|
1501
1715
|
process.exitCode = 1;
|
|
1502
|
-
|
|
1716
|
+
resolve5();
|
|
1503
1717
|
}, 5e3);
|
|
1504
1718
|
client.onMessage((event) => {
|
|
1505
1719
|
if (event.type !== "debug_result") return;
|
|
1506
1720
|
clearTimeout(timeout);
|
|
1507
1721
|
printDebugResult(query, event.data);
|
|
1508
|
-
|
|
1722
|
+
resolve5();
|
|
1509
1723
|
});
|
|
1510
1724
|
client.send({ type: "debug", query, args });
|
|
1511
1725
|
});
|
|
@@ -1569,7 +1783,7 @@ function envRecord() {
|
|
|
1569
1783
|
async function buildDeployContext(projectDir) {
|
|
1570
1784
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
1571
1785
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
1572
|
-
const workspaceId = config.name ??
|
|
1786
|
+
const workspaceId = config.name ?? path14__default.basename(projectDir);
|
|
1573
1787
|
let log;
|
|
1574
1788
|
try {
|
|
1575
1789
|
const { createLogger } = await import('../core/logging.js');
|
|
@@ -1601,13 +1815,13 @@ async function ensureTargetsRegistered(projectDir) {
|
|
|
1601
1815
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
1602
1816
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
1603
1817
|
if (config.plugins && config.plugins.length > 0) {
|
|
1604
|
-
const { ensurePluginsLoaded } = await import('../plugin-store-
|
|
1818
|
+
const { ensurePluginsLoaded } = await import('../plugin-store-2X2YXJVG.js');
|
|
1605
1819
|
const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
|
|
1606
1820
|
for (const f of result.failed) logWarn(f.error);
|
|
1607
1821
|
}
|
|
1608
1822
|
}
|
|
1609
1823
|
async function runUp(opts) {
|
|
1610
|
-
const projectDir =
|
|
1824
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1611
1825
|
await ensureTargetsRegistered(projectDir);
|
|
1612
1826
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
1613
1827
|
const { resolveDeployTarget, pluginRegistry } = await import('../plugin-registry/index.js');
|
|
@@ -1639,12 +1853,12 @@ async function runUp(opts) {
|
|
|
1639
1853
|
await holdUntilSignal(handle, controller);
|
|
1640
1854
|
}
|
|
1641
1855
|
function holdUntilSignal(handle, controller) {
|
|
1642
|
-
return new Promise((
|
|
1856
|
+
return new Promise((resolve5) => {
|
|
1643
1857
|
const onSig = () => {
|
|
1644
1858
|
process.removeListener("SIGINT", onSig);
|
|
1645
1859
|
controller.abort();
|
|
1646
1860
|
logInfo("Stopping\u2026");
|
|
1647
|
-
handle.stop().then(() => logOk("Stopped.")).catch((e) => logErr(`stop failed: ${e instanceof Error ? e.message : String(e)}`)).finally(() =>
|
|
1861
|
+
handle.stop().then(() => logOk("Stopped.")).catch((e) => logErr(`stop failed: ${e instanceof Error ? e.message : String(e)}`)).finally(() => resolve5());
|
|
1648
1862
|
};
|
|
1649
1863
|
process.on("SIGINT", onSig);
|
|
1650
1864
|
});
|
|
@@ -1675,7 +1889,7 @@ async function restoreFromHandle(projectDir) {
|
|
|
1675
1889
|
return { target, handle, ctx };
|
|
1676
1890
|
}
|
|
1677
1891
|
async function runDown(opts) {
|
|
1678
|
-
const projectDir =
|
|
1892
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1679
1893
|
const restored = await restoreFromHandle(projectDir);
|
|
1680
1894
|
if (!restored) return;
|
|
1681
1895
|
await restored.handle.stop();
|
|
@@ -1684,7 +1898,7 @@ async function runDown(opts) {
|
|
|
1684
1898
|
logOk(`Stopped ${S.cmd(restored.target.id)} and cleared the handle.`);
|
|
1685
1899
|
}
|
|
1686
1900
|
async function runStatus(opts) {
|
|
1687
|
-
const projectDir =
|
|
1901
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1688
1902
|
const restored = await restoreFromHandle(projectDir);
|
|
1689
1903
|
if (!restored) return;
|
|
1690
1904
|
const health = await restored.handle.health();
|
|
@@ -1698,7 +1912,7 @@ async function runStatus(opts) {
|
|
|
1698
1912
|
console.log();
|
|
1699
1913
|
}
|
|
1700
1914
|
async function runLogs(opts) {
|
|
1701
|
-
const projectDir =
|
|
1915
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
1702
1916
|
const restored = await restoreFromHandle(projectDir);
|
|
1703
1917
|
if (!restored) return;
|
|
1704
1918
|
if (!restored.handle.logs) {
|
|
@@ -1722,7 +1936,7 @@ function makeDeployCommand() {
|
|
|
1722
1936
|
}
|
|
1723
1937
|
function makeDiffCommand() {
|
|
1724
1938
|
return new Command("diff").description("Show changes between deployed and source versions").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
1725
|
-
const am2 = new AssetManager({ projectDir:
|
|
1939
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
1726
1940
|
const result = am2.diff(ref);
|
|
1727
1941
|
if (result === null) {
|
|
1728
1942
|
logInfo("No differences (or asset not found).");
|
|
@@ -1775,7 +1989,7 @@ function makeFlowCommand() {
|
|
|
1775
1989
|
function makeHistoryCommand() {
|
|
1776
1990
|
const cmd = new Command("history").description("Show recent add/remove/update actions");
|
|
1777
1991
|
cmd.argument("[limit]", "Number of entries to show", "20").option("--project-dir <path>", "Project directory", process.cwd()).action((limitStr, opts) => {
|
|
1778
|
-
const am2 = new AssetManager({ projectDir:
|
|
1992
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
1779
1993
|
const limit = parseInt(limitStr, 10) || 20;
|
|
1780
1994
|
const entries = am2.history(limit);
|
|
1781
1995
|
if (entries.length === 0) {
|
|
@@ -1795,7 +2009,7 @@ function makeHistoryCommand() {
|
|
|
1795
2009
|
console.log();
|
|
1796
2010
|
});
|
|
1797
2011
|
cmd.command("clear").description("Clear action history").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
1798
|
-
const am2 = new AssetManager({ projectDir:
|
|
2012
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
1799
2013
|
am2.clearHistory();
|
|
1800
2014
|
logOk("History cleared.");
|
|
1801
2015
|
});
|
|
@@ -1808,12 +2022,12 @@ var MCP_SERVER_ENTRY = {
|
|
|
1808
2022
|
env: {}
|
|
1809
2023
|
};
|
|
1810
2024
|
function pluginDir(projectDir) {
|
|
1811
|
-
return
|
|
2025
|
+
return path14__default.join(projectDir, ".claude", "plugins", "skaile");
|
|
1812
2026
|
}
|
|
1813
2027
|
async function readJsonStrict(p9) {
|
|
1814
2028
|
let raw;
|
|
1815
2029
|
try {
|
|
1816
|
-
raw = await
|
|
2030
|
+
raw = await fs6.readFile(p9, "utf-8");
|
|
1817
2031
|
} catch {
|
|
1818
2032
|
return null;
|
|
1819
2033
|
}
|
|
@@ -1826,32 +2040,32 @@ async function readJsonStrict(p9) {
|
|
|
1826
2040
|
}
|
|
1827
2041
|
}
|
|
1828
2042
|
async function writeJson(p9, value) {
|
|
1829
|
-
await
|
|
1830
|
-
await
|
|
2043
|
+
await fs6.mkdir(path14__default.dirname(p9), { recursive: true });
|
|
2044
|
+
await fs6.writeFile(p9, `${JSON.stringify(value, null, 2)}
|
|
1831
2045
|
`);
|
|
1832
2046
|
}
|
|
1833
2047
|
async function copyDir(src, dest) {
|
|
1834
|
-
await
|
|
1835
|
-
const entries = await
|
|
2048
|
+
await fs6.mkdir(dest, { recursive: true });
|
|
2049
|
+
const entries = await fs6.readdir(src, { withFileTypes: true });
|
|
1836
2050
|
for (const entry of entries) {
|
|
1837
|
-
const srcPath =
|
|
1838
|
-
const destPath =
|
|
2051
|
+
const srcPath = path14__default.join(src, entry.name);
|
|
2052
|
+
const destPath = path14__default.join(dest, entry.name);
|
|
1839
2053
|
if (entry.isDirectory()) await copyDir(srcPath, destPath);
|
|
1840
|
-
else await
|
|
2054
|
+
else await fs6.copyFile(srcPath, destPath);
|
|
1841
2055
|
}
|
|
1842
2056
|
}
|
|
1843
2057
|
async function install(projectDir, opts) {
|
|
1844
2058
|
return opts?.full ? installFullPlugin(projectDir) : installMcp(projectDir);
|
|
1845
2059
|
}
|
|
1846
2060
|
async function installMcp(projectDir) {
|
|
1847
|
-
const mcpPath =
|
|
2061
|
+
const mcpPath = path14__default.join(projectDir, ".claude", "mcp.json");
|
|
1848
2062
|
const existing = await readJsonStrict(mcpPath) ?? {};
|
|
1849
2063
|
const mcpServers = { ...existing.mcpServers ?? {} };
|
|
1850
2064
|
const previous = mcpServers[SKAILE_MCP_NAME];
|
|
1851
2065
|
const matches = previous && JSON.stringify(previous) === JSON.stringify(MCP_SERVER_ENTRY);
|
|
1852
2066
|
let warning;
|
|
1853
2067
|
if (previous && !matches) {
|
|
1854
|
-
warning = `overwrote existing ${SKAILE_MCP_NAME} entry in ${
|
|
2068
|
+
warning = `overwrote existing ${SKAILE_MCP_NAME} entry in ${path14__default.relative(projectDir, mcpPath)}`;
|
|
1855
2069
|
}
|
|
1856
2070
|
mcpServers[SKAILE_MCP_NAME] = MCP_SERVER_ENTRY;
|
|
1857
2071
|
await writeJson(mcpPath, { ...existing, mcpServers });
|
|
@@ -1860,15 +2074,15 @@ async function installMcp(projectDir) {
|
|
|
1860
2074
|
async function installFullPlugin(projectDir) {
|
|
1861
2075
|
const dir = pluginDir(projectDir);
|
|
1862
2076
|
for (const [rel, content] of Object.entries(buildClaudePluginFiles())) {
|
|
1863
|
-
const dest =
|
|
1864
|
-
await
|
|
1865
|
-
await
|
|
2077
|
+
const dest = path14__default.join(dir, rel);
|
|
2078
|
+
await fs6.mkdir(path14__default.dirname(dest), { recursive: true });
|
|
2079
|
+
await fs6.writeFile(dest, content);
|
|
1866
2080
|
}
|
|
1867
|
-
const projectSkillsDir =
|
|
2081
|
+
const projectSkillsDir = path14__default.join(projectDir, ".skaile", "skills");
|
|
1868
2082
|
if (existsSync(projectSkillsDir)) {
|
|
1869
|
-
await copyDir(projectSkillsDir,
|
|
2083
|
+
await copyDir(projectSkillsDir, path14__default.join(dir, "skills"));
|
|
1870
2084
|
}
|
|
1871
|
-
const settingsPath =
|
|
2085
|
+
const settingsPath = path14__default.join(projectDir, ".claude", "settings.json");
|
|
1872
2086
|
const settings = await readJsonStrict(settingsPath) ?? {};
|
|
1873
2087
|
const plugins = settings.plugins ?? [];
|
|
1874
2088
|
if (!plugins.includes(dir)) plugins.push(dir);
|
|
@@ -1876,8 +2090,8 @@ async function installFullPlugin(projectDir) {
|
|
|
1876
2090
|
return { changed: true, method: "plugin" };
|
|
1877
2091
|
}
|
|
1878
2092
|
async function uninstall(projectDir) {
|
|
1879
|
-
const settingsPath =
|
|
1880
|
-
const mcpPath =
|
|
2093
|
+
const settingsPath = path14__default.join(projectDir, ".claude", "settings.json");
|
|
2094
|
+
const mcpPath = path14__default.join(projectDir, ".claude", "mcp.json");
|
|
1881
2095
|
const dir = pluginDir(projectDir);
|
|
1882
2096
|
let changed = false;
|
|
1883
2097
|
const settings = await readJsonStrict(settingsPath);
|
|
@@ -1891,7 +2105,7 @@ async function uninstall(projectDir) {
|
|
|
1891
2105
|
}
|
|
1892
2106
|
}
|
|
1893
2107
|
if (existsSync(dir)) {
|
|
1894
|
-
await
|
|
2108
|
+
await fs6.rm(dir, { recursive: true, force: true });
|
|
1895
2109
|
changed = true;
|
|
1896
2110
|
}
|
|
1897
2111
|
const mcp = await readJsonStrict(mcpPath);
|
|
@@ -1901,7 +2115,7 @@ async function uninstall(projectDir) {
|
|
|
1901
2115
|
const updated = { ...mcp, mcpServers: rest };
|
|
1902
2116
|
if (Object.keys(rest).length === 0) delete updated.mcpServers;
|
|
1903
2117
|
if (Object.keys(updated).length === 0) {
|
|
1904
|
-
await
|
|
2118
|
+
await fs6.unlink(mcpPath);
|
|
1905
2119
|
} else {
|
|
1906
2120
|
await writeJson(mcpPath, updated);
|
|
1907
2121
|
}
|
|
@@ -1911,12 +2125,12 @@ async function uninstall(projectDir) {
|
|
|
1911
2125
|
async function detectInstall(projectDir) {
|
|
1912
2126
|
const dir = pluginDir(projectDir);
|
|
1913
2127
|
const settings = await readJsonStrict(
|
|
1914
|
-
|
|
2128
|
+
path14__default.join(projectDir, ".claude", "settings.json")
|
|
1915
2129
|
);
|
|
1916
|
-
if (existsSync(
|
|
2130
|
+
if (existsSync(path14__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir)) {
|
|
1917
2131
|
return { method: "plugin", pluginPath: dir };
|
|
1918
2132
|
}
|
|
1919
|
-
const mcp = await readJsonStrict(
|
|
2133
|
+
const mcp = await readJsonStrict(path14__default.join(projectDir, ".claude", "mcp.json"));
|
|
1920
2134
|
if (mcp?.mcpServers && SKAILE_MCP_NAME in mcp.mcpServers) {
|
|
1921
2135
|
return { method: "mcp" };
|
|
1922
2136
|
}
|
|
@@ -1925,7 +2139,7 @@ async function detectInstall(projectDir) {
|
|
|
1925
2139
|
async function enable(projectDir) {
|
|
1926
2140
|
const detected = await detectInstall(projectDir);
|
|
1927
2141
|
if (!detected) throw new Error("plugin not installed for claude-code");
|
|
1928
|
-
const settingsPath =
|
|
2142
|
+
const settingsPath = path14__default.join(projectDir, ".claude", "settings.json");
|
|
1929
2143
|
const settings = await readJsonStrict(settingsPath) ?? {};
|
|
1930
2144
|
if (detected.method === "plugin") {
|
|
1931
2145
|
const disabled2 = settings.disabledPlugins ?? [];
|
|
@@ -1947,7 +2161,7 @@ async function enable(projectDir) {
|
|
|
1947
2161
|
async function disable(projectDir) {
|
|
1948
2162
|
const detected = await detectInstall(projectDir);
|
|
1949
2163
|
if (!detected) throw new Error("plugin not installed for claude-code");
|
|
1950
|
-
const settingsPath =
|
|
2164
|
+
const settingsPath = path14__default.join(projectDir, ".claude", "settings.json");
|
|
1951
2165
|
const settings = await readJsonStrict(settingsPath) ?? {};
|
|
1952
2166
|
if (detected.method === "plugin") {
|
|
1953
2167
|
const list2 = settings.disabledPlugins ?? [];
|
|
@@ -1967,12 +2181,12 @@ async function disable(projectDir) {
|
|
|
1967
2181
|
return { changed: true };
|
|
1968
2182
|
}
|
|
1969
2183
|
async function status(projectDir) {
|
|
1970
|
-
const settingsPath =
|
|
1971
|
-
const mcpPath =
|
|
2184
|
+
const settingsPath = path14__default.join(projectDir, ".claude", "settings.json");
|
|
2185
|
+
const mcpPath = path14__default.join(projectDir, ".claude", "mcp.json");
|
|
1972
2186
|
const dir = pluginDir(projectDir);
|
|
1973
2187
|
const settings = await readJsonStrict(settingsPath);
|
|
1974
2188
|
const mcp = await readJsonStrict(mcpPath);
|
|
1975
|
-
const pluginInstalled = !!(existsSync(
|
|
2189
|
+
const pluginInstalled = !!(existsSync(path14__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir));
|
|
1976
2190
|
const mcpInstalled = !!(mcp?.mcpServers && SKAILE_MCP_NAME in mcp.mcpServers);
|
|
1977
2191
|
if (!pluginInstalled && !mcpInstalled) {
|
|
1978
2192
|
return {
|
|
@@ -1990,7 +2204,7 @@ async function status(projectDir) {
|
|
|
1990
2204
|
installed: "yes",
|
|
1991
2205
|
enabled: disabled2 ? "no" : "yes",
|
|
1992
2206
|
method: "plugin",
|
|
1993
|
-
location:
|
|
2207
|
+
location: path14__default.relative(projectDir, dir)
|
|
1994
2208
|
};
|
|
1995
2209
|
}
|
|
1996
2210
|
const disabled = settings?.disabledMcpjsonServers?.includes(SKAILE_MCP_NAME) ?? false;
|
|
@@ -1999,7 +2213,7 @@ async function status(projectDir) {
|
|
|
1999
2213
|
installed: "yes",
|
|
2000
2214
|
enabled: disabled ? "no" : "yes",
|
|
2001
2215
|
method: "mcp",
|
|
2002
|
-
location:
|
|
2216
|
+
location: path14__default.relative(projectDir, mcpPath)
|
|
2003
2217
|
};
|
|
2004
2218
|
}
|
|
2005
2219
|
var SKAILE_MCP_NAME2 = "skaile-workspace";
|
|
@@ -2013,7 +2227,7 @@ function buildEntry(projectDir) {
|
|
|
2013
2227
|
async function readConfig(p9) {
|
|
2014
2228
|
let raw;
|
|
2015
2229
|
try {
|
|
2016
|
-
raw = await
|
|
2230
|
+
raw = await fs6.readFile(p9, "utf-8");
|
|
2017
2231
|
} catch {
|
|
2018
2232
|
return null;
|
|
2019
2233
|
}
|
|
@@ -2026,16 +2240,16 @@ async function readConfig(p9) {
|
|
|
2026
2240
|
}
|
|
2027
2241
|
}
|
|
2028
2242
|
async function writeConfig(p9, value) {
|
|
2029
|
-
await
|
|
2243
|
+
await fs6.mkdir(path14__default.dirname(p9), { recursive: true });
|
|
2030
2244
|
const cleaned = {};
|
|
2031
2245
|
for (const [k, v] of Object.entries(value)) {
|
|
2032
2246
|
if (v === void 0) continue;
|
|
2033
2247
|
cleaned[k] = v;
|
|
2034
2248
|
}
|
|
2035
|
-
await
|
|
2249
|
+
await fs6.writeFile(p9, stringify$1(cleaned));
|
|
2036
2250
|
}
|
|
2037
2251
|
function configPath(projectDir) {
|
|
2038
|
-
return
|
|
2252
|
+
return path14__default.join(projectDir, ".codex", "config.toml");
|
|
2039
2253
|
}
|
|
2040
2254
|
async function install2(projectDir) {
|
|
2041
2255
|
const p9 = configPath(projectDir);
|
|
@@ -2046,7 +2260,7 @@ async function install2(projectDir) {
|
|
|
2046
2260
|
const matches = previous && JSON.stringify(previous) === JSON.stringify(next);
|
|
2047
2261
|
let warning;
|
|
2048
2262
|
if (previous && !matches) {
|
|
2049
|
-
warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${
|
|
2263
|
+
warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${path14__default.relative(projectDir, p9)}`;
|
|
2050
2264
|
}
|
|
2051
2265
|
if (matches) return { changed: false, method: "toml" };
|
|
2052
2266
|
servers[SKAILE_MCP_NAME2] = next;
|
|
@@ -2063,7 +2277,7 @@ async function uninstall2(projectDir) {
|
|
|
2063
2277
|
const updated = { ...cfg, mcp_servers: rest };
|
|
2064
2278
|
if (Object.keys(rest).length === 0) delete updated.mcp_servers;
|
|
2065
2279
|
if (Object.keys(updated).length === 0) {
|
|
2066
|
-
await
|
|
2280
|
+
await fs6.unlink(p9);
|
|
2067
2281
|
} else {
|
|
2068
2282
|
await writeConfig(p9, updated);
|
|
2069
2283
|
}
|
|
@@ -2087,43 +2301,43 @@ async function status2(projectDir) {
|
|
|
2087
2301
|
installed: "yes",
|
|
2088
2302
|
enabled: "n/a",
|
|
2089
2303
|
method: "mcp",
|
|
2090
|
-
location:
|
|
2304
|
+
location: path14__default.relative(projectDir, p9)
|
|
2091
2305
|
};
|
|
2092
2306
|
}
|
|
2093
2307
|
async function install3(projectDir) {
|
|
2094
|
-
const extDir =
|
|
2095
|
-
const extPath =
|
|
2096
|
-
await
|
|
2308
|
+
const extDir = path14__default.join(projectDir, ".omp", "extensions");
|
|
2309
|
+
const extPath = path14__default.join(extDir, "skaile.ts");
|
|
2310
|
+
await fs6.mkdir(extDir, { recursive: true });
|
|
2097
2311
|
const { WorkspacePlugin } = await import('../workspace-plugin/index.js');
|
|
2098
2312
|
const plugin = new WorkspacePlugin({ projectDir });
|
|
2099
2313
|
const nextSrc = await plugin.buildOmpExtensionSource();
|
|
2100
2314
|
let prevSrc = null;
|
|
2101
2315
|
try {
|
|
2102
|
-
prevSrc = await
|
|
2316
|
+
prevSrc = await fs6.readFile(extPath, "utf-8");
|
|
2103
2317
|
} catch {
|
|
2104
2318
|
}
|
|
2105
2319
|
if (prevSrc === nextSrc) return { changed: false, method: "generated" };
|
|
2106
|
-
await
|
|
2320
|
+
await fs6.writeFile(extPath, nextSrc);
|
|
2107
2321
|
return { changed: true, method: "generated" };
|
|
2108
2322
|
}
|
|
2109
2323
|
async function uninstall3(projectDir) {
|
|
2110
|
-
const extPath =
|
|
2324
|
+
const extPath = path14__default.join(projectDir, ".omp", "extensions", "skaile.ts");
|
|
2111
2325
|
try {
|
|
2112
|
-
await
|
|
2326
|
+
await fs6.unlink(extPath);
|
|
2113
2327
|
return { changed: true };
|
|
2114
2328
|
} catch {
|
|
2115
2329
|
return { changed: false };
|
|
2116
2330
|
}
|
|
2117
2331
|
}
|
|
2118
2332
|
async function status3(projectDir) {
|
|
2119
|
-
const extPath =
|
|
2333
|
+
const extPath = path14__default.join(projectDir, ".omp", "extensions", "skaile.ts");
|
|
2120
2334
|
if (existsSync(extPath)) {
|
|
2121
2335
|
return {
|
|
2122
2336
|
backend: "omp",
|
|
2123
2337
|
installed: "yes",
|
|
2124
2338
|
enabled: "n/a",
|
|
2125
2339
|
method: "extension",
|
|
2126
|
-
location:
|
|
2340
|
+
location: path14__default.relative(projectDir, extPath)
|
|
2127
2341
|
};
|
|
2128
2342
|
}
|
|
2129
2343
|
return {
|
|
@@ -2186,7 +2400,7 @@ async function installCodex(projectDir) {
|
|
|
2186
2400
|
console.log(` ${S.dim("\u2192")} Restart Codex CLI to pick up the change.`);
|
|
2187
2401
|
}
|
|
2188
2402
|
async function runInstall(opts) {
|
|
2189
|
-
const projectDir =
|
|
2403
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
2190
2404
|
const targets = resolveDriver(opts.driver);
|
|
2191
2405
|
let exitCode = 0;
|
|
2192
2406
|
if (targets.includes("claude-code")) {
|
|
@@ -2220,7 +2434,7 @@ async function uninstallCodex(projectDir) {
|
|
|
2220
2434
|
else logInfo(`codex: not installed`);
|
|
2221
2435
|
}
|
|
2222
2436
|
async function runUninstall(opts) {
|
|
2223
|
-
const projectDir =
|
|
2437
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
2224
2438
|
const targets = resolveDriver(opts.driver);
|
|
2225
2439
|
let exitCode = 0;
|
|
2226
2440
|
if (targets.includes("claude-code")) {
|
|
@@ -2263,7 +2477,7 @@ async function toggleTarget(t, projectDir, action3) {
|
|
|
2263
2477
|
});
|
|
2264
2478
|
}
|
|
2265
2479
|
async function runToggle(opts, action3) {
|
|
2266
|
-
const projectDir =
|
|
2480
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
2267
2481
|
const requestedAll = opts.driver === "all";
|
|
2268
2482
|
const targets = resolveDriver(opts.driver);
|
|
2269
2483
|
const usageError = checkToggleSupported(targets, requestedAll, action3);
|
|
@@ -2275,7 +2489,7 @@ async function runToggle(opts, action3) {
|
|
|
2275
2489
|
return exitCode;
|
|
2276
2490
|
}
|
|
2277
2491
|
async function runStatus2(opts) {
|
|
2278
|
-
const projectDir =
|
|
2492
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
2279
2493
|
const targets = resolveDriver(opts.driver);
|
|
2280
2494
|
const rows = [];
|
|
2281
2495
|
let exitCode = 0;
|
|
@@ -2346,7 +2560,7 @@ async function runHook(event) {
|
|
|
2346
2560
|
await plugin.shutdown();
|
|
2347
2561
|
return;
|
|
2348
2562
|
}
|
|
2349
|
-
const store = new PluginStore(
|
|
2563
|
+
const store = new PluginStore(path14__default.join(projectDir, ".skaile", "plugin-state.json"));
|
|
2350
2564
|
await store.load();
|
|
2351
2565
|
const status4 = store.get("connector:status");
|
|
2352
2566
|
if (status4 && typeof status4 === "object" && Object.keys(status4).length > 0) {
|
|
@@ -2468,12 +2682,12 @@ function makeLibraryCommand() {
|
|
|
2468
2682
|
cmd.command("init <name>").description("Create a new local library at ~/.skaile/libraries/<name>").option("--git <url>", "Initialize as a git library tracking <url>").option("--owner", "Mark as owner (default for local)").option("--contributor", "Mark as contributor").option("--reader", "Mark as reader").action(
|
|
2469
2683
|
async (name, opts) => {
|
|
2470
2684
|
const libDir = resolveLibraryDir();
|
|
2471
|
-
const libPath =
|
|
2685
|
+
const libPath = path14.join(libDir, name);
|
|
2472
2686
|
const ownership = opts.contributor ? "contributor" : opts.reader ? "reader" : "owner";
|
|
2473
2687
|
const { manager, close } = await openLibraryManager();
|
|
2474
2688
|
try {
|
|
2475
2689
|
if (opts.git) {
|
|
2476
|
-
|
|
2690
|
+
fs12.mkdirSync(libPath, { recursive: true });
|
|
2477
2691
|
await manager.addLibrary({
|
|
2478
2692
|
name,
|
|
2479
2693
|
path: libPath,
|
|
@@ -2482,7 +2696,7 @@ function makeLibraryCommand() {
|
|
|
2482
2696
|
ownership
|
|
2483
2697
|
});
|
|
2484
2698
|
} else {
|
|
2485
|
-
|
|
2699
|
+
fs12.mkdirSync(libPath, { recursive: true });
|
|
2486
2700
|
await manager.addLibrary({
|
|
2487
2701
|
name,
|
|
2488
2702
|
path: libPath,
|
|
@@ -2539,7 +2753,7 @@ function makeLibraryCommand() {
|
|
|
2539
2753
|
target = def;
|
|
2540
2754
|
}
|
|
2541
2755
|
const am2 = new AssetManager({ projectDir: process.cwd() });
|
|
2542
|
-
const destDir = opts.dir ?
|
|
2756
|
+
const destDir = opts.dir ? path14.join(target.path, opts.dir) : target.path;
|
|
2543
2757
|
const res = am2.create(name, opts.kind ?? kind, destDir);
|
|
2544
2758
|
if (res.ok) {
|
|
2545
2759
|
logOk(`Created ${opts.kind ?? kind}: ${pc5.dim(res.path)}`);
|
|
@@ -2552,6 +2766,80 @@ function makeLibraryCommand() {
|
|
|
2552
2766
|
}
|
|
2553
2767
|
}
|
|
2554
2768
|
);
|
|
2769
|
+
const domain = cmd.command("domain").description("Manage domains (publisher namespaces) inside a library");
|
|
2770
|
+
async function resolveTargetLibrary(manager, libraryName) {
|
|
2771
|
+
if (libraryName) return manager.requireLibrary(libraryName);
|
|
2772
|
+
const all = await manager.listLibraries();
|
|
2773
|
+
const def = all.find((l) => l.isDefault);
|
|
2774
|
+
if (def) return def;
|
|
2775
|
+
if (all.length === 1) return all[0];
|
|
2776
|
+
if (all.length === 0) {
|
|
2777
|
+
logErr("No libraries registered. Run `skaile library init <name>` first.");
|
|
2778
|
+
process.exit(1);
|
|
2779
|
+
}
|
|
2780
|
+
logErr("No default library set. Run `skaile library default <name>` or pass --library.");
|
|
2781
|
+
process.exit(1);
|
|
2782
|
+
}
|
|
2783
|
+
domain.command("create <name>").description("Scaffold a domain dir + DOMAIN.md inside a library").option("--library <name>", "Target library (default: the default-marked one)").option("--publisher <p>", "Publisher slug (default: the domain name kebab-cased)").option("--description <text>", "Domain description for DOMAIN.md").action(
|
|
2784
|
+
async (name, opts) => {
|
|
2785
|
+
const { manager, close } = await openLibraryManager();
|
|
2786
|
+
try {
|
|
2787
|
+
const target = await resolveTargetLibrary(manager, opts.library);
|
|
2788
|
+
if (target.ownership === "reader") {
|
|
2789
|
+
logErr(`Library "${target.name}" is read-only (ownership=reader).`);
|
|
2790
|
+
process.exit(1);
|
|
2791
|
+
}
|
|
2792
|
+
const res = ensureDomain(target.path, name, {
|
|
2793
|
+
publisher: opts.publisher,
|
|
2794
|
+
description: opts.description
|
|
2795
|
+
});
|
|
2796
|
+
if (target.structure !== "domain") {
|
|
2797
|
+
await manager.updateLibrary(target.id, { structure: "domain" });
|
|
2798
|
+
}
|
|
2799
|
+
if (res.created) {
|
|
2800
|
+
logOk(`Created domain ${S.cmd(name)} (publisher @${res.publisher}) \u2192 ${res.dir}`);
|
|
2801
|
+
} else {
|
|
2802
|
+
logInfo(`Domain ${S.cmd(name)} already exists at ${res.dir}`);
|
|
2803
|
+
}
|
|
2804
|
+
} finally {
|
|
2805
|
+
close();
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
);
|
|
2809
|
+
domain.command("list").description("List domains in a library").option("--library <name>", "Target library (default: the default-marked one)").option("--json", "Output as JSON").action(async (opts) => {
|
|
2810
|
+
const { manager, close } = await openLibraryManager();
|
|
2811
|
+
try {
|
|
2812
|
+
const target = await resolveTargetLibrary(manager, opts.library);
|
|
2813
|
+
const domains = listDomains(target.path);
|
|
2814
|
+
if (opts.json) return console.log(JSON.stringify(domains, null, 2));
|
|
2815
|
+
if (domains.length === 0) {
|
|
2816
|
+
logInfo(
|
|
2817
|
+
`No domains in "${target.name}". Create one: \`skaile library domain create <name>\`.`
|
|
2818
|
+
);
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
for (const d of domains) console.log(` ${S.cmd(d)}`);
|
|
2822
|
+
console.log(`
|
|
2823
|
+
${S.dim(`${domains.length} domain(s) in ${target.name}`)}
|
|
2824
|
+
`);
|
|
2825
|
+
} finally {
|
|
2826
|
+
close();
|
|
2827
|
+
}
|
|
2828
|
+
});
|
|
2829
|
+
domain.command("show <name>").description("Print a domain's DOMAIN.md").option("--library <name>", "Target library (default: the default-marked one)").action(async (name, opts) => {
|
|
2830
|
+
const { manager, close } = await openLibraryManager();
|
|
2831
|
+
try {
|
|
2832
|
+
const target = await resolveTargetLibrary(manager, opts.library);
|
|
2833
|
+
const domainFile = path14.join(target.path, name, "DOMAIN.md");
|
|
2834
|
+
if (!existsSync(domainFile)) {
|
|
2835
|
+
logErr(`Domain "${name}" not found in "${target.name}" (no ${domainFile}).`);
|
|
2836
|
+
process.exit(1);
|
|
2837
|
+
}
|
|
2838
|
+
console.log(fs12.readFileSync(domainFile, "utf8"));
|
|
2839
|
+
} finally {
|
|
2840
|
+
close();
|
|
2841
|
+
}
|
|
2842
|
+
});
|
|
2555
2843
|
cmd.command("default <name>").description("Set <name> as the default library").action(async (name) => {
|
|
2556
2844
|
const { manager, close } = await openLibraryManager();
|
|
2557
2845
|
try {
|
|
@@ -2565,13 +2853,13 @@ function makeLibraryCommand() {
|
|
|
2565
2853
|
const { manager, close } = await openLibraryManager();
|
|
2566
2854
|
try {
|
|
2567
2855
|
const lib = await manager.requireLibrary(oldName);
|
|
2568
|
-
const parent =
|
|
2569
|
-
const newPath =
|
|
2570
|
-
if (
|
|
2856
|
+
const parent = path14.dirname(lib.path);
|
|
2857
|
+
const newPath = path14.join(parent, newName);
|
|
2858
|
+
if (fs12.existsSync(newPath)) {
|
|
2571
2859
|
logErr(`Target directory already exists: ${newPath}`);
|
|
2572
2860
|
process.exit(1);
|
|
2573
2861
|
}
|
|
2574
|
-
|
|
2862
|
+
fs12.renameSync(lib.path, newPath);
|
|
2575
2863
|
await manager.updateLibrary(lib.id, { name: newName, path: newPath });
|
|
2576
2864
|
logOk(`Renamed ${oldName} \u2192 ${newName}`);
|
|
2577
2865
|
} finally {
|
|
@@ -2755,9 +3043,9 @@ async function printOverallStatus(projectDir, asJson) {
|
|
|
2755
3043
|
} catch {
|
|
2756
3044
|
secretsStrategy = "unavailable";
|
|
2757
3045
|
}
|
|
2758
|
-
const resolvedProjectDir =
|
|
2759
|
-
const hasWorkspaceConfig = existsSync(
|
|
2760
|
-
const hasLockFile = existsSync(
|
|
3046
|
+
const resolvedProjectDir = path14.resolve(projectDir);
|
|
3047
|
+
const hasWorkspaceConfig = existsSync(path14.join(resolvedProjectDir, "skaile.yaml"));
|
|
3048
|
+
const hasLockFile = existsSync(path14.join(resolvedProjectDir, "skaile.lock.yaml"));
|
|
2761
3049
|
let assignments = [];
|
|
2762
3050
|
if (hasWorkspaceConfig) {
|
|
2763
3051
|
try {
|
|
@@ -3113,7 +3401,7 @@ function actOnHeader(row, action3) {
|
|
|
3113
3401
|
return row.type === "domain-header" || row.type === "domain-info";
|
|
3114
3402
|
}
|
|
3115
3403
|
async function loadAssets() {
|
|
3116
|
-
const { gatherAssetFeeds } = await import('../asset-feeds-
|
|
3404
|
+
const { gatherAssetFeeds } = await import('../asset-feeds-AOZLZMDV.js');
|
|
3117
3405
|
const { entries, domains, notes } = await gatherAssetFeeds(am, am.projectDir);
|
|
3118
3406
|
if (notes.length > 0) {
|
|
3119
3407
|
state.message = notes.map((n) => `[${n.feed}] ${n.message}`).join(" \u2022 ");
|
|
@@ -3218,7 +3506,7 @@ async function loadSourcesAndLibraries() {
|
|
|
3218
3506
|
const { manager, library, close } = await openLibraryManager2();
|
|
3219
3507
|
try {
|
|
3220
3508
|
const newRoot = getGlobalCacheDir2();
|
|
3221
|
-
const legacyRoot =
|
|
3509
|
+
const legacyRoot = path14__default.join(skaileHomeDir(), "sources");
|
|
3222
3510
|
const isSourceRow = (l) => l.path.startsWith(newRoot) || l.path.startsWith(legacyRoot);
|
|
3223
3511
|
const libs = await manager.listLibraries();
|
|
3224
3512
|
const defs = await library.listAssetDefs();
|
|
@@ -3598,10 +3886,10 @@ async function showInfo() {
|
|
|
3598
3886
|
}
|
|
3599
3887
|
console.log();
|
|
3600
3888
|
console.log(pc5.dim(" Press any key to return..."));
|
|
3601
|
-
await new Promise((
|
|
3889
|
+
await new Promise((resolve5) => {
|
|
3602
3890
|
const onData = () => {
|
|
3603
3891
|
process.stdin.removeListener("data", onData);
|
|
3604
|
-
|
|
3892
|
+
resolve5();
|
|
3605
3893
|
};
|
|
3606
3894
|
process.stdin.once("data", onData);
|
|
3607
3895
|
});
|
|
@@ -3854,13 +4142,13 @@ async function run(projectDir) {
|
|
|
3854
4142
|
}
|
|
3855
4143
|
function makeManageCommand() {
|
|
3856
4144
|
return new Command("manage").description("Interactive TUI for managing assets, sources, and libraries").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
3857
|
-
await run(
|
|
4145
|
+
await run(path14__default.resolve(opts.projectDir));
|
|
3858
4146
|
});
|
|
3859
4147
|
}
|
|
3860
4148
|
function makeMcpServerCommand() {
|
|
3861
4149
|
return new Command("mcp-server").description("Start skaile workspace MCP server (stdio transport)").option("--project-dir <path>", "Project directory (default: cwd)", process.cwd()).action(async (opts) => {
|
|
3862
|
-
const
|
|
3863
|
-
const projectDir =
|
|
4150
|
+
const path37 = await import('path');
|
|
4151
|
+
const projectDir = path37.default.resolve(opts.projectDir);
|
|
3864
4152
|
const { LogStore, StdoutSink, registerLogStore } = await import('../core/logging.js');
|
|
3865
4153
|
registerLogStore(
|
|
3866
4154
|
new LogStore({
|
|
@@ -3897,8 +4185,8 @@ function makeNpxCommand() {
|
|
|
3897
4185
|
skills.command("add <url>").description(
|
|
3898
4186
|
"Clone a repo, register it in the project's skaile.yaml sources[], and install a skill from it"
|
|
3899
4187
|
).requiredOption("--skill <name>", "Skill name to install from the repo").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").option("--global", "Deploy globally").action(async (url, opts) => {
|
|
3900
|
-
const projectDir =
|
|
3901
|
-
const projYaml =
|
|
4188
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4189
|
+
const projYaml = path14__default.join(projectDir, "skaile.yaml");
|
|
3902
4190
|
if (!existsSync(projYaml)) {
|
|
3903
4191
|
logErr(`No skaile.yaml in ${projectDir} \u2014 run \`skaile init\` first.`);
|
|
3904
4192
|
process.exit(1);
|
|
@@ -3911,7 +4199,7 @@ function makeNpxCommand() {
|
|
|
3911
4199
|
}
|
|
3912
4200
|
const spinner5 = p6.spinner();
|
|
3913
4201
|
const slug = sourceSlug(url);
|
|
3914
|
-
const clonePath =
|
|
4202
|
+
const clonePath = path14__default.join(getGlobalCacheDir(), slug);
|
|
3915
4203
|
spinner5.start(`Cloning ${url}`);
|
|
3916
4204
|
try {
|
|
3917
4205
|
if (!existsSync(clonePath)) {
|
|
@@ -3960,7 +4248,7 @@ function makeNpxCommand() {
|
|
|
3960
4248
|
return npx;
|
|
3961
4249
|
}
|
|
3962
4250
|
function resolvePublisher(clonePath, url) {
|
|
3963
|
-
const manifestPath =
|
|
4251
|
+
const manifestPath = path14__default.join(clonePath, SKAILE_MANIFEST_FILENAME);
|
|
3964
4252
|
if (existsSync(manifestPath)) {
|
|
3965
4253
|
try {
|
|
3966
4254
|
const { manifest } = decodeSkaileManifest(readFileSync(manifestPath, "utf8"));
|
|
@@ -3973,12 +4261,12 @@ function resolvePublisher(clonePath, url) {
|
|
|
3973
4261
|
return url.match(/github\.com[/:]([^/]+)\/[^/]+/)?.[1];
|
|
3974
4262
|
}
|
|
3975
4263
|
function resolveSkillName(clonePath, requested) {
|
|
3976
|
-
const skillsDir =
|
|
3977
|
-
if (existsSync(
|
|
4264
|
+
const skillsDir = path14__default.join(clonePath, "skills");
|
|
4265
|
+
if (existsSync(path14__default.join(skillsDir, requested, "SKILL.md"))) return requested;
|
|
3978
4266
|
if (!existsSync(skillsDir)) return requested;
|
|
3979
4267
|
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
3980
4268
|
if (!entry.isDirectory()) continue;
|
|
3981
|
-
const md =
|
|
4269
|
+
const md = path14__default.join(skillsDir, entry.name, "SKILL.md");
|
|
3982
4270
|
if (!existsSync(md)) continue;
|
|
3983
4271
|
try {
|
|
3984
4272
|
const { data } = parseFrontmatter(readFileSync(md, "utf8"));
|
|
@@ -3996,7 +4284,7 @@ function makeOutdatedCommand() {
|
|
|
3996
4284
|
new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
|
|
3997
4285
|
).action((name, opts) => {
|
|
3998
4286
|
const am2 = new AssetManager({
|
|
3999
|
-
projectDir:
|
|
4287
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
4000
4288
|
driverTarget: opts.target
|
|
4001
4289
|
});
|
|
4002
4290
|
const entries = am2.outdated();
|
|
@@ -4025,7 +4313,7 @@ function makeOutdatedCommand() {
|
|
|
4025
4313
|
function makePatchCommand() {
|
|
4026
4314
|
const cmd = new Command("patch").description("Patch workflow for skill improvement");
|
|
4027
4315
|
cmd.command("extract <ref>").alias("start").description("Extract asset for local editing").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
4028
|
-
const am2 = new AssetManager({ projectDir:
|
|
4316
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
4029
4317
|
try {
|
|
4030
4318
|
const dest = am2.patch(ref);
|
|
4031
4319
|
logOk(`Extracted to ${S.dim(dest)}`);
|
|
@@ -4036,7 +4324,7 @@ function makePatchCommand() {
|
|
|
4036
4324
|
}
|
|
4037
4325
|
});
|
|
4038
4326
|
cmd.command("commit <ref>").description("Generate .patch file from edits").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
4039
|
-
const am2 = new AssetManager({ projectDir:
|
|
4327
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
4040
4328
|
try {
|
|
4041
4329
|
const patchFile = am2.patchCommit(ref);
|
|
4042
4330
|
logOk(`Patch saved to ${S.dim(patchFile)}`);
|
|
@@ -4047,7 +4335,7 @@ function makePatchCommand() {
|
|
|
4047
4335
|
}
|
|
4048
4336
|
});
|
|
4049
4337
|
cmd.command("submit <ref>").description("Apply patch to repo clone and prepare for PR").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
4050
|
-
const am2 = new AssetManager({ projectDir:
|
|
4338
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
4051
4339
|
try {
|
|
4052
4340
|
am2.patchSubmit(ref);
|
|
4053
4341
|
logOk("Patch applied to repo clone and committed.");
|
|
@@ -4060,7 +4348,7 @@ function makePatchCommand() {
|
|
|
4060
4348
|
}
|
|
4061
4349
|
});
|
|
4062
4350
|
cmd.command("remove <ref>").description("Remove local patch after upstream merge").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
4063
|
-
const am2 = new AssetManager({ projectDir:
|
|
4351
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
4064
4352
|
am2.patchRemove(ref);
|
|
4065
4353
|
logOk(`Patch removed for ${ref}`);
|
|
4066
4354
|
});
|
|
@@ -4078,7 +4366,7 @@ function action2(fn) {
|
|
|
4078
4366
|
};
|
|
4079
4367
|
}
|
|
4080
4368
|
async function reconcileAndReport(projectDir, plugins) {
|
|
4081
|
-
const { reconcilePlugins } = await import('../plugin-store-
|
|
4369
|
+
const { reconcilePlugins } = await import('../plugin-store-2X2YXJVG.js');
|
|
4082
4370
|
if (plugins.length === 0) {
|
|
4083
4371
|
logInfo("No plugins declared \u2014 nothing to reconcile.");
|
|
4084
4372
|
return;
|
|
@@ -4092,10 +4380,10 @@ async function reconcileAndReport(projectDir, plugins) {
|
|
|
4092
4380
|
}
|
|
4093
4381
|
}
|
|
4094
4382
|
async function runInstall2(spec, opts) {
|
|
4095
|
-
const projectDir =
|
|
4383
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4096
4384
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
4097
|
-
const { specName } = await import('../plugin-store-
|
|
4098
|
-
const yamlPath =
|
|
4385
|
+
const { specName } = await import('../plugin-store-2X2YXJVG.js');
|
|
4386
|
+
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
4099
4387
|
const editor = WorkspaceYamlEditor2.load(yamlPath);
|
|
4100
4388
|
const replaced = editor.addPlugin(spec, specName);
|
|
4101
4389
|
editor.save();
|
|
@@ -4104,10 +4392,10 @@ async function runInstall2(spec, opts) {
|
|
|
4104
4392
|
await reconcileAndReport(projectDir, editor.getPlugins());
|
|
4105
4393
|
}
|
|
4106
4394
|
async function runRemove(name, opts) {
|
|
4107
|
-
const projectDir =
|
|
4395
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4108
4396
|
const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
|
|
4109
|
-
const { specName } = await import('../plugin-store-
|
|
4110
|
-
const yamlPath =
|
|
4397
|
+
const { specName } = await import('../plugin-store-2X2YXJVG.js');
|
|
4398
|
+
const yamlPath = path14__default.join(projectDir, "skaile.yaml");
|
|
4111
4399
|
const editor = WorkspaceYamlEditor2.load(yamlPath);
|
|
4112
4400
|
const removed = editor.removePlugin(name, specName);
|
|
4113
4401
|
if (!removed) {
|
|
@@ -4119,7 +4407,7 @@ async function runRemove(name, opts) {
|
|
|
4119
4407
|
await reconcileAndReport(projectDir, editor.getPlugins());
|
|
4120
4408
|
}
|
|
4121
4409
|
async function runList(opts) {
|
|
4122
|
-
const projectDir =
|
|
4410
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4123
4411
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
4124
4412
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
4125
4413
|
const declared = config.plugins ?? [];
|
|
@@ -4134,7 +4422,7 @@ async function runList(opts) {
|
|
|
4134
4422
|
const registry = createPluginRegistry();
|
|
4135
4423
|
if (declared.length > 0) {
|
|
4136
4424
|
try {
|
|
4137
|
-
const { loadPlugins } = await import('../plugin-store-
|
|
4425
|
+
const { loadPlugins } = await import('../plugin-store-2X2YXJVG.js');
|
|
4138
4426
|
const result = await loadPlugins(projectDir, declared, registry);
|
|
4139
4427
|
for (const f of result.failed) logWarn(f.error);
|
|
4140
4428
|
} catch (err) {
|
|
@@ -4173,7 +4461,7 @@ function makePresetCommand() {
|
|
|
4173
4461
|
cmd.command("init [name]").description("Scaffold a new .preset.yaml file").option("--dir <path>", "Output directory", process.cwd()).action(async (name, opts) => {
|
|
4174
4462
|
const presetName = name ?? "my-preset";
|
|
4175
4463
|
const filename = `${presetName}.preset.yaml`;
|
|
4176
|
-
const outPath =
|
|
4464
|
+
const outPath = path14__default.join(path14__default.resolve(opts.dir), filename);
|
|
4177
4465
|
if (existsSync(outPath)) {
|
|
4178
4466
|
logErr(`File already exists: ${outPath}`);
|
|
4179
4467
|
logInfo("Choose a different name or remove the existing file.");
|
|
@@ -4221,7 +4509,7 @@ async function reportNestedPresetRefs(preset) {
|
|
|
4221
4509
|
}
|
|
4222
4510
|
async function checkPresetCycles(preset, resolved) {
|
|
4223
4511
|
const { detectCycles } = await import('../discovery/index.js');
|
|
4224
|
-
const presetRef =
|
|
4512
|
+
const presetRef = path14__default.basename(resolved, ".preset.yaml");
|
|
4225
4513
|
const edges = [];
|
|
4226
4514
|
for (const item of preset.items) {
|
|
4227
4515
|
if (item.ref) {
|
|
@@ -4272,7 +4560,7 @@ function printPresetSummary(preset, placeholderCount, hasWarnings) {
|
|
|
4272
4560
|
}
|
|
4273
4561
|
}
|
|
4274
4562
|
async function runPresetValidate(filePath) {
|
|
4275
|
-
const resolved =
|
|
4563
|
+
const resolved = path14__default.resolve(filePath);
|
|
4276
4564
|
const preset = await loadPresetForValidation(resolved);
|
|
4277
4565
|
await reportNestedPresetRefs(preset);
|
|
4278
4566
|
await checkPresetCycles(preset, resolved);
|
|
@@ -4367,7 +4655,7 @@ async function runRefInstall(ref, opts) {
|
|
|
4367
4655
|
spinner5.start(`Installing ${ref}`);
|
|
4368
4656
|
try {
|
|
4369
4657
|
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-362BZ6OW.js');
|
|
4370
|
-
const catalog = await openCatalogSource2({ projectDir:
|
|
4658
|
+
const catalog = await openCatalogSource2({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
4371
4659
|
if (!supportsInstallManifest(catalog)) {
|
|
4372
4660
|
throw new Error(
|
|
4373
4661
|
"pointer-only install (skaile install <ref>) requires a tRPC-framed Catalog. The configured catalog uses REST framing, which does not serve install manifests. Set catalog.url to https://skaile.store, or catalog.framing: trpc, in ~/.skaile/config.yaml."
|
|
@@ -4396,7 +4684,7 @@ async function runRefInstall(ref, opts) {
|
|
|
4396
4684
|
}
|
|
4397
4685
|
}
|
|
4398
4686
|
async function runYamlInstall(opts) {
|
|
4399
|
-
const projectDir =
|
|
4687
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4400
4688
|
try {
|
|
4401
4689
|
const { ensureSourcesCloned } = await import('../ensure-sources-NSDMTAWN.js');
|
|
4402
4690
|
const hydrate = ensureSourcesCloned(projectDir, { quiet: true });
|
|
@@ -4441,7 +4729,7 @@ async function runYamlInstall(opts) {
|
|
|
4441
4729
|
}
|
|
4442
4730
|
function makeCheckCommand() {
|
|
4443
4731
|
return new Command("check").description("Check for unmet requirements").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
4444
|
-
const am2 = new AssetManager({ projectDir:
|
|
4732
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
4445
4733
|
const issues = am2.doctor();
|
|
4446
4734
|
if (issues.length === 0) {
|
|
4447
4735
|
logOk("All dependencies satisfied.");
|
|
@@ -4458,10 +4746,10 @@ function makeCheckCommand() {
|
|
|
4458
4746
|
function makeCleanCommand() {
|
|
4459
4747
|
return new Command("clean").description("Remove all skaile-managed assets from the workspace").option("--all", "Full reset: also remove history, patches, repos, and lock file").option("--dry-run", "Show what would be removed without doing it").option("-y, --yes", "Skip confirmation prompt").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").action(async (opts) => {
|
|
4460
4748
|
const am2 = new AssetManager({
|
|
4461
|
-
projectDir:
|
|
4749
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
4462
4750
|
driverTarget: opts.target
|
|
4463
4751
|
});
|
|
4464
|
-
const lock = readLock(
|
|
4752
|
+
const lock = readLock(path14__default.resolve(opts.projectDir, "skaile.lock.yaml"));
|
|
4465
4753
|
if (!lock || Object.keys(lock.assets).length === 0) {
|
|
4466
4754
|
logInfo("Nothing to clean (no skaile-managed assets found).");
|
|
4467
4755
|
return;
|
|
@@ -4514,14 +4802,14 @@ function makeCleanCommand() {
|
|
|
4514
4802
|
}
|
|
4515
4803
|
function makeRebuildCommand() {
|
|
4516
4804
|
return new Command("rebuild").description("Re-snapshot inline-snapshot composition items and bump prompt version").argument("[agent]", "Agent name or path (defaults to current project agent)").option("--project-dir <dir>", "Project directory", process.cwd()).action(async (agentArg, opts) => {
|
|
4517
|
-
const projectDir =
|
|
4805
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4518
4806
|
let agentDir;
|
|
4519
4807
|
if (agentArg) {
|
|
4520
4808
|
if (agentArg.includes("/") || agentArg.includes("\\")) {
|
|
4521
|
-
agentDir =
|
|
4809
|
+
agentDir = path14__default.resolve(projectDir, agentArg);
|
|
4522
4810
|
} else {
|
|
4523
4811
|
const resolved = resolveAgentDir(projectDir);
|
|
4524
|
-
agentDir = resolved ??
|
|
4812
|
+
agentDir = resolved ?? path14__default.resolve(projectDir, agentArg);
|
|
4525
4813
|
}
|
|
4526
4814
|
} else {
|
|
4527
4815
|
const resolved = resolveAgentDir(projectDir);
|
|
@@ -4599,7 +4887,7 @@ function makeFlowEventHandler() {
|
|
|
4599
4887
|
}
|
|
4600
4888
|
function makeRunCommand() {
|
|
4601
4889
|
const cmd = new Command("run").description("Start a flow or run a single-shot text prompt").argument("[flow-id-or-text...]", "Flow ID or text prompt").option("--project-dir <path>", "Project directory", process.cwd()).option("--driver <name>", "Driver backend (claude-sdk, codex, omp)").option("--provider <name>", "LLM provider").option("--model <name>", "Model override").option("--label <label>", "Human-readable session label").option("--dry-run", "Print plan without executing").option("--skill <name>", "Skill name (for single-shot mode)").action(async (positional, opts) => {
|
|
4602
|
-
const projectDir =
|
|
4890
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4603
4891
|
const cliDriver = opts.driver;
|
|
4604
4892
|
const dryRun = opts.dryRun ?? false;
|
|
4605
4893
|
let flowId = positional[0];
|
|
@@ -4634,12 +4922,12 @@ function makeRunCommand() {
|
|
|
4634
4922
|
const priorityRoots = [];
|
|
4635
4923
|
let dir = projectDir;
|
|
4636
4924
|
for (let i = 0; i < 6; i++) {
|
|
4637
|
-
const candidate =
|
|
4638
|
-
if (
|
|
4925
|
+
const candidate = path14__default.join(dir, "ai-assets");
|
|
4926
|
+
if (fs12__default.existsSync(candidate)) {
|
|
4639
4927
|
priorityRoots.push(candidate);
|
|
4640
4928
|
break;
|
|
4641
4929
|
}
|
|
4642
|
-
dir =
|
|
4930
|
+
dir = path14__default.dirname(dir);
|
|
4643
4931
|
}
|
|
4644
4932
|
const flowPath = findFlowFile(flowId, priorityRoots);
|
|
4645
4933
|
if (!flowPath) {
|
|
@@ -4694,7 +4982,7 @@ function makeRunCommand() {
|
|
|
4694
4982
|
}
|
|
4695
4983
|
function makeResumeCommand() {
|
|
4696
4984
|
const cmd = new Command("resume").description("Resume current session").option("--project-dir <path>", "Project directory", process.cwd()).option("--session <run-id>", "Target session by runId").option("--dry-run", "Print plan without executing").action(async (opts) => {
|
|
4697
|
-
const projectDir =
|
|
4985
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4698
4986
|
const sessionId = opts.session;
|
|
4699
4987
|
const dryRun = opts.dryRun ?? false;
|
|
4700
4988
|
const session = sessionId ? await loadSessionById(projectDir, sessionId) : await loadSession(projectDir);
|
|
@@ -4721,7 +5009,7 @@ function makeResumeCommand() {
|
|
|
4721
5009
|
}
|
|
4722
5010
|
function makeStatusCommand() {
|
|
4723
5011
|
return new Command("status").description("Show current session state").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
4724
|
-
const projectDir =
|
|
5012
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4725
5013
|
const session = await loadSession(projectDir);
|
|
4726
5014
|
if (!session) {
|
|
4727
5015
|
logInfo("No active session.");
|
|
@@ -4746,7 +5034,7 @@ function makeStatusCommand() {
|
|
|
4746
5034
|
}
|
|
4747
5035
|
function makeClearCommand() {
|
|
4748
5036
|
return new Command("clear").description("Unset current session pointer").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
4749
|
-
const projectDir =
|
|
5037
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
4750
5038
|
await clearSession(projectDir);
|
|
4751
5039
|
logOk("Session cleared.");
|
|
4752
5040
|
});
|
|
@@ -4755,8 +5043,8 @@ function makeReplCommand() {
|
|
|
4755
5043
|
return new Command("repl").description("Start an interactive agent session").option("--project-dir <path>", "Project directory").option("--driver <name>", "Driver backend (claude-sdk, omp)").option("--provider <name>", "LLM provider").option("--model <name>", "Model override").option("--resume", "Resume last session").option("--resume-session <id>", "Resume specific session").action(async (opts) => {
|
|
4756
5044
|
const { findWorkspaceRoot: findWorkspaceRoot2 } = await import('../core/index.js');
|
|
4757
5045
|
const { startRepl } = await import('../tui/index.js');
|
|
4758
|
-
const
|
|
4759
|
-
const userCwd =
|
|
5046
|
+
const os2 = await import('os');
|
|
5047
|
+
const userCwd = path14__default.resolve(opts.projectDir ?? process.cwd());
|
|
4760
5048
|
const workspaceRoot = findWorkspaceRoot2(userCwd);
|
|
4761
5049
|
let projectDir;
|
|
4762
5050
|
let agentCwd;
|
|
@@ -4778,13 +5066,13 @@ function makeReplCommand() {
|
|
|
4778
5066
|
p6.cancel("Cancelled.");
|
|
4779
5067
|
process.exit(0);
|
|
4780
5068
|
}
|
|
4781
|
-
const tmpDir =
|
|
5069
|
+
const tmpDir = fs12__default.mkdtempSync(path14__default.join(os2.tmpdir(), "skaile-repl-"));
|
|
4782
5070
|
projectDir = tmpDir;
|
|
4783
5071
|
agentCwd = userCwd;
|
|
4784
5072
|
logOk(`Temporary workspace: ${S.cmd(tmpDir)}`);
|
|
4785
5073
|
if (!driverOverride) {
|
|
4786
|
-
const claudeDir =
|
|
4787
|
-
if (
|
|
5074
|
+
const claudeDir = path14__default.join(os2.homedir(), ".claude");
|
|
5075
|
+
if (fs12__default.existsSync(claudeDir)) {
|
|
4788
5076
|
driverOverride = "claude-sdk";
|
|
4789
5077
|
logInfo(`Detected ${S.cmd("~/.claude")} \u2192 using ${S.cmd("claude-sdk")} backend`);
|
|
4790
5078
|
} else {
|
|
@@ -4835,7 +5123,7 @@ async function ensurePluginsLoadedForServe(projectDir) {
|
|
|
4835
5123
|
const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
|
|
4836
5124
|
const config = resolveSkWorkspaceConfig2(projectDir);
|
|
4837
5125
|
if (!config.plugins || config.plugins.length === 0) return;
|
|
4838
|
-
const { ensurePluginsLoaded } = await import('../plugin-store-
|
|
5126
|
+
const { ensurePluginsLoaded } = await import('../plugin-store-2X2YXJVG.js');
|
|
4839
5127
|
const { pluginRegistry } = await import('../plugin-registry/index.js');
|
|
4840
5128
|
const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
|
|
4841
5129
|
if (result.loaded.length > 0) {
|
|
@@ -4851,9 +5139,9 @@ async function ensurePluginsLoadedForServe(projectDir) {
|
|
|
4851
5139
|
async function runCompileTest(opts) {
|
|
4852
5140
|
const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-F4NZ66VD.js');
|
|
4853
5141
|
const { tmpdir } = await import('os');
|
|
4854
|
-
const { dirname:
|
|
5142
|
+
const { dirname: dirname4, join: join6, resolve: resolve5 } = await import('path');
|
|
4855
5143
|
const { fileURLToPath: fileURLToPath2 } = await import('url');
|
|
4856
|
-
const { unlinkSync, existsSync:
|
|
5144
|
+
const { unlinkSync, existsSync: existsSync14 } = await import('fs');
|
|
4857
5145
|
const { spawn } = await import('child_process');
|
|
4858
5146
|
const { portableSpawnSync: portableSpawnSync2 } = await import('../core/index.js');
|
|
4859
5147
|
const { MONOREPO_ROOT } = await import('../paths-4SSFMX5Z.js');
|
|
@@ -4863,9 +5151,9 @@ async function runCompileTest(opts) {
|
|
|
4863
5151
|
process.exitCode = 2;
|
|
4864
5152
|
return;
|
|
4865
5153
|
}
|
|
4866
|
-
const outfile =
|
|
5154
|
+
const outfile = join6(tmpdir(), `skaile-compile-test-${Date.now()}`);
|
|
4867
5155
|
const __thisFile = fileURLToPath2(import.meta.url);
|
|
4868
|
-
const entryPoint =
|
|
5156
|
+
const entryPoint = resolve5(dirname4(__thisFile), "..", "index.ts");
|
|
4869
5157
|
logInfo2(`Building compiled binary...`);
|
|
4870
5158
|
logInfo2(`Entry: ${S2.dim(entryPoint)}`);
|
|
4871
5159
|
logInfo2(`Output: ${S2.dim(outfile)}`);
|
|
@@ -4915,7 +5203,7 @@ async function runCompileTest(opts) {
|
|
|
4915
5203
|
} catch {
|
|
4916
5204
|
}
|
|
4917
5205
|
try {
|
|
4918
|
-
if (
|
|
5206
|
+
if (existsSync14(outfile)) unlinkSync(outfile);
|
|
4919
5207
|
} catch {
|
|
4920
5208
|
}
|
|
4921
5209
|
}
|
|
@@ -5168,19 +5456,19 @@ function buildTailSelect(q) {
|
|
|
5168
5456
|
return { sql, params };
|
|
5169
5457
|
}
|
|
5170
5458
|
function sleepUnlessAborted(ms, signal) {
|
|
5171
|
-
return new Promise((
|
|
5459
|
+
return new Promise((resolve5) => {
|
|
5172
5460
|
if (signal?.aborted) {
|
|
5173
|
-
|
|
5461
|
+
resolve5();
|
|
5174
5462
|
return;
|
|
5175
5463
|
}
|
|
5176
5464
|
const timer = setTimeout(() => {
|
|
5177
5465
|
signal?.removeEventListener("abort", onAbort);
|
|
5178
|
-
|
|
5466
|
+
resolve5();
|
|
5179
5467
|
}, ms);
|
|
5180
5468
|
const onAbort = () => {
|
|
5181
5469
|
clearTimeout(timer);
|
|
5182
5470
|
signal?.removeEventListener("abort", onAbort);
|
|
5183
|
-
|
|
5471
|
+
resolve5();
|
|
5184
5472
|
};
|
|
5185
5473
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5186
5474
|
});
|
|
@@ -5257,7 +5545,7 @@ async function remoteTail(opts) {
|
|
|
5257
5545
|
]
|
|
5258
5546
|
});
|
|
5259
5547
|
const filter = makeFilter(opts.query);
|
|
5260
|
-
return new Promise((
|
|
5548
|
+
return new Promise((resolve5, reject) => {
|
|
5261
5549
|
let settled = false;
|
|
5262
5550
|
const finish = (err) => {
|
|
5263
5551
|
if (settled) return;
|
|
@@ -5268,11 +5556,11 @@ async function remoteTail(opts) {
|
|
|
5268
5556
|
}
|
|
5269
5557
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
5270
5558
|
if (err) reject(err);
|
|
5271
|
-
else
|
|
5559
|
+
else resolve5();
|
|
5272
5560
|
};
|
|
5273
5561
|
const onAbort = () => finish();
|
|
5274
5562
|
if (opts.signal?.aborted) {
|
|
5275
|
-
|
|
5563
|
+
resolve5();
|
|
5276
5564
|
return;
|
|
5277
5565
|
}
|
|
5278
5566
|
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -5326,7 +5614,7 @@ function resolveMode(opts) {
|
|
|
5326
5614
|
if (opts.forceLocal && opts.forceRemote) {
|
|
5327
5615
|
throw new Error("Cannot use both --local and --remote");
|
|
5328
5616
|
}
|
|
5329
|
-
const startDir =
|
|
5617
|
+
const startDir = path14__default.resolve(opts.projectDir ?? process.cwd());
|
|
5330
5618
|
const localDb = findLogsDb(startDir);
|
|
5331
5619
|
if (opts.forceLocal) {
|
|
5332
5620
|
if (!localDb) {
|
|
@@ -5359,14 +5647,14 @@ function resolveMode(opts) {
|
|
|
5359
5647
|
function findLogsDb(startDir) {
|
|
5360
5648
|
let dir = startDir;
|
|
5361
5649
|
for (let i = 0; i < MAX_WALK_LEVELS; i++) {
|
|
5362
|
-
const candidate =
|
|
5650
|
+
const candidate = path14__default.join(dir, ".skaile", "logs.db");
|
|
5363
5651
|
if (existsSync(candidate)) {
|
|
5364
5652
|
try {
|
|
5365
5653
|
if (statSync(candidate).isFile()) return candidate;
|
|
5366
5654
|
} catch {
|
|
5367
5655
|
}
|
|
5368
5656
|
}
|
|
5369
|
-
const parent =
|
|
5657
|
+
const parent = path14__default.dirname(dir);
|
|
5370
5658
|
if (parent === dir) return void 0;
|
|
5371
5659
|
dir = parent;
|
|
5372
5660
|
}
|
|
@@ -5392,7 +5680,7 @@ function readApiToken() {
|
|
|
5392
5680
|
}
|
|
5393
5681
|
function readGlobalSettings() {
|
|
5394
5682
|
try {
|
|
5395
|
-
const settingsPath =
|
|
5683
|
+
const settingsPath = path14__default.join(homedir(), ".skaile", "settings.json");
|
|
5396
5684
|
if (!existsSync(settingsPath)) return {};
|
|
5397
5685
|
return JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
5398
5686
|
} catch {
|
|
@@ -5541,7 +5829,7 @@ function parsePositiveInt(value, flag) {
|
|
|
5541
5829
|
function makeSessionCommand() {
|
|
5542
5830
|
const cmd = new Command("session").description("Manage sessions");
|
|
5543
5831
|
cmd.command("list").description("List all sessions for a project").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
5544
|
-
const projectDir =
|
|
5832
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5545
5833
|
const sessions = await listSessions(projectDir);
|
|
5546
5834
|
const current = await loadSession(projectDir);
|
|
5547
5835
|
if (sessions.length === 0) {
|
|
@@ -5569,7 +5857,7 @@ function makeSessionCommand() {
|
|
|
5569
5857
|
console.log();
|
|
5570
5858
|
});
|
|
5571
5859
|
cmd.command("show <run-id>").description("Show a specific session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
|
|
5572
|
-
const projectDir =
|
|
5860
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5573
5861
|
const session = await loadSessionById(projectDir, runId);
|
|
5574
5862
|
if (!session) {
|
|
5575
5863
|
logErr(`Session not found: ${runId}`);
|
|
@@ -5578,12 +5866,12 @@ function makeSessionCommand() {
|
|
|
5578
5866
|
console.log(JSON.stringify(session, null, 2));
|
|
5579
5867
|
});
|
|
5580
5868
|
cmd.command("switch <run-id>").description("Switch the current session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
|
|
5581
|
-
const projectDir =
|
|
5869
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5582
5870
|
await setCurrentSession(projectDir, runId);
|
|
5583
5871
|
logOk(`Switched to session: ${S.dim(runId.slice(0, 8))}`);
|
|
5584
5872
|
});
|
|
5585
5873
|
cmd.command("delete <run-id>").description("Delete a session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
|
|
5586
|
-
const projectDir =
|
|
5874
|
+
const projectDir = path14__default.resolve(opts.projectDir);
|
|
5587
5875
|
await deleteSession(projectDir, runId);
|
|
5588
5876
|
logOk(`Deleted session: ${S.dim(runId.slice(0, 8))}`);
|
|
5589
5877
|
});
|
|
@@ -5637,12 +5925,12 @@ function showOverview(am2) {
|
|
|
5637
5925
|
}
|
|
5638
5926
|
function showAsset(am2, kind, name) {
|
|
5639
5927
|
const entry = am2.info(`${kind}:${name}`);
|
|
5640
|
-
if (entry?.source &&
|
|
5928
|
+
if (entry?.source && fs12__default.existsSync(entry.source)) {
|
|
5641
5929
|
console.log();
|
|
5642
5930
|
console.log(` ${kindColor(entry.kind)} ${S.heading(entry.name)}`);
|
|
5643
5931
|
console.log(` ${S.rule(40)}`);
|
|
5644
5932
|
console.log();
|
|
5645
|
-
console.log(
|
|
5933
|
+
console.log(fs12__default.readFileSync(entry.source, "utf-8"));
|
|
5646
5934
|
return;
|
|
5647
5935
|
}
|
|
5648
5936
|
logErr(`Asset not found: ${kind}:${name}`);
|
|
@@ -5651,7 +5939,7 @@ function showAsset(am2, kind, name) {
|
|
|
5651
5939
|
function makeShowCommand() {
|
|
5652
5940
|
return new Command("show").description("Show deployed assets overview, or print asset content").argument("[kind]", "Asset kind (skill, agent, prompt, flow, bundle, contract)").argument("[name]", "Asset name").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").action((kind, name, opts) => {
|
|
5653
5941
|
const am2 = new AssetManager({
|
|
5654
|
-
projectDir:
|
|
5942
|
+
projectDir: path14__default.resolve(opts.projectDir),
|
|
5655
5943
|
driverTarget: opts.target
|
|
5656
5944
|
});
|
|
5657
5945
|
if (!kind) {
|
|
@@ -5689,7 +5977,7 @@ function addSourceManifestCommands(src) {
|
|
|
5689
5977
|
|
|
5690
5978
|
// cli/src/commands/source.ts
|
|
5691
5979
|
function sourceClonePath(name) {
|
|
5692
|
-
return
|
|
5980
|
+
return path14.join(getGlobalCacheDir(), name);
|
|
5693
5981
|
}
|
|
5694
5982
|
function deriveSlug(url) {
|
|
5695
5983
|
return url.replace(/\.git$/, "").split(/[/:]/).pop() ?? "source";
|
|
@@ -5714,7 +6002,7 @@ function requireProjectYamlPath() {
|
|
|
5714
6002
|
);
|
|
5715
6003
|
process.exit(1);
|
|
5716
6004
|
}
|
|
5717
|
-
return
|
|
6005
|
+
return path14.join(root, workspaceConfigFilename());
|
|
5718
6006
|
}
|
|
5719
6007
|
function readProjectSources(yamlPath) {
|
|
5720
6008
|
if (!existsSync(yamlPath)) return [];
|
|
@@ -5812,7 +6100,7 @@ function makeSourceCommand() {
|
|
|
5812
6100
|
const result = await refreshManifestCache(entry, opts.dev);
|
|
5813
6101
|
logOk(`Indexed ${result.assetsUpdated} of ${result.assetsFound} asset(s) from "${slug}".`);
|
|
5814
6102
|
for (const err of result.errors) logWarn(err);
|
|
5815
|
-
logOk(`Source "${slug}" registered in ${
|
|
6103
|
+
logOk(`Source "${slug}" registered in ${path14.relative(process.cwd(), yamlPath)}.`);
|
|
5816
6104
|
}
|
|
5817
6105
|
);
|
|
5818
6106
|
cmd.command("list").description("List sources registered in this project's skaile.yaml").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -5940,10 +6228,10 @@ function makeStoreCommand() {
|
|
|
5940
6228
|
if (opts.email) {
|
|
5941
6229
|
const readline2 = await import('readline');
|
|
5942
6230
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
5943
|
-
const password = await new Promise((
|
|
6231
|
+
const password = await new Promise((resolve5) => {
|
|
5944
6232
|
rl.question("Password: ", (answer) => {
|
|
5945
6233
|
rl.close();
|
|
5946
|
-
|
|
6234
|
+
resolve5(answer);
|
|
5947
6235
|
});
|
|
5948
6236
|
});
|
|
5949
6237
|
try {
|
|
@@ -6098,7 +6386,7 @@ function printTree(node, prefix = "", isLast = true) {
|
|
|
6098
6386
|
}
|
|
6099
6387
|
function makeTreeCommand() {
|
|
6100
6388
|
return new Command("tree").description("Show full dependency tree").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
6101
|
-
const am2 = new AssetManager({ projectDir:
|
|
6389
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
6102
6390
|
const root = am2.tree();
|
|
6103
6391
|
if (root.children.length === 0) {
|
|
6104
6392
|
logInfo("No dependencies in lock file. Run `skaile install` first.");
|
|
@@ -6116,7 +6404,7 @@ function makeUpdateCommand() {
|
|
|
6116
6404
|
try {
|
|
6117
6405
|
const catalogSpinner = p6.spinner();
|
|
6118
6406
|
catalogSpinner.start("Refreshing catalog cache");
|
|
6119
|
-
const remote = await openCatalogSource({ projectDir:
|
|
6407
|
+
const remote = await openCatalogSource({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
6120
6408
|
const result2 = await remote.refresh();
|
|
6121
6409
|
catalogSpinner.stop(
|
|
6122
6410
|
`Catalog refreshed: ${S.heading(String(result2.assetsCached))} assets cached`
|
|
@@ -6128,7 +6416,7 @@ function makeUpdateCommand() {
|
|
|
6128
6416
|
}
|
|
6129
6417
|
}
|
|
6130
6418
|
if (opts.catalogOnly) return;
|
|
6131
|
-
const am2 = new AssetManager({ projectDir:
|
|
6419
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
6132
6420
|
const spinner5 = p6.spinner();
|
|
6133
6421
|
spinner5.start("Re-deploying assets");
|
|
6134
6422
|
const result = await am2.install();
|
|
@@ -6162,12 +6450,12 @@ function findManifestCandidates(rootPath) {
|
|
|
6162
6450
|
function walk(dir) {
|
|
6163
6451
|
let entries;
|
|
6164
6452
|
try {
|
|
6165
|
-
entries =
|
|
6453
|
+
entries = fs12__default.readdirSync(dir, { withFileTypes: true });
|
|
6166
6454
|
} catch {
|
|
6167
6455
|
return;
|
|
6168
6456
|
}
|
|
6169
6457
|
for (const entry of entries) {
|
|
6170
|
-
const fullPath =
|
|
6458
|
+
const fullPath = path14__default.join(dir, entry.name);
|
|
6171
6459
|
if (entry.isDirectory()) {
|
|
6172
6460
|
if (!SKIP_DIRS.has(entry.name)) walk(fullPath);
|
|
6173
6461
|
} else if (entry.isFile()) {
|
|
@@ -6208,7 +6496,7 @@ function checkManifestIdentity(kind, parsed) {
|
|
|
6208
6496
|
return null;
|
|
6209
6497
|
}
|
|
6210
6498
|
function parseManifestCandidate(c, absRoot) {
|
|
6211
|
-
const content =
|
|
6499
|
+
const content = fs12__default.readFileSync(c.filePath, "utf-8");
|
|
6212
6500
|
if (c.filePath.endsWith(".md")) {
|
|
6213
6501
|
const parsed = parseMdFrontmatter(content);
|
|
6214
6502
|
if (parsed === null) {
|
|
@@ -6220,13 +6508,13 @@ function parseManifestCandidate(c, absRoot) {
|
|
|
6220
6508
|
const parsed = c.filePath.endsWith(".json") ? JSON.parse(content) : parse(content);
|
|
6221
6509
|
return { kind: "value", parsed };
|
|
6222
6510
|
} catch (e) {
|
|
6223
|
-
const relPath =
|
|
6511
|
+
const relPath = path14__default.relative(absRoot, c.filePath);
|
|
6224
6512
|
logErr(`${relPath} \u2014 parse error: ${e instanceof Error ? e.message : String(e)}`);
|
|
6225
6513
|
return { kind: "error" };
|
|
6226
6514
|
}
|
|
6227
6515
|
}
|
|
6228
6516
|
function validateManifestCandidate(c, parsed, absRoot, registry) {
|
|
6229
|
-
const relPath =
|
|
6517
|
+
const relPath = path14__default.relative(absRoot, c.filePath);
|
|
6230
6518
|
let errors = 0;
|
|
6231
6519
|
const identityError = checkManifestIdentity(c.kind, parsed);
|
|
6232
6520
|
if (identityError) {
|
|
@@ -6248,8 +6536,8 @@ function validateManifestCandidate(c, parsed, absRoot, registry) {
|
|
|
6248
6536
|
return { errors, warnings: 0 };
|
|
6249
6537
|
}
|
|
6250
6538
|
function validateManifests(rootPath) {
|
|
6251
|
-
const absRoot =
|
|
6252
|
-
if (!
|
|
6539
|
+
const absRoot = path14__default.resolve(rootPath);
|
|
6540
|
+
if (!fs12__default.existsSync(absRoot)) {
|
|
6253
6541
|
logErr(`Path does not exist: ${absRoot}`);
|
|
6254
6542
|
return { total: 0, errors: 1, warnings: 0 };
|
|
6255
6543
|
}
|
|
@@ -6275,12 +6563,12 @@ function findWorkspaceManifests(rootPath) {
|
|
|
6275
6563
|
function walk(dir) {
|
|
6276
6564
|
let entries;
|
|
6277
6565
|
try {
|
|
6278
|
-
entries =
|
|
6566
|
+
entries = fs12__default.readdirSync(dir, { withFileTypes: true });
|
|
6279
6567
|
} catch {
|
|
6280
6568
|
return;
|
|
6281
6569
|
}
|
|
6282
6570
|
for (const entry of entries) {
|
|
6283
|
-
const full =
|
|
6571
|
+
const full = path14__default.join(dir, entry.name);
|
|
6284
6572
|
if (entry.isDirectory()) {
|
|
6285
6573
|
if (!SKIP_DIRS.has(entry.name)) walk(full);
|
|
6286
6574
|
} else if (entry.isFile() && /(^|\.)skaile\.yaml$/.test(entry.name)) {
|
|
@@ -6343,14 +6631,14 @@ function validateWorkspaceAssets(parsed, relPath) {
|
|
|
6343
6631
|
return errors;
|
|
6344
6632
|
}
|
|
6345
6633
|
function validateWorkspaceManifests(rootPath) {
|
|
6346
|
-
const absRoot =
|
|
6634
|
+
const absRoot = path14__default.resolve(rootPath);
|
|
6347
6635
|
const files = findWorkspaceManifests(absRoot);
|
|
6348
6636
|
let errors = 0;
|
|
6349
6637
|
for (const file of files) {
|
|
6350
|
-
const relPath =
|
|
6638
|
+
const relPath = path14__default.relative(absRoot, file);
|
|
6351
6639
|
let parsed;
|
|
6352
6640
|
try {
|
|
6353
|
-
parsed = parse(
|
|
6641
|
+
parsed = parse(fs12__default.readFileSync(file, "utf-8")) ?? {};
|
|
6354
6642
|
} catch (e) {
|
|
6355
6643
|
logErr(`${relPath} \u2014 parse error: ${e instanceof Error ? e.message : String(e)}`);
|
|
6356
6644
|
errors++;
|
|
@@ -6364,34 +6652,34 @@ function validateWorkspaceManifests(rootPath) {
|
|
|
6364
6652
|
var EXCLUDED_DOMAINS = /* @__PURE__ */ new Set(["skaileup-shared", "external", "docs"]);
|
|
6365
6653
|
function collectAssetVersions() {
|
|
6366
6654
|
const assets = [];
|
|
6367
|
-
if (!
|
|
6368
|
-
const domains =
|
|
6655
|
+
if (!fs12__default.existsSync(AI_RESOURCES)) return assets;
|
|
6656
|
+
const domains = fs12__default.readdirSync(AI_RESOURCES, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DOMAINS.has(d.name));
|
|
6369
6657
|
for (const d of domains) {
|
|
6370
|
-
const domainDir =
|
|
6371
|
-
const skillsDir =
|
|
6372
|
-
if (
|
|
6658
|
+
const domainDir = path14__default.join(AI_RESOURCES, d.name);
|
|
6659
|
+
const skillsDir = path14__default.join(domainDir, "skills");
|
|
6660
|
+
if (fs12__default.existsSync(skillsDir)) {
|
|
6373
6661
|
collectSkillVersions(skillsDir, d.name, assets);
|
|
6374
6662
|
}
|
|
6375
|
-
const agentsDir =
|
|
6376
|
-
if (
|
|
6663
|
+
const agentsDir = path14__default.join(domainDir, "agents");
|
|
6664
|
+
if (fs12__default.existsSync(agentsDir)) {
|
|
6377
6665
|
collectAgentVersions(agentsDir, d.name, assets);
|
|
6378
6666
|
}
|
|
6379
|
-
const flowsDir =
|
|
6380
|
-
if (
|
|
6667
|
+
const flowsDir = path14__default.join(domainDir, "flows");
|
|
6668
|
+
if (fs12__default.existsSync(flowsDir)) {
|
|
6381
6669
|
collectFlowVersions(flowsDir, d.name, assets);
|
|
6382
6670
|
}
|
|
6383
|
-
const promptsDir =
|
|
6384
|
-
if (
|
|
6671
|
+
const promptsDir = path14__default.join(domainDir, "prompts");
|
|
6672
|
+
if (fs12__default.existsSync(promptsDir)) {
|
|
6385
6673
|
collectPromptVersions(promptsDir, d.name, assets);
|
|
6386
6674
|
}
|
|
6387
6675
|
}
|
|
6388
6676
|
return assets;
|
|
6389
6677
|
}
|
|
6390
6678
|
function collectFlowVersions(dir, domain, out) {
|
|
6391
|
-
for (const f of
|
|
6679
|
+
for (const f of fs12__default.readdirSync(dir)) {
|
|
6392
6680
|
if (!f.endsWith(".flow.yaml")) continue;
|
|
6393
|
-
const fp =
|
|
6394
|
-
const content =
|
|
6681
|
+
const fp = path14__default.join(dir, f);
|
|
6682
|
+
const content = fs12__default.readFileSync(fp, "utf-8");
|
|
6395
6683
|
const parsed = parse(content);
|
|
6396
6684
|
out.push({
|
|
6397
6685
|
kind: "flow",
|
|
@@ -6403,10 +6691,10 @@ function collectFlowVersions(dir, domain, out) {
|
|
|
6403
6691
|
}
|
|
6404
6692
|
}
|
|
6405
6693
|
function collectPromptVersions(dir, domain, out) {
|
|
6406
|
-
for (const f of
|
|
6694
|
+
for (const f of fs12__default.readdirSync(dir)) {
|
|
6407
6695
|
if (!f.endsWith(".prompt.md")) continue;
|
|
6408
|
-
const fp =
|
|
6409
|
-
const content =
|
|
6696
|
+
const fp = path14__default.join(dir, f);
|
|
6697
|
+
const content = fs12__default.readFileSync(fp, "utf-8");
|
|
6410
6698
|
const fm = parseSkillFrontmatter(content);
|
|
6411
6699
|
out.push({
|
|
6412
6700
|
kind: "prompt",
|
|
@@ -6418,12 +6706,12 @@ function collectPromptVersions(dir, domain, out) {
|
|
|
6418
6706
|
}
|
|
6419
6707
|
}
|
|
6420
6708
|
function collectSkillVersions(dir, domain, out) {
|
|
6421
|
-
for (const entry of
|
|
6709
|
+
for (const entry of fs12__default.readdirSync(dir, { withFileTypes: true })) {
|
|
6422
6710
|
if (!entry.isDirectory()) continue;
|
|
6423
|
-
const full =
|
|
6424
|
-
const skillMd =
|
|
6425
|
-
if (
|
|
6426
|
-
const content =
|
|
6711
|
+
const full = path14__default.join(dir, entry.name);
|
|
6712
|
+
const skillMd = path14__default.join(full, "SKILL.md");
|
|
6713
|
+
if (fs12__default.existsSync(skillMd)) {
|
|
6714
|
+
const content = fs12__default.readFileSync(skillMd, "utf-8");
|
|
6427
6715
|
const fm = parseSkillFrontmatter(content);
|
|
6428
6716
|
out.push({
|
|
6429
6717
|
kind: "skill",
|
|
@@ -6438,11 +6726,11 @@ function collectSkillVersions(dir, domain, out) {
|
|
|
6438
6726
|
}
|
|
6439
6727
|
}
|
|
6440
6728
|
function collectAgentVersions(dir, domain, out) {
|
|
6441
|
-
for (const entry of
|
|
6729
|
+
for (const entry of fs12__default.readdirSync(dir, { withFileTypes: true })) {
|
|
6442
6730
|
if (!entry.isDirectory()) continue;
|
|
6443
|
-
const agentYaml =
|
|
6444
|
-
if (!
|
|
6445
|
-
const content =
|
|
6731
|
+
const agentYaml = path14__default.join(dir, entry.name, "agent.yaml");
|
|
6732
|
+
if (!fs12__default.existsSync(agentYaml)) continue;
|
|
6733
|
+
const content = fs12__default.readFileSync(agentYaml, "utf-8");
|
|
6446
6734
|
const parsed = parse(content);
|
|
6447
6735
|
out.push({
|
|
6448
6736
|
kind: "agent",
|
|
@@ -6473,7 +6761,7 @@ function filterToChangedAssets(assets) {
|
|
|
6473
6761
|
encoding: "utf-8"
|
|
6474
6762
|
});
|
|
6475
6763
|
const changedFiles = new Set(
|
|
6476
|
-
diffOutput.trim().split("\n").filter(Boolean).map((f) =>
|
|
6764
|
+
diffOutput.trim().split("\n").filter(Boolean).map((f) => path14__default.resolve(AI_RESOURCES, f))
|
|
6477
6765
|
);
|
|
6478
6766
|
return assets.filter((a) => changedFiles.has(a.filePath));
|
|
6479
6767
|
} catch {
|
|
@@ -6499,7 +6787,7 @@ function checkVersionBumps(assets) {
|
|
|
6499
6787
|
let warnings = 0;
|
|
6500
6788
|
for (const a of assets) {
|
|
6501
6789
|
if (!a.version) continue;
|
|
6502
|
-
const relPath =
|
|
6790
|
+
const relPath = path14__default.relative(AI_RESOURCES, a.filePath);
|
|
6503
6791
|
try {
|
|
6504
6792
|
const headContent = execSync(`git show HEAD:${relPath}`, {
|
|
6505
6793
|
cwd: AI_RESOURCES,
|
|
@@ -6525,7 +6813,7 @@ function checkFlowVersionPins(assets) {
|
|
|
6525
6813
|
}
|
|
6526
6814
|
let errors = 0;
|
|
6527
6815
|
for (const f of flows) {
|
|
6528
|
-
const content =
|
|
6816
|
+
const content = fs12__default.readFileSync(f.filePath, "utf-8");
|
|
6529
6817
|
const parsed = parse(content);
|
|
6530
6818
|
const nodes = (parsed?.nodes ?? []).filter((n) => n.type === "skill" && n.data?.version).map((n) => ({
|
|
6531
6819
|
nodeId: n.id,
|
|
@@ -6572,7 +6860,7 @@ function makeValidateCommand() {
|
|
|
6572
6860
|
"Validate asset manifests, versions, and changelogs"
|
|
6573
6861
|
);
|
|
6574
6862
|
cmd.argument("[path]", "Path to asset repo or directory to validate", ".").action((targetPath) => {
|
|
6575
|
-
const absPath =
|
|
6863
|
+
const absPath = path14__default.resolve(targetPath);
|
|
6576
6864
|
logInfo(`Validating manifests in ${absPath}`);
|
|
6577
6865
|
const { total, errors } = validateManifests(absPath);
|
|
6578
6866
|
const ws = validateWorkspaceManifests(absPath);
|
|
@@ -6618,7 +6906,7 @@ function makeValidateCommand() {
|
|
|
6618
6906
|
let errors = 0;
|
|
6619
6907
|
for (const domain of modifiedDomains) {
|
|
6620
6908
|
const changelogModified = modifiedFiles.some(
|
|
6621
|
-
(f) => f === `${domain}/CHANGELOG.md` || f ===
|
|
6909
|
+
(f) => f === `${domain}/CHANGELOG.md` || f === path14__default.join(domain, "CHANGELOG.md")
|
|
6622
6910
|
);
|
|
6623
6911
|
if (changelogModified) {
|
|
6624
6912
|
logOk(`${domain}/CHANGELOG.md updated`);
|
|
@@ -6700,7 +6988,7 @@ function makeVerifyCommand() {
|
|
|
6700
6988
|
}
|
|
6701
6989
|
function makeWhyCommand() {
|
|
6702
6990
|
return new Command("why").description("Show why an asset is installed (dependency chain)").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
6703
|
-
const am2 = new AssetManager({ projectDir:
|
|
6991
|
+
const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
|
|
6704
6992
|
const chain = am2.why(ref);
|
|
6705
6993
|
if (chain.length === 0) {
|
|
6706
6994
|
logErr(`${ref} not found in lock file. Run \`skaile install\` first.`);
|
|
@@ -6721,7 +7009,7 @@ function makeWhyCommand() {
|
|
|
6721
7009
|
var _defaultFormatHelp = Help.prototype.formatHelp;
|
|
6722
7010
|
var pkg = JSON.parse(
|
|
6723
7011
|
readFileSync(
|
|
6724
|
-
|
|
7012
|
+
path14__default.resolve(path14__default.dirname(fileURLToPath(import.meta.url)), "../../package.json"),
|
|
6725
7013
|
"utf-8"
|
|
6726
7014
|
)
|
|
6727
7015
|
);
|
|
@@ -6842,7 +7130,7 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
6842
7130
|
(projectDir, opts) => runInit(projectDir, opts)
|
|
6843
7131
|
);
|
|
6844
7132
|
async function runInit(projectDir, opts) {
|
|
6845
|
-
const { mkdirSync:
|
|
7133
|
+
const { mkdirSync: mkdirSync4, writeFileSync: writeFileSync4 } = await import('fs');
|
|
6846
7134
|
const { stringify } = await import('yaml');
|
|
6847
7135
|
const { DRIVER_TARGETS, SUPPORTED_DRIVER_TARGETS: SUPPORTED_DRIVER_TARGETS2 } = await import('../core/index.js');
|
|
6848
7136
|
const backend = opts.backend;
|
|
@@ -6851,33 +7139,33 @@ async function runInit(projectDir, opts) {
|
|
|
6851
7139
|
process.exitCode = 1;
|
|
6852
7140
|
return;
|
|
6853
7141
|
}
|
|
6854
|
-
const resolved =
|
|
6855
|
-
const projectName =
|
|
7142
|
+
const resolved = path14__default.resolve(projectDir ?? ".");
|
|
7143
|
+
const projectName = path14__default.basename(resolved);
|
|
6856
7144
|
const created = [];
|
|
6857
|
-
const { existsSync:
|
|
6858
|
-
if (!
|
|
6859
|
-
|
|
7145
|
+
const { existsSync: existsSync14 } = await import('fs');
|
|
7146
|
+
if (!existsSync14(resolved)) {
|
|
7147
|
+
mkdirSync4(resolved, { recursive: true });
|
|
6860
7148
|
created.push(".");
|
|
6861
7149
|
}
|
|
6862
|
-
const skaileDir =
|
|
6863
|
-
if (!
|
|
6864
|
-
|
|
7150
|
+
const skaileDir = path14__default.join(resolved, ".skaile");
|
|
7151
|
+
if (!existsSync14(skaileDir)) {
|
|
7152
|
+
mkdirSync4(path14__default.join(skaileDir, "sessions"), { recursive: true });
|
|
6865
7153
|
created.push(".skaile/");
|
|
6866
7154
|
}
|
|
6867
|
-
const settingsPath =
|
|
6868
|
-
if (!
|
|
6869
|
-
|
|
7155
|
+
const settingsPath = path14__default.join(skaileDir, "settings.json");
|
|
7156
|
+
if (!existsSync14(settingsPath)) {
|
|
7157
|
+
writeFileSync4(settingsPath, "{}\n");
|
|
6870
7158
|
created.push(".skaile/settings.json");
|
|
6871
7159
|
}
|
|
6872
|
-
const wsConfigPath =
|
|
6873
|
-
if (!
|
|
6874
|
-
|
|
7160
|
+
const wsConfigPath = path14__default.join(resolved, "skaile.yaml");
|
|
7161
|
+
if (!existsSync14(wsConfigPath)) {
|
|
7162
|
+
writeFileSync4(wsConfigPath, stringify(buildInitWorkspaceConfig(projectName, backend)));
|
|
6875
7163
|
created.push("skaile.yaml");
|
|
6876
7164
|
}
|
|
6877
7165
|
for (const dir of new Set(Object.values(DRIVER_TARGETS[backend].local))) {
|
|
6878
|
-
const full =
|
|
6879
|
-
if (!
|
|
6880
|
-
|
|
7166
|
+
const full = path14__default.join(resolved, dir);
|
|
7167
|
+
if (!existsSync14(full)) {
|
|
7168
|
+
mkdirSync4(full, { recursive: true });
|
|
6881
7169
|
created.push(`${dir}/`);
|
|
6882
7170
|
}
|
|
6883
7171
|
}
|
|
@@ -6907,8 +7195,8 @@ function buildInitWorkspaceConfig(projectName, backend) {
|
|
|
6907
7195
|
}
|
|
6908
7196
|
async function initGitScaffold(resolved, created) {
|
|
6909
7197
|
const { execSync: execSync3 } = await import('child_process');
|
|
6910
|
-
const { existsSync:
|
|
6911
|
-
const gitignorePath =
|
|
7198
|
+
const { existsSync: existsSync14, readFileSync: readFileSync8, writeFileSync: writeFileSync4 } = await import('fs');
|
|
7199
|
+
const gitignorePath = path14__default.join(resolved, ".gitignore");
|
|
6912
7200
|
const entries = [
|
|
6913
7201
|
"node_modules/",
|
|
6914
7202
|
".skaile/sessions/",
|
|
@@ -6917,16 +7205,16 @@ async function initGitScaffold(resolved, created) {
|
|
|
6917
7205
|
".env",
|
|
6918
7206
|
".env.local"
|
|
6919
7207
|
];
|
|
6920
|
-
const existing =
|
|
7208
|
+
const existing = existsSync14(gitignorePath) ? readFileSync8(gitignorePath, "utf-8") : "";
|
|
6921
7209
|
const have = new Set(existing.split("\n").map((l) => l.trim()));
|
|
6922
7210
|
const append = entries.filter((e) => !have.has(e));
|
|
6923
7211
|
if (append.length > 0) {
|
|
6924
7212
|
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
6925
|
-
|
|
7213
|
+
writeFileSync4(gitignorePath, `${existing + prefix}${append.join("\n")}
|
|
6926
7214
|
`);
|
|
6927
7215
|
if (!existing) created.push(".gitignore");
|
|
6928
7216
|
}
|
|
6929
|
-
if (!
|
|
7217
|
+
if (!existsSync14(path14__default.join(resolved, ".git"))) {
|
|
6930
7218
|
try {
|
|
6931
7219
|
execSync3("git init", { cwd: resolved, stdio: "pipe" });
|
|
6932
7220
|
created.push(".git/");
|
|
@@ -6938,10 +7226,10 @@ async function initGitScaffold(resolved, created) {
|
|
|
6938
7226
|
}
|
|
6939
7227
|
async function bootstrapUserConfig() {
|
|
6940
7228
|
try {
|
|
6941
|
-
const
|
|
7229
|
+
const fs13 = await import('fs');
|
|
6942
7230
|
const { userConfigPath, saveConfig, getConfigDefaults } = await import('../library/index.js');
|
|
6943
7231
|
const userCfgPath = userConfigPath();
|
|
6944
|
-
if (!
|
|
7232
|
+
if (!fs13.existsSync(userCfgPath)) {
|
|
6945
7233
|
const defaults = getConfigDefaults();
|
|
6946
7234
|
saveConfig(userCfgPath, {
|
|
6947
7235
|
catalog: { url: defaults.catalog.url, cache_ttl: defaults.catalog.cache_ttl }
|
|
@@ -6972,7 +7260,7 @@ function printInitSummary(resolved, projectDir, created) {
|
|
|
6972
7260
|
logOk(`Initialized project at ${S.heading(resolved)}`);
|
|
6973
7261
|
console.log();
|
|
6974
7262
|
console.log(S.heading(" Next steps:"));
|
|
6975
|
-
const isCurrentDir = resolved ===
|
|
7263
|
+
const isCurrentDir = resolved === path14__default.resolve(".");
|
|
6976
7264
|
let step = 1;
|
|
6977
7265
|
if (!isCurrentDir) {
|
|
6978
7266
|
console.log(` ${S.dim(`${step}.`)} ${S.cmd(`cd ${projectDir}`)}`);
|