@skein-code/cli 0.3.8 → 0.3.9

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/README.md CHANGED
@@ -78,7 +78,7 @@ To build, verify, and install a local package artifact from this checkout:
78
78
 
79
79
  ```bash
80
80
  npm run verify:package -- --output-dir artifacts/package
81
- npm install -g ./artifacts/package/skein-code-cli-0.3.8.tgz
81
+ npm install -g ./artifacts/package/skein-code-cli-0.3.9.tgz
82
82
  ```
83
83
 
84
84
  To install the published package from npm:
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.3.8",
223
+ version: "0.3.9",
224
224
  description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
225
225
  type: "module",
226
226
  license: "MIT",
@@ -236,9 +236,9 @@ var package_default = {
236
236
  },
237
237
  skein: {
238
238
  releaseNotes: [
239
- "Startup builds or reuses the local index and validates persisted workspace content before chat",
240
- "Wide fresh sessions add a factual workspace rail for model, context, permissions, tools, and extensions",
241
- "Completion requires current runtime evidence and conservatively tracks dynamic shell mutations"
239
+ "First-run context preparation now shows the real inspect, build, persist, and verify stages",
240
+ "Fresh sessions add a compact Skein identity and grouped workspace rail without filling the terminal",
241
+ "Short and narrow terminals collapse the index handoff while preserving validation and recovery states"
242
242
  ]
243
243
  },
244
244
  bin: {
@@ -11917,15 +11917,18 @@ function WorkspacePanel({ status, width = 36, glyphMode = "auto" }) {
11917
11917
  const inner = Math.max(8, safeWidth(width) - 4);
11918
11918
  const contextLabel = status.context === "empty" ? "ready \xB7 empty workspace" : "ready";
11919
11919
  const mcpLabel = status.mcpTotal ? `${status.mcpConnected}/${status.mcpTotal} connected` : "off";
11920
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, borderStyle: glyphs.borderStyle, borderColor: theme.border, paddingX: 1, children: [
11921
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: truncateDisplay(`${glyphs.context} WORKSPACE`, inner) }),
11922
- /* @__PURE__ */ jsx(Text, { color: status.context === "empty" ? theme.warning : theme.success, children: truncateDisplay(`${glyphs.success} context ${contextLabel}`, inner) }),
11923
- status.context === "ready" ? /* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`${status.files} files ${glyphs.separator} ${status.chunks} chunks`, inner) }) : null,
11920
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, height: 13, borderStyle: glyphs.borderStyle, borderColor: theme.border, paddingX: 1, children: [
11921
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: truncateDisplay(`${glyphs.brand} WORKSPACE`, inner) }),
11922
+ /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("CONTEXT", inner) }),
11923
+ /* @__PURE__ */ jsx(Text, { color: status.context === "empty" ? theme.warning : theme.success, children: truncateDisplay(`${glyphs.success} local index ${contextLabel}`, inner) }),
11924
+ /* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`${status.files} files ${glyphs.separator} ${status.chunks} chunks`, inner) }),
11925
+ /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("RUNTIME", inner) }),
11924
11926
  /* @__PURE__ */ jsx(Text, { color: theme.text, children: truncateDisplay(status.model, inner) }),
11925
11927
  /* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`mode ${status.mode.toUpperCase()} ${glyphs.separator} ${status.permissions}`, inner) }),
11928
+ /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("EXTENSIONS", inner) }),
11926
11929
  /* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`${status.tools} tools ${glyphs.separator} ${status.skills} skills`, inner) }),
11927
11930
  /* @__PURE__ */ jsx(Text, { color: theme.muted, children: truncateDisplay(`MCP ${mcpLabel} ${glyphs.separator} memory ${status.memory}`, inner) }),
11928
- /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay("@file pin \xB7 /status inspect", inner) })
11931
+ /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`@file pin ${glyphs.separator} /status inspect`, inner) })
11929
11932
  ] });
11930
11933
  }
