@skein-code/cli 0.2.0 → 0.2.2
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/dist/cli.js +64 -15
- package/dist/cli.js.map +1 -1
- package/docs/NEXT_STEPS.md +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -220,7 +220,7 @@ function isSqliteBusy(error) {
|
|
|
220
220
|
// package.json
|
|
221
221
|
var package_default = {
|
|
222
222
|
name: "@skein-code/cli",
|
|
223
|
-
version: "0.2.
|
|
223
|
+
version: "0.2.2",
|
|
224
224
|
description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
|
|
225
225
|
type: "module",
|
|
226
226
|
license: "MIT",
|
|
@@ -383,13 +383,15 @@ async function resolveProjectNamespace(workspace) {
|
|
|
383
383
|
const { workspace: root, canonical, legacy } = projectNamespacePaths(workspace);
|
|
384
384
|
await assertNamespacePathsSeparated(legacy, canonical);
|
|
385
385
|
const [canonicalExists, legacyExists] = await Promise.all([isDirectory(canonical), isDirectory(legacy)]);
|
|
386
|
-
const
|
|
386
|
+
const phase = legacyCompatibilityStatus().phase;
|
|
387
|
+
const activeKind = activeProjectNamespaceKind(canonicalExists, legacyExists, phase);
|
|
387
388
|
return {
|
|
388
389
|
workspace: root,
|
|
389
390
|
canonical,
|
|
390
391
|
legacy,
|
|
391
392
|
active: activeKind === "canonical" ? canonical : legacy,
|
|
392
393
|
activeKind,
|
|
394
|
+
phase,
|
|
393
395
|
canonicalExists,
|
|
394
396
|
legacyExists,
|
|
395
397
|
conflict: canonicalExists && legacyExists
|
|
@@ -399,18 +401,25 @@ function resolveProjectNamespaceSync(workspace) {
|
|
|
399
401
|
const { workspace: root, canonical, legacy } = projectNamespacePaths(workspace);
|
|
400
402
|
const canonicalExists = isDirectorySync(canonical);
|
|
401
403
|
const legacyExists = isDirectorySync(legacy);
|
|
402
|
-
const
|
|
404
|
+
const phase = legacyCompatibilityStatus().phase;
|
|
405
|
+
const activeKind = activeProjectNamespaceKind(canonicalExists, legacyExists, phase);
|
|
403
406
|
return {
|
|
404
407
|
workspace: root,
|
|
405
408
|
canonical,
|
|
406
409
|
legacy,
|
|
407
410
|
active: activeKind === "canonical" ? canonical : legacy,
|
|
408
411
|
activeKind,
|
|
412
|
+
phase,
|
|
409
413
|
canonicalExists,
|
|
410
414
|
legacyExists,
|
|
411
415
|
conflict: canonicalExists && legacyExists
|
|
412
416
|
};
|
|
413
417
|
}
|
|
418
|
+
function activeProjectNamespaceKind(canonicalExists, legacyExists, phase) {
|
|
419
|
+
if (canonicalExists) return "canonical";
|
|
420
|
+
if (legacyExists) return "legacy";
|
|
421
|
+
return phase === "active" ? "legacy" : "canonical";
|
|
422
|
+
}
|
|
414
423
|
function resolveHomeNamespace(environment = process.env) {
|
|
415
424
|
const paths = homeNamespacePaths(environment);
|
|
416
425
|
if (environment.SKEIN_HOME?.trim()) return paths.canonical;
|
|
@@ -421,12 +430,14 @@ async function resolveHomeStorageNamespace(environment = process.env) {
|
|
|
421
430
|
await assertNamespacePathsSeparated(legacy, canonical);
|
|
422
431
|
const [canonicalExists, legacyExists] = await Promise.all([isDirectory(canonical), isDirectory(legacy)]);
|
|
423
432
|
const activeKind = canonicalExists ? "canonical" : "legacy";
|
|
433
|
+
const phase = legacyCompatibilityStatus({ environment }).phase;
|
|
424
434
|
return {
|
|
425
435
|
workspace: root,
|
|
426
436
|
canonical,
|
|
427
437
|
legacy,
|
|
428
438
|
active: activeKind === "canonical" ? canonical : legacy,
|
|
429
439
|
activeKind,
|
|
440
|
+
phase,
|
|
430
441
|
canonicalExists,
|
|
431
442
|
legacyExists,
|
|
432
443
|
conflict: canonicalExists && legacyExists
|
|
@@ -1966,6 +1977,9 @@ var envKeysForProvider = {
|
|
|
1966
1977
|
gemini: ["GEMINI_API_KEY"],
|
|
1967
1978
|
compatible: ["SKEIN_API_KEY", "MOSAIC_API_KEY"]
|
|
1968
1979
|
};
|
|
1980
|
+
function providerApiKeyEnv(provider) {
|
|
1981
|
+
return envKeysForProvider[provider][0];
|
|
1982
|
+
}
|
|
1969
1983
|
var defaultPermissions = {
|
|
1970
1984
|
read: "allow",
|
|
1971
1985
|
write: "ask",
|
|
@@ -9749,10 +9763,11 @@ async function runDoctor(config, options = {}) {
|
|
|
9749
9763
|
let legacyCompatibility;
|
|
9750
9764
|
try {
|
|
9751
9765
|
namespace = await inspectProjectNamespace(root);
|
|
9766
|
+
const activeNamespace = resolveProjectNamespaceSync(root);
|
|
9752
9767
|
checks.push({
|
|
9753
9768
|
name: "Storage namespace",
|
|
9754
9769
|
ok: namespace.status !== "conflict",
|
|
9755
|
-
detail: namespace.status === "ready" ? `legacy .mosaic detected; migrate to ${namespace.destination}` : namespace.status === "conflict" ? `conflict in ${namespace.conflicts.length} path(s); migration paused` : !namespace.sourceExists && !namespace.destinationExists ? `no durable state yet; first write uses ${
|
|
9770
|
+
detail: namespace.status === "ready" ? `legacy .mosaic detected; migrate to ${namespace.destination}` : namespace.status === "conflict" ? `conflict in ${namespace.conflicts.length} path(s); migration paused` : !namespace.sourceExists && !namespace.destinationExists ? `no durable state yet; first write uses ${activeNamespace.active}` : `canonical .skein namespace active at ${namespace.destination}`,
|
|
9756
9771
|
required: false
|
|
9757
9772
|
});
|
|
9758
9773
|
} catch (error) {
|
|
@@ -10420,8 +10435,9 @@ function command(name, description, usage, aliases) {
|
|
|
10420
10435
|
import stringWidth from "string-width";
|
|
10421
10436
|
import stripAnsi2 from "strip-ansi";
|
|
10422
10437
|
var controlCharacters = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/gu;
|
|
10438
|
+
var escapeSequences = /[[\]][0-9;?=>!]*[ -/]*[@-~]|[[\]][?=>][0-9;?=>!]*[a-zA-Z~]/gu;
|
|
10423
10439
|
function sanitizeTerminalText(value) {
|
|
10424
|
-
return stripAnsi2(value).replace(/\r\n?/g, "\n").replace(controlCharacters, "");
|
|
10440
|
+
return stripAnsi2(value).replace(escapeSequences, "").replace(/\r\n?/g, "\n").replace(controlCharacters, "");
|
|
10425
10441
|
}
|
|
10426
10442
|
function terminalEllipsis() {
|
|
10427
10443
|
return process.env.SKEIN_GLYPHS === "ascii" || process.env.MOSAIC_GLYPHS === "ascii" ? "..." : "\u2026";
|
|
@@ -11678,12 +11694,7 @@ function ThemePreview({ name, width, glyphs }) {
|
|
|
11678
11694
|
function Banner({ model, engine, workspace, version, width, glyphs }) {
|
|
11679
11695
|
const theme = useTheme();
|
|
11680
11696
|
const innerWidth = Math.max(1, safeWidth(width) - 2);
|
|
11681
|
-
const
|
|
11682
|
-
"\u2591\u2588\u2580\u2580\u2591\u2588\u2591\u2588\u2591\u2588\u2580\u2580\u2591\u2580\u2588\u2580\u2591\u2588\u2580\u2588",
|
|
11683
|
-
"\u2591\u2580\u2580\u2588\u2591\u2588\u2580\u2584\u2591\u2588\u2580\u2580\u2591\u2591\u2588\u2591\u2591\u2588\u2591\u2588",
|
|
11684
|
-
"\u2591\u2580\u2580\u2580\u2591\u2580\u2591\u2580\u2591\u2580\u2580\u2580\u2591\u2580\u2580\u2580\u2591\u2580\u2591\u2580"
|
|
11685
|
-
];
|
|
11686
|
-
const wordmarkFits = safeWidth(width) >= 44 && glyphs.borderStyle !== "classic";
|
|
11697
|
+
const wordmark = `${glyphs.brand} ${PRODUCT_NAME.toUpperCase().split("").join(" ")}`;
|
|
11687
11698
|
const meta = [
|
|
11688
11699
|
`model ${sanitizeInlineTerminalText(model)}`,
|
|
11689
11700
|
`engine ${sanitizeInlineTerminalText(engine)}`,
|
|
@@ -11691,8 +11702,8 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
|
|
|
11691
11702
|
].join(` ${glyphs.separator} `);
|
|
11692
11703
|
const tagline = "a terminal coding agent you can see through";
|
|
11693
11704
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
|
|
11694
|
-
|
|
11695
|
-
/* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(
|
|
11705
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: truncateDisplay(wordmark, innerWidth) }),
|
|
11706
|
+
/* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`v${version} ${glyphs.separator} ${tagline}`, innerWidth) }),
|
|
11696
11707
|
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(meta, innerWidth) }),
|
|
11697
11708
|
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`type a request ${glyphs.separator} /help for commands ${glyphs.separator} @ to attach files`, innerWidth) })
|
|
11698
11709
|
] });
|
|
@@ -12638,7 +12649,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
12638
12649
|
const separator = ` ${glyphs.separator} `;
|
|
12639
12650
|
const ellipsis = terminalEllipsis();
|
|
12640
12651
|
const initialSession = runner.getSession();
|
|
12641
|
-
const setupProblem = config.model.provider !== "compatible" && !config.model.apiKey ? `No ${config.model.provider} API key
|
|
12652
|
+
const setupProblem = config.model.provider !== "compatible" && !config.model.apiKey ? `No ${config.model.provider} API key found. Set it and restart: export ${providerApiKeyEnv(config.model.provider)}=<your-key>${separator}then run ${PRODUCT_COMMAND} again. Use ${PRODUCT_COMMAND} doctor to verify, or --model to switch provider.` : config.model.provider === "compatible" && !config.model.baseUrl ? `No model endpoint configured. Set one and restart: export SKEIN_BASE_URL=<endpoint>${separator}or pass --base-url <endpoint>. Run ${PRODUCT_COMMAND} doctor to verify.` : void 0;
|
|
12642
12653
|
const colorEnabled = config.ui.color && !process.env.NO_COLOR;
|
|
12643
12654
|
const [theme, setTheme] = useState2(() => resolveThemeWithColor(config.ui.theme, colorEnabled));
|
|
12644
12655
|
const [themeCatalogRevision, setThemeCatalogRevision] = useState2(0);
|
|
@@ -15463,7 +15474,12 @@ program.command("status").description("Show model, context, workspace, and index
|
|
|
15463
15474
|
const config = await runtimeConfig(workspaceOption(options.workspace), runtimeOptions(options));
|
|
15464
15475
|
const engine = new ContextEngine(config);
|
|
15465
15476
|
const status = await engine.status();
|
|
15466
|
-
|
|
15477
|
+
const namespace = resolveProjectNamespaceSync(config.workspaceRoots[0] ?? process.cwd());
|
|
15478
|
+
if (options.json === true) {
|
|
15479
|
+
printObject({ config: configSummary(config), context: status, namespace }, true);
|
|
15480
|
+
} else {
|
|
15481
|
+
printStatusSummary(config, status, namespace);
|
|
15482
|
+
}
|
|
15467
15483
|
});
|
|
15468
15484
|
program.command("doctor").description("Diagnose prerequisites and safe fallbacks").option("-w, --workspace <path>", "workspace root").option("--config <path>", "explicit config file").option("--json", "print JSON").option("--visual", "inspect terminal rendering, glyphs, and keyboard support").action(async (options) => {
|
|
15469
15485
|
const config = await runtimeConfig(workspaceOption(options.workspace), runtimeOptions(options));
|
|
@@ -16203,6 +16219,39 @@ function printObject(value, json) {
|
|
|
16203
16219
|
else process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
16204
16220
|
`);
|
|
16205
16221
|
}
|
|
16222
|
+
function printStatusSummary(config, context, namespace) {
|
|
16223
|
+
const glyphs = cliGlyphs;
|
|
16224
|
+
const dim = (text) => chalk3.dim(text);
|
|
16225
|
+
const line = (level, name, detail) => {
|
|
16226
|
+
const icon = level === "ok" ? chalk3.green(glyphs.success) : level === "error" ? chalk3.red(glyphs.error) : chalk3.yellow("!");
|
|
16227
|
+
process.stdout.write(`${icon} ${name.padEnd(16)} ${dim(detail)}
|
|
16228
|
+
`);
|
|
16229
|
+
};
|
|
16230
|
+
const keyReady = Boolean(config.model.apiKey) || config.model.provider === "compatible";
|
|
16231
|
+
const endpoint = redactEndpoint(config.model.baseUrl);
|
|
16232
|
+
const local = context.local ?? {};
|
|
16233
|
+
const selected = String(context.selected ?? "local");
|
|
16234
|
+
const engineDetail = selected === "contextengine" ? "ContextEngine (external)" : selected === "unindexed" ? `ContextEngine available; index not built ${glyphs.separator} run ${PRODUCT_COMMAND} index` : selected === "unavailable" ? `ContextEngine required but unavailable ${glyphs.separator} run ${PRODUCT_COMMAND} doctor` : "local index";
|
|
16235
|
+
const indexFiles = local.files ?? 0;
|
|
16236
|
+
const indexReady = Boolean(local.available) && indexFiles > 0;
|
|
16237
|
+
const indexDetail = indexReady ? `${indexFiles} files ${glyphs.separator} ${local.chunks ?? 0} chunks` : `not built ${glyphs.separator} run ${PRODUCT_COMMAND} index`;
|
|
16238
|
+
process.stdout.write(`${chalk3.hex("#A78BFA").bold(`${glyphs.brand} ${PRODUCT_NAME.toUpperCase()} STATUS`)}
|
|
16239
|
+
|
|
16240
|
+
`);
|
|
16241
|
+
line("ok", "Model", `${config.model.provider}/${config.model.model}`);
|
|
16242
|
+
line("ok", "Endpoint", endpoint);
|
|
16243
|
+
line(keyReady ? "ok" : "warn", "API key", keyReady ? "configured" : `missing ${glyphs.separator} set it, then run ${PRODUCT_COMMAND} doctor to verify`);
|
|
16244
|
+
line(selected === "unavailable" ? "error" : "ok", "Context engine", engineDetail);
|
|
16245
|
+
line(indexReady ? "ok" : "warn", "Code index", indexDetail);
|
|
16246
|
+
line("ok", "Workspace", config.workspaceRoots.join(` ${glyphs.separator} `));
|
|
16247
|
+
const namespaceName = namespace.activeKind === "canonical" ? ".skein" : ".mosaic";
|
|
16248
|
+
const storageDetail = namespace.activeKind === "canonical" ? `${namespaceName} (canonical)` : namespace.phase === "active" ? `${namespaceName} (legacy; new projects switch to .skein from 0.3.0)` : `${namespaceName} (legacy; run ${PRODUCT_COMMAND} migrate --yes before removal)`;
|
|
16249
|
+
const storageReady = namespace.activeKind === "canonical" || namespace.phase === "active";
|
|
16250
|
+
line(storageReady ? "ok" : "warn", "Storage", storageDetail);
|
|
16251
|
+
process.stdout.write(`
|
|
16252
|
+
${dim(`Run ${PRODUCT_COMMAND} status --json for the full machine-readable record.`)}
|
|
16253
|
+
`);
|
|
16254
|
+
}
|
|
16206
16255
|
function printSessionList(sessions) {
|
|
16207
16256
|
if (!sessions.length) {
|
|
16208
16257
|
process.stdout.write("No saved sessions.\n");
|