totopo 0.2.0-rc-2 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "totopo",
3
- "version": "0.2.0-rc-2",
3
+ "version": "0.2.0",
4
4
  "description": "Secure AI Box — isolated dev environments for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
  // src/core/select-tools.ts — multiselect UI for choosing container runtimes
3
3
  // =============================================================================
4
4
 
5
- import { cancel, isCancel, multiselect } from "@clack/prompts";
5
+ import { cancel, isCancel, log, multiselect } from "@clack/prompts";
6
6
  import type { HostRuntimes } from "./detect-host.ts";
7
7
 
8
8
  const dim = (s: string) => `\x1b[2m${s}\x1b[0m`;
@@ -12,8 +12,8 @@ interface ToolEntry {
12
12
  label: string;
13
13
  }
14
14
 
15
- const TOOL_CATALOGUE: ToolEntry[] = [
16
- { key: "node", label: "Node.js" },
15
+ // Node is always included — not shown as a checkbox
16
+ const OPTIONAL_TOOLS: ToolEntry[] = [
17
17
  { key: "python", label: "Python" },
18
18
  { key: "go", label: "Go" },
19
19
  { key: "rust", label: "Rust / Cargo" },
@@ -22,22 +22,22 @@ const TOOL_CATALOGUE: ToolEntry[] = [
22
22
  ];
23
23
 
24
24
  export async function selectTools(hostRuntimes: HostRuntimes): Promise<string[]> {
25
- const options = TOOL_CATALOGUE.map(({ key, label }) => {
25
+ // Node is always included — show as a fixed line, not a deselectable checkbox
26
+ const nodeVersion = hostRuntimes.node ? `v${hostRuntimes.node} · host` : "latest";
27
+ log.success(`Node.js ${dim(`${nodeVersion} · always included`)}`);
28
+
29
+ const options = OPTIONAL_TOOLS.map(({ key, label }) => {
26
30
  const detected = hostRuntimes[key];
27
- const base = {
31
+ return {
28
32
  value: key as string,
29
33
  label: detected ? `${label} ${dim(`v${detected} · host`)}` : `${label} ${dim("latest")}`,
30
34
  };
31
- return key === "node" ? { ...base, hint: "always included" } : base;
32
35
  });
33
36
 
34
- // node is always pre-selected (required); other tools pre-selected when detected on host
35
- const initialValues = TOOL_CATALOGUE.filter(({ key }) => key === "node" || hostRuntimes[key] !== undefined).map(
36
- ({ key }) => key as string,
37
- );
37
+ const initialValues = OPTIONAL_TOOLS.filter(({ key }) => hostRuntimes[key] !== undefined).map(({ key }) => key as string);
38
38
 
39
39
  const selected = await multiselect({
40
- message: `Select tools to include in container: ${dim("Space to toggle · Enter to confirm")}`,
40
+ message: `Select additional tools:\n ${dim("Space to toggle · Enter to confirm")}`,
41
41
  options,
42
42
  initialValues,
43
43
  required: false,
@@ -48,12 +48,5 @@ export async function selectTools(hostRuntimes: HostRuntimes): Promise<string[]>
48
48
  process.exit(0);
49
49
  }
50
50
 
51
- const result = [...(selected as string[])];
52
-
53
- // Node is always forced-selected — AI tools (claude, kilo, opencode) require it
54
- if (!result.includes("node")) {
55
- result.unshift("node");
56
- }
57
-
58
- return result;
51
+ return ["node", ...(selected as string[])];
59
52
  }