11931
11934
  function TeamWorkbench({ items, tasks, width = 80, glyphMode = "auto", view = "agents", selectedIndex = 0, expanded = false, run, notice }) {
@@ -12466,10 +12469,13 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
12466
12469
  const padding = rowWidth >= 24 ? 2 : 0;
12467
12470
  const innerWidth = Math.max(1, rowWidth - padding);
12468
12471
  const safeEngine = sanitizeInlineTerminalText(engine);
12469
- const meta = rowWidth >= 48 ? `${PRODUCT_NAME.toUpperCase()} ${glyphs.separator} local-first coding workspace` : rowWidth >= 28 ? `New session ${glyphs.separator} v${version}` : `New ${glyphs.separator} v${version}`;
12470
- const cwd = rowWidth >= 48 ? `${glyphs.success} Ready ${glyphs.separator} ${safeEngine} context ${glyphs.separator} ${sanitizeInlineTerminalText(model)} ${glyphs.separator} v${version}` : `cwd ${compactDisplayPath(sanitizeInlineTerminalText(workspace), Math.max(1, innerWidth - 4))}`;
12472
+ const expanded = rowWidth >= 48;
12473
+ const ascii = glyphs.brand === "*";
12474
+ const weaveTop = ascii ? "/\\/\\" : "\u2572\u2571\u2572\u2571";
12475
+ const weaveBottom = ascii ? "\\/\\/" : "\u2571\u2572\u2571\u2572";
12476
+ const meta = expanded ? "grounded coding workspace" : rowWidth >= 28 ? `New session ${glyphs.separator} v${version}` : `New ${glyphs.separator} v${version}`;
12477
+ const status = expanded ? `${glyphs.success} ${safeEngine} index verified ${glyphs.separator} ${sanitizeInlineTerminalText(model)} ${glyphs.separator} v${version}` : `cwd ${compactDisplayPath(sanitizeInlineTerminalText(workspace), Math.max(1, innerWidth - 4))}`;
12471
12478
  const hint = `context runs automatically ${glyphs.separator} @file pins ${glyphs.separator} /help commands`;
12472
- const statusWidth = displayWidth(glyphs.success) + 1;
12473
12479
  return /* @__PURE__ */ jsxs(
12474
12480
  Box,
12475
12481
  {
@@ -12477,15 +12483,27 @@ function Banner({ model, engine, workspace, version, width, glyphs }) {
12477
12483
  flexDirection: "column",
12478
12484
  paddingLeft: padding,
12479
12485
  children: [
12480
- /* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
12486
+ expanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
12487
+ /* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
12488
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: weaveTop }),
12489
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, children: " S K E I N" })
12490
+ ] }),
12491
+ /* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
12492
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: weaveBottom }),
12493
+ /* @__PURE__ */ jsxs(Text, { color: theme.muted, children: [
12494
+ " ",
12495
+ truncateDisplay(meta, Math.max(1, innerWidth - displayWidth(weaveBottom) - 2))
12496
+ ] })
12497
+ ] })
12498
+ ] }) : /* @__PURE__ */ jsxs(Box, { height: 1, overflowY: "hidden", children: [
12481
12499
  /* @__PURE__ */ jsxs(Text, { bold: true, color: theme.accent, children: [
12482
12500
  glyphs.brand,
12483
12501
  " "
12484
12502
  ] }),
12485
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, wrap: "truncate", children: truncateDisplay(meta, Math.max(1, innerWidth - statusWidth)) })
12503
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.textStrong, children: truncateDisplay(meta, Math.max(1, innerWidth - displayWidth(glyphs.brand) - 1)) })
12486
12504
  ] }),
