@skaile/workspaces 0.14.0 → 0.15.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 +76 -0
- package/dist/base-assets/connectors/flow/run-flow.js +1 -1
- package/dist/{chunk-42OQF7UU.js → chunk-2NIOMFSQ.js} +305 -225
- package/dist/chunk-2NIOMFSQ.js.map +1 -0
- package/dist/{chunk-VAJB2UJ5.js → chunk-6EN5IJ2Y.js} +13 -13
- package/dist/chunk-6EN5IJ2Y.js.map +1 -0
- package/dist/{chunk-OIFGKFZY.js → chunk-SO43XRWF.js} +2 -2
- package/dist/{chunk-OIFGKFZY.js.map → chunk-SO43XRWF.js.map} +1 -1
- package/dist/{chunk-DN5476SV.js → chunk-Z24KPZKU.js} +17 -10
- package/dist/chunk-Z24KPZKU.js.map +1 -0
- package/dist/cli/index.js +674 -516
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts +4 -1
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/library-cmd.d.ts +6 -4
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/npx.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts +2 -2
- package/dist/cli/src/commands/source-manifest.d.ts +19 -0
- package/dist/cli/src/commands/source-manifest.d.ts.map +1 -0
- package/dist/cli/src/commands/source.d.ts +6 -2
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/store.d.ts.map +1 -1
- package/dist/cli/src/open-library.d.ts +18 -18
- package/dist/cli/src/open-library.d.ts.map +1 -1
- package/dist/library/index.js +1 -1
- package/dist/library/src/config.d.ts +12 -3
- package/dist/library/src/config.d.ts.map +1 -1
- package/dist/library/src/index.d.ts +7 -8
- package/dist/library/src/index.d.ts.map +1 -1
- package/dist/library/src/library.d.ts +24 -77
- package/dist/library/src/library.d.ts.map +1 -1
- package/dist/library/src/local/db.d.ts +3 -2
- package/dist/library/src/local/db.d.ts.map +1 -1
- package/dist/library/src/local/{user-library-manager.d.ts → library-manager.d.ts} +15 -16
- package/dist/library/src/local/library-manager.d.ts.map +1 -0
- package/dist/library/src/local/library.d.ts +27 -23
- package/dist/library/src/local/library.d.ts.map +1 -1
- package/dist/library/src/local/local-catalog-source.d.ts +5 -5
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
- package/dist/library/src/local/sidecar-paths.d.ts +3 -3
- package/dist/library/src/local/store-paths.d.ts +42 -0
- package/dist/library/src/local/store-paths.d.ts.map +1 -0
- package/dist/library/src/preset/apply.d.ts +2 -2
- package/dist/library/src/preset/apply.d.ts.map +1 -1
- package/dist/library/src/preset/placeholders.d.ts +3 -3
- package/dist/library/src/preset/placeholders.d.ts.map +1 -1
- package/dist/library/src/preset/resolve-item.d.ts +3 -3
- package/dist/library/src/preset/resolve-item.d.ts.map +1 -1
- package/dist/library/src/sync/driver.d.ts +6 -6
- package/dist/library/src/sync/driver.d.ts.map +1 -1
- package/dist/library/src/sync/git-driver.d.ts +6 -6
- package/dist/library/src/sync/git-driver.d.ts.map +1 -1
- package/dist/library/src/sync/local-driver.d.ts +6 -6
- package/dist/library/src/sync/local-driver.d.ts.map +1 -1
- package/dist/library/src/user-library.d.ts +12 -17
- package/dist/library/src/user-library.d.ts.map +1 -1
- package/dist/{open-library-S6FK4N4S.js → open-library-XD7QYLMW.js} +4 -4
- package/dist/{open-library-S6FK4N4S.js.map → open-library-XD7QYLMW.js.map} +1 -1
- package/dist/runner/index.js +1 -1
- package/dist/runner/src/composition/resolve.d.ts +3 -3
- package/dist/runner/src/composition/resolve.d.ts.map +1 -1
- package/dist/sdk/index.js +1 -1
- package/dist/sdk/runner.js +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/types/src/install-manifest.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-42OQF7UU.js.map +0 -1
- package/dist/chunk-DN5476SV.js.map +0 -1
- package/dist/chunk-VAJB2UJ5.js.map +0 -1
- package/dist/cli/src/commands/library-status.d.ts +0 -19
- package/dist/cli/src/commands/library-status.d.ts.map +0 -1
- package/dist/cli/src/commands/source-sidecar.d.ts +0 -6
- package/dist/cli/src/commands/source-sidecar.d.ts.map +0 -1
- package/dist/library/src/local/user-library-manager.d.ts.map +0 -1
- package/dist/library/src/sync/store-driver.d.ts +0 -21
- package/dist/library/src/sync/store-driver.d.ts.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { openCatalogSource, openLibrary, createFullRegistry,
|
|
2
|
+
import { openCatalogSource, openLibrary, createFullRegistry, openLibraryManager } from '../chunk-6EN5IJ2Y.js';
|
|
3
3
|
import { logErr, S, logOk, colorRef, logInfo, logWarn, kindColorPad, kindColor, formatRelativeTime } from '../chunk-4NDWKA64.js';
|
|
4
4
|
import { getStoreConfig, storeFetch, saveStoreTokens, clearStoreTokens, isStoreAuthenticated } from '../chunk-6DEGWPAR.js';
|
|
5
5
|
import { AI_RESOURCES } from '../chunk-2M3XTMOL.js';
|
|
6
6
|
import { LocalSecretsProvider } from '../chunk-JDX54X4Y.js';
|
|
7
|
-
import { resolveLibraryDir } from '../chunk-
|
|
7
|
+
import { resolveLibraryDir, skaileHomeDir } from '../chunk-2NIOMFSQ.js';
|
|
8
8
|
import '../chunk-R7FOF242.js';
|
|
9
9
|
import '../chunk-GKIA2PU5.js';
|
|
10
10
|
import '../chunk-OKRUTSG7.js';
|
|
11
|
-
import { runFlow, resumeFlow } from '../chunk-
|
|
11
|
+
import { runFlow, resumeFlow } from '../chunk-SO43XRWF.js';
|
|
12
12
|
import '../chunk-GCJXPUHG.js';
|
|
13
13
|
import { validateFlowVersions, parseSkillFrontmatter } from '../chunk-IPUYL6TD.js';
|
|
14
|
-
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-
|
|
14
|
+
import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-Z24KPZKU.js';
|
|
15
15
|
import { buildClaudePluginFiles } from '../chunk-G7O7WDXX.js';
|
|
16
16
|
import '../chunk-X5YPJV4N.js';
|
|
17
17
|
import '../chunk-O7SG5PC2.js';
|
|
@@ -53,15 +53,15 @@ import '../chunk-LV2HPH3C.js';
|
|
|
53
53
|
import '../chunk-NSBPE2FW.js';
|
|
54
54
|
import * as fs10 from 'fs';
|
|
55
55
|
import fs10__default, { readFileSync, existsSync, writeFileSync, statSync } from 'fs';
|
|
56
|
-
import * as
|
|
57
|
-
import
|
|
56
|
+
import * as path15 from 'path';
|
|
57
|
+
import path15__default, { resolve, join } from 'path';
|
|
58
58
|
import { fileURLToPath } from 'url';
|
|
59
59
|
import { Help, Command, Option } from 'commander';
|
|
60
60
|
import * as p5 from '@clack/prompts';
|
|
61
|
-
import
|
|
61
|
+
import pc5 from 'picocolors';
|
|
62
62
|
import * as readline from 'readline';
|
|
63
63
|
import { createInterface } from 'readline';
|
|
64
|
-
import { execSync } from 'child_process';
|
|
64
|
+
import { execSync, spawnSync } from 'child_process';
|
|
65
65
|
import { homedir } from 'os';
|
|
66
66
|
import fs5 from 'fs/promises';
|
|
67
67
|
import { parse as parse$1, stringify } from 'smol-toml';
|
|
@@ -80,7 +80,7 @@ function makeAssetCommand() {
|
|
|
80
80
|
logErr(`Source path does not exist: ${srcPath}`);
|
|
81
81
|
process.exit(1);
|
|
82
82
|
}
|
|
83
|
-
const { manager, close } = await
|
|
83
|
+
const { manager, close } = await openLibraryManager();
|
|
84
84
|
try {
|
|
85
85
|
let target;
|
|
86
86
|
if (opts.to) {
|
|
@@ -103,10 +103,10 @@ function makeAssetCommand() {
|
|
|
103
103
|
);
|
|
104
104
|
process.exit(1);
|
|
105
105
|
}
|
|
106
|
-
const basename2 =
|
|
107
|
-
const destDir = target.structure === "domain" && opts.domain ?
|
|
106
|
+
const basename2 = path15.basename(srcPath);
|
|
107
|
+
const destDir = target.structure === "domain" && opts.domain ? path15.join(target.path, opts.domain) : target.path;
|
|
108
108
|
fs10.mkdirSync(destDir, { recursive: true });
|
|
109
|
-
const destPath =
|
|
109
|
+
const destPath = path15.join(destDir, basename2);
|
|
110
110
|
if (fs10.existsSync(destPath)) {
|
|
111
111
|
logErr(`Destination already exists: ${destPath}`);
|
|
112
112
|
process.exit(1);
|
|
@@ -119,13 +119,13 @@ function makeAssetCommand() {
|
|
|
119
119
|
fs10.renameSync(srcPath, destPath);
|
|
120
120
|
break;
|
|
121
121
|
case "link":
|
|
122
|
-
fs10.symlinkSync(
|
|
122
|
+
fs10.symlinkSync(path15.resolve(srcPath), destPath);
|
|
123
123
|
break;
|
|
124
124
|
}
|
|
125
125
|
if (target.backend === "git" && opts.commit) {
|
|
126
|
-
const { spawnSync } = await import('child_process');
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
const { spawnSync: spawnSync2 } = await import('child_process');
|
|
127
|
+
spawnSync2("git", ["add", "-A"], { cwd: target.path, stdio: "ignore" });
|
|
128
|
+
spawnSync2("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
|
|
129
129
|
cwd: target.path,
|
|
130
130
|
stdio: "ignore"
|
|
131
131
|
});
|
|
@@ -149,7 +149,7 @@ function makeAssetCommand() {
|
|
|
149
149
|
logErr(`Invalid --mode "${opts.mode}". Expected: copy | link.`);
|
|
150
150
|
process.exit(1);
|
|
151
151
|
}
|
|
152
|
-
const { manager, library, close } = await
|
|
152
|
+
const { manager, library, close } = await openLibraryManager();
|
|
153
153
|
try {
|
|
154
154
|
const def = await library.getAssetDef(ref);
|
|
155
155
|
if (!def) {
|
|
@@ -157,7 +157,7 @@ function makeAssetCommand() {
|
|
|
157
157
|
process.exit(1);
|
|
158
158
|
}
|
|
159
159
|
const target = opts.target ?? process.cwd();
|
|
160
|
-
const lib = def.
|
|
160
|
+
const lib = def.libraryId ? (await manager.listLibraries()).find((l) => l.id === def.libraryId) : void 0;
|
|
161
161
|
if (!lib) {
|
|
162
162
|
logErr(`Asset has no associated library; install path unknown.`);
|
|
163
163
|
process.exit(1);
|
|
@@ -167,17 +167,17 @@ function makeAssetCommand() {
|
|
|
167
167
|
}
|
|
168
168
|
const manifestPath = def.manifest.path;
|
|
169
169
|
const candidateSubpath = typeof manifestPath === "string" && manifestPath.length > 0 ? manifestPath : def.name;
|
|
170
|
-
const srcPath =
|
|
170
|
+
const srcPath = path15.join(lib.path, candidateSubpath);
|
|
171
171
|
if (!fs10.existsSync(srcPath)) {
|
|
172
172
|
logErr(`Asset path not found: ${srcPath}`);
|
|
173
173
|
process.exit(1);
|
|
174
174
|
}
|
|
175
|
-
const destPath =
|
|
176
|
-
fs10.mkdirSync(
|
|
175
|
+
const destPath = path15.join(target, candidateSubpath);
|
|
176
|
+
fs10.mkdirSync(path15.dirname(destPath), { recursive: true });
|
|
177
177
|
if (opts.mode === "copy") {
|
|
178
178
|
fs10.cpSync(srcPath, destPath, { recursive: true });
|
|
179
179
|
} else {
|
|
180
|
-
fs10.symlinkSync(
|
|
180
|
+
fs10.symlinkSync(path15.resolve(srcPath), destPath);
|
|
181
181
|
}
|
|
182
182
|
logOk(`Installed ${ref} \u2192 ${destPath} (${opts.mode})`);
|
|
183
183
|
} finally {
|
|
@@ -186,12 +186,12 @@ function makeAssetCommand() {
|
|
|
186
186
|
}
|
|
187
187
|
);
|
|
188
188
|
cmd.command("list").description("List asset definitions across libraries").option("--library <name>", "Filter by library").option("--domain <name>", "Filter by domain").option("--kind <kind>", "Filter by kind").option("--json", "Output as JSON").action(async (opts) => {
|
|
189
|
-
const { manager, library, close } = await
|
|
189
|
+
const { manager, library, close } = await openLibraryManager();
|
|
190
190
|
try {
|
|
191
191
|
let defs = await library.listAssetDefs(opts.kind ? { kind: opts.kind } : void 0);
|
|
192
192
|
if (opts.library) {
|
|
193
193
|
const lib = await manager.requireLibrary(opts.library);
|
|
194
|
-
defs = defs.filter((d) => d.
|
|
194
|
+
defs = defs.filter((d) => d.libraryId === lib.id);
|
|
195
195
|
}
|
|
196
196
|
if (opts.json) return console.log(JSON.stringify(defs, null, 2));
|
|
197
197
|
if (defs.length === 0) {
|
|
@@ -209,7 +209,7 @@ function makeAssetCommand() {
|
|
|
209
209
|
}
|
|
210
210
|
});
|
|
211
211
|
cmd.command("show <ref>").description("Show details for an asset by canonical ref").action(async (ref) => {
|
|
212
|
-
const { library, close } = await
|
|
212
|
+
const { library, close } = await openLibraryManager();
|
|
213
213
|
try {
|
|
214
214
|
const def = await library.getAssetDef(ref);
|
|
215
215
|
if (!def) {
|
|
@@ -221,10 +221,6 @@ function makeAssetCommand() {
|
|
|
221
221
|
close();
|
|
222
222
|
}
|
|
223
223
|
});
|
|
224
|
-
cmd.command("publish <ref>").description("Publish to the store (STUB)").option("--scope <scope>", "team | public", "team").action(async (_ref, _opts) => {
|
|
225
|
-
logErr("`skaile asset publish` is not yet wired (store write path stub).");
|
|
226
|
-
process.exit(2);
|
|
227
|
-
});
|
|
228
224
|
return cmd;
|
|
229
225
|
}
|
|
230
226
|
var VALID_STRATEGIES = ["keychain", "passphrase", "machine"];
|
|
@@ -275,7 +271,7 @@ function makeSearchCommand() {
|
|
|
275
271
|
const showLocal = !opts.store;
|
|
276
272
|
const showStore = !opts.local;
|
|
277
273
|
if (showLocal) {
|
|
278
|
-
const am2 = new AssetManager({ projectDir:
|
|
274
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
279
275
|
const entries = am2.search(query, kind);
|
|
280
276
|
if (entries.length === 0) {
|
|
281
277
|
if (!showStore) {
|
|
@@ -341,7 +337,7 @@ function makeSearchCommand() {
|
|
|
341
337
|
function makeAddCommand() {
|
|
342
338
|
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((ref, opts) => {
|
|
343
339
|
const am2 = new AssetManager({
|
|
344
|
-
projectDir:
|
|
340
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
345
341
|
global: opts.global,
|
|
346
342
|
driverTarget: opts.target
|
|
347
343
|
});
|
|
@@ -362,7 +358,7 @@ function makeAddCommand() {
|
|
|
362
358
|
function makeRemoveCommand() {
|
|
363
359
|
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) => {
|
|
364
360
|
const am2 = new AssetManager({
|
|
365
|
-
projectDir:
|
|
361
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
366
362
|
global: opts.global,
|
|
367
363
|
driverTarget: opts.target
|
|
368
364
|
});
|
|
@@ -376,7 +372,7 @@ function makeListCommand() {
|
|
|
376
372
|
new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
|
|
377
373
|
).action((kind, opts) => {
|
|
378
374
|
const am2 = new AssetManager({
|
|
379
|
-
projectDir:
|
|
375
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
380
376
|
global: opts.global,
|
|
381
377
|
driverTarget: opts.target
|
|
382
378
|
});
|
|
@@ -400,7 +396,7 @@ function makeListCommand() {
|
|
|
400
396
|
}
|
|
401
397
|
function makeInfoCommand() {
|
|
402
398
|
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) => {
|
|
403
|
-
const am2 = new AssetManager({ projectDir:
|
|
399
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
404
400
|
const entry = am2.info(ref);
|
|
405
401
|
if (!entry) {
|
|
406
402
|
logErr(
|
|
@@ -433,9 +429,9 @@ function makeCreateCommand() {
|
|
|
433
429
|
new Option("-k, --kind <kind>", "Asset kind").default("skill").choices([...ASSET_KINDS])
|
|
434
430
|
).option("-d, --dir <dir>", "Target directory (default: cwd)").action((name, opts) => {
|
|
435
431
|
const am2 = new AssetManager({ projectDir: process.cwd() });
|
|
436
|
-
const destDir = opts.dir ?
|
|
432
|
+
const destDir = opts.dir ? path15__default.resolve(opts.dir) : process.cwd();
|
|
437
433
|
const result = am2.create(name, opts.kind, destDir);
|
|
438
|
-
if (result.ok) logOk(`Created ${kindColor(opts.kind)}: ${
|
|
434
|
+
if (result.ok) logOk(`Created ${kindColor(opts.kind)}: ${pc5.dim(result.path)}`);
|
|
439
435
|
else {
|
|
440
436
|
logErr(result.path);
|
|
441
437
|
process.exit(1);
|
|
@@ -444,7 +440,7 @@ function makeCreateCommand() {
|
|
|
444
440
|
}
|
|
445
441
|
function makeDoctorCommand() {
|
|
446
442
|
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) => {
|
|
447
|
-
const am2 = new AssetManager({ projectDir:
|
|
443
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
448
444
|
const issues = am2.doctor();
|
|
449
445
|
if (issues.length === 0) {
|
|
450
446
|
logOk("No missing dependencies.");
|
|
@@ -470,11 +466,11 @@ function makeCatalogCommand() {
|
|
|
470
466
|
const catalog = new Command("catalog").description("Catalog source health and configuration");
|
|
471
467
|
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) => {
|
|
472
468
|
const { resolveConfig, isLocalCatalogUrl, trpcGetUrl } = await import('../library/index.js');
|
|
473
|
-
const projectDir = opts.projectDir ?
|
|
469
|
+
const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : void 0;
|
|
474
470
|
const cfg = resolveConfig({ projectDir });
|
|
475
471
|
const baseUrl = opts.url ?? cfg.catalog.url;
|
|
476
472
|
if (isLocalCatalogUrl(baseUrl)) {
|
|
477
|
-
const { resolveCatalogSource } = await import('../open-library-
|
|
473
|
+
const { resolveCatalogSource } = await import('../open-library-XD7QYLMW.js');
|
|
478
474
|
let resolved;
|
|
479
475
|
try {
|
|
480
476
|
resolved = await resolveCatalogSource({ projectDir: opts.projectDir });
|
|
@@ -563,7 +559,7 @@ function makeCatalogCommand() {
|
|
|
563
559
|
});
|
|
564
560
|
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) => {
|
|
565
561
|
const { resolveConfig } = await import('../library/index.js');
|
|
566
|
-
const projectDir = opts.projectDir ?
|
|
562
|
+
const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : void 0;
|
|
567
563
|
const cfg = resolveConfig({ projectDir });
|
|
568
564
|
console.log(`url: ${cfg.catalog.url}`);
|
|
569
565
|
console.log(`framing: ${cfg.catalog.framing}`);
|
|
@@ -620,7 +616,7 @@ function findSkills(domain) {
|
|
|
620
616
|
if (!fs10__default.existsSync(AI_RESOURCES)) return skills;
|
|
621
617
|
const domains = fs10__default.readdirSync(AI_RESOURCES, { withFileTypes: true }).filter((d) => d.isDirectory()).filter((d) => true);
|
|
622
618
|
for (const d of domains) {
|
|
623
|
-
const skillsDir =
|
|
619
|
+
const skillsDir = path15__default.join(AI_RESOURCES, d.name, "skills");
|
|
624
620
|
if (!fs10__default.existsSync(skillsDir)) continue;
|
|
625
621
|
walkSkills(skillsDir, d.name, skills);
|
|
626
622
|
}
|
|
@@ -628,9 +624,9 @@ function findSkills(domain) {
|
|
|
628
624
|
}
|
|
629
625
|
function walkSkills(dir, domain, out) {
|
|
630
626
|
for (const entry of fs10__default.readdirSync(dir, { withFileTypes: true })) {
|
|
631
|
-
const full =
|
|
627
|
+
const full = path15__default.join(dir, entry.name);
|
|
632
628
|
if (entry.isDirectory()) {
|
|
633
|
-
const skillMd =
|
|
629
|
+
const skillMd = path15__default.join(full, "SKILL.md");
|
|
634
630
|
if (fs10__default.existsSync(skillMd)) {
|
|
635
631
|
out.push({ name: entry.name, path: full, skillPath: skillMd, domain });
|
|
636
632
|
} else {
|
|
@@ -656,7 +652,7 @@ function resolveFlowIds() {
|
|
|
656
652
|
}
|
|
657
653
|
}
|
|
658
654
|
function resolveSessionIds(projectDir) {
|
|
659
|
-
const sessionsDir =
|
|
655
|
+
const sessionsDir = path15__default.join(projectDir, ".skaile", "sessions");
|
|
660
656
|
if (!fs10__default.existsSync(sessionsDir)) return [];
|
|
661
657
|
try {
|
|
662
658
|
return fs10__default.readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
|
|
@@ -717,7 +713,7 @@ var API_KEY_PREFIX = "apiKey.";
|
|
|
717
713
|
function makeConfigCommand() {
|
|
718
714
|
const cmd = new Command("config").description("Manage personal config (.skaile/settings.json)");
|
|
719
715
|
cmd.command("show").description("Show effective config with sources").option("--project-dir <path>", "Project directory").action(async (opts) => {
|
|
720
|
-
const projectDir = opts.projectDir ?
|
|
716
|
+
const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : process.cwd();
|
|
721
717
|
const config = await resolveSettings(projectDir);
|
|
722
718
|
const wsDefaults = {};
|
|
723
719
|
try {
|
|
@@ -774,13 +770,13 @@ function makeConfigCommand() {
|
|
|
774
770
|
console.log();
|
|
775
771
|
});
|
|
776
772
|
cmd.command("get <key>").description("Get an effective config value").option("--project-dir <path>", "Project directory").action(async (key, opts) => {
|
|
777
|
-
const projectDir = opts.projectDir ?
|
|
773
|
+
const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : process.cwd();
|
|
778
774
|
const config = await resolveSettings(projectDir);
|
|
779
775
|
const value = config[key];
|
|
780
776
|
console.log(value ?? S.dim("(not set)"));
|
|
781
777
|
});
|
|
782
778
|
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) => {
|
|
783
|
-
const projectDir = opts.projectDir ?
|
|
779
|
+
const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : process.cwd();
|
|
784
780
|
const isApiKey = key.startsWith(API_KEY_PREFIX);
|
|
785
781
|
if (!PERSONAL_KEYS.has(key) && !isApiKey) {
|
|
786
782
|
logErr(
|
|
@@ -796,11 +792,11 @@ function makeConfigCommand() {
|
|
|
796
792
|
const provider = key.slice(API_KEY_PREFIX.length);
|
|
797
793
|
existing.apiKeys = { ...existing.apiKeys, [provider]: value };
|
|
798
794
|
await saveSettings(existing, filePath);
|
|
799
|
-
logOk(`Set ${
|
|
795
|
+
logOk(`Set ${pc5.bold(`apiKeys.${provider}`)} = ****${value.slice(-4)}`);
|
|
800
796
|
} else {
|
|
801
797
|
existing[key] = value;
|
|
802
798
|
await saveSettings(existing, filePath);
|
|
803
|
-
logOk(`Set ${
|
|
799
|
+
logOk(`Set ${pc5.bold(key)} = ${value}`);
|
|
804
800
|
}
|
|
805
801
|
console.log(S.dim(` \u2192 ${filePath}`));
|
|
806
802
|
});
|
|
@@ -897,11 +893,11 @@ function makeConnectCommand() {
|
|
|
897
893
|
process.exitCode = 1;
|
|
898
894
|
return;
|
|
899
895
|
}
|
|
900
|
-
await new Promise((
|
|
896
|
+
await new Promise((resolve4) => {
|
|
901
897
|
client.onMessage((event) => {
|
|
902
898
|
console.log(formatEvent(event));
|
|
903
899
|
if (event.type === "finished" || event.type === "debug_result") {
|
|
904
|
-
|
|
900
|
+
resolve4();
|
|
905
901
|
}
|
|
906
902
|
});
|
|
907
903
|
client.send(parsed);
|
|
@@ -945,12 +941,12 @@ function makeConnectCommand() {
|
|
|
945
941
|
client.send(cmd);
|
|
946
942
|
rl.prompt();
|
|
947
943
|
});
|
|
948
|
-
await new Promise((
|
|
949
|
-
rl.on("close",
|
|
944
|
+
await new Promise((resolve4) => {
|
|
945
|
+
rl.on("close", resolve4);
|
|
950
946
|
client.onDisconnect(() => {
|
|
951
947
|
logErr("Server disconnected");
|
|
952
948
|
rl.close();
|
|
953
|
-
|
|
949
|
+
resolve4();
|
|
954
950
|
});
|
|
955
951
|
});
|
|
956
952
|
await client.disconnect();
|
|
@@ -1016,15 +1012,15 @@ function parseOpArgs(args) {
|
|
|
1016
1012
|
async function promptText(label, defaultVal) {
|
|
1017
1013
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1018
1014
|
const hint = defaultVal ? ` [${defaultVal}]` : "";
|
|
1019
|
-
return new Promise((
|
|
1015
|
+
return new Promise((resolve4) => {
|
|
1020
1016
|
rl.question(` ${label}${hint}: `, (answer) => {
|
|
1021
1017
|
rl.close();
|
|
1022
|
-
|
|
1018
|
+
resolve4(answer.trim() || defaultVal || "");
|
|
1023
1019
|
});
|
|
1024
1020
|
});
|
|
1025
1021
|
}
|
|
1026
1022
|
async function promptSecret(label) {
|
|
1027
|
-
return new Promise((
|
|
1023
|
+
return new Promise((resolve4) => {
|
|
1028
1024
|
process.stdout.write(` ${label} (hidden): `);
|
|
1029
1025
|
const stdin = process.stdin;
|
|
1030
1026
|
stdin.setRawMode?.(true);
|
|
@@ -1037,7 +1033,7 @@ async function promptSecret(label) {
|
|
|
1037
1033
|
stdin.pause();
|
|
1038
1034
|
stdin.removeListener("data", onData);
|
|
1039
1035
|
process.stdout.write("\n");
|
|
1040
|
-
|
|
1036
|
+
resolve4(value);
|
|
1041
1037
|
} else if (char === "") {
|
|
1042
1038
|
process.exit(1);
|
|
1043
1039
|
} else if (char === "\x7F") {
|
|
@@ -1087,8 +1083,8 @@ function makeConnectorCommand() {
|
|
|
1087
1083
|
async (driver, opts) => {
|
|
1088
1084
|
const { installNpmPackages } = await import('../connectors/index.js');
|
|
1089
1085
|
const { scanDirectory, resolveBaseAssetsRoot, WorkspaceYamlEditor } = await import('../core/index.js');
|
|
1090
|
-
const projectDir =
|
|
1091
|
-
const yamlPath =
|
|
1086
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1087
|
+
const yamlPath = path15__default.join(projectDir, "skaile.yaml");
|
|
1092
1088
|
if (!existsSync(yamlPath)) {
|
|
1093
1089
|
logErr("No skaile.yaml found in current directory. Run 'skaile init' first.");
|
|
1094
1090
|
process.exit(1);
|
|
@@ -1151,8 +1147,8 @@ ${installResult.output}`);
|
|
|
1151
1147
|
);
|
|
1152
1148
|
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) => {
|
|
1153
1149
|
const { WorkspaceYamlEditor } = await import('../core/index.js');
|
|
1154
|
-
const projectDir =
|
|
1155
|
-
const yamlPath =
|
|
1150
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1151
|
+
const yamlPath = path15__default.join(projectDir, "skaile.yaml");
|
|
1156
1152
|
if (!existsSync(yamlPath)) {
|
|
1157
1153
|
logErr("No skaile.yaml found in current directory.");
|
|
1158
1154
|
process.exit(1);
|
|
@@ -1169,7 +1165,7 @@ ${installResult.output}`);
|
|
|
1169
1165
|
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) => {
|
|
1170
1166
|
const res = await import('../connectors/index.js');
|
|
1171
1167
|
res.registerBuiltinConnectors();
|
|
1172
|
-
const projectDir =
|
|
1168
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1173
1169
|
const declarations = res.loadConnectorDeclarations(projectDir);
|
|
1174
1170
|
if (declarations.length === 0) {
|
|
1175
1171
|
console.log("No connectors configured in skaile.yaml.");
|
|
@@ -1193,7 +1189,7 @@ ${installResult.output}`);
|
|
|
1193
1189
|
await manager.disconnectAll();
|
|
1194
1190
|
});
|
|
1195
1191
|
cmd.command("list").description("List all configured connectors").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
1196
|
-
const projectDir =
|
|
1192
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1197
1193
|
const manager = await connectConnectors(projectDir);
|
|
1198
1194
|
try {
|
|
1199
1195
|
console.log(JSON.stringify(manager.listConnectors(), null, 2));
|
|
@@ -1202,7 +1198,7 @@ ${installResult.output}`);
|
|
|
1202
1198
|
}
|
|
1203
1199
|
});
|
|
1204
1200
|
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) => {
|
|
1205
|
-
const projectDir =
|
|
1201
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1206
1202
|
const manager = await connectConnectors(projectDir);
|
|
1207
1203
|
try {
|
|
1208
1204
|
if (opts.all) {
|
|
@@ -1226,7 +1222,7 @@ ${installResult.output}`);
|
|
|
1226
1222
|
}
|
|
1227
1223
|
});
|
|
1228
1224
|
cmd.command("ops <id>").description("List available operations for a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, opts) => {
|
|
1229
|
-
const projectDir =
|
|
1225
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1230
1226
|
const manager = await connectConnectors(projectDir);
|
|
1231
1227
|
try {
|
|
1232
1228
|
if (!manager.has(id)) {
|
|
@@ -1241,7 +1237,7 @@ ${installResult.output}`);
|
|
|
1241
1237
|
}
|
|
1242
1238
|
});
|
|
1243
1239
|
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) => {
|
|
1244
|
-
const projectDir =
|
|
1240
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1245
1241
|
const manager = await connectConnectors(projectDir);
|
|
1246
1242
|
try {
|
|
1247
1243
|
const content = await manager.read(id, resourcePath);
|
|
@@ -1251,7 +1247,7 @@ ${installResult.output}`);
|
|
|
1251
1247
|
}
|
|
1252
1248
|
});
|
|
1253
1249
|
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) => {
|
|
1254
|
-
const projectDir =
|
|
1250
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1255
1251
|
const manager = await connectConnectors(projectDir);
|
|
1256
1252
|
try {
|
|
1257
1253
|
await manager.write(id, resourcePath, { data: content });
|
|
@@ -1261,7 +1257,7 @@ ${installResult.output}`);
|
|
|
1261
1257
|
}
|
|
1262
1258
|
});
|
|
1263
1259
|
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", parseInt).action(async (id, resourcePath, opts) => {
|
|
1264
|
-
const projectDir =
|
|
1260
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1265
1261
|
const manager = await connectConnectors(projectDir);
|
|
1266
1262
|
try {
|
|
1267
1263
|
const entries = await manager.list(id, resourcePath, {
|
|
@@ -1274,7 +1270,7 @@ ${installResult.output}`);
|
|
|
1274
1270
|
}
|
|
1275
1271
|
});
|
|
1276
1272
|
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) => {
|
|
1277
|
-
const projectDir =
|
|
1273
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1278
1274
|
const manager = await connectConnectors(projectDir);
|
|
1279
1275
|
try {
|
|
1280
1276
|
const results = await manager.search(id, query);
|
|
@@ -1284,7 +1280,7 @@ ${installResult.output}`);
|
|
|
1284
1280
|
}
|
|
1285
1281
|
});
|
|
1286
1282
|
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) => {
|
|
1287
|
-
const projectDir =
|
|
1283
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1288
1284
|
const manager = await connectConnectors(projectDir);
|
|
1289
1285
|
try {
|
|
1290
1286
|
const ok = await manager.delete(id, resourcePath);
|
|
@@ -1294,7 +1290,7 @@ ${installResult.output}`);
|
|
|
1294
1290
|
}
|
|
1295
1291
|
});
|
|
1296
1292
|
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) => {
|
|
1297
|
-
const projectDir =
|
|
1293
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
1298
1294
|
const manager = await connectConnectors(projectDir);
|
|
1299
1295
|
try {
|
|
1300
1296
|
if (!manager.has(id)) {
|
|
@@ -1329,17 +1325,17 @@ async function runDebugQuery(query, parentOpts, args) {
|
|
|
1329
1325
|
process.exitCode = 1;
|
|
1330
1326
|
return;
|
|
1331
1327
|
}
|
|
1332
|
-
await new Promise((
|
|
1328
|
+
await new Promise((resolve4) => {
|
|
1333
1329
|
const timeout = setTimeout(() => {
|
|
1334
1330
|
logErr("Timeout: no debug_result received within 5s");
|
|
1335
1331
|
process.exitCode = 1;
|
|
1336
|
-
|
|
1332
|
+
resolve4();
|
|
1337
1333
|
}, 5e3);
|
|
1338
1334
|
client.onMessage((event) => {
|
|
1339
1335
|
if (event.type !== "debug_result") return;
|
|
1340
1336
|
clearTimeout(timeout);
|
|
1341
1337
|
printDebugResult(query, event.data);
|
|
1342
|
-
|
|
1338
|
+
resolve4();
|
|
1343
1339
|
});
|
|
1344
1340
|
client.send({ type: "debug", query, args });
|
|
1345
1341
|
});
|
|
@@ -1385,7 +1381,7 @@ function makeDebugCommand() {
|
|
|
1385
1381
|
}
|
|
1386
1382
|
function makeDiffCommand() {
|
|
1387
1383
|
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) => {
|
|
1388
|
-
const am2 = new AssetManager({ projectDir:
|
|
1384
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
1389
1385
|
const result = am2.diff(ref);
|
|
1390
1386
|
if (result === null) {
|
|
1391
1387
|
logInfo("No differences (or asset not found).");
|
|
@@ -1438,7 +1434,7 @@ function makeFlowCommand() {
|
|
|
1438
1434
|
function makeHistoryCommand() {
|
|
1439
1435
|
const cmd = new Command("history").description("Show recent add/remove/update actions");
|
|
1440
1436
|
cmd.argument("[limit]", "Number of entries to show", "20").option("--project-dir <path>", "Project directory", process.cwd()).action((limitStr, opts) => {
|
|
1441
|
-
const am2 = new AssetManager({ projectDir:
|
|
1437
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
1442
1438
|
const limit = parseInt(limitStr, 10) || 20;
|
|
1443
1439
|
const entries = am2.history(limit);
|
|
1444
1440
|
if (entries.length === 0) {
|
|
@@ -1458,18 +1454,21 @@ function makeHistoryCommand() {
|
|
|
1458
1454
|
console.log();
|
|
1459
1455
|
});
|
|
1460
1456
|
cmd.command("clear").description("Clear action history").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
1461
|
-
const am2 = new AssetManager({ projectDir:
|
|
1457
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
1462
1458
|
am2.clearHistory();
|
|
1463
1459
|
logOk("History cleared.");
|
|
1464
1460
|
});
|
|
1465
1461
|
return cmd;
|
|
1466
1462
|
}
|
|
1463
|
+
var NOT_WIRED_MSG_PUBLISH = "`skaile library publish` is scaffolded but not yet wired. Server endpoint `POST /sources/<id>/manifest` lands in a follow-up PR.";
|
|
1464
|
+
function notWired(verb, msg) {
|
|
1465
|
+
logErr(`${msg} (verb: library ${verb})`);
|
|
1466
|
+
process.exit(2);
|
|
1467
|
+
}
|
|
1467
1468
|
function makeLibraryCommand() {
|
|
1468
|
-
const cmd = new Command("library").description(
|
|
1469
|
-
"Manage user-facing libraries (local / git / store)"
|
|
1470
|
-
);
|
|
1469
|
+
const cmd = new Command("library").description("Manage user authoring libraries (local / git)");
|
|
1471
1470
|
cmd.command("list").description("List all registered libraries").option("--json", "Output as JSON").action(async (opts) => {
|
|
1472
|
-
const { manager, close } = await
|
|
1471
|
+
const { manager, close } = await openLibraryManager();
|
|
1473
1472
|
try {
|
|
1474
1473
|
const ls = await manager.listLibraries();
|
|
1475
1474
|
if (opts.json) return console.log(JSON.stringify(ls, null, 2));
|
|
@@ -1481,9 +1480,9 @@ function makeLibraryCommand() {
|
|
|
1481
1480
|
console.log(S.heading(" Libraries"));
|
|
1482
1481
|
console.log(` ${S.rule(80)}`);
|
|
1483
1482
|
for (const l of ls) {
|
|
1484
|
-
const def = l.isDefault ?
|
|
1483
|
+
const def = l.isDefault ? pc5.green("\u25B8 ") : " ";
|
|
1485
1484
|
console.log(
|
|
1486
|
-
`${def}${S.cmd(l.name.padEnd(16))} ${
|
|
1485
|
+
`${def}${S.cmd(l.name.padEnd(16))} ${pc5.dim(l.backend.padEnd(7))} ${pc5.dim(l.ownership.padEnd(12))} ${pc5.dim(l.path)}`
|
|
1487
1486
|
);
|
|
1488
1487
|
}
|
|
1489
1488
|
console.log(`
|
|
@@ -1493,41 +1492,15 @@ function makeLibraryCommand() {
|
|
|
1493
1492
|
close();
|
|
1494
1493
|
}
|
|
1495
1494
|
});
|
|
1496
|
-
cmd.command("status [name]").description("Show
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
const results = await Promise.all(
|
|
1501
|
-
targets.map(async (l) => ({
|
|
1502
|
-
library: l.name,
|
|
1503
|
-
status: await manager.driverFor(l.backend).status(l)
|
|
1504
|
-
}))
|
|
1505
|
-
);
|
|
1506
|
-
if (opts.json) return console.log(JSON.stringify(results, null, 2));
|
|
1507
|
-
for (const { library, status: status4 } of results) {
|
|
1508
|
-
console.log(`
|
|
1509
|
-
${S.heading(library)}`);
|
|
1510
|
-
console.log(` reachable: ${status4.reachable ? S.ok("yes") : S.err("no")}`);
|
|
1511
|
-
if (status4.remoteChanges) {
|
|
1512
|
-
console.log(
|
|
1513
|
-
` behind/ahead: ${status4.remoteChanges.behind}/${status4.remoteChanges.ahead}`
|
|
1514
|
-
);
|
|
1515
|
-
}
|
|
1516
|
-
const lc = status4.localChanges;
|
|
1517
|
-
if (lc.added.length + lc.modified.length + lc.deleted.length > 0) {
|
|
1518
|
-
console.log(
|
|
1519
|
-
` local changes: +${lc.added.length} ~${lc.modified.length} -${lc.deleted.length}`
|
|
1520
|
-
);
|
|
1521
|
-
}
|
|
1522
|
-
for (const note of status4.notes) console.log(` ${pc6.dim("note:")} ${note}`);
|
|
1523
|
-
}
|
|
1524
|
-
console.log();
|
|
1525
|
-
} finally {
|
|
1526
|
-
close();
|
|
1495
|
+
cmd.command("status [name]").description("Show overall Library health or per-library sync status").option("--project-dir <path>", "Project directory", process.cwd()).option("--json", "Output as JSON").action(async (name, opts) => {
|
|
1496
|
+
if (name) {
|
|
1497
|
+
await printPerLibraryStatus(name, opts.json ?? false);
|
|
1498
|
+
return;
|
|
1527
1499
|
}
|
|
1500
|
+
await printOverallStatus(opts.projectDir, opts.json ?? false);
|
|
1528
1501
|
});
|
|
1529
1502
|
cmd.command("show <name>").description("Detailed info about a library").action(async (name) => {
|
|
1530
|
-
const { manager, close } = await
|
|
1503
|
+
const { manager, close } = await openLibraryManager();
|
|
1531
1504
|
try {
|
|
1532
1505
|
const l = await manager.requireLibrary(name);
|
|
1533
1506
|
console.log();
|
|
@@ -1546,12 +1519,12 @@ function makeLibraryCommand() {
|
|
|
1546
1519
|
close();
|
|
1547
1520
|
}
|
|
1548
1521
|
});
|
|
1549
|
-
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("--
|
|
1522
|
+
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(
|
|
1550
1523
|
async (name, opts) => {
|
|
1551
1524
|
const libDir = resolveLibraryDir();
|
|
1552
|
-
const libPath =
|
|
1525
|
+
const libPath = path15.join(libDir, name);
|
|
1553
1526
|
const ownership = opts.contributor ? "contributor" : opts.reader ? "reader" : "owner";
|
|
1554
|
-
const { manager, close } = await
|
|
1527
|
+
const { manager, close } = await openLibraryManager();
|
|
1555
1528
|
try {
|
|
1556
1529
|
if (opts.git) {
|
|
1557
1530
|
fs10.mkdirSync(libPath, { recursive: true });
|
|
@@ -1562,14 +1535,6 @@ function makeLibraryCommand() {
|
|
|
1562
1535
|
backendConfig: { url: opts.git, branch: "main", authHint: "ssh" },
|
|
1563
1536
|
ownership
|
|
1564
1537
|
});
|
|
1565
|
-
} else if (opts.store) {
|
|
1566
|
-
await manager.addLibrary({
|
|
1567
|
-
name,
|
|
1568
|
-
path: libPath,
|
|
1569
|
-
backend: "store",
|
|
1570
|
-
backendConfig: { url: opts.store, publisher: "", tokenRef: "" },
|
|
1571
|
-
ownership
|
|
1572
|
-
});
|
|
1573
1538
|
} else {
|
|
1574
1539
|
fs10.mkdirSync(libPath, { recursive: true });
|
|
1575
1540
|
await manager.addLibrary({
|
|
@@ -1586,45 +1551,65 @@ function makeLibraryCommand() {
|
|
|
1586
1551
|
}
|
|
1587
1552
|
}
|
|
1588
1553
|
);
|
|
1589
|
-
cmd.command("
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1554
|
+
cmd.command("link <name> <git-url>").description("Attach a github remote to a local library (makes it store-publishable)").option("--branch <name>", "Default branch", "main").action(async (name, url, opts) => {
|
|
1555
|
+
const { manager, close } = await openLibraryManager();
|
|
1556
|
+
try {
|
|
1557
|
+
const lib = await manager.requireLibrary(name);
|
|
1558
|
+
if (lib.backend === "git") {
|
|
1559
|
+
logErr(
|
|
1560
|
+
`Library "${name}" is already git-backed. Use \`skaile library set ${name} backendConfig.url=${url}\` to change its remote.`
|
|
1561
|
+
);
|
|
1562
|
+
process.exit(1);
|
|
1563
|
+
}
|
|
1564
|
+
await manager.updateLibrary(name, {
|
|
1565
|
+
backend: "git",
|
|
1566
|
+
backendConfig: { url, branch: opts.branch, authHint: "ssh" }
|
|
1567
|
+
});
|
|
1568
|
+
logOk(`Library "${name}" linked to ${url}.`);
|
|
1569
|
+
} finally {
|
|
1570
|
+
close();
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
cmd.command("create <kind> <name>").description("Scaffold a new asset inside the default (or named) library").addOption(
|
|
1574
|
+
new Option("--kind <kind>", "Asset kind override").choices([...ASSET_KINDS])
|
|
1575
|
+
).option("--library <name>", "Target library (default: the default-marked one)").option("--dir <dir>", "Target directory inside the library (default: library root)").action(
|
|
1576
|
+
async (kind, name, opts) => {
|
|
1577
|
+
if (!ASSET_KINDS.includes(kind)) {
|
|
1578
|
+
logErr(`Unknown asset kind "${kind}". Expected: ${ASSET_KINDS.join(", ")}.`);
|
|
1598
1579
|
process.exit(1);
|
|
1599
1580
|
}
|
|
1600
|
-
const
|
|
1601
|
-
const { manager, close } = await openUserLibraryManager();
|
|
1581
|
+
const { manager, close } = await openLibraryManager();
|
|
1602
1582
|
try {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1583
|
+
let target;
|
|
1584
|
+
if (opts.library) {
|
|
1585
|
+
target = await manager.requireLibrary(opts.library);
|
|
1586
|
+
} else {
|
|
1587
|
+
const all = await manager.listLibraries();
|
|
1588
|
+
const def = all.find((l) => l.isDefault);
|
|
1589
|
+
if (!def) {
|
|
1590
|
+
logErr(
|
|
1591
|
+
"No default library set. Either run `skaile library default <name>` first or pass --library."
|
|
1592
|
+
);
|
|
1593
|
+
process.exit(1);
|
|
1594
|
+
}
|
|
1595
|
+
target = def;
|
|
1596
|
+
}
|
|
1597
|
+
const am2 = new AssetManager({ projectDir: process.cwd() });
|
|
1598
|
+
const destDir = opts.dir ? path15.join(target.path, opts.dir) : target.path;
|
|
1599
|
+
const res = am2.create(name, opts.kind ?? kind, destDir);
|
|
1600
|
+
if (res.ok) {
|
|
1601
|
+
logOk(`Created ${opts.kind ?? kind}: ${pc5.dim(res.path)}`);
|
|
1602
|
+
} else {
|
|
1603
|
+
logErr(res.path);
|
|
1604
|
+
process.exit(1);
|
|
1619
1605
|
}
|
|
1620
|
-
logOk(`Library "${derived}" added (${ownership}).`);
|
|
1621
1606
|
} finally {
|
|
1622
1607
|
close();
|
|
1623
1608
|
}
|
|
1624
1609
|
}
|
|
1625
1610
|
);
|
|
1626
1611
|
cmd.command("default <name>").description("Set <name> as the default library").action(async (name) => {
|
|
1627
|
-
const { manager, close } = await
|
|
1612
|
+
const { manager, close } = await openLibraryManager();
|
|
1628
1613
|
try {
|
|
1629
1614
|
const updated = await manager.setDefault(name);
|
|
1630
1615
|
logOk(`Default \u2192 ${updated.name}`);
|
|
@@ -1633,11 +1618,11 @@ function makeLibraryCommand() {
|
|
|
1633
1618
|
}
|
|
1634
1619
|
});
|
|
1635
1620
|
cmd.command("rename <old> <new>").description("Rename a library (also moves the directory)").action(async (oldName, newName) => {
|
|
1636
|
-
const { manager, close } = await
|
|
1621
|
+
const { manager, close } = await openLibraryManager();
|
|
1637
1622
|
try {
|
|
1638
1623
|
const lib = await manager.requireLibrary(oldName);
|
|
1639
|
-
const parent =
|
|
1640
|
-
const newPath =
|
|
1624
|
+
const parent = path15.dirname(lib.path);
|
|
1625
|
+
const newPath = path15.join(parent, newName);
|
|
1641
1626
|
if (fs10.existsSync(newPath)) {
|
|
1642
1627
|
logErr(`Target directory already exists: ${newPath}`);
|
|
1643
1628
|
process.exit(1);
|
|
@@ -1652,7 +1637,7 @@ function makeLibraryCommand() {
|
|
|
1652
1637
|
cmd.command("set <name> <field=value>").description("Update a single library field (e.g. ownership=contributor)").action(async (name, expr) => {
|
|
1653
1638
|
const [field, ...rest] = expr.split("=");
|
|
1654
1639
|
const value = rest.join("=");
|
|
1655
|
-
const { manager, close } = await
|
|
1640
|
+
const { manager, close } = await openLibraryManager();
|
|
1656
1641
|
try {
|
|
1657
1642
|
const lib = await manager.requireLibrary(name);
|
|
1658
1643
|
const patch = {};
|
|
@@ -1673,7 +1658,7 @@ function makeLibraryCommand() {
|
|
|
1673
1658
|
}
|
|
1674
1659
|
});
|
|
1675
1660
|
cmd.command("remove <name>").description("Unregister a library (use --purge to also delete files)").option("--purge", "Also delete the library directory from disk", false).option("-y, --yes", "Skip confirmation", false).action(async (name, opts) => {
|
|
1676
|
-
const { manager, close } = await
|
|
1661
|
+
const { manager, close } = await openLibraryManager();
|
|
1677
1662
|
try {
|
|
1678
1663
|
if (!opts.yes) {
|
|
1679
1664
|
const confirmed = await p5.confirm({
|
|
@@ -1692,7 +1677,7 @@ function makeLibraryCommand() {
|
|
|
1692
1677
|
}
|
|
1693
1678
|
});
|
|
1694
1679
|
cmd.command("sync <name>").description("Pull then push (as backend permits)").action(async (name) => {
|
|
1695
|
-
const { manager, close } = await
|
|
1680
|
+
const { manager, close } = await openLibraryManager();
|
|
1696
1681
|
try {
|
|
1697
1682
|
const lib = await manager.requireLibrary(name);
|
|
1698
1683
|
const drv = manager.driverFor(lib.backend);
|
|
@@ -1709,7 +1694,7 @@ function makeLibraryCommand() {
|
|
|
1709
1694
|
}
|
|
1710
1695
|
});
|
|
1711
1696
|
cmd.command("pull <name>").description("Pull from remote").action(async (name) => {
|
|
1712
|
-
const { manager, close } = await
|
|
1697
|
+
const { manager, close } = await openLibraryManager();
|
|
1713
1698
|
try {
|
|
1714
1699
|
const lib = await manager.requireLibrary(name);
|
|
1715
1700
|
const res = await manager.driverFor(lib.backend).pull(lib);
|
|
@@ -1723,7 +1708,7 @@ function makeLibraryCommand() {
|
|
|
1723
1708
|
}
|
|
1724
1709
|
});
|
|
1725
1710
|
cmd.command("push <name>").description("Push local commits (owner only)").option("--force", "Force-with-lease push", false).action(async (name, opts) => {
|
|
1726
|
-
const { manager, close } = await
|
|
1711
|
+
const { manager, close } = await openLibraryManager();
|
|
1727
1712
|
try {
|
|
1728
1713
|
const lib = await manager.requireLibrary(name);
|
|
1729
1714
|
const res = await manager.driverFor(lib.backend).push(lib, { force: opts.force });
|
|
@@ -1736,7 +1721,7 @@ function makeLibraryCommand() {
|
|
|
1736
1721
|
}
|
|
1737
1722
|
});
|
|
1738
1723
|
cmd.command("propose <name>").description("Open a pull request on the upstream repo (contributor only)").option("--title <title>", "PR title").option("--body <body>", "PR body").option("--branch <name>", "Branch name (default: skaile/<timestamp>)").action(async (name, opts) => {
|
|
1739
|
-
const { manager, close } = await
|
|
1724
|
+
const { manager, close } = await openLibraryManager();
|
|
1740
1725
|
try {
|
|
1741
1726
|
const lib = await manager.requireLibrary(name);
|
|
1742
1727
|
const res = await manager.driverFor(lib.backend).propose(lib, opts);
|
|
@@ -1749,16 +1734,16 @@ function makeLibraryCommand() {
|
|
|
1749
1734
|
}
|
|
1750
1735
|
});
|
|
1751
1736
|
cmd.command("commit <name>").description("Git-commit local changes inside the library (git only)").option("-m, --message <msg>", "Commit message", "skaile: update assets").action(async (name, opts) => {
|
|
1752
|
-
const { manager, close } = await
|
|
1737
|
+
const { manager, close } = await openLibraryManager();
|
|
1753
1738
|
try {
|
|
1754
1739
|
const lib = await manager.requireLibrary(name);
|
|
1755
1740
|
if (lib.backend !== "git") {
|
|
1756
1741
|
logErr("`library commit` only applies to git-backed libraries.");
|
|
1757
1742
|
process.exit(1);
|
|
1758
1743
|
}
|
|
1759
|
-
const { spawnSync } = await import('child_process');
|
|
1760
|
-
|
|
1761
|
-
const r =
|
|
1744
|
+
const { spawnSync: spawnSync2 } = await import('child_process');
|
|
1745
|
+
spawnSync2("git", ["add", "-A"], { cwd: lib.path, stdio: "inherit" });
|
|
1746
|
+
const r = spawnSync2("git", ["commit", "-m", opts.message], {
|
|
1762
1747
|
cwd: lib.path,
|
|
1763
1748
|
stdio: "inherit"
|
|
1764
1749
|
});
|
|
@@ -1773,126 +1758,151 @@ function makeLibraryCommand() {
|
|
|
1773
1758
|
});
|
|
1774
1759
|
cmd.command("git <name>").description("Pass-through: run arbitrary git commands inside the library").allowUnknownOption().action(async (name, _, command) => {
|
|
1775
1760
|
const args = command.args.slice(1);
|
|
1776
|
-
const { manager, close } = await
|
|
1761
|
+
const { manager, close } = await openLibraryManager();
|
|
1777
1762
|
try {
|
|
1778
1763
|
const lib = await manager.requireLibrary(name);
|
|
1779
|
-
const { spawnSync } = await import('child_process');
|
|
1780
|
-
const r =
|
|
1764
|
+
const { spawnSync: spawnSync2 } = await import('child_process');
|
|
1765
|
+
const r = spawnSync2("git", args, { cwd: lib.path, stdio: "inherit" });
|
|
1781
1766
|
process.exit(r.status ?? 0);
|
|
1782
1767
|
} finally {
|
|
1783
1768
|
close();
|
|
1784
1769
|
}
|
|
1785
1770
|
});
|
|
1771
|
+
cmd.command("publish <ref>").description("Push + register manifest atomically (needs git backend)").action((_ref) => notWired("publish", NOT_WIRED_MSG_PUBLISH));
|
|
1772
|
+
cmd.command("register <ref>").description("Register manifest in store without pushing (bytes already on github)").action((_ref) => notWired("register", NOT_WIRED_MSG_PUBLISH));
|
|
1773
|
+
cmd.command("yank <ref>").description("Retract a catalog entry").option("--version <v>", "Version to yank").action((_ref) => notWired("yank", NOT_WIRED_MSG_PUBLISH));
|
|
1786
1774
|
return cmd;
|
|
1787
1775
|
}
|
|
1788
|
-
function
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
const provider = new LocalSecretsProvider2();
|
|
1799
|
-
secretsStrategy = provider.getKeyStrategy();
|
|
1800
|
-
} catch {
|
|
1801
|
-
secretsStrategy = "unavailable";
|
|
1802
|
-
}
|
|
1803
|
-
const projectDir = path16__default.resolve(opts.projectDir);
|
|
1804
|
-
const hasWorkspaceConfig = existsSync(path16__default.join(projectDir, "skaile.yaml"));
|
|
1805
|
-
const hasLockFile = existsSync(path16__default.join(projectDir, "skaile.lock.yaml"));
|
|
1806
|
-
let subscriptions = [];
|
|
1807
|
-
if (hasWorkspaceConfig) {
|
|
1808
|
-
try {
|
|
1809
|
-
subscriptions = await library.listSubscriptions(projectDir);
|
|
1810
|
-
} catch {
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
const registry = createFullRegistry();
|
|
1814
|
-
const registeredKinds = registry.getAllKinds();
|
|
1815
|
-
if (opts.json) {
|
|
1816
|
-
console.log(
|
|
1817
|
-
JSON.stringify(
|
|
1818
|
-
{
|
|
1819
|
-
sources: sources.length,
|
|
1820
|
-
assetDefinitions: defs.length,
|
|
1821
|
-
instances: instances.length,
|
|
1822
|
-
subscriptions: subscriptions.length,
|
|
1823
|
-
secretsStrategy,
|
|
1824
|
-
registeredKinds,
|
|
1825
|
-
workspace: {
|
|
1826
|
-
dir: projectDir,
|
|
1827
|
-
hasConfig: hasWorkspaceConfig,
|
|
1828
|
-
hasLock: hasLockFile
|
|
1829
|
-
}
|
|
1830
|
-
},
|
|
1831
|
-
null,
|
|
1832
|
-
2
|
|
1833
|
-
)
|
|
1834
|
-
);
|
|
1835
|
-
return;
|
|
1836
|
-
}
|
|
1837
|
-
console.log();
|
|
1838
|
-
console.log(S.heading(" Library Status"));
|
|
1839
|
-
console.log(` ${S.rule(50)}`);
|
|
1776
|
+
async function printPerLibraryStatus(name, asJson) {
|
|
1777
|
+
const { manager, close } = await openLibraryManager();
|
|
1778
|
+
try {
|
|
1779
|
+
const lib = await manager.requireLibrary(name);
|
|
1780
|
+
const status4 = await manager.driverFor(lib.backend).status(lib);
|
|
1781
|
+
if (asJson) return console.log(JSON.stringify({ library: lib.name, status: status4 }, null, 2));
|
|
1782
|
+
console.log(`
|
|
1783
|
+
${S.heading(lib.name)}`);
|
|
1784
|
+
console.log(` reachable: ${status4.reachable ? S.ok("yes") : S.err("no")}`);
|
|
1785
|
+
if (status4.remoteChanges) {
|
|
1840
1786
|
console.log(
|
|
1841
|
-
`
|
|
1787
|
+
` behind/ahead: ${status4.remoteChanges.behind}/${status4.remoteChanges.ahead}`
|
|
1842
1788
|
);
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
console.log(
|
|
1847
|
-
` ${S.dim(s.id.slice(0, 8))} ${s.name} ${S.dim(`(${s.type})`)} ${S.dim(s.ownership)} ${S.dim(synced)}${defaultMark}`
|
|
1848
|
-
);
|
|
1849
|
-
}
|
|
1850
|
-
if (sources.length > 3) {
|
|
1851
|
-
console.log(` ${S.dim(`...and ${sources.length - 3} more`)}`);
|
|
1852
|
-
}
|
|
1853
|
-
const byKind = /* @__PURE__ */ new Map();
|
|
1854
|
-
for (const d of defs) {
|
|
1855
|
-
byKind.set(d.kind, (byKind.get(d.kind) ?? 0) + 1);
|
|
1856
|
-
}
|
|
1789
|
+
}
|
|
1790
|
+
const lc = status4.localChanges;
|
|
1791
|
+
if (lc.added.length + lc.modified.length + lc.deleted.length > 0) {
|
|
1857
1792
|
console.log(
|
|
1858
|
-
`
|
|
1793
|
+
` local changes: +${lc.added.length} ~${lc.modified.length} -${lc.deleted.length}`
|
|
1859
1794
|
);
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1795
|
+
}
|
|
1796
|
+
for (const note of status4.notes) console.log(` ${pc5.dim("note:")} ${note}`);
|
|
1797
|
+
console.log();
|
|
1798
|
+
} finally {
|
|
1799
|
+
close();
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
async function printOverallStatus(projectDir, asJson) {
|
|
1803
|
+
const library = await openLibrary();
|
|
1804
|
+
try {
|
|
1805
|
+
const libs = await library.listSources();
|
|
1806
|
+
const defs = await library.listAssetDefs();
|
|
1807
|
+
const instances = await library.listInstances();
|
|
1808
|
+
let secretsStrategy = "unknown";
|
|
1809
|
+
try {
|
|
1810
|
+
const { LocalSecretsProvider: LocalSecretsProvider2 } = await import('../secrets/index.js');
|
|
1811
|
+
const provider = new LocalSecretsProvider2();
|
|
1812
|
+
secretsStrategy = provider.getKeyStrategy();
|
|
1813
|
+
} catch {
|
|
1814
|
+
secretsStrategy = "unavailable";
|
|
1815
|
+
}
|
|
1816
|
+
const resolvedProjectDir = path15.resolve(projectDir);
|
|
1817
|
+
const hasWorkspaceConfig = existsSync(path15.join(resolvedProjectDir, "skaile.yaml"));
|
|
1818
|
+
const hasLockFile = existsSync(path15.join(resolvedProjectDir, "skaile.lock.yaml"));
|
|
1819
|
+
let subscriptions = [];
|
|
1820
|
+
if (hasWorkspaceConfig) {
|
|
1821
|
+
try {
|
|
1822
|
+
subscriptions = await library.listSubscriptions(resolvedProjectDir);
|
|
1823
|
+
} catch {
|
|
1863
1824
|
}
|
|
1825
|
+
}
|
|
1826
|
+
const registry = createFullRegistry();
|
|
1827
|
+
const registeredKinds = registry.getAllKinds();
|
|
1828
|
+
if (asJson) {
|
|
1864
1829
|
console.log(
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1830
|
+
JSON.stringify(
|
|
1831
|
+
{
|
|
1832
|
+
libraries: libs.length,
|
|
1833
|
+
assetDefinitions: defs.length,
|
|
1834
|
+
instances: instances.length,
|
|
1835
|
+
subscriptions: subscriptions.length,
|
|
1836
|
+
secretsStrategy,
|
|
1837
|
+
registeredKinds,
|
|
1838
|
+
workspace: {
|
|
1839
|
+
dir: resolvedProjectDir,
|
|
1840
|
+
hasConfig: hasWorkspaceConfig,
|
|
1841
|
+
hasLock: hasLockFile
|
|
1842
|
+
}
|
|
1843
|
+
},
|
|
1844
|
+
null,
|
|
1845
|
+
2
|
|
1846
|
+
)
|
|
1880
1847
|
);
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
console.log();
|
|
1851
|
+
console.log(S.heading(" Library Status"));
|
|
1852
|
+
console.log(` ${S.rule(50)}`);
|
|
1853
|
+
console.log(
|
|
1854
|
+
` ${S.label("Libraries")} ${libs.length === 0 ? S.dim("none") : pc5.green(String(libs.length))}`
|
|
1855
|
+
);
|
|
1856
|
+
for (const l of libs.slice(0, 3)) {
|
|
1857
|
+
const synced = l.lastSyncAt ? `synced ${formatRelativeTime(l.lastSyncAt)}` : "never synced";
|
|
1858
|
+
const defaultMark = l.isDefault ? pc5.green(" *") : "";
|
|
1881
1859
|
console.log(
|
|
1882
|
-
`
|
|
1860
|
+
` ${S.dim(l.id.slice(0, 8))} ${l.name} ${S.dim(`(${l.backend})`)} ${S.dim(l.ownership)} ${S.dim(synced)}${defaultMark}`
|
|
1883
1861
|
);
|
|
1884
|
-
console.log();
|
|
1885
|
-
if (sources.length === 0) {
|
|
1886
|
-
logInfo("Get started: `skaile library init personal` or `skaile library add <git-url>`");
|
|
1887
|
-
} else if (defs.length === 0) {
|
|
1888
|
-
logInfo("Run `skaile library sync <name>` to discover assets.");
|
|
1889
|
-
} else if (instances.length === 0) {
|
|
1890
|
-
logInfo("Run `skaile asset install <ref>` to install an asset into a workspace.");
|
|
1891
|
-
}
|
|
1892
|
-
} finally {
|
|
1893
|
-
library.close();
|
|
1894
1862
|
}
|
|
1895
|
-
|
|
1863
|
+
if (libs.length > 3) {
|
|
1864
|
+
console.log(` ${S.dim(`...and ${libs.length - 3} more`)}`);
|
|
1865
|
+
}
|
|
1866
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
1867
|
+
for (const d of defs) byKind.set(d.kind, (byKind.get(d.kind) ?? 0) + 1);
|
|
1868
|
+
console.log(
|
|
1869
|
+
` ${S.label("Cached assets")} ${defs.length === 0 ? S.dim("none") : pc5.green(String(defs.length))}`
|
|
1870
|
+
);
|
|
1871
|
+
if (byKind.size > 0) {
|
|
1872
|
+
const parts = [...byKind.entries()].sort((a, b) => b[1] - a[1]).map(([k, v]) => `${v} ${k}${v > 1 ? "s" : ""}`);
|
|
1873
|
+
console.log(` ${S.dim(parts.join(", "))}`);
|
|
1874
|
+
}
|
|
1875
|
+
console.log(
|
|
1876
|
+
` ${S.label("Registered kinds")} ${pc5.green(String(registeredKinds.length))}`
|
|
1877
|
+
);
|
|
1878
|
+
console.log(` ${S.dim(registeredKinds.join(", "))}`);
|
|
1879
|
+
console.log(
|
|
1880
|
+
` ${S.label("Instances")} ${instances.length === 0 ? S.dim("none") : pc5.green(String(instances.length))}`
|
|
1881
|
+
);
|
|
1882
|
+
console.log(
|
|
1883
|
+
` ${S.label("Subscriptions")} ${subscriptions.length === 0 ? S.dim("none (this workspace)") : pc5.green(String(subscriptions.length))}`
|
|
1884
|
+
);
|
|
1885
|
+
const strategyColor = secretsStrategy === "unavailable" ? S.dim : pc5.green;
|
|
1886
|
+
console.log(` ${S.label("Secrets strategy")} ${strategyColor(secretsStrategy)}`);
|
|
1887
|
+
console.log(` ${S.rule(50)}`);
|
|
1888
|
+
console.log(` ${S.label("Workspace")} ${resolvedProjectDir}`);
|
|
1889
|
+
console.log(
|
|
1890
|
+
` ${S.label("skaile.yaml")} ${hasWorkspaceConfig ? pc5.green("present") : S.dim("not found")}`
|
|
1891
|
+
);
|
|
1892
|
+
console.log(
|
|
1893
|
+
` ${S.label("skaile.lock.yaml")} ${hasLockFile ? pc5.green("present") : S.dim("not found")}`
|
|
1894
|
+
);
|
|
1895
|
+
console.log();
|
|
1896
|
+
if (libs.length === 0) {
|
|
1897
|
+
logInfo("Get started: `skaile library init personal` or `skaile source add <git-url>`");
|
|
1898
|
+
} else if (defs.length === 0) {
|
|
1899
|
+
logInfo("Run `skaile library sync <name>` to discover assets.");
|
|
1900
|
+
} else if (instances.length === 0) {
|
|
1901
|
+
logInfo("Run `skaile asset install <ref>` to install an asset into a workspace.");
|
|
1902
|
+
}
|
|
1903
|
+
} finally {
|
|
1904
|
+
library.close();
|
|
1905
|
+
}
|
|
1896
1906
|
}
|
|
1897
1907
|
function parseContainers(raw) {
|
|
1898
1908
|
return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
@@ -1901,11 +1911,11 @@ function parseContainers(raw) {
|
|
|
1901
1911
|
});
|
|
1902
1912
|
}
|
|
1903
1913
|
function colorLine(line) {
|
|
1904
|
-
if (/error|Error|ERROR|failed|Failed/.test(line)) return
|
|
1905
|
-
if (/connector|MCP|tool/.test(line)) return
|
|
1906
|
-
if (/rebuilt|registered|ready/.test(line)) return
|
|
1907
|
-
if (/\[driver\]/.test(line)) return
|
|
1908
|
-
if (/\[serve\]/.test(line)) return
|
|
1914
|
+
if (/error|Error|ERROR|failed|Failed/.test(line)) return pc5.red(line);
|
|
1915
|
+
if (/connector|MCP|tool/.test(line)) return pc5.yellow(line);
|
|
1916
|
+
if (/rebuilt|registered|ready/.test(line)) return pc5.green(line);
|
|
1917
|
+
if (/\[driver\]/.test(line)) return pc5.cyan(line);
|
|
1918
|
+
if (/\[serve\]/.test(line)) return pc5.dim(line);
|
|
1909
1919
|
return line;
|
|
1910
1920
|
}
|
|
1911
1921
|
function dockerAvailable() {
|
|
@@ -2143,14 +2153,14 @@ function loadAssets() {
|
|
|
2143
2153
|
}
|
|
2144
2154
|
async function loadLibraries() {
|
|
2145
2155
|
try {
|
|
2146
|
-
const {
|
|
2147
|
-
const { manager, library, close } = await
|
|
2156
|
+
const { openLibraryManager: openLibraryManager2 } = await import('../open-library-XD7QYLMW.js');
|
|
2157
|
+
const { manager, library, close } = await openLibraryManager2();
|
|
2148
2158
|
try {
|
|
2149
2159
|
const libs = await manager.listLibraries();
|
|
2150
2160
|
const defs = await library.listAssetDefs();
|
|
2151
2161
|
const counts = /* @__PURE__ */ new Map();
|
|
2152
2162
|
for (const d of defs) {
|
|
2153
|
-
const id = d.
|
|
2163
|
+
const id = d.libraryId ?? "";
|
|
2154
2164
|
counts.set(id, (counts.get(id) ?? 0) + 1);
|
|
2155
2165
|
}
|
|
2156
2166
|
state.libraryRows = libs.map((l) => ({
|
|
@@ -2234,8 +2244,8 @@ function showCursor() {
|
|
|
2234
2244
|
function renderTabs() {
|
|
2235
2245
|
return Object.entries(TABS).map(([id, spec]) => {
|
|
2236
2246
|
const text = `${spec.label} (${spec.selectableCount()})`;
|
|
2237
|
-
return id === state.tab ?
|
|
2238
|
-
}).join(
|
|
2247
|
+
return id === state.tab ? pc5.bgCyan(pc5.black(` ${text} `)) : pc5.dim(` ${text} `);
|
|
2248
|
+
}).join(pc5.dim("\u2502"));
|
|
2239
2249
|
}
|
|
2240
2250
|
function pendingCountsFor(match) {
|
|
2241
2251
|
let add = 0;
|
|
@@ -2251,11 +2261,11 @@ function pendingCountsFor(match) {
|
|
|
2251
2261
|
return [add, remove];
|
|
2252
2262
|
}
|
|
2253
2263
|
function groupStatus(refs) {
|
|
2254
|
-
if (refs.length === 0) return
|
|
2255
|
-
if (refs.some((r) => state.pendingAdds.has(r))) return
|
|
2256
|
-
if (refs.some((r) => state.pendingRemoves.has(r))) return
|
|
2264
|
+
if (refs.length === 0) return pc5.dim("\xB7 ");
|
|
2265
|
+
if (refs.some((r) => state.pendingAdds.has(r))) return pc5.blue("+ ");
|
|
2266
|
+
if (refs.some((r) => state.pendingRemoves.has(r))) return pc5.red("- ");
|
|
2257
2267
|
const allDeployed = refs.every((r) => findAssetRow(r)?.deployed);
|
|
2258
|
-
return allDeployed ?
|
|
2268
|
+
return allDeployed ? pc5.green("\u2713 ") : pc5.dim("\xB7 ");
|
|
2259
2269
|
}
|
|
2260
2270
|
function renderHeaderLine(opts) {
|
|
2261
2271
|
const indicator = opts.collapsed ? "\u25B6" : "\u25BC";
|
|
@@ -2263,12 +2273,12 @@ function renderHeaderLine(opts) {
|
|
|
2263
2273
|
const installed = state.assetRows.filter((r) => opts.match(r) && r.deployed).length;
|
|
2264
2274
|
const [add, remove] = pendingCountsFor(opts.match);
|
|
2265
2275
|
let count = String(installed);
|
|
2266
|
-
if (add > 0) count +=
|
|
2267
|
-
if (remove > 0) count +=
|
|
2276
|
+
if (add > 0) count += pc5.green(`+${add}`);
|
|
2277
|
+
if (remove > 0) count += pc5.red(`-${remove}`);
|
|
2268
2278
|
count += `/${total}`;
|
|
2269
2279
|
const status4 = groupStatus(opts.refs);
|
|
2270
2280
|
const line = `${opts.indent}${status4}${indicator} ${opts.label} (${count} assets)`;
|
|
2271
|
-
return opts.selected ?
|
|
2281
|
+
return opts.selected ? pc5.bgWhite(pc5.black(`${line} `.padEnd(state.cols))) : line;
|
|
2272
2282
|
}
|
|
2273
2283
|
function renderAssetRow(row, selected) {
|
|
2274
2284
|
if (row.type === "repo-header") {
|
|
@@ -2277,7 +2287,7 @@ function renderAssetRow(row, selected) {
|
|
|
2277
2287
|
collapsed: state.collapsedRepos.has(row.repo),
|
|
2278
2288
|
match: (r) => isAsset(r) && inRepo(r, row.repo),
|
|
2279
2289
|
refs: repoAssetRefs(state.assetRows, row.repo),
|
|
2280
|
-
label:
|
|
2290
|
+
label: pc5.bold(pc5.cyan(row.repo)),
|
|
2281
2291
|
selected
|
|
2282
2292
|
});
|
|
2283
2293
|
}
|
|
@@ -2287,27 +2297,27 @@ function renderAssetRow(row, selected) {
|
|
|
2287
2297
|
collapsed: state.collapsedDomains.has(`${row.repo}:${row.domain}`),
|
|
2288
2298
|
match: (r) => isAsset(r) && inDomain(r, row.repo, row.domain),
|
|
2289
2299
|
refs: domainAssetRefs(state.assetRows, row.repo, row.domain),
|
|
2290
|
-
label:
|
|
2300
|
+
label: pc5.bold(row.domain),
|
|
2291
2301
|
selected
|
|
2292
2302
|
});
|
|
2293
2303
|
}
|
|
2294
2304
|
const e = row.entry;
|
|
2295
2305
|
const ref = assetRefOf(row);
|
|
2296
2306
|
let status4;
|
|
2297
|
-
if (state.pendingAdds.has(ref)) status4 =
|
|
2298
|
-
else if (state.pendingRemoves.has(ref)) status4 =
|
|
2299
|
-
else if (row.deployed) status4 =
|
|
2300
|
-
else status4 =
|
|
2307
|
+
if (state.pendingAdds.has(ref)) status4 = pc5.blue("+ ");
|
|
2308
|
+
else if (state.pendingRemoves.has(ref)) status4 = pc5.red("- ");
|
|
2309
|
+
else if (row.deployed) status4 = pc5.green("\u2713 ");
|
|
2310
|
+
else status4 = pc5.dim("\xB7 ");
|
|
2301
2311
|
const kind = kindColorPad(e.kind, 8);
|
|
2302
2312
|
const name = e.name.padEnd(30);
|
|
2303
2313
|
const desc = e.description?.slice(0, state.cols - 52) ?? "";
|
|
2304
|
-
const line = ` ${status4} ${kind} ${name} ${
|
|
2305
|
-
return selected ?
|
|
2314
|
+
const line = ` ${status4} ${kind} ${name} ${pc5.dim(desc)}`;
|
|
2315
|
+
return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
|
|
2306
2316
|
}
|
|
2307
2317
|
function renderLibraryRow(row, selected) {
|
|
2308
|
-
const mark = row.isDefault ?
|
|
2309
|
-
const line = `${mark} ${S.cmd(row.name.padEnd(16))} ${
|
|
2310
|
-
return selected ?
|
|
2318
|
+
const mark = row.isDefault ? pc5.green("\u25B8") : " ";
|
|
2319
|
+
const line = `${mark} ${S.cmd(row.name.padEnd(16))} ${pc5.dim(row.backend.padEnd(7))} ${pc5.dim(row.ownership.padEnd(12))} ${pc5.dim(`${row.assetCount} assets`)}`;
|
|
2320
|
+
return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
|
|
2311
2321
|
}
|
|
2312
2322
|
function render() {
|
|
2313
2323
|
clearScreen();
|
|
@@ -2317,12 +2327,12 @@ function render() {
|
|
|
2317
2327
|
const overhead = 5 + pendingLines + msgLines;
|
|
2318
2328
|
const maxRows = Math.max(5, (process.stdout.rows || 30) - overhead);
|
|
2319
2329
|
console.log();
|
|
2320
|
-
console.log(` ${
|
|
2330
|
+
console.log(` ${pc5.bold("skaile manage")} ${renderTabs()}`);
|
|
2321
2331
|
console.log(` ${S.rule(state.cols - 4)}`);
|
|
2322
2332
|
const spec = TABS[state.tab];
|
|
2323
2333
|
const total = spec.rowCount();
|
|
2324
2334
|
if (total === 0 && spec.emptyMsg) {
|
|
2325
|
-
console.log(
|
|
2335
|
+
console.log(pc5.dim(spec.emptyMsg));
|
|
2326
2336
|
} else {
|
|
2327
2337
|
const start = Math.max(0, state.cursor - maxRows + 3);
|
|
2328
2338
|
const end = Math.min(total, start + maxRows);
|
|
@@ -2333,9 +2343,9 @@ function render() {
|
|
|
2333
2343
|
if (state.pendingAdds.size > 0 || state.pendingRemoves.size > 0) {
|
|
2334
2344
|
console.log();
|
|
2335
2345
|
if (state.pendingAdds.size > 0)
|
|
2336
|
-
console.log(` ${
|
|
2346
|
+
console.log(` ${pc5.blue(`+ ${state.pendingAdds.size} to add`)}`);
|
|
2337
2347
|
if (state.pendingRemoves.size > 0)
|
|
2338
|
-
console.log(` ${
|
|
2348
|
+
console.log(` ${pc5.red(`- ${state.pendingRemoves.size} to remove`)}`);
|
|
2339
2349
|
}
|
|
2340
2350
|
if (state.message) {
|
|
2341
2351
|
console.log();
|
|
@@ -2343,27 +2353,27 @@ function render() {
|
|
|
2343
2353
|
state.message = "";
|
|
2344
2354
|
}
|
|
2345
2355
|
console.log();
|
|
2346
|
-
console.log(
|
|
2356
|
+
console.log(pc5.dim(spec.footer));
|
|
2347
2357
|
}
|
|
2348
2358
|
function renderExitPrompt() {
|
|
2349
2359
|
clearScreen();
|
|
2350
2360
|
console.log();
|
|
2351
|
-
console.log(` ${
|
|
2361
|
+
console.log(` ${pc5.yellow("!")} ${pc5.bold("You have unapplied changes:")}`);
|
|
2352
2362
|
if (state.pendingAdds.size > 0)
|
|
2353
|
-
console.log(` ${
|
|
2363
|
+
console.log(` ${pc5.blue(`+ ${state.pendingAdds.size} to add`)}`);
|
|
2354
2364
|
if (state.pendingRemoves.size > 0)
|
|
2355
|
-
console.log(` ${
|
|
2365
|
+
console.log(` ${pc5.red(`- ${state.pendingRemoves.size} to remove`)}`);
|
|
2356
2366
|
console.log();
|
|
2357
2367
|
console.log(
|
|
2358
|
-
` Apply before exiting? ${
|
|
2368
|
+
` Apply before exiting? ${pc5.bold("[y]")} apply ${pc5.bold("[n]")} discard ${pc5.bold("[c/Esc]")} cancel`
|
|
2359
2369
|
);
|
|
2360
2370
|
}
|
|
2361
2371
|
async function applyChanges() {
|
|
2362
2372
|
if (state.pendingAdds.size === 0 && state.pendingRemoves.size === 0) {
|
|
2363
|
-
state.message =
|
|
2373
|
+
state.message = pc5.dim("Nothing to apply.");
|
|
2364
2374
|
return;
|
|
2365
2375
|
}
|
|
2366
|
-
state.message =
|
|
2376
|
+
state.message = pc5.yellow("Applying changes...");
|
|
2367
2377
|
render();
|
|
2368
2378
|
let added = 0;
|
|
2369
2379
|
let removed = 0;
|
|
@@ -2375,24 +2385,24 @@ async function applyChanges() {
|
|
|
2375
2385
|
am.add(ref);
|
|
2376
2386
|
added++;
|
|
2377
2387
|
} catch (err) {
|
|
2378
|
-
state.message =
|
|
2388
|
+
state.message = pc5.red(`Failed to add ${ref}: ${err}`);
|
|
2379
2389
|
}
|
|
2380
2390
|
}
|
|
2381
2391
|
state.pendingAdds.clear();
|
|
2382
2392
|
state.pendingRemoves.clear();
|
|
2383
2393
|
loadAssets();
|
|
2384
2394
|
const parts = [];
|
|
2385
|
-
if (added > 0) parts.push(
|
|
2386
|
-
if (removed > 0) parts.push(
|
|
2395
|
+
if (added > 0) parts.push(pc5.green(`+${added} added`));
|
|
2396
|
+
if (removed > 0) parts.push(pc5.red(`-${removed} removed`));
|
|
2387
2397
|
if (parts.length) state.message = parts.join(" ");
|
|
2388
2398
|
}
|
|
2389
2399
|
async function syncLibraries() {
|
|
2390
|
-
state.message =
|
|
2400
|
+
state.message = pc5.yellow(
|
|
2391
2401
|
"Library sync is not yet driven from the manage TUI. Run `skaile library sync <name>` from the shell."
|
|
2392
2402
|
);
|
|
2393
2403
|
}
|
|
2394
2404
|
function shellHint(action) {
|
|
2395
|
-
state.message =
|
|
2405
|
+
state.message = pc5.yellow(
|
|
2396
2406
|
`${action} is a shell command in the Libraries redesign. Run \`skaile library \u2026\` from the shell.`
|
|
2397
2407
|
);
|
|
2398
2408
|
}
|
|
@@ -2403,13 +2413,13 @@ async function showInfo() {
|
|
|
2403
2413
|
const e = row.entry;
|
|
2404
2414
|
clearScreen();
|
|
2405
2415
|
console.log();
|
|
2406
|
-
console.log(` ${kindColor(e.kind)} ${
|
|
2416
|
+
console.log(` ${kindColor(e.kind)} ${pc5.bold(e.name)}`);
|
|
2407
2417
|
console.log(` ${S.rule(50)}`);
|
|
2408
2418
|
if (e.version) console.log(` version: ${e.version}`);
|
|
2409
2419
|
if (e.description) console.log(` description: ${e.description}`);
|
|
2410
|
-
if (e.repository) console.log(` repository: ${
|
|
2411
|
-
console.log(` source: ${
|
|
2412
|
-
console.log(` deployed: ${row.deployed ?
|
|
2420
|
+
if (e.repository) console.log(` repository: ${pc5.dim(e.repository)}`);
|
|
2421
|
+
console.log(` source: ${pc5.dim(e.source)}`);
|
|
2422
|
+
console.log(` deployed: ${row.deployed ? pc5.green("yes") : pc5.red("no")}`);
|
|
2413
2423
|
if (e.requires.length) {
|
|
2414
2424
|
console.log(` requires:`);
|
|
2415
2425
|
for (const d of e.requires) console.log(` ${kindColor(d.kind)}:${d.name}`);
|
|
@@ -2419,11 +2429,11 @@ async function showInfo() {
|
|
|
2419
2429
|
for (const d of e.dependencies) console.log(` ${d}`);
|
|
2420
2430
|
}
|
|
2421
2431
|
console.log();
|
|
2422
|
-
console.log(
|
|
2423
|
-
await new Promise((
|
|
2432
|
+
console.log(pc5.dim(" Press any key to return..."));
|
|
2433
|
+
await new Promise((resolve4) => {
|
|
2424
2434
|
const onData = () => {
|
|
2425
2435
|
process.stdin.removeListener("data", onData);
|
|
2426
|
-
|
|
2436
|
+
resolve4();
|
|
2427
2437
|
};
|
|
2428
2438
|
process.stdin.once("data", onData);
|
|
2429
2439
|
});
|
|
@@ -2601,7 +2611,7 @@ async function run(projectDir) {
|
|
|
2601
2611
|
}
|
|
2602
2612
|
function makeManageCommand() {
|
|
2603
2613
|
return new Command("manage").description("Interactive TUI for managing libraries and assets").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
2604
|
-
await run(
|
|
2614
|
+
await run(path15__default.resolve(opts.projectDir));
|
|
2605
2615
|
});
|
|
2606
2616
|
}
|
|
2607
2617
|
function makeMcpServerCommand() {
|
|
@@ -2642,7 +2652,7 @@ function makeNpxCommand() {
|
|
|
2642
2652
|
const npx = new Command("npx").description("Compatibility shim for npx skills syntax");
|
|
2643
2653
|
const skills = npx.command("skills").description("Skill installation from external repos");
|
|
2644
2654
|
skills.command("add <url>").description("Register a repo as a Library Source and install a skill from it").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) => {
|
|
2645
|
-
const projectDir =
|
|
2655
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
2646
2656
|
const spinner5 = p5.spinner();
|
|
2647
2657
|
let sourcePath;
|
|
2648
2658
|
const isUrl = /^(https?:|git@|git:)/.test(url);
|
|
@@ -2653,14 +2663,14 @@ function makeNpxCommand() {
|
|
|
2653
2663
|
if (!existsSync(sourcePath)) {
|
|
2654
2664
|
execSync(`git clone ${url} ${sourcePath}`, { stdio: "ignore" });
|
|
2655
2665
|
}
|
|
2656
|
-
spinner5.stop(`Cloned to ${
|
|
2666
|
+
spinner5.stop(`Cloned to ${path15__default.basename(sourcePath)}`);
|
|
2657
2667
|
} catch (err) {
|
|
2658
2668
|
spinner5.stop("Clone failed");
|
|
2659
2669
|
logErr(err instanceof Error ? err.message : String(err));
|
|
2660
2670
|
process.exit(1);
|
|
2661
2671
|
}
|
|
2662
2672
|
} else {
|
|
2663
|
-
sourcePath =
|
|
2673
|
+
sourcePath = path15__default.resolve(url);
|
|
2664
2674
|
if (!existsSync(sourcePath)) {
|
|
2665
2675
|
logErr(`Path does not exist: ${sourcePath}`);
|
|
2666
2676
|
process.exit(1);
|
|
@@ -2672,9 +2682,10 @@ function makeNpxCommand() {
|
|
|
2672
2682
|
let source = existing.find((s) => s.path === sourcePath);
|
|
2673
2683
|
if (!source) {
|
|
2674
2684
|
source = await library.addSource({
|
|
2675
|
-
|
|
2676
|
-
name:
|
|
2677
|
-
path: sourcePath
|
|
2685
|
+
backend: "local",
|
|
2686
|
+
name: path15__default.basename(sourcePath),
|
|
2687
|
+
path: sourcePath,
|
|
2688
|
+
ownership: "owner"
|
|
2678
2689
|
});
|
|
2679
2690
|
}
|
|
2680
2691
|
spinner5.start("Syncing source");
|
|
@@ -2713,7 +2724,7 @@ function makeNpxCommand() {
|
|
|
2713
2724
|
}
|
|
2714
2725
|
function cloneDestination(url) {
|
|
2715
2726
|
const cleaned = url.replace(/\.git$/, "");
|
|
2716
|
-
const root =
|
|
2727
|
+
const root = path15__default.join(homedir(), ".skaile", "clones");
|
|
2717
2728
|
let host = "unknown";
|
|
2718
2729
|
let pathPart = cleaned;
|
|
2719
2730
|
const httpMatch = cleaned.match(/^https?:\/\/([^/]+)\/(.+)$/);
|
|
@@ -2729,14 +2740,14 @@ function cloneDestination(url) {
|
|
|
2729
2740
|
host = gitProtoMatch[1];
|
|
2730
2741
|
pathPart = gitProtoMatch[2];
|
|
2731
2742
|
}
|
|
2732
|
-
return
|
|
2743
|
+
return path15__default.join(root, host, pathPart);
|
|
2733
2744
|
}
|
|
2734
2745
|
function makeOutdatedCommand() {
|
|
2735
2746
|
return new Command("outdated").description("Check for assets behind their repo").argument("[name]", "Check a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).addOption(
|
|
2736
2747
|
new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
|
|
2737
2748
|
).action((name, opts) => {
|
|
2738
2749
|
const am2 = new AssetManager({
|
|
2739
|
-
projectDir:
|
|
2750
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
2740
2751
|
driverTarget: opts.target
|
|
2741
2752
|
});
|
|
2742
2753
|
const entries = am2.outdated();
|
|
@@ -2755,7 +2766,7 @@ function makeOutdatedCommand() {
|
|
|
2755
2766
|
console.log(` ${S.rule(nameW + 40)}`);
|
|
2756
2767
|
for (const e of filtered) {
|
|
2757
2768
|
console.log(
|
|
2758
|
-
` ${kindColorPad(e.kind)} ${e.name.padEnd(nameW)} ${S.dim(e.repository)} ${
|
|
2769
|
+
` ${kindColorPad(e.kind)} ${e.name.padEnd(nameW)} ${S.dim(e.repository)} ${pc5.yellow(`${e.behind} commit(s) behind`)}`
|
|
2759
2770
|
);
|
|
2760
2771
|
}
|
|
2761
2772
|
console.log();
|
|
@@ -2765,7 +2776,7 @@ function makeOutdatedCommand() {
|
|
|
2765
2776
|
function makePatchCommand() {
|
|
2766
2777
|
const cmd = new Command("patch").description("Patch workflow for skill improvement");
|
|
2767
2778
|
cmd.command("extract <ref>").alias("start").description("Extract asset for local editing").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
2768
|
-
const am2 = new AssetManager({ projectDir:
|
|
2779
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
2769
2780
|
try {
|
|
2770
2781
|
const dest = am2.patch(ref);
|
|
2771
2782
|
logOk(`Extracted to ${S.dim(dest)}`);
|
|
@@ -2776,7 +2787,7 @@ function makePatchCommand() {
|
|
|
2776
2787
|
}
|
|
2777
2788
|
});
|
|
2778
2789
|
cmd.command("commit <ref>").description("Generate .patch file from edits").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
2779
|
-
const am2 = new AssetManager({ projectDir:
|
|
2790
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
2780
2791
|
try {
|
|
2781
2792
|
const patchFile = am2.patchCommit(ref);
|
|
2782
2793
|
logOk(`Patch saved to ${S.dim(patchFile)}`);
|
|
@@ -2787,7 +2798,7 @@ function makePatchCommand() {
|
|
|
2787
2798
|
}
|
|
2788
2799
|
});
|
|
2789
2800
|
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) => {
|
|
2790
|
-
const am2 = new AssetManager({ projectDir:
|
|
2801
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
2791
2802
|
try {
|
|
2792
2803
|
am2.patchSubmit(ref);
|
|
2793
2804
|
logOk("Patch applied to repo clone and committed.");
|
|
@@ -2800,7 +2811,7 @@ function makePatchCommand() {
|
|
|
2800
2811
|
}
|
|
2801
2812
|
});
|
|
2802
2813
|
cmd.command("remove <ref>").description("Remove local patch after upstream merge").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
|
|
2803
|
-
const am2 = new AssetManager({ projectDir:
|
|
2814
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
2804
2815
|
am2.patchRemove(ref);
|
|
2805
2816
|
logOk(`Patch removed for ${ref}`);
|
|
2806
2817
|
});
|
|
@@ -2814,7 +2825,7 @@ var MCP_SERVER_ENTRY = {
|
|
|
2814
2825
|
env: {}
|
|
2815
2826
|
};
|
|
2816
2827
|
function pluginDir(projectDir) {
|
|
2817
|
-
return
|
|
2828
|
+
return path15__default.join(projectDir, ".claude", "plugins", "skaile");
|
|
2818
2829
|
}
|
|
2819
2830
|
async function readJsonStrict(p7) {
|
|
2820
2831
|
let raw;
|
|
@@ -2832,7 +2843,7 @@ async function readJsonStrict(p7) {
|
|
|
2832
2843
|
}
|
|
2833
2844
|
}
|
|
2834
2845
|
async function writeJson(p7, value) {
|
|
2835
|
-
await fs5.mkdir(
|
|
2846
|
+
await fs5.mkdir(path15__default.dirname(p7), { recursive: true });
|
|
2836
2847
|
await fs5.writeFile(p7, `${JSON.stringify(value, null, 2)}
|
|
2837
2848
|
`);
|
|
2838
2849
|
}
|
|
@@ -2840,8 +2851,8 @@ async function copyDir(src, dest) {
|
|
|
2840
2851
|
await fs5.mkdir(dest, { recursive: true });
|
|
2841
2852
|
const entries = await fs5.readdir(src, { withFileTypes: true });
|
|
2842
2853
|
for (const entry of entries) {
|
|
2843
|
-
const srcPath =
|
|
2844
|
-
const destPath =
|
|
2854
|
+
const srcPath = path15__default.join(src, entry.name);
|
|
2855
|
+
const destPath = path15__default.join(dest, entry.name);
|
|
2845
2856
|
if (entry.isDirectory()) await copyDir(srcPath, destPath);
|
|
2846
2857
|
else await fs5.copyFile(srcPath, destPath);
|
|
2847
2858
|
}
|
|
@@ -2850,14 +2861,14 @@ async function install(projectDir, opts) {
|
|
|
2850
2861
|
return opts?.full ? installFullPlugin(projectDir) : installMcp(projectDir);
|
|
2851
2862
|
}
|
|
2852
2863
|
async function installMcp(projectDir) {
|
|
2853
|
-
const mcpPath =
|
|
2864
|
+
const mcpPath = path15__default.join(projectDir, ".claude", "mcp.json");
|
|
2854
2865
|
const existing = await readJsonStrict(mcpPath) ?? {};
|
|
2855
2866
|
const mcpServers = { ...existing.mcpServers ?? {} };
|
|
2856
2867
|
const previous = mcpServers[SKAILE_MCP_NAME];
|
|
2857
2868
|
const matches = previous && JSON.stringify(previous) === JSON.stringify(MCP_SERVER_ENTRY);
|
|
2858
2869
|
let warning;
|
|
2859
2870
|
if (previous && !matches) {
|
|
2860
|
-
warning = `overwrote existing ${SKAILE_MCP_NAME} entry in ${
|
|
2871
|
+
warning = `overwrote existing ${SKAILE_MCP_NAME} entry in ${path15__default.relative(projectDir, mcpPath)}`;
|
|
2861
2872
|
}
|
|
2862
2873
|
mcpServers[SKAILE_MCP_NAME] = MCP_SERVER_ENTRY;
|
|
2863
2874
|
await writeJson(mcpPath, { ...existing, mcpServers });
|
|
@@ -2866,15 +2877,15 @@ async function installMcp(projectDir) {
|
|
|
2866
2877
|
async function installFullPlugin(projectDir) {
|
|
2867
2878
|
const dir = pluginDir(projectDir);
|
|
2868
2879
|
for (const [rel, content] of Object.entries(buildClaudePluginFiles())) {
|
|
2869
|
-
const dest =
|
|
2870
|
-
await fs5.mkdir(
|
|
2880
|
+
const dest = path15__default.join(dir, rel);
|
|
2881
|
+
await fs5.mkdir(path15__default.dirname(dest), { recursive: true });
|
|
2871
2882
|
await fs5.writeFile(dest, content);
|
|
2872
2883
|
}
|
|
2873
|
-
const projectSkillsDir =
|
|
2884
|
+
const projectSkillsDir = path15__default.join(projectDir, ".skaile", "skills");
|
|
2874
2885
|
if (existsSync(projectSkillsDir)) {
|
|
2875
|
-
await copyDir(projectSkillsDir,
|
|
2886
|
+
await copyDir(projectSkillsDir, path15__default.join(dir, "skills"));
|
|
2876
2887
|
}
|
|
2877
|
-
const settingsPath =
|
|
2888
|
+
const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
|
|
2878
2889
|
const settings = await readJsonStrict(settingsPath) ?? {};
|
|
2879
2890
|
const plugins = settings.plugins ?? [];
|
|
2880
2891
|
if (!plugins.includes(dir)) plugins.push(dir);
|
|
@@ -2882,8 +2893,8 @@ async function installFullPlugin(projectDir) {
|
|
|
2882
2893
|
return { changed: true, method: "plugin" };
|
|
2883
2894
|
}
|
|
2884
2895
|
async function uninstall(projectDir) {
|
|
2885
|
-
const settingsPath =
|
|
2886
|
-
const mcpPath =
|
|
2896
|
+
const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
|
|
2897
|
+
const mcpPath = path15__default.join(projectDir, ".claude", "mcp.json");
|
|
2887
2898
|
const dir = pluginDir(projectDir);
|
|
2888
2899
|
let changed = false;
|
|
2889
2900
|
const settings = await readJsonStrict(settingsPath);
|
|
@@ -2917,12 +2928,12 @@ async function uninstall(projectDir) {
|
|
|
2917
2928
|
async function detectInstall(projectDir) {
|
|
2918
2929
|
const dir = pluginDir(projectDir);
|
|
2919
2930
|
const settings = await readJsonStrict(
|
|
2920
|
-
|
|
2931
|
+
path15__default.join(projectDir, ".claude", "settings.json")
|
|
2921
2932
|
);
|
|
2922
|
-
if (existsSync(
|
|
2933
|
+
if (existsSync(path15__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir)) {
|
|
2923
2934
|
return { method: "plugin", pluginPath: dir };
|
|
2924
2935
|
}
|
|
2925
|
-
const mcp = await readJsonStrict(
|
|
2936
|
+
const mcp = await readJsonStrict(path15__default.join(projectDir, ".claude", "mcp.json"));
|
|
2926
2937
|
if (mcp?.mcpServers && SKAILE_MCP_NAME in mcp.mcpServers) {
|
|
2927
2938
|
return { method: "mcp" };
|
|
2928
2939
|
}
|
|
@@ -2931,7 +2942,7 @@ async function detectInstall(projectDir) {
|
|
|
2931
2942
|
async function enable(projectDir) {
|
|
2932
2943
|
const detected = await detectInstall(projectDir);
|
|
2933
2944
|
if (!detected) throw new Error("plugin not installed for claude-code");
|
|
2934
|
-
const settingsPath =
|
|
2945
|
+
const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
|
|
2935
2946
|
const settings = await readJsonStrict(settingsPath) ?? {};
|
|
2936
2947
|
if (detected.method === "plugin") {
|
|
2937
2948
|
const disabled2 = settings.disabledPlugins ?? [];
|
|
@@ -2953,7 +2964,7 @@ async function enable(projectDir) {
|
|
|
2953
2964
|
async function disable(projectDir) {
|
|
2954
2965
|
const detected = await detectInstall(projectDir);
|
|
2955
2966
|
if (!detected) throw new Error("plugin not installed for claude-code");
|
|
2956
|
-
const settingsPath =
|
|
2967
|
+
const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
|
|
2957
2968
|
const settings = await readJsonStrict(settingsPath) ?? {};
|
|
2958
2969
|
if (detected.method === "plugin") {
|
|
2959
2970
|
const list2 = settings.disabledPlugins ?? [];
|
|
@@ -2973,12 +2984,12 @@ async function disable(projectDir) {
|
|
|
2973
2984
|
return { changed: true };
|
|
2974
2985
|
}
|
|
2975
2986
|
async function status(projectDir) {
|
|
2976
|
-
const settingsPath =
|
|
2977
|
-
const mcpPath =
|
|
2987
|
+
const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
|
|
2988
|
+
const mcpPath = path15__default.join(projectDir, ".claude", "mcp.json");
|
|
2978
2989
|
const dir = pluginDir(projectDir);
|
|
2979
2990
|
const settings = await readJsonStrict(settingsPath);
|
|
2980
2991
|
const mcp = await readJsonStrict(mcpPath);
|
|
2981
|
-
const pluginInstalled = !!(existsSync(
|
|
2992
|
+
const pluginInstalled = !!(existsSync(path15__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir));
|
|
2982
2993
|
const mcpInstalled = !!(mcp?.mcpServers && SKAILE_MCP_NAME in mcp.mcpServers);
|
|
2983
2994
|
if (!pluginInstalled && !mcpInstalled) {
|
|
2984
2995
|
return {
|
|
@@ -2996,7 +3007,7 @@ async function status(projectDir) {
|
|
|
2996
3007
|
installed: "yes",
|
|
2997
3008
|
enabled: disabled2 ? "no" : "yes",
|
|
2998
3009
|
method: "plugin",
|
|
2999
|
-
location:
|
|
3010
|
+
location: path15__default.relative(projectDir, dir)
|
|
3000
3011
|
};
|
|
3001
3012
|
}
|
|
3002
3013
|
const disabled = settings?.disabledMcpjsonServers?.includes(SKAILE_MCP_NAME) ?? false;
|
|
@@ -3005,7 +3016,7 @@ async function status(projectDir) {
|
|
|
3005
3016
|
installed: "yes",
|
|
3006
3017
|
enabled: disabled ? "no" : "yes",
|
|
3007
3018
|
method: "mcp",
|
|
3008
|
-
location:
|
|
3019
|
+
location: path15__default.relative(projectDir, mcpPath)
|
|
3009
3020
|
};
|
|
3010
3021
|
}
|
|
3011
3022
|
var SKAILE_MCP_NAME2 = "skaile-workspace";
|
|
@@ -3032,7 +3043,7 @@ async function readConfig(p7) {
|
|
|
3032
3043
|
}
|
|
3033
3044
|
}
|
|
3034
3045
|
async function writeConfig(p7, value) {
|
|
3035
|
-
await fs5.mkdir(
|
|
3046
|
+
await fs5.mkdir(path15__default.dirname(p7), { recursive: true });
|
|
3036
3047
|
const cleaned = {};
|
|
3037
3048
|
for (const [k, v] of Object.entries(value)) {
|
|
3038
3049
|
if (v === void 0) continue;
|
|
@@ -3041,7 +3052,7 @@ async function writeConfig(p7, value) {
|
|
|
3041
3052
|
await fs5.writeFile(p7, stringify(cleaned));
|
|
3042
3053
|
}
|
|
3043
3054
|
function configPath(projectDir) {
|
|
3044
|
-
return
|
|
3055
|
+
return path15__default.join(projectDir, ".codex", "config.toml");
|
|
3045
3056
|
}
|
|
3046
3057
|
async function install2(projectDir) {
|
|
3047
3058
|
const p7 = configPath(projectDir);
|
|
@@ -3052,7 +3063,7 @@ async function install2(projectDir) {
|
|
|
3052
3063
|
const matches = previous && JSON.stringify(previous) === JSON.stringify(next);
|
|
3053
3064
|
let warning;
|
|
3054
3065
|
if (previous && !matches) {
|
|
3055
|
-
warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${
|
|
3066
|
+
warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${path15__default.relative(projectDir, p7)}`;
|
|
3056
3067
|
}
|
|
3057
3068
|
if (matches) return { changed: false, method: "toml" };
|
|
3058
3069
|
servers[SKAILE_MCP_NAME2] = next;
|
|
@@ -3093,12 +3104,12 @@ async function status2(projectDir) {
|
|
|
3093
3104
|
installed: "yes",
|
|
3094
3105
|
enabled: "n/a",
|
|
3095
3106
|
method: "mcp",
|
|
3096
|
-
location:
|
|
3107
|
+
location: path15__default.relative(projectDir, p7)
|
|
3097
3108
|
};
|
|
3098
3109
|
}
|
|
3099
3110
|
async function install3(projectDir) {
|
|
3100
|
-
const extDir =
|
|
3101
|
-
const extPath =
|
|
3111
|
+
const extDir = path15__default.join(projectDir, ".omp", "extensions");
|
|
3112
|
+
const extPath = path15__default.join(extDir, "skaile.ts");
|
|
3102
3113
|
await fs5.mkdir(extDir, { recursive: true });
|
|
3103
3114
|
const { WorkspacePlugin } = await import('../workspace-plugin/index.js');
|
|
3104
3115
|
const plugin = new WorkspacePlugin({ projectDir });
|
|
@@ -3113,7 +3124,7 @@ async function install3(projectDir) {
|
|
|
3113
3124
|
return { changed: true, method: "generated" };
|
|
3114
3125
|
}
|
|
3115
3126
|
async function uninstall3(projectDir) {
|
|
3116
|
-
const extPath =
|
|
3127
|
+
const extPath = path15__default.join(projectDir, ".omp", "extensions", "skaile.ts");
|
|
3117
3128
|
try {
|
|
3118
3129
|
await fs5.unlink(extPath);
|
|
3119
3130
|
return { changed: true };
|
|
@@ -3122,14 +3133,14 @@ async function uninstall3(projectDir) {
|
|
|
3122
3133
|
}
|
|
3123
3134
|
}
|
|
3124
3135
|
async function status3(projectDir) {
|
|
3125
|
-
const extPath =
|
|
3136
|
+
const extPath = path15__default.join(projectDir, ".omp", "extensions", "skaile.ts");
|
|
3126
3137
|
if (existsSync(extPath)) {
|
|
3127
3138
|
return {
|
|
3128
3139
|
backend: "omp",
|
|
3129
3140
|
installed: "yes",
|
|
3130
3141
|
enabled: "n/a",
|
|
3131
3142
|
method: "extension",
|
|
3132
|
-
location:
|
|
3143
|
+
location: path15__default.relative(projectDir, extPath)
|
|
3133
3144
|
};
|
|
3134
3145
|
}
|
|
3135
3146
|
return {
|
|
@@ -3150,7 +3161,7 @@ function resolveDriver(driver) {
|
|
|
3150
3161
|
throw new Error(`unknown driver: ${driver} (expected: claude-code | omp | codex | all)`);
|
|
3151
3162
|
}
|
|
3152
3163
|
async function runInstall(opts) {
|
|
3153
|
-
const projectDir =
|
|
3164
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3154
3165
|
const targets = resolveDriver(opts.driver);
|
|
3155
3166
|
let exitCode = 0;
|
|
3156
3167
|
if (targets.includes("claude-code")) {
|
|
@@ -3205,7 +3216,7 @@ async function runInstall(opts) {
|
|
|
3205
3216
|
return exitCode;
|
|
3206
3217
|
}
|
|
3207
3218
|
async function runUninstall(opts) {
|
|
3208
|
-
const projectDir =
|
|
3219
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3209
3220
|
const targets = resolveDriver(opts.driver);
|
|
3210
3221
|
let exitCode = 0;
|
|
3211
3222
|
if (targets.includes("claude-code")) {
|
|
@@ -3242,7 +3253,7 @@ async function runUninstall(opts) {
|
|
|
3242
3253
|
return exitCode;
|
|
3243
3254
|
}
|
|
3244
3255
|
async function runToggle(opts, action) {
|
|
3245
|
-
const projectDir =
|
|
3256
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3246
3257
|
const requestedAll = opts.driver === "all";
|
|
3247
3258
|
const targets = resolveDriver(opts.driver);
|
|
3248
3259
|
if (!requestedAll) {
|
|
@@ -3277,7 +3288,7 @@ async function runToggle(opts, action) {
|
|
|
3277
3288
|
return exitCode;
|
|
3278
3289
|
}
|
|
3279
3290
|
async function runStatus(opts) {
|
|
3280
|
-
const projectDir =
|
|
3291
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3281
3292
|
const targets = resolveDriver(opts.driver);
|
|
3282
3293
|
const rows = [];
|
|
3283
3294
|
let exitCode = 0;
|
|
@@ -3348,7 +3359,7 @@ async function runHook(event) {
|
|
|
3348
3359
|
await plugin.shutdown();
|
|
3349
3360
|
return;
|
|
3350
3361
|
}
|
|
3351
|
-
const store = new PluginStore(
|
|
3362
|
+
const store = new PluginStore(path15__default.join(projectDir, ".skaile", "plugin-state.json"));
|
|
3352
3363
|
await store.load();
|
|
3353
3364
|
const status4 = store.get("connector:status");
|
|
3354
3365
|
if (status4 && typeof status4 === "object" && Object.keys(status4).length > 0) {
|
|
@@ -3413,7 +3424,7 @@ function makePresetCommand() {
|
|
|
3413
3424
|
cmd.command("init [name]").description("Scaffold a new .preset.yaml file").option("--dir <path>", "Output directory", process.cwd()).action(async (name, opts) => {
|
|
3414
3425
|
const presetName = name ?? "my-preset";
|
|
3415
3426
|
const filename = `${presetName}.preset.yaml`;
|
|
3416
|
-
const outPath =
|
|
3427
|
+
const outPath = path15__default.join(path15__default.resolve(opts.dir), filename);
|
|
3417
3428
|
if (existsSync(outPath)) {
|
|
3418
3429
|
logErr(`File already exists: ${outPath}`);
|
|
3419
3430
|
logInfo("Choose a different name or remove the existing file.");
|
|
@@ -3427,7 +3438,7 @@ function makePresetCommand() {
|
|
|
3427
3438
|
logInfo(` skaile preset validate ${filename}`);
|
|
3428
3439
|
});
|
|
3429
3440
|
cmd.command("validate <path>").description("Validate a preset YAML file (schema + cycles + nesting depth)").action(async (filePath) => {
|
|
3430
|
-
const resolved =
|
|
3441
|
+
const resolved = path15__default.resolve(filePath);
|
|
3431
3442
|
if (!existsSync(resolved)) {
|
|
3432
3443
|
logErr(`File not found: ${resolved}`);
|
|
3433
3444
|
process.exit(1);
|
|
@@ -3453,7 +3464,7 @@ function makePresetCommand() {
|
|
|
3453
3464
|
logInfo(`Nested preset refs: ${nestedRefs.length} (depth validated at apply-time)`);
|
|
3454
3465
|
}
|
|
3455
3466
|
const { detectCycles } = await import('../discovery/index.js');
|
|
3456
|
-
const presetRef =
|
|
3467
|
+
const presetRef = path15__default.basename(resolved, ".preset.yaml");
|
|
3457
3468
|
const edges = [];
|
|
3458
3469
|
for (const item of preset.items) {
|
|
3459
3470
|
if (item.ref) {
|
|
@@ -3577,8 +3588,8 @@ function makeInstallCommand() {
|
|
|
3577
3588
|
const spinner6 = p5.spinner();
|
|
3578
3589
|
spinner6.start(`Installing ${ref}`);
|
|
3579
3590
|
try {
|
|
3580
|
-
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-
|
|
3581
|
-
const catalog = await openCatalogSource2({ projectDir:
|
|
3591
|
+
const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-XD7QYLMW.js');
|
|
3592
|
+
const catalog = await openCatalogSource2({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
3582
3593
|
if (!supportsInstallManifest(catalog)) {
|
|
3583
3594
|
throw new Error(
|
|
3584
3595
|
"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."
|
|
@@ -3608,7 +3619,7 @@ function makeInstallCommand() {
|
|
|
3608
3619
|
return;
|
|
3609
3620
|
}
|
|
3610
3621
|
const am2 = new AssetManager({
|
|
3611
|
-
projectDir:
|
|
3622
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
3612
3623
|
driverTarget: opts.target
|
|
3613
3624
|
});
|
|
3614
3625
|
const spinner5 = p5.spinner();
|
|
@@ -3647,7 +3658,7 @@ function makeInstallCommand() {
|
|
|
3647
3658
|
}
|
|
3648
3659
|
function makeCheckCommand() {
|
|
3649
3660
|
return new Command("check").description("Check for unmet requirements").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
3650
|
-
const am2 = new AssetManager({ projectDir:
|
|
3661
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
3651
3662
|
const issues = am2.doctor();
|
|
3652
3663
|
if (issues.length === 0) {
|
|
3653
3664
|
logOk("All dependencies satisfied.");
|
|
@@ -3664,10 +3675,10 @@ function makeCheckCommand() {
|
|
|
3664
3675
|
function makeCleanCommand() {
|
|
3665
3676
|
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) => {
|
|
3666
3677
|
const am2 = new AssetManager({
|
|
3667
|
-
projectDir:
|
|
3678
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
3668
3679
|
driverTarget: opts.target
|
|
3669
3680
|
});
|
|
3670
|
-
const lock = readLock(
|
|
3681
|
+
const lock = readLock(path15__default.resolve(opts.projectDir, "skaile.lock.yaml"));
|
|
3671
3682
|
if (!lock || Object.keys(lock.assets).length === 0) {
|
|
3672
3683
|
logInfo("Nothing to clean (no skaile-managed assets found).");
|
|
3673
3684
|
return;
|
|
@@ -3720,14 +3731,14 @@ function makeCleanCommand() {
|
|
|
3720
3731
|
}
|
|
3721
3732
|
function makeRebuildCommand() {
|
|
3722
3733
|
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) => {
|
|
3723
|
-
const projectDir =
|
|
3734
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3724
3735
|
let agentDir;
|
|
3725
3736
|
if (agentArg) {
|
|
3726
3737
|
if (agentArg.includes("/") || agentArg.includes("\\")) {
|
|
3727
|
-
agentDir =
|
|
3738
|
+
agentDir = path15__default.resolve(projectDir, agentArg);
|
|
3728
3739
|
} else {
|
|
3729
3740
|
const resolved = resolveAgentDir(projectDir);
|
|
3730
|
-
agentDir = resolved ??
|
|
3741
|
+
agentDir = resolved ?? path15__default.resolve(projectDir, agentArg);
|
|
3731
3742
|
}
|
|
3732
3743
|
} else {
|
|
3733
3744
|
const resolved = resolveAgentDir(projectDir);
|
|
@@ -3788,7 +3799,7 @@ function makeFlowEventHandler() {
|
|
|
3788
3799
|
if (n.status === "running") {
|
|
3789
3800
|
process.stdout.write(` ${S.dim("\u2192")} ${id}`);
|
|
3790
3801
|
} else if (n.status === "complete") {
|
|
3791
|
-
process.stdout.write(` ${
|
|
3802
|
+
process.stdout.write(` ${pc5.green("\u2713")}
|
|
3792
3803
|
`);
|
|
3793
3804
|
} else if (n.status === "skipped") {
|
|
3794
3805
|
process.stdout.write(` ${S.dim("\u21B7 skipped")}
|
|
@@ -3805,7 +3816,7 @@ function makeFlowEventHandler() {
|
|
|
3805
3816
|
}
|
|
3806
3817
|
function makeRunCommand() {
|
|
3807
3818
|
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) => {
|
|
3808
|
-
const projectDir =
|
|
3819
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3809
3820
|
const cliDriver = opts.driver;
|
|
3810
3821
|
const dryRun = opts.dryRun ?? false;
|
|
3811
3822
|
let flowId = positional[0];
|
|
@@ -3859,15 +3870,15 @@ function makeRunCommand() {
|
|
|
3859
3870
|
let flowPath;
|
|
3860
3871
|
let dir = projectDir;
|
|
3861
3872
|
for (let i = 0; i < 6; i++) {
|
|
3862
|
-
const candidate =
|
|
3873
|
+
const candidate = path15__default.join(dir, "ai-assets");
|
|
3863
3874
|
if (fs10__default.existsSync(candidate)) {
|
|
3864
3875
|
for (const domain of fs10__default.readdirSync(candidate)) {
|
|
3865
|
-
const p_ =
|
|
3876
|
+
const p_ = path15__default.join(candidate, domain, "flows", `${flowId}.flow.yaml`);
|
|
3866
3877
|
if (fs10__default.existsSync(p_)) {
|
|
3867
3878
|
flowPath = p_;
|
|
3868
3879
|
break;
|
|
3869
3880
|
}
|
|
3870
|
-
const legacy =
|
|
3881
|
+
const legacy = path15__default.join(candidate, domain, "flows", `${flowId}.json`);
|
|
3871
3882
|
if (fs10__default.existsSync(legacy)) {
|
|
3872
3883
|
flowPath = legacy;
|
|
3873
3884
|
break;
|
|
@@ -3875,16 +3886,16 @@ function makeRunCommand() {
|
|
|
3875
3886
|
}
|
|
3876
3887
|
break;
|
|
3877
3888
|
}
|
|
3878
|
-
dir =
|
|
3889
|
+
dir = path15__default.dirname(dir);
|
|
3879
3890
|
}
|
|
3880
3891
|
if (!flowPath) {
|
|
3881
3892
|
for (const domain of fs10__default.readdirSync(AI_RESOURCES)) {
|
|
3882
|
-
const p_ =
|
|
3893
|
+
const p_ = path15__default.join(AI_RESOURCES, domain, "flows", `${flowId}.flow.yaml`);
|
|
3883
3894
|
if (fs10__default.existsSync(p_)) {
|
|
3884
3895
|
flowPath = p_;
|
|
3885
3896
|
break;
|
|
3886
3897
|
}
|
|
3887
|
-
const legacy =
|
|
3898
|
+
const legacy = path15__default.join(AI_RESOURCES, domain, "flows", `${flowId}.json`);
|
|
3888
3899
|
if (fs10__default.existsSync(legacy)) {
|
|
3889
3900
|
flowPath = legacy;
|
|
3890
3901
|
break;
|
|
@@ -3918,7 +3929,7 @@ function makeRunCommand() {
|
|
|
3918
3929
|
}
|
|
3919
3930
|
function makeResumeCommand() {
|
|
3920
3931
|
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) => {
|
|
3921
|
-
const projectDir =
|
|
3932
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3922
3933
|
const sessionId = opts.session;
|
|
3923
3934
|
const dryRun = opts.dryRun ?? false;
|
|
3924
3935
|
const session = sessionId ? await loadSessionById(projectDir, sessionId) : await loadSession(projectDir);
|
|
@@ -3945,14 +3956,14 @@ function makeResumeCommand() {
|
|
|
3945
3956
|
}
|
|
3946
3957
|
function makeStatusCommand() {
|
|
3947
3958
|
return new Command("status").description("Show current session state").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
3948
|
-
const projectDir =
|
|
3959
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3949
3960
|
const session = await loadSession(projectDir);
|
|
3950
3961
|
if (!session) {
|
|
3951
3962
|
logInfo("No active session.");
|
|
3952
3963
|
return;
|
|
3953
3964
|
}
|
|
3954
3965
|
const age = Math.round((Date.now() - new Date(session.updatedAt).getTime()) / 1e3);
|
|
3955
|
-
const statusColor = session.status === "complete" ?
|
|
3966
|
+
const statusColor = session.status === "complete" ? pc5.green : session.status === "failed" ? pc5.red : session.status === "running" ? pc5.cyan : pc5.yellow;
|
|
3956
3967
|
console.log();
|
|
3957
3968
|
console.log(` ${S.label("Flow:")} ${S.heading(session.flowId)}`);
|
|
3958
3969
|
console.log(` ${S.label("Run ID:")} ${session.runId.slice(0, 8)}`);
|
|
@@ -3970,7 +3981,7 @@ function makeStatusCommand() {
|
|
|
3970
3981
|
}
|
|
3971
3982
|
function makeClearCommand() {
|
|
3972
3983
|
return new Command("clear").description("Unset current session pointer").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
3973
|
-
const projectDir =
|
|
3984
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
3974
3985
|
await clearSession(projectDir);
|
|
3975
3986
|
logOk("Session cleared.");
|
|
3976
3987
|
});
|
|
@@ -3980,7 +3991,7 @@ function makeReplCommand() {
|
|
|
3980
3991
|
const { findWorkspaceRoot } = await import('../core/index.js');
|
|
3981
3992
|
const { startRepl } = await import('../tui/index.js');
|
|
3982
3993
|
const os = await import('os');
|
|
3983
|
-
const userCwd =
|
|
3994
|
+
const userCwd = path15__default.resolve(opts.projectDir ?? process.cwd());
|
|
3984
3995
|
const workspaceRoot = findWorkspaceRoot(userCwd);
|
|
3985
3996
|
let projectDir;
|
|
3986
3997
|
let agentCwd;
|
|
@@ -4002,12 +4013,12 @@ function makeReplCommand() {
|
|
|
4002
4013
|
p5.cancel("Cancelled.");
|
|
4003
4014
|
process.exit(0);
|
|
4004
4015
|
}
|
|
4005
|
-
const tmpDir = fs10__default.mkdtempSync(
|
|
4016
|
+
const tmpDir = fs10__default.mkdtempSync(path15__default.join(os.tmpdir(), "skaile-repl-"));
|
|
4006
4017
|
projectDir = tmpDir;
|
|
4007
4018
|
agentCwd = userCwd;
|
|
4008
4019
|
logOk(`Temporary workspace: ${S.cmd(tmpDir)}`);
|
|
4009
4020
|
if (!driverOverride) {
|
|
4010
|
-
const claudeDir =
|
|
4021
|
+
const claudeDir = path15__default.join(os.homedir(), ".claude");
|
|
4011
4022
|
if (fs10__default.existsSync(claudeDir)) {
|
|
4012
4023
|
driverOverride = "claude-sdk";
|
|
4013
4024
|
logInfo(`Detected ${S.cmd("~/.claude")} \u2192 using ${S.cmd("claude-sdk")} backend`);
|
|
@@ -4055,7 +4066,7 @@ function makeServeCommand() {
|
|
|
4055
4066
|
async function runCompileTest(opts) {
|
|
4056
4067
|
const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-I3SREIC3.js');
|
|
4057
4068
|
const { tmpdir } = await import('os');
|
|
4058
|
-
const { dirname: dirname3, join:
|
|
4069
|
+
const { dirname: dirname3, join: join5, resolve: resolve4 } = await import('path');
|
|
4059
4070
|
const { fileURLToPath: fileURLToPath2 } = await import('url');
|
|
4060
4071
|
const { unlinkSync, existsSync: existsSync11 } = await import('fs');
|
|
4061
4072
|
const { spawn } = await import('child_process');
|
|
@@ -4067,9 +4078,9 @@ async function runCompileTest(opts) {
|
|
|
4067
4078
|
process.exitCode = 2;
|
|
4068
4079
|
return;
|
|
4069
4080
|
}
|
|
4070
|
-
const outfile =
|
|
4081
|
+
const outfile = join5(tmpdir(), `skaile-compile-test-${Date.now()}`);
|
|
4071
4082
|
const __thisFile = fileURLToPath2(import.meta.url);
|
|
4072
|
-
const entryPoint =
|
|
4083
|
+
const entryPoint = resolve4(dirname3(__thisFile), "..", "index.ts");
|
|
4073
4084
|
logInfo2(`Building compiled binary...`);
|
|
4074
4085
|
logInfo2(`Entry: ${S2.dim(entryPoint)}`);
|
|
4075
4086
|
logInfo2(`Output: ${S2.dim(outfile)}`);
|
|
@@ -4145,7 +4156,7 @@ function formatEntries(entries, opts = {}) {
|
|
|
4145
4156
|
lines.push(...renderEntryLines(e));
|
|
4146
4157
|
}
|
|
4147
4158
|
if (opts.nextCursor) {
|
|
4148
|
-
lines.push(
|
|
4159
|
+
lines.push(pc5.dim(`... more available. Use --cursor ${opts.nextCursor} to page back.`));
|
|
4149
4160
|
}
|
|
4150
4161
|
return lines.join("\n");
|
|
4151
4162
|
}
|
|
@@ -4166,9 +4177,9 @@ function renderEntryLines(e) {
|
|
|
4166
4177
|
return lines;
|
|
4167
4178
|
}
|
|
4168
4179
|
function formatLine(e) {
|
|
4169
|
-
const ts =
|
|
4180
|
+
const ts = pc5.dim(`[${formatTime(e.timestamp)}]`);
|
|
4170
4181
|
const lvl = colorLevel(e.level);
|
|
4171
|
-
const src =
|
|
4182
|
+
const src = pc5.cyan(`[${formatSource(e.source)}]`);
|
|
4172
4183
|
return `${ts} ${lvl} ${src} ${e.message}`;
|
|
4173
4184
|
}
|
|
4174
4185
|
function formatTime(iso) {
|
|
@@ -4187,13 +4198,13 @@ function formatSource(src) {
|
|
|
4187
4198
|
function colorLevel(level) {
|
|
4188
4199
|
switch (level) {
|
|
4189
4200
|
case "error":
|
|
4190
|
-
return
|
|
4201
|
+
return pc5.red("ERROR");
|
|
4191
4202
|
case "warn":
|
|
4192
|
-
return
|
|
4203
|
+
return pc5.yellow("WARN ");
|
|
4193
4204
|
case "info":
|
|
4194
|
-
return
|
|
4205
|
+
return pc5.green("INFO ");
|
|
4195
4206
|
case "debug":
|
|
4196
|
-
return
|
|
4207
|
+
return pc5.dim("DEBUG");
|
|
4197
4208
|
default:
|
|
4198
4209
|
return String(level).toUpperCase();
|
|
4199
4210
|
}
|
|
@@ -4201,15 +4212,15 @@ function colorLevel(level) {
|
|
|
4201
4212
|
function formatData(data) {
|
|
4202
4213
|
const oneLine = JSON.stringify(data);
|
|
4203
4214
|
if (oneLine.length <= 120) {
|
|
4204
|
-
return [` ${
|
|
4215
|
+
return [` ${pc5.dim("> data:")} ${oneLine}`];
|
|
4205
4216
|
}
|
|
4206
4217
|
const pretty = JSON.stringify(data, null, 2);
|
|
4207
|
-
return [` ${
|
|
4218
|
+
return [` ${pc5.dim("> data:")}`, ...pretty.split("\n").map((l) => ` ${l}`)];
|
|
4208
4219
|
}
|
|
4209
4220
|
function formatError(err) {
|
|
4210
|
-
const head = ` ${
|
|
4221
|
+
const head = ` ${pc5.dim("> error:")} ${pc5.red(err.name)}: ${err.message}`;
|
|
4211
4222
|
if (!err.stack) return [head];
|
|
4212
|
-
const stackLines = err.stack.split("\n").filter((l) => l.trim().length > 0).map((l) => ` ${
|
|
4223
|
+
const stackLines = err.stack.split("\n").filter((l) => l.trim().length > 0).map((l) => ` ${pc5.dim(l)}`);
|
|
4213
4224
|
return [head, ...stackLines];
|
|
4214
4225
|
}
|
|
4215
4226
|
|
|
@@ -4372,19 +4383,19 @@ function buildTailSelect(q) {
|
|
|
4372
4383
|
return { sql, params };
|
|
4373
4384
|
}
|
|
4374
4385
|
function sleepUnlessAborted(ms, signal) {
|
|
4375
|
-
return new Promise((
|
|
4386
|
+
return new Promise((resolve4) => {
|
|
4376
4387
|
if (signal?.aborted) {
|
|
4377
|
-
|
|
4388
|
+
resolve4();
|
|
4378
4389
|
return;
|
|
4379
4390
|
}
|
|
4380
4391
|
const timer = setTimeout(() => {
|
|
4381
4392
|
signal?.removeEventListener("abort", onAbort);
|
|
4382
|
-
|
|
4393
|
+
resolve4();
|
|
4383
4394
|
}, ms);
|
|
4384
4395
|
const onAbort = () => {
|
|
4385
4396
|
clearTimeout(timer);
|
|
4386
4397
|
signal?.removeEventListener("abort", onAbort);
|
|
4387
|
-
|
|
4398
|
+
resolve4();
|
|
4388
4399
|
};
|
|
4389
4400
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
4390
4401
|
});
|
|
@@ -4461,7 +4472,7 @@ async function remoteTail(opts) {
|
|
|
4461
4472
|
]
|
|
4462
4473
|
});
|
|
4463
4474
|
const filter = makeFilter(opts.query);
|
|
4464
|
-
return new Promise((
|
|
4475
|
+
return new Promise((resolve4, reject) => {
|
|
4465
4476
|
let settled = false;
|
|
4466
4477
|
const finish = (err) => {
|
|
4467
4478
|
if (settled) return;
|
|
@@ -4472,11 +4483,11 @@ async function remoteTail(opts) {
|
|
|
4472
4483
|
}
|
|
4473
4484
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
4474
4485
|
if (err) reject(err);
|
|
4475
|
-
else
|
|
4486
|
+
else resolve4();
|
|
4476
4487
|
};
|
|
4477
4488
|
const onAbort = () => finish();
|
|
4478
4489
|
if (opts.signal?.aborted) {
|
|
4479
|
-
|
|
4490
|
+
resolve4();
|
|
4480
4491
|
return;
|
|
4481
4492
|
}
|
|
4482
4493
|
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -4530,7 +4541,7 @@ function resolveMode(opts) {
|
|
|
4530
4541
|
if (opts.forceLocal && opts.forceRemote) {
|
|
4531
4542
|
throw new Error("Cannot use both --local and --remote");
|
|
4532
4543
|
}
|
|
4533
|
-
const startDir =
|
|
4544
|
+
const startDir = path15__default.resolve(opts.projectDir ?? process.cwd());
|
|
4534
4545
|
const localDb = findLogsDb(startDir);
|
|
4535
4546
|
if (opts.forceLocal) {
|
|
4536
4547
|
if (!localDb) {
|
|
@@ -4563,14 +4574,14 @@ function resolveMode(opts) {
|
|
|
4563
4574
|
function findLogsDb(startDir) {
|
|
4564
4575
|
let dir = startDir;
|
|
4565
4576
|
for (let i = 0; i < MAX_WALK_LEVELS; i++) {
|
|
4566
|
-
const candidate =
|
|
4577
|
+
const candidate = path15__default.join(dir, ".skaile", "logs.db");
|
|
4567
4578
|
if (existsSync(candidate)) {
|
|
4568
4579
|
try {
|
|
4569
4580
|
if (statSync(candidate).isFile()) return candidate;
|
|
4570
4581
|
} catch {
|
|
4571
4582
|
}
|
|
4572
4583
|
}
|
|
4573
|
-
const parent =
|
|
4584
|
+
const parent = path15__default.dirname(dir);
|
|
4574
4585
|
if (parent === dir) return void 0;
|
|
4575
4586
|
dir = parent;
|
|
4576
4587
|
}
|
|
@@ -4596,7 +4607,7 @@ function readApiToken() {
|
|
|
4596
4607
|
}
|
|
4597
4608
|
function readGlobalSettings() {
|
|
4598
4609
|
try {
|
|
4599
|
-
const settingsPath =
|
|
4610
|
+
const settingsPath = path15__default.join(homedir(), ".skaile", "settings.json");
|
|
4600
4611
|
if (!existsSync(settingsPath)) return {};
|
|
4601
4612
|
return JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
4602
4613
|
} catch {
|
|
@@ -4744,7 +4755,7 @@ function parsePositiveInt(value, flag) {
|
|
|
4744
4755
|
function makeSessionCommand() {
|
|
4745
4756
|
const cmd = new Command("session").description("Manage sessions");
|
|
4746
4757
|
cmd.command("list").description("List all sessions for a project").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
|
|
4747
|
-
const projectDir =
|
|
4758
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
4748
4759
|
const sessions = await listSessions(projectDir);
|
|
4749
4760
|
const current = await loadSession(projectDir);
|
|
4750
4761
|
if (sessions.length === 0) {
|
|
@@ -4760,10 +4771,10 @@ function makeSessionCommand() {
|
|
|
4760
4771
|
console.log(` ${S.dim(" ")} ${S.rule(75)}`);
|
|
4761
4772
|
for (const s of sessions) {
|
|
4762
4773
|
const isCurrent = current?.runId === s.runId;
|
|
4763
|
-
const marker = isCurrent ?
|
|
4774
|
+
const marker = isCurrent ? pc5.cyan(" \u25B6 ") : " ";
|
|
4764
4775
|
const age = Math.round((Date.now() - new Date(s.updatedAt).getTime()) / 6e4);
|
|
4765
4776
|
const label = (s.label ?? "").padEnd(20);
|
|
4766
|
-
const statusColor = s.status === "complete" ?
|
|
4777
|
+
const statusColor = s.status === "complete" ? pc5.green : s.status === "failed" ? pc5.red : s.status === "running" ? pc5.cyan : pc5.dim;
|
|
4767
4778
|
const status4 = statusColor((s.status ?? "").padEnd(12));
|
|
4768
4779
|
console.log(
|
|
4769
4780
|
`${marker} ${S.dim(s.runId.slice(0, 8))} ${s.flowId.padEnd(20)} ${label} ${status4} ${S.dim(`${age}m ago`)}`
|
|
@@ -4772,7 +4783,7 @@ function makeSessionCommand() {
|
|
|
4772
4783
|
console.log();
|
|
4773
4784
|
});
|
|
4774
4785
|
cmd.command("show <run-id>").description("Show a specific session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
|
|
4775
|
-
const projectDir =
|
|
4786
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
4776
4787
|
const session = await loadSessionById(projectDir, runId);
|
|
4777
4788
|
if (!session) {
|
|
4778
4789
|
logErr(`Session not found: ${runId}`);
|
|
@@ -4781,12 +4792,12 @@ function makeSessionCommand() {
|
|
|
4781
4792
|
console.log(JSON.stringify(session, null, 2));
|
|
4782
4793
|
});
|
|
4783
4794
|
cmd.command("switch <run-id>").description("Switch the current session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
|
|
4784
|
-
const projectDir =
|
|
4795
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
4785
4796
|
await setCurrentSession(projectDir, runId);
|
|
4786
4797
|
logOk(`Switched to session: ${S.dim(runId.slice(0, 8))}`);
|
|
4787
4798
|
});
|
|
4788
4799
|
cmd.command("delete <run-id>").description("Delete a session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
|
|
4789
|
-
const projectDir =
|
|
4800
|
+
const projectDir = path15__default.resolve(opts.projectDir);
|
|
4790
4801
|
await deleteSession(projectDir, runId);
|
|
4791
4802
|
logOk(`Deleted session: ${S.dim(runId.slice(0, 8))}`);
|
|
4792
4803
|
});
|
|
@@ -4795,11 +4806,11 @@ function makeSessionCommand() {
|
|
|
4795
4806
|
return cmd;
|
|
4796
4807
|
}
|
|
4797
4808
|
var SYNC_ICONS = {
|
|
4798
|
-
synced:
|
|
4799
|
-
outdated:
|
|
4800
|
-
local:
|
|
4801
|
-
error:
|
|
4802
|
-
unknown:
|
|
4809
|
+
synced: pc5.green("synced"),
|
|
4810
|
+
outdated: pc5.yellow("outdated"),
|
|
4811
|
+
local: pc5.cyan("local"),
|
|
4812
|
+
error: pc5.red("error"),
|
|
4813
|
+
unknown: pc5.dim("\u2014")
|
|
4803
4814
|
};
|
|
4804
4815
|
function showOverview(am2) {
|
|
4805
4816
|
const result = am2.overview();
|
|
@@ -4812,25 +4823,25 @@ function showOverview(am2) {
|
|
|
4812
4823
|
if (result.repos.length > 0) {
|
|
4813
4824
|
console.log();
|
|
4814
4825
|
for (const r of result.repos) {
|
|
4815
|
-
const icon = r.error ?
|
|
4816
|
-
const status4 = r.error ?
|
|
4817
|
-
console.log(` ${icon} ${S.cmd(r.name)} ${
|
|
4826
|
+
const icon = r.error ? pc5.red("!") : r.upToDate ? pc5.green("\u2713") : pc5.yellow("\u2193");
|
|
4827
|
+
const status4 = r.error ? pc5.red(r.error) : r.upToDate ? pc5.green("up to date") : pc5.yellow(`${r.behind} behind`);
|
|
4828
|
+
console.log(` ${icon} ${S.cmd(r.name)} ${pc5.dim(`[${r.kind}]`)} ${status4}`);
|
|
4818
4829
|
}
|
|
4819
4830
|
}
|
|
4820
4831
|
const nameW = Math.max(4, ...[...result.byDomain.values()].flat().map((e) => e.name.length));
|
|
4821
4832
|
const kindW = 8;
|
|
4822
4833
|
for (const [domain, entries] of result.byDomain) {
|
|
4823
4834
|
console.log();
|
|
4824
|
-
console.log(` ${S.heading(domain)} ${
|
|
4835
|
+
console.log(` ${S.heading(domain)} ${pc5.dim(`(${entries.length})`)}`);
|
|
4825
4836
|
console.log(` ${S.rule(nameW + kindW + 20)}`);
|
|
4826
4837
|
for (const e of entries) {
|
|
4827
4838
|
const sync = SYNC_ICONS[e.syncStatus] ?? SYNC_ICONS.unknown;
|
|
4828
|
-
const ver = e.version ?
|
|
4839
|
+
const ver = e.version ? pc5.dim(` v${e.version}`) : "";
|
|
4829
4840
|
console.log(` ${kindColorPad(e.kind, kindW)} ${S.cmd(e.name.padEnd(nameW))} ${sync}${ver}`);
|
|
4830
4841
|
}
|
|
4831
4842
|
}
|
|
4832
4843
|
console.log();
|
|
4833
|
-
console.log(` ${
|
|
4844
|
+
console.log(` ${pc5.dim(`${result.total} assets deployed`)}`);
|
|
4834
4845
|
console.log();
|
|
4835
4846
|
}
|
|
4836
4847
|
function showAsset(am2, kind, name) {
|
|
@@ -4849,7 +4860,7 @@ function showAsset(am2, kind, name) {
|
|
|
4849
4860
|
function makeShowCommand() {
|
|
4850
4861
|
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) => {
|
|
4851
4862
|
const am2 = new AssetManager({
|
|
4852
|
-
projectDir:
|
|
4863
|
+
projectDir: path15__default.resolve(opts.projectDir),
|
|
4853
4864
|
driverTarget: opts.target
|
|
4854
4865
|
});
|
|
4855
4866
|
if (!kind) {
|
|
@@ -4867,16 +4878,139 @@ function makeShowCommand() {
|
|
|
4867
4878
|
}
|
|
4868
4879
|
});
|
|
4869
4880
|
}
|
|
4870
|
-
|
|
4881
|
+
|
|
4882
|
+
// cli/src/commands/source-manifest.ts
|
|
4883
|
+
var NOT_WIRED_MSG = "`skaile source manifest *` is scaffolded but not yet wired. Server-side endpoint (`POST /sources/<id>/manifest`) lands in a follow-up PR.";
|
|
4884
|
+
function notWired2(verb) {
|
|
4885
|
+
logErr(`${NOT_WIRED_MSG} (verb: source manifest ${verb})`);
|
|
4886
|
+
process.exit(2);
|
|
4887
|
+
}
|
|
4888
|
+
function addSourceManifestCommands(src) {
|
|
4889
|
+
const manifest = src.command("manifest").description("Sidecar manifest lifecycle for a source");
|
|
4890
|
+
manifest.command("init <src>").description("Start a sidecar manifest for a source").action(() => notWired2("init"));
|
|
4891
|
+
manifest.command("edit <src>").description("Open the sidecar manifest in $EDITOR").action(() => notWired2("edit"));
|
|
4892
|
+
manifest.command("rebuild <src>").description("Re-derive the manifest after an upstream change").option("--merge", "Merge with existing entries instead of overwriting", false).action(() => notWired2("rebuild"));
|
|
4893
|
+
manifest.command("verify <src>").description("Verify hashes, deps, and schema").option("--strict", "Fail on advisory checks", false).action(() => notWired2("verify"));
|
|
4894
|
+
manifest.command("publish <src>").description("Register the manifest in the store (provenance=curator)").action(() => notWired2("publish"));
|
|
4895
|
+
manifest.command("propose <src>").description("Open a PR to upstream with the sidecar manifest").action(() => notWired2("propose"));
|
|
4896
|
+
manifest.command("yank <src>").description("Retract a published manifest from the remote store").option("--version <v>", "Version to yank").action(() => notWired2("yank"));
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4899
|
+
// cli/src/commands/source.ts
|
|
4900
|
+
function sourcesDir() {
|
|
4901
|
+
return path15.join(skaileHomeDir(), "sources");
|
|
4902
|
+
}
|
|
4903
|
+
function deriveSlug(url) {
|
|
4904
|
+
return url.replace(/\.git$/, "").split(/[/:]/).pop() ?? "source";
|
|
4905
|
+
}
|
|
4906
|
+
function isSourceRow(lib) {
|
|
4907
|
+
return lib.path.startsWith(sourcesDir());
|
|
4908
|
+
}
|
|
4871
4909
|
function makeSourceCommand() {
|
|
4872
|
-
const cmd = new Command("source").description(
|
|
4873
|
-
|
|
4910
|
+
const cmd = new Command("source").description(
|
|
4911
|
+
"Manage github sources (third-party repos of AI assets)"
|
|
4912
|
+
);
|
|
4913
|
+
cmd.command("add <git-url>").description("Clone a github repo into ~/.skaile/sources/<slug> and register it").option("--name <slug>", "Override the derived slug").action(async (url, opts) => {
|
|
4914
|
+
const slug = opts.name ?? deriveSlug(url);
|
|
4915
|
+
const dest = path15.join(sourcesDir(), slug);
|
|
4916
|
+
const clone = spawnSync("git", ["clone", url, dest], { stdio: "inherit" });
|
|
4917
|
+
if (clone.status !== 0) {
|
|
4918
|
+
logErr(`git clone failed for ${url}`);
|
|
4919
|
+
process.exit(1);
|
|
4920
|
+
}
|
|
4921
|
+
const { manager, close } = await openLibraryManager();
|
|
4922
|
+
try {
|
|
4923
|
+
await manager.addLibrary({
|
|
4924
|
+
name: slug,
|
|
4925
|
+
path: dest,
|
|
4926
|
+
backend: "git",
|
|
4927
|
+
backendConfig: { url, branch: "main", authHint: "ssh" },
|
|
4928
|
+
ownership: "reader"
|
|
4929
|
+
});
|
|
4930
|
+
logOk(`Source "${slug}" added at ${dest}.`);
|
|
4931
|
+
} finally {
|
|
4932
|
+
close();
|
|
4933
|
+
}
|
|
4934
|
+
});
|
|
4935
|
+
cmd.command("list").description("List registered sources").option("--json", "Output as JSON").action(async (opts) => {
|
|
4936
|
+
const { manager, close } = await openLibraryManager();
|
|
4937
|
+
try {
|
|
4938
|
+
const all = await manager.listLibraries();
|
|
4939
|
+
const sources = all.filter(isSourceRow);
|
|
4940
|
+
if (opts.json) return console.log(JSON.stringify(sources, null, 2));
|
|
4941
|
+
if (sources.length === 0) {
|
|
4942
|
+
logInfo("No sources registered. Run `skaile source add <git-url>` to start.");
|
|
4943
|
+
return;
|
|
4944
|
+
}
|
|
4945
|
+
console.log();
|
|
4946
|
+
console.log(S.heading(" Sources"));
|
|
4947
|
+
for (const s of sources) {
|
|
4948
|
+
console.log(` ${S.cmd(s.name.padEnd(20))} ${S.dim(s.path)}`);
|
|
4949
|
+
}
|
|
4950
|
+
console.log(`
|
|
4951
|
+
${S.dim(`${sources.length} source(s)`)}
|
|
4952
|
+
`);
|
|
4953
|
+
} finally {
|
|
4954
|
+
close();
|
|
4955
|
+
}
|
|
4956
|
+
});
|
|
4957
|
+
cmd.command("show <name>").description("Show details for a source").action(async (name) => {
|
|
4958
|
+
const { manager, close } = await openLibraryManager();
|
|
4959
|
+
try {
|
|
4960
|
+
const s = await manager.requireLibrary(name);
|
|
4961
|
+
if (!isSourceRow(s)) {
|
|
4962
|
+
logErr(`"${name}" is a library, not a source \u2014 use \`skaile library show ${name}\`.`);
|
|
4963
|
+
process.exit(1);
|
|
4964
|
+
}
|
|
4965
|
+
console.log(JSON.stringify(s, null, 2));
|
|
4966
|
+
} finally {
|
|
4967
|
+
close();
|
|
4968
|
+
}
|
|
4969
|
+
});
|
|
4970
|
+
cmd.command("remove <name>").description("Unregister a source").option("--purge", "Also delete the clone directory from disk", false).action(async (name, opts) => {
|
|
4971
|
+
const { manager, close } = await openLibraryManager();
|
|
4972
|
+
try {
|
|
4973
|
+
const s = await manager.requireLibrary(name);
|
|
4974
|
+
if (!isSourceRow(s)) {
|
|
4975
|
+
logErr(`"${name}" is a library, not a source \u2014 use \`skaile library remove ${name}\`.`);
|
|
4976
|
+
process.exit(1);
|
|
4977
|
+
}
|
|
4978
|
+
await manager.removeLibrary(name, { purge: opts.purge });
|
|
4979
|
+
logOk(`Removed source "${name}".`);
|
|
4980
|
+
} finally {
|
|
4981
|
+
close();
|
|
4982
|
+
}
|
|
4983
|
+
});
|
|
4984
|
+
cmd.command("sync [name]").description("Re-fetch upstream changes for one or all sources").action(async (name) => {
|
|
4985
|
+
const { manager, close } = await openLibraryManager();
|
|
4986
|
+
try {
|
|
4987
|
+
const all = await manager.listLibraries();
|
|
4988
|
+
const targets = name ? all.filter((l) => l.name === name && isSourceRow(l)) : all.filter(isSourceRow);
|
|
4989
|
+
if (targets.length === 0) {
|
|
4990
|
+
logInfo(name ? `No source named "${name}".` : "No sources registered.");
|
|
4991
|
+
return;
|
|
4992
|
+
}
|
|
4993
|
+
for (const s of targets) {
|
|
4994
|
+
const res = await manager.driverFor(s.backend).pull(s);
|
|
4995
|
+
logOk(`${s.name}: pulled ${res.applied} change(s).`);
|
|
4996
|
+
}
|
|
4997
|
+
} finally {
|
|
4998
|
+
close();
|
|
4999
|
+
}
|
|
5000
|
+
});
|
|
5001
|
+
cmd.command("patch <ref>").description("Extract an asset for editing against the source").action((_ref) => {
|
|
5002
|
+
logErr(
|
|
5003
|
+
"`skaile source patch` is scaffolded but not yet wired. The patch flow lands in a follow-up PR."
|
|
5004
|
+
);
|
|
4874
5005
|
process.exit(2);
|
|
4875
5006
|
});
|
|
4876
|
-
cmd.command("
|
|
4877
|
-
logErr(
|
|
5007
|
+
cmd.command("propose <ref>").description("Open a PR with the patch against the source upstream").action((_ref) => {
|
|
5008
|
+
logErr(
|
|
5009
|
+
"`skaile source propose` is scaffolded but not yet wired. The propose flow lands in a follow-up PR."
|
|
5010
|
+
);
|
|
4878
5011
|
process.exit(2);
|
|
4879
5012
|
});
|
|
5013
|
+
addSourceManifestCommands(cmd);
|
|
4880
5014
|
return cmd;
|
|
4881
5015
|
}
|
|
4882
5016
|
function makeStoreCommand() {
|
|
@@ -4886,10 +5020,10 @@ function makeStoreCommand() {
|
|
|
4886
5020
|
if (opts.email) {
|
|
4887
5021
|
const readline2 = await import('readline');
|
|
4888
5022
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
4889
|
-
const password = await new Promise((
|
|
5023
|
+
const password = await new Promise((resolve4) => {
|
|
4890
5024
|
rl.question("Password: ", (answer) => {
|
|
4891
5025
|
rl.close();
|
|
4892
|
-
|
|
5026
|
+
resolve4(answer);
|
|
4893
5027
|
});
|
|
4894
5028
|
});
|
|
4895
5029
|
try {
|
|
@@ -4975,28 +5109,35 @@ function makeStoreCommand() {
|
|
|
4975
5109
|
process.exit(1);
|
|
4976
5110
|
}
|
|
4977
5111
|
});
|
|
4978
|
-
store.command("
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5112
|
+
store.command("mode <auto|local|remote>").description("Set the catalog resolution mode (not yet wired)").action((_mode) => {
|
|
5113
|
+
logErr(
|
|
5114
|
+
"`skaile store mode` is scaffolded but not yet wired. Store config lives at ~/.skaile/store/config.yaml."
|
|
5115
|
+
);
|
|
5116
|
+
process.exit(2);
|
|
5117
|
+
});
|
|
5118
|
+
store.command("search <query>").description("Search the aggregated catalog (not yet wired)").action((_query) => {
|
|
5119
|
+
logErr("`skaile store search` is scaffolded but not yet wired.");
|
|
5120
|
+
process.exit(2);
|
|
5121
|
+
});
|
|
5122
|
+
store.command("show <ref>").description("Show details + provenance for a manifest (not yet wired)").action((_ref) => {
|
|
5123
|
+
logErr("`skaile store show` is scaffolded but not yet wired.");
|
|
5124
|
+
process.exit(2);
|
|
5125
|
+
});
|
|
5126
|
+
store.command("favourite <ref>").description("Pin a ref to your favourites (not yet wired)").action((_ref) => {
|
|
5127
|
+
logErr("`skaile store favourite` is scaffolded but not yet wired.");
|
|
5128
|
+
process.exit(2);
|
|
5129
|
+
});
|
|
5130
|
+
store.command("unfavourite <ref>").description("Remove a ref from your favourites (not yet wired)").action((_ref) => {
|
|
5131
|
+
logErr("`skaile store unfavourite` is scaffolded but not yet wired.");
|
|
5132
|
+
process.exit(2);
|
|
5133
|
+
});
|
|
5134
|
+
store.command("sync").description("Refresh the local cache from the remote store (not yet wired)").action(() => {
|
|
5135
|
+
logErr("`skaile store sync` is scaffolded but not yet wired.");
|
|
5136
|
+
process.exit(2);
|
|
5137
|
+
});
|
|
5138
|
+
store.command("push").description("Push the local store to a git remote (not yet wired)").option("--remote <name>", "Git remote name", "origin").action(() => {
|
|
5139
|
+
logErr("`skaile store push` is scaffolded but not yet wired.");
|
|
5140
|
+
process.exit(2);
|
|
5000
5141
|
});
|
|
5001
5142
|
store.command("yank <version>").description("Yank (soft-delete) a published version").option("--asset <ref>", "Asset reference (@publisher/slug)").action(async (version, opts) => {
|
|
5002
5143
|
const config = getStoreConfig();
|
|
@@ -5037,7 +5178,7 @@ function printTree(node, prefix = "", isLast = true) {
|
|
|
5037
5178
|
}
|
|
5038
5179
|
function makeTreeCommand() {
|
|
5039
5180
|
return new Command("tree").description("Show full dependency tree").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
|
|
5040
|
-
const am2 = new AssetManager({ projectDir:
|
|
5181
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
5041
5182
|
const root = am2.tree();
|
|
5042
5183
|
if (root.children.length === 0) {
|
|
5043
5184
|
logInfo("No dependencies in lock file. Run `skaile install` first.");
|
|
@@ -5055,7 +5196,7 @@ function makeUpdateCommand() {
|
|
|
5055
5196
|
try {
|
|
5056
5197
|
const catalogSpinner = p5.spinner();
|
|
5057
5198
|
catalogSpinner.start("Refreshing catalog cache");
|
|
5058
|
-
const remote = await openCatalogSource({ projectDir:
|
|
5199
|
+
const remote = await openCatalogSource({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
5059
5200
|
const result2 = await remote.refresh();
|
|
5060
5201
|
catalogSpinner.stop(
|
|
5061
5202
|
`Catalog refreshed: ${S.heading(String(result2.assetsCached))} assets cached`
|
|
@@ -5067,7 +5208,7 @@ function makeUpdateCommand() {
|
|
|
5067
5208
|
}
|
|
5068
5209
|
}
|
|
5069
5210
|
if (opts.catalogOnly) return;
|
|
5070
|
-
const am2 = new AssetManager({ projectDir:
|
|
5211
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
5071
5212
|
const spinner5 = p5.spinner();
|
|
5072
5213
|
spinner5.start("Re-deploying assets");
|
|
5073
5214
|
const result = await am2.install();
|
|
@@ -5113,7 +5254,7 @@ function findManifestCandidates(rootPath) {
|
|
|
5113
5254
|
return;
|
|
5114
5255
|
}
|
|
5115
5256
|
for (const entry of entries) {
|
|
5116
|
-
const fullPath =
|
|
5257
|
+
const fullPath = path15__default.join(dir, entry.name);
|
|
5117
5258
|
if (entry.isDirectory()) {
|
|
5118
5259
|
if (!SKIP_DIRS.has(entry.name)) walk(fullPath);
|
|
5119
5260
|
} else if (entry.isFile()) {
|
|
@@ -5135,7 +5276,7 @@ function parseMdFrontmatter(content) {
|
|
|
5135
5276
|
return parse(fmMatch[1]);
|
|
5136
5277
|
}
|
|
5137
5278
|
function validateManifests(rootPath) {
|
|
5138
|
-
const absRoot =
|
|
5279
|
+
const absRoot = path15__default.resolve(rootPath);
|
|
5139
5280
|
if (!fs10__default.existsSync(absRoot)) {
|
|
5140
5281
|
logErr(`Path does not exist: ${absRoot}`);
|
|
5141
5282
|
return { total: 0, errors: 1, warnings: 0 };
|
|
@@ -5156,14 +5297,14 @@ function validateManifests(rootPath) {
|
|
|
5156
5297
|
try {
|
|
5157
5298
|
parsed = c.filePath.endsWith(".json") ? JSON.parse(content) : parse(content);
|
|
5158
5299
|
} catch (e) {
|
|
5159
|
-
const relPath2 =
|
|
5300
|
+
const relPath2 = path15__default.relative(absRoot, c.filePath);
|
|
5160
5301
|
logErr(`${relPath2} \u2014 parse error: ${e instanceof Error ? e.message : String(e)}`);
|
|
5161
5302
|
errors++;
|
|
5162
5303
|
continue;
|
|
5163
5304
|
}
|
|
5164
5305
|
}
|
|
5165
5306
|
const provider = registry.getProvider(c.kind);
|
|
5166
|
-
const relPath =
|
|
5307
|
+
const relPath = path15__default.relative(absRoot, c.filePath);
|
|
5167
5308
|
if (!provider) {
|
|
5168
5309
|
logWarn(`${relPath} [${c.kind}] \u2014 kind "${c.kind}" is not registered, skipping validation`);
|
|
5169
5310
|
warnings++;
|
|
@@ -5185,20 +5326,20 @@ function collectAssetVersions() {
|
|
|
5185
5326
|
if (!fs10__default.existsSync(AI_RESOURCES)) return assets;
|
|
5186
5327
|
const domains = fs10__default.readdirSync(AI_RESOURCES, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DOMAINS.has(d.name));
|
|
5187
5328
|
for (const d of domains) {
|
|
5188
|
-
const domainDir =
|
|
5189
|
-
const skillsDir =
|
|
5329
|
+
const domainDir = path15__default.join(AI_RESOURCES, d.name);
|
|
5330
|
+
const skillsDir = path15__default.join(domainDir, "skills");
|
|
5190
5331
|
if (fs10__default.existsSync(skillsDir)) {
|
|
5191
5332
|
collectSkillVersions(skillsDir, d.name, assets);
|
|
5192
5333
|
}
|
|
5193
|
-
const agentsDir =
|
|
5334
|
+
const agentsDir = path15__default.join(domainDir, "agents");
|
|
5194
5335
|
if (fs10__default.existsSync(agentsDir)) {
|
|
5195
5336
|
collectAgentVersions(agentsDir, d.name, assets);
|
|
5196
5337
|
}
|
|
5197
|
-
const flowsDir =
|
|
5338
|
+
const flowsDir = path15__default.join(domainDir, "flows");
|
|
5198
5339
|
if (fs10__default.existsSync(flowsDir)) {
|
|
5199
5340
|
for (const f of fs10__default.readdirSync(flowsDir)) {
|
|
5200
5341
|
if (!f.endsWith(".flow.yaml")) continue;
|
|
5201
|
-
const fp =
|
|
5342
|
+
const fp = path15__default.join(flowsDir, f);
|
|
5202
5343
|
const content = fs10__default.readFileSync(fp, "utf-8");
|
|
5203
5344
|
const parsed = parse(content);
|
|
5204
5345
|
assets.push({
|
|
@@ -5210,11 +5351,11 @@ function collectAssetVersions() {
|
|
|
5210
5351
|
});
|
|
5211
5352
|
}
|
|
5212
5353
|
}
|
|
5213
|
-
const promptsDir =
|
|
5354
|
+
const promptsDir = path15__default.join(domainDir, "prompts");
|
|
5214
5355
|
if (fs10__default.existsSync(promptsDir)) {
|
|
5215
5356
|
for (const f of fs10__default.readdirSync(promptsDir)) {
|
|
5216
5357
|
if (!f.endsWith(".prompt.md")) continue;
|
|
5217
|
-
const fp =
|
|
5358
|
+
const fp = path15__default.join(promptsDir, f);
|
|
5218
5359
|
const content = fs10__default.readFileSync(fp, "utf-8");
|
|
5219
5360
|
const fm = parseSkillFrontmatter(content);
|
|
5220
5361
|
assets.push({
|
|
@@ -5232,8 +5373,8 @@ function collectAssetVersions() {
|
|
|
5232
5373
|
function collectSkillVersions(dir, domain, out) {
|
|
5233
5374
|
for (const entry of fs10__default.readdirSync(dir, { withFileTypes: true })) {
|
|
5234
5375
|
if (!entry.isDirectory()) continue;
|
|
5235
|
-
const full =
|
|
5236
|
-
const skillMd =
|
|
5376
|
+
const full = path15__default.join(dir, entry.name);
|
|
5377
|
+
const skillMd = path15__default.join(full, "SKILL.md");
|
|
5237
5378
|
if (fs10__default.existsSync(skillMd)) {
|
|
5238
5379
|
const content = fs10__default.readFileSync(skillMd, "utf-8");
|
|
5239
5380
|
const fm = parseSkillFrontmatter(content);
|
|
@@ -5252,7 +5393,7 @@ function collectSkillVersions(dir, domain, out) {
|
|
|
5252
5393
|
function collectAgentVersions(dir, domain, out) {
|
|
5253
5394
|
for (const entry of fs10__default.readdirSync(dir, { withFileTypes: true })) {
|
|
5254
5395
|
if (!entry.isDirectory()) continue;
|
|
5255
|
-
const agentYaml =
|
|
5396
|
+
const agentYaml = path15__default.join(dir, entry.name, "agent.yaml");
|
|
5256
5397
|
if (!fs10__default.existsSync(agentYaml)) continue;
|
|
5257
5398
|
const content = fs10__default.readFileSync(agentYaml, "utf-8");
|
|
5258
5399
|
const parsed = parse(content);
|
|
@@ -5283,7 +5424,7 @@ function makeValidateCommand() {
|
|
|
5283
5424
|
"Validate asset manifests, versions, and changelogs"
|
|
5284
5425
|
);
|
|
5285
5426
|
cmd.argument("[path]", "Path to asset repo or directory to validate", ".").action((targetPath) => {
|
|
5286
|
-
const absPath =
|
|
5427
|
+
const absPath = path15__default.resolve(targetPath);
|
|
5287
5428
|
logInfo(`Validating manifests in ${absPath}`);
|
|
5288
5429
|
const { total, errors } = validateManifests(absPath);
|
|
5289
5430
|
console.log();
|
|
@@ -5304,7 +5445,7 @@ function makeValidateCommand() {
|
|
|
5304
5445
|
encoding: "utf-8"
|
|
5305
5446
|
});
|
|
5306
5447
|
const changedFiles = new Set(
|
|
5307
|
-
diffOutput.trim().split("\n").filter(Boolean).map((f) =>
|
|
5448
|
+
diffOutput.trim().split("\n").filter(Boolean).map((f) => path15__default.resolve(AI_RESOURCES, f))
|
|
5308
5449
|
);
|
|
5309
5450
|
assets = assets.filter((a) => changedFiles.has(a.filePath));
|
|
5310
5451
|
} catch {
|
|
@@ -5326,7 +5467,7 @@ function makeValidateCommand() {
|
|
|
5326
5467
|
if (opts.changedOnly) {
|
|
5327
5468
|
for (const a of assets) {
|
|
5328
5469
|
if (!a.version) continue;
|
|
5329
|
-
const relPath =
|
|
5470
|
+
const relPath = path15__default.relative(AI_RESOURCES, a.filePath);
|
|
5330
5471
|
try {
|
|
5331
5472
|
const headContent = execSync(`git show HEAD:${relPath}`, {
|
|
5332
5473
|
cwd: AI_RESOURCES,
|
|
@@ -5406,7 +5547,7 @@ function makeValidateCommand() {
|
|
|
5406
5547
|
let errors = 0;
|
|
5407
5548
|
for (const domain of modifiedDomains) {
|
|
5408
5549
|
const changelogModified = modifiedFiles.some(
|
|
5409
|
-
(f) => f === `${domain}/CHANGELOG.md` || f ===
|
|
5550
|
+
(f) => f === `${domain}/CHANGELOG.md` || f === path15__default.join(domain, "CHANGELOG.md")
|
|
5410
5551
|
);
|
|
5411
5552
|
if (changelogModified) {
|
|
5412
5553
|
logOk(`${domain}/CHANGELOG.md updated`);
|
|
@@ -5488,7 +5629,7 @@ function makeVerifyCommand() {
|
|
|
5488
5629
|
}
|
|
5489
5630
|
function makeWhyCommand() {
|
|
5490
5631
|
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) => {
|
|
5491
|
-
const am2 = new AssetManager({ projectDir:
|
|
5632
|
+
const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
|
|
5492
5633
|
const chain = am2.why(ref);
|
|
5493
5634
|
if (chain.length === 0) {
|
|
5494
5635
|
logErr(`${ref} not found in lock file. Run \`skaile install\` first.`);
|
|
@@ -5509,7 +5650,7 @@ function makeWhyCommand() {
|
|
|
5509
5650
|
var _defaultFormatHelp = Help.prototype.formatHelp;
|
|
5510
5651
|
var pkg = JSON.parse(
|
|
5511
5652
|
readFileSync(
|
|
5512
|
-
|
|
5653
|
+
path15__default.resolve(path15__default.dirname(fileURLToPath(import.meta.url)), "../../package.json"),
|
|
5513
5654
|
"utf-8"
|
|
5514
5655
|
)
|
|
5515
5656
|
);
|
|
@@ -5573,18 +5714,36 @@ Validation:
|
|
|
5573
5714
|
validate versions Check asset version fields and flow pins
|
|
5574
5715
|
validate changelog Check changelogs for modified domains
|
|
5575
5716
|
|
|
5576
|
-
|
|
5577
|
-
source add <
|
|
5578
|
-
source list
|
|
5579
|
-
source sync [
|
|
5580
|
-
source
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
library
|
|
5717
|
+
Sources (github repos of AI assets):
|
|
5718
|
+
source add <git-url> Clone + register a github source
|
|
5719
|
+
source list / show / remove Source registry CRUD
|
|
5720
|
+
source sync [name] Re-fetch upstream changes
|
|
5721
|
+
source patch / propose Contribute back via PR
|
|
5722
|
+
source manifest * Sidecar manifest lifecycle
|
|
5723
|
+
|
|
5724
|
+
Libraries (your authoring workspaces):
|
|
5725
|
+
library init <name> Create a local library (use --git URL to attach a remote)
|
|
5726
|
+
library link <name> <url> Attach a github remote to a local library
|
|
5727
|
+
library create <kind> <name> Scaffold a new asset in a library
|
|
5728
|
+
library list / show / status Library inspection
|
|
5729
|
+
library default <name> Set the default library
|
|
5730
|
+
library rename / set / remove
|
|
5731
|
+
library commit / pull / push / propose / git Git ops (git backend only)
|
|
5732
|
+
library sync <name> Pull then push (as backend permits)
|
|
5733
|
+
library publish / register / yank <ref> Store publish flow (stubs)
|
|
5734
|
+
|
|
5735
|
+
Store (manifest catalog + auth):
|
|
5736
|
+
store login / logout / whoami / yank Auth + admin
|
|
5737
|
+
store mode <auto|local|remote> Resolution mode (stub)
|
|
5738
|
+
store search / show / favourite / unfavourite Catalog browsing (stub)
|
|
5739
|
+
store sync / push Local-store sync (stub)
|
|
5740
|
+
|
|
5741
|
+
Catalog (debug):
|
|
5742
|
+
catalog test / show Probe a catalog endpoint, print resolved config
|
|
5743
|
+
|
|
5744
|
+
Presets:
|
|
5585
5745
|
preset init [name] Scaffold a .preset.yaml
|
|
5586
5746
|
preset validate <path> Validate a preset file
|
|
5587
|
-
lib-status Show Library health summary
|
|
5588
5747
|
|
|
5589
5748
|
Advanced:
|
|
5590
5749
|
flow list|show Flow browsing
|
|
@@ -5613,24 +5772,24 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
5613
5772
|
process.exitCode = 1;
|
|
5614
5773
|
return;
|
|
5615
5774
|
}
|
|
5616
|
-
const resolved =
|
|
5617
|
-
const projectName =
|
|
5775
|
+
const resolved = path15__default.resolve(projectDir ?? ".");
|
|
5776
|
+
const projectName = path15__default.basename(resolved);
|
|
5618
5777
|
const created = [];
|
|
5619
5778
|
if (!existsSync11(resolved)) {
|
|
5620
5779
|
mkdirSync3(resolved, { recursive: true });
|
|
5621
5780
|
created.push(".");
|
|
5622
5781
|
}
|
|
5623
|
-
const skaileDir =
|
|
5782
|
+
const skaileDir = path15__default.join(resolved, ".skaile");
|
|
5624
5783
|
if (!existsSync11(skaileDir)) {
|
|
5625
|
-
mkdirSync3(
|
|
5784
|
+
mkdirSync3(path15__default.join(skaileDir, "sessions"), { recursive: true });
|
|
5626
5785
|
created.push(".skaile/");
|
|
5627
5786
|
}
|
|
5628
|
-
const settingsPath =
|
|
5787
|
+
const settingsPath = path15__default.join(skaileDir, "settings.json");
|
|
5629
5788
|
if (!existsSync11(settingsPath)) {
|
|
5630
5789
|
writeFileSync2(settingsPath, "{}\n");
|
|
5631
5790
|
created.push(".skaile/settings.json");
|
|
5632
5791
|
}
|
|
5633
|
-
const wsConfigPath =
|
|
5792
|
+
const wsConfigPath = path15__default.join(resolved, "skaile.yaml");
|
|
5634
5793
|
if (!existsSync11(wsConfigPath)) {
|
|
5635
5794
|
writeFileSync2(
|
|
5636
5795
|
wsConfigPath,
|
|
@@ -5652,14 +5811,14 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
5652
5811
|
created.push("skaile.yaml");
|
|
5653
5812
|
}
|
|
5654
5813
|
for (const dir of new Set(Object.values(DRIVER_TARGETS[backend].local))) {
|
|
5655
|
-
const full =
|
|
5814
|
+
const full = path15__default.join(resolved, dir);
|
|
5656
5815
|
if (!existsSync11(full)) {
|
|
5657
5816
|
mkdirSync3(full, { recursive: true });
|
|
5658
5817
|
created.push(`${dir}/`);
|
|
5659
5818
|
}
|
|
5660
5819
|
}
|
|
5661
5820
|
if (opts.git) {
|
|
5662
|
-
const gitignorePath =
|
|
5821
|
+
const gitignorePath = path15__default.join(resolved, ".gitignore");
|
|
5663
5822
|
const entries = ["node_modules/", ".skaile/sessions/", "*.log", ".env", ".env.local"];
|
|
5664
5823
|
const existing = existsSync11(gitignorePath) ? readFileSync5(gitignorePath, "utf-8") : "";
|
|
5665
5824
|
const have = new Set(existing.split("\n").map((l) => l.trim()));
|
|
@@ -5670,7 +5829,7 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
5670
5829
|
`);
|
|
5671
5830
|
if (!existing) created.push(".gitignore");
|
|
5672
5831
|
}
|
|
5673
|
-
if (!existsSync11(
|
|
5832
|
+
if (!existsSync11(path15__default.join(resolved, ".git"))) {
|
|
5674
5833
|
try {
|
|
5675
5834
|
execSync3("git init", { cwd: resolved, stdio: "pipe" });
|
|
5676
5835
|
created.push(".git/");
|
|
@@ -5700,7 +5859,7 @@ program.command("init [project-dir]").description("Initialize a project director
|
|
|
5700
5859
|
logOk(`Initialized project at ${S.heading(resolved)}`);
|
|
5701
5860
|
console.log();
|
|
5702
5861
|
console.log(S.heading(" Next steps:"));
|
|
5703
|
-
const isCurrentDir = resolved ===
|
|
5862
|
+
const isCurrentDir = resolved === path15__default.resolve(".");
|
|
5704
5863
|
let step = 1;
|
|
5705
5864
|
if (!isCurrentDir) {
|
|
5706
5865
|
console.log(` ${S.dim(`${step}.`)} ${S.cmd(`cd ${projectDir}`)}`);
|
|
@@ -5761,7 +5920,6 @@ program.addCommand(makeSourceCommand());
|
|
|
5761
5920
|
program.addCommand(makeLibraryCommand());
|
|
5762
5921
|
program.addCommand(makeAssetCommand());
|
|
5763
5922
|
program.addCommand(makePresetCommand());
|
|
5764
|
-
program.addCommand(makeLibraryStatusCommand());
|
|
5765
5923
|
program.command("path").description("Show resolved paths").action(() => {
|
|
5766
5924
|
console.log();
|
|
5767
5925
|
console.log(` ${S.dim("ai-assets")} ${S.heading(AI_RESOURCES)}`);
|