12487
- /* @__PURE__ */ jsx(Text, { color: rowWidth >= 48 ? theme.success : theme.muted, children: truncateDisplay(cwd, innerWidth) }),
12488
- rowWidth >= 48 ? /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`${hint} ${glyphs.separator} cwd ${compactDisplayPath(sanitizeInlineTerminalText(workspace), 24)}`, innerWidth) }) : null
12505
+ /* @__PURE__ */ jsx(Text, { color: expanded ? theme.success : theme.muted, children: truncateDisplay(status, innerWidth) }),
12506
+ expanded ? /* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncateDisplay(`${hint} ${glyphs.separator} cwd ${compactDisplayPath(sanitizeInlineTerminalText(workspace), 24)}`, innerWidth) }) : null
12489
12507
  ]
12490
12508
  }
12491
12509
  );
@@ -13466,7 +13484,7 @@ function estimateTimelineItemRows(item, { width, compact = false, showToolOutput
13466
13484
  if (item.kind === "agent" || item.kind === "agent-message") return rowWidth < 64 ? 2 : 1;
13467
13485
  if (item.kind === "workflow") return rowWidth < 64 ? 2 : 1;
13468
13486
  if (item.kind === "banner") {
13469
- return rowWidth >= 48 ? 4 : 3;
13487
+ return rowWidth >= 48 ? 5 : 3;
13470
13488
  }
13471
13489
  return 1;
13472
13490
  }
@@ -14818,7 +14836,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
14818
14836
  const chromeRows = headerRows + composerRows + footerRows + taskRows + paletteRows + inspectorRows + activityRows;
14819
14837
  const availableTimelineRows = Math.max(0, terminalHeight - chromeRows);
14820
14838
  const teamItems = timeline.filter((item) => item.kind === "agent" || item.kind === "agent-message");
14821
- const showWorkspacePanel = Boolean(workspaceReadiness) && contentWidth >= 96 && !teamWorkbenchOpen && !teamItems.some((item) => item.kind === "agent");
14839
+ const showWorkspacePanel = Boolean(workspaceReadiness) && contentWidth >= 88 && terminalHeight >= 20 && !teamWorkbenchOpen && !teamItems.some((item) => item.kind === "agent");
14822
14840
  const workspacePanelWidth = showWorkspacePanel ? Math.min(38, Math.max(32, Math.floor(contentWidth * 0.34))) : 0;
14823
14841
  const workspaceTimelineWidth = Math.max(1, contentWidth - workspacePanelWidth - (showWorkspacePanel ? 1 : 0));
14824
14842
  const timelineContentRows = timeline.reduce((rows2, item) => rows2 + estimateTimelineItemRows(item, {
@@ -14828,7 +14846,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
14828
14846
  showToolOutput,
14829
14847
  ...expandedToolId ? { expandedToolId } : {}
14830
14848
  }), 0);
14831
- const timelineRows = teamWorkbenchOpen ? availableTimelineRows : Math.min(availableTimelineRows, Math.max(timelineContentRows, showWorkspacePanel ? 10 : 0));
14849
+ const timelineRows = teamWorkbenchOpen ? availableTimelineRows : Math.min(availableTimelineRows, Math.max(timelineContentRows, showWorkspacePanel ? 13 : 0));
14832
14850
  const showTeamCockpit = config.agents?.cockpit !== false && contentWidth >= 100 && timelineRows >= 7 && teamItems.some((item) => item.kind === "agent");
14833
14851
  const cockpitWidth = showTeamCockpit ? Math.min(38, Math.max(30, Math.floor(contentWidth * 0.32))) : workspacePanelWidth;
14834
14852
  const hasSidePanel = showTeamCockpit || showWorkspacePanel;
@@ -15143,46 +15161,99 @@ function WorkspacePreparationView({
15143
15161
  workspace,
15144
15162
  model,
15145
15163
  width,
15164
+ height = 24,
15146
15165
  frame = 0
15147
15166
  }) {
15148
15167
  const theme = useTheme();
15149
15168
  const safeWidth2 = Math.max(1, Math.floor(width));
15150
15169
  const innerWidth = Math.max(1, safeWidth2 - (safeWidth2 >= 24 ? 4 : 0));
15151
15170
  const compact = safeWidth2 < 48;
15171
+ const constrained = height < 14;
15152
15172
  const ascii = process.env.SKEIN_GLYPHS === "ascii" || process.env.MOSAIC_GLYPHS === "ascii";
15153
15173
  const spinner = (ascii ? [".", "o", "O", "o"] : ["\u25DC", "\u25E0", "\u25DD", "\u25DE", "\u25E1", "\u25DF"])[frame % (ascii ? 4 : 6)];
15154
15174
  const separator = ascii ? "|" : "\xB7";
15155
15175
  const brand = ascii ? "*" : PRODUCT_MARK;
15156
15176
  const phase = readiness ? "ready" : error ? "error" : progress.phase;
15157
- const activeGlyph = readiness ? ascii ? "[ok]" : "\u2713" : error ? ascii ? "[x]" : "\xD7" : spinner;
15158
15177
  const phaseLabel = preparationLabel(phase, progress, readiness, compact);
15159
15178
  const detail = preparationDetail(phase, progress, readiness, error);
15160
15179
  const modelLine = `model ${sanitizeTerminalText(model)}`;
15161
15180
  const workspaceLine = `workspace ${compactDisplayPath(sanitizeTerminalText(workspace), Math.max(1, innerWidth - 10))}`;
15162
- const steps = ["inspect", "index", "validate"];
15163
- const currentIndex = readiness ? steps.length : phase === "validate" ? 2 : phase === "scan" || phase === "index" || phase === "write" ? 1 : 0;
15164
- const tracker = steps.map((step2, index) => {
15165
- const marker = index < currentIndex ? ascii ? "[x]" : "\u25CF" : index === currentIndex && !error ? ascii ? "[>]" : "\u25C6" : ascii ? "[ ]" : "\u25CB";
15166
- return `${marker} ${step2}`;
15167
- }).join(compact ? " " : " ");
15181
+ const steps = preparationSteps(phase, progress, readiness, error, { ascii, spinner });
15168
15182
  return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", paddingX: safeWidth2 >= 24 ? 2 : 0, children: [
15169
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.accent, children: truncateDisplay(`${brand} ${PRODUCT_NAME.toUpperCase()} WORKSPACE PREP`, innerWidth) }),
15170
- !compact ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`${modelLine} ${separator} ${workspaceLine}`, innerWidth) }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
15183
+ /* @__PURE__ */ jsxs4(Box3, { children: [
15184
+ /* @__PURE__ */ jsxs4(Text4, { bold: true, color: theme.accent, children: [
15185
+ brand,
15186
+ " ",
15187
+ PRODUCT_NAME.toUpperCase()
15188
+ ] }),
15189
+ !compact && !constrained ? /* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
15190
+ " ",
15191
+ separator,
15192
+ " LOCAL CONTEXT"
15193
+ ] }) : null
15194
+ ] }),
15195
+ !constrained ? /* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: truncateDisplay("Ground the workspace before the first request.", innerWidth) }) : null,
15196
+ !constrained && !compact ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`${modelLine} ${separator} ${workspaceLine}`, innerWidth) }) : !constrained ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
15171
15197
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(modelLine, innerWidth) }),
15172
15198
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) })
15173
- ] }),
15174
- /* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: theme.border, children: truncateDisplay(tracker, innerWidth) }) }),
15199
+ ] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) }),
15200
+ /* @__PURE__ */ jsx4(Box3, { marginTop: 1, flexDirection: constrained ? "row" : "column", children: steps.map((step2) => constrained ? /* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.dim, children: [
15201
+ step2.glyph,
15202
+ " ",
15203
+ step2.id === "persist" ? "save" : step2.id,
15204
+ step2.id === "verify" ? "" : " "
15205
+ ] }, step2.id) : /* @__PURE__ */ jsxs4(Box3, { height: 1, overflowY: "hidden", children: [
15206
+ /* @__PURE__ */ jsxs4(Text4, { bold: true, color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.border, children: [
15207
+ step2.glyph,
15208
+ " "
15209
+ ] }),
15210
+ /* @__PURE__ */ jsx4(Text4, { bold: step2.state === "active", color: step2.state === "pending" ? theme.dim : theme.textStrong, children: truncateDisplay(step2.label, compact ? 8 : 10) }),
15211
+ /* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.muted : theme.dim, children: [
15212
+ " ",
15213
+ truncateDisplay(step2.detail, Math.max(1, innerWidth - displayWidth(step2.glyph) - (compact ? 12 : 14)))
15214
+ ] })
15215
+ ] }, step2.id)) }),
15175
15216
  /* @__PURE__ */ jsxs4(Box3, { marginTop: 1, children: [
15176
15217
  /* @__PURE__ */ jsxs4(Text4, { bold: true, color: error ? theme.error : readiness ? theme.success : theme.accent, children: [
15177
- activeGlyph,
15218
+ readiness ? ascii ? "[ok]" : "\u2713" : error ? ascii ? "[x]" : "\xD7" : spinner,
15178
15219
  " "
15179
15220
  ] }),
15180
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.textStrong, children: truncateDisplay(phaseLabel, Math.max(1, innerWidth - displayWidth(activeGlyph) - 1)) })
15221
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.textStrong, children: truncateDisplay(phaseLabel, Math.max(1, innerWidth - 5)) })
15181
15222
  ] }),
15182
15223
  /* @__PURE__ */ jsx4(Text4, { color: error ? theme.error : theme.muted, wrap: "truncate", children: truncateDisplay(detail, innerWidth) }),
15183
- error ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`Enter retry ${separator} Esc exit`, innerWidth) }) : null
15224
+ error ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`Enter retry ${separator} Esc exit`, innerWidth) }) : !constrained ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(`local only ${separator} no source code uploaded`, innerWidth) }) : null
15184
15225
  ] });
15185
15226
  }
15227
+ function preparationSteps(phase, progress, readiness, error, glyphs) {
15228
+ const runtimePhase = phase === "error" ? progress.phase : phase;
15229
+ const current = runtimePhase === "scan" || runtimePhase === "index" ? "build" : runtimePhase === "write" ? "persist" : runtimePhase === "validate" ? "verify" : "inspect";
15230
+ const order = ["inspect", "build", "persist", "verify"];
15231
+ const currentIndex = phase === "ready" ? order.length : order.indexOf(current);
15232
+ const activeDetail = runtimePhase === "inspect" ? "manifest and workspace boundaries" : runtimePhase === "scan" ? `${progress.total} source files discovered` : runtimePhase === "index" ? `${progress.completed}/${progress.total} source files` : runtimePhase === "write" ? "atomic local index write" : runtimePhase === "validate" ? progress.total ? `${progress.completed}/${progress.total} content hashes` : "generation and content hashes" : "";
15233
+ const readyDetails = {
15234
+ inspect: "workspace boundaries checked",
15235
+ build: readiness?.rebuilt ? `${readiness.files} files \xB7 ${readiness.chunks} chunks` : "existing index is current",
15236
+ persist: readiness?.rebuilt ? "local artifact committed" : "local artifact loaded",
15237
+ verify: "content and generation matched"
15238
+ };
15239
+ const pendingDetails = {
15240
+ inspect: "manifest and workspace boundaries",
15241
+ build: "source files and code chunks",
15242
+ persist: "atomic local index write",
15243
+ verify: "generation and content hashes"
15244
+ };
15245
+ return order.map((id, index) => {
15246
+ const state = error && index === currentIndex ? "error" : index < currentIndex || phase === "ready" ? "complete" : index === currentIndex ? "active" : "pending";
15247
+ const glyph = state === "complete" ? glyphs.ascii ? "[x]" : "\u25CF" : state === "error" ? glyphs.ascii ? "[!]" : "\xD7" : state === "active" ? glyphs.spinner : glyphs.ascii ? "[ ]" : "\u25CB";
15248
+ return {
15249
+ id,
15250
+ label: id === "persist" ? "Persist" : `${id[0]?.toUpperCase()}${id.slice(1)}`,
15251
+ detail: phase === "ready" ? readyDetails[id] : state === "active" || state === "error" ? activeDetail : pendingDetails[id],
15252
+ state,
15253
+ glyph
15254
+ };
15255
+ });
15256
+ }
15186
15257
  function WorkspacePreparationApp({
15187
15258
  engine,
15188
15259
  config,
@@ -15192,7 +15263,7 @@ function WorkspacePreparationApp({
15192
15263
  onFinish
15193
15264
  }) {
15194
15265
  const { exit } = useApp2();
15195
- const { columns } = useWindowSize2();
15266
+ const { columns, rows } = useWindowSize2();
15196
15267
  const [attempt, setAttempt] = useState3(0);
15197
15268
  const [frame, setFrame] = useState3(0);
15198
15269
  const [progress, setProgress] = useState3({ phase: "inspect", completed: 0, total: 0 });
@@ -15244,6 +15315,7 @@ function WorkspacePreparationApp({
15244
15315
  workspace,
15245
15316
  model: `${config.model.provider}/${config.model.model}`,
15246
15317
  width: Math.max(1, columns || 80),
15318
+ height: Math.max(1, rows || 24),
15247
15319
  frame
15248
15320
  }
15249
15321
  );