nextclaw 0.3.2 → 0.3.3

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/index.js CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  buildReloadPlan,
18
18
  diffConfigPaths,
19
19
  getWorkspacePath,
20
+ expandHome,
20
21
  MessageBus,
21
22
  AgentLoop,
22
23
  LiteLLMProvider,
@@ -26,7 +27,9 @@ import {
26
27
  CronService,
27
28
  HeartbeatService,
28
29
  PROVIDERS,
29
- APP_NAME
30
+ APP_NAME,
31
+ DEFAULT_WORKSPACE_DIR,
32
+ DEFAULT_WORKSPACE_PATH
30
33
  } from "nextclaw-core";
31
34
  import { startUiServer } from "nextclaw-server";
32
35
  import {
@@ -39,7 +42,7 @@ import {
39
42
  rmSync as rmSync2,
40
43
  writeFileSync as writeFileSync2
41
44
  } from "fs";
42
- import { join as join2, resolve as resolve2 } from "path";
45
+ import { dirname, join as join2, resolve as resolve2 } from "path";
43
46
  import { spawn as spawn2, spawnSync } from "child_process";
44
47
  import { createInterface } from "readline";
45
48
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -294,21 +297,46 @@ var CliRuntime = class {
294
297
  return getPackageVersion();
295
298
  }
296
299
  async onboard() {
300
+ console.warn(`Warning: ${APP_NAME} onboard is deprecated. Use "${APP_NAME} init" instead.`);
301
+ await this.init({ source: "onboard" });
302
+ }
303
+ async init(options = {}) {
304
+ const source = options.source ?? "init";
305
+ const prefix = options.auto ? "Auto init" : "Init";
297
306
  const configPath = getConfigPath();
298
- if (existsSync2(configPath)) {
299
- console.log(`Config already exists at ${configPath}`);
300
- }
301
- const config = ConfigSchema.parse({});
302
- saveConfig(config);
303
- console.log(`\u2713 Created config at ${configPath}`);
304
- const workspace = getWorkspacePath();
305
- console.log(`\u2713 Created workspace at ${workspace}`);
306
- this.createWorkspaceTemplates(workspace);
307
- console.log(`
308
- ${this.logo} ${APP_NAME} is ready!`);
309
- console.log("\nNext steps:");
310
- console.log(` 1. Add your API key to ${configPath}`);
311
- console.log(` 2. Chat: ${APP_NAME} agent -m "Hello!"`);
307
+ let createdConfig = false;
308
+ if (!existsSync2(configPath)) {
309
+ const config2 = ConfigSchema.parse({});
310
+ saveConfig(config2);
311
+ createdConfig = true;
312
+ }
313
+ const config = loadConfig();
314
+ const workspaceSetting = config.agents.defaults.workspace;
315
+ const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join2(getDataDir2(), DEFAULT_WORKSPACE_DIR) : expandHome(workspaceSetting);
316
+ const workspaceExisted = existsSync2(workspacePath);
317
+ mkdirSync2(workspacePath, { recursive: true });
318
+ const templateResult = this.createWorkspaceTemplates(workspacePath);
319
+ if (createdConfig) {
320
+ console.log(`\u2713 ${prefix}: created config at ${configPath}`);
321
+ }
322
+ if (!workspaceExisted) {
323
+ console.log(`\u2713 ${prefix}: created workspace at ${workspacePath}`);
324
+ }
325
+ for (const file of templateResult.created) {
326
+ console.log(`\u2713 ${prefix}: created ${file}`);
327
+ }
328
+ if (!createdConfig && workspaceExisted && templateResult.created.length === 0) {
329
+ console.log(`${prefix}: already initialized.`);
330
+ }
331
+ if (!options.auto) {
332
+ console.log(`
333
+ ${this.logo} ${APP_NAME} is ready! (${source})`);
334
+ console.log("\nNext steps:");
335
+ console.log(` 1. Add your API key to ${configPath}`);
336
+ console.log(` 2. Chat: ${APP_NAME} agent -m "Hello!"`);
337
+ } else {
338
+ console.log(`Tip: Run "${APP_NAME} init" to re-run initialization if needed.`);
339
+ }
312
340
  }
313
341
  async gateway(opts) {
314
342
  const uiOverrides = {};
@@ -340,6 +368,7 @@ ${this.logo} ${APP_NAME} is ready!`);
340
368
  await this.startGateway({ uiOverrides, allowMissingProvider: true });
341
369
  }
342
370
  async start(opts) {
371
+ await this.init({ source: "start", auto: true });
343
372
  const uiOverrides = {
344
373
  enabled: true,
345
374
  open: false
@@ -930,44 +959,55 @@ ${this.logo} ${APP_NAME} is ready!`);
930
959
  });
931
960
  }
932
961
  createWorkspaceTemplates(workspace) {
933
- const templates = {
934
- "AGENTS.md": "# Agent Instructions\n\nYou are a helpful AI assistant. Be concise, accurate, and friendly.\n\n## Guidelines\n\n- Always explain what you're doing before taking actions\n- Ask for clarification when the request is ambiguous\n- Use tools to help accomplish tasks\n- Remember important information in your memory files\n",
935
- "SOUL.md": `# Soul
936
-
937
- I am ${APP_NAME}, a lightweight AI assistant.
938
-
939
- ## Personality
940
-
941
- - Helpful and friendly
942
- - Concise and to the point
943
- - Curious and eager to learn
944
-
945
- ## Values
946
-
947
- - Accuracy over speed
948
- - User privacy and safety
949
- - Transparency in actions
950
-
951
- `,
952
- "USER.md": "# User\n\nInformation about the user goes here.\n\n## Preferences\n\n- Communication style: (casual/formal)\n- Timezone: (your timezone)\n- Language: (your preferred language)\n"
953
- };
954
- for (const [filename, content] of Object.entries(templates)) {
955
- const filePath = join2(workspace, filename);
956
- if (!existsSync2(filePath)) {
957
- writeFileSync2(filePath, content);
958
- }
962
+ const created = [];
963
+ const templateDir = this.resolveTemplateDir();
964
+ if (!templateDir) {
965
+ console.warn("Warning: Template directory not found. Skipping workspace templates.");
966
+ return { created };
959
967
  }
960
- const memoryDir = join2(workspace, "memory");
961
- mkdirSync2(memoryDir, { recursive: true });
962
- const memoryFile = join2(memoryDir, "MEMORY.md");
963
- if (!existsSync2(memoryFile)) {
964
- writeFileSync2(
965
- memoryFile,
966
- "# Long-term Memory\n\nThis file stores important information that should persist across sessions.\n\n## User Information\n\n(Important facts about the user)\n\n## Preferences\n\n(User preferences learned over time)\n\n## Important Notes\n\n(Things to remember)\n"
967
- );
968
+ const templateFiles = [
969
+ { source: "AGENTS.md", target: "AGENTS.md" },
970
+ { source: "SOUL.md", target: "SOUL.md" },
971
+ { source: "USER.md", target: "USER.md" },
972
+ { source: join2("memory", "MEMORY.md"), target: join2("memory", "MEMORY.md") }
973
+ ];
974
+ for (const entry of templateFiles) {
975
+ const filePath = join2(workspace, entry.target);
976
+ if (existsSync2(filePath)) {
977
+ continue;
978
+ }
979
+ const templatePath = join2(templateDir, entry.source);
980
+ if (!existsSync2(templatePath)) {
981
+ console.warn(`Warning: Template file missing: ${templatePath}`);
982
+ continue;
983
+ }
984
+ const raw = readFileSync2(templatePath, "utf-8");
985
+ const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME);
986
+ mkdirSync2(dirname(filePath), { recursive: true });
987
+ writeFileSync2(filePath, content);
988
+ created.push(entry.target);
968
989
  }
969
990
  const skillsDir = join2(workspace, "skills");
970
- mkdirSync2(skillsDir, { recursive: true });
991
+ if (!existsSync2(skillsDir)) {
992
+ mkdirSync2(skillsDir, { recursive: true });
993
+ created.push(join2("skills", ""));
994
+ }
995
+ return { created };
996
+ }
997
+ resolveTemplateDir() {
998
+ const override = process.env.NEXTCLAW_TEMPLATE_DIR?.trim();
999
+ if (override) {
1000
+ return override;
1001
+ }
1002
+ const cliDir = resolve2(fileURLToPath2(new URL(".", import.meta.url)));
1003
+ const pkgRoot = resolve2(cliDir, "..", "..");
1004
+ const candidates = [join2(pkgRoot, "templates")];
1005
+ for (const candidate of candidates) {
1006
+ if (existsSync2(candidate)) {
1007
+ return candidate;
1008
+ }
1009
+ }
1010
+ return null;
971
1011
  }
972
1012
  getBridgeDir() {
973
1013
  const userBridge = join2(getDataDir2(), "bridge");
@@ -1027,6 +1067,7 @@ var program = new Command();
1027
1067
  var runtime = new CliRuntime({ logo: LOGO });
1028
1068
  program.name(APP_NAME2).description(`${LOGO} ${APP_NAME2} - ${APP_TAGLINE}`).version(getPackageVersion(), "-v, --version", "show version");
1029
1069
  program.command("onboard").description(`Initialize ${APP_NAME2} configuration and workspace`).action(async () => runtime.onboard());
1070
+ program.command("init").description(`Initialize ${APP_NAME2} configuration and workspace`).action(async () => runtime.init());
1030
1071
  program.command("gateway").description(`Start the ${APP_NAME2} gateway`).option("-p, --port <port>", "Gateway port", "18790").option("-v, --verbose", "Verbose output", false).option("--ui", "Enable UI server", false).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--ui-open", "Open browser when UI starts", false).action(async (opts) => runtime.gateway(opts));
1031
1072
  program.command("ui").description(`Start the ${APP_NAME2} UI with gateway`).option("--host <host>", "UI host").option("--port <port>", "UI port").option("--no-open", "Disable opening browser").action(async (opts) => runtime.ui(opts));
1032
1073
  program.command("start").description(`Start the ${APP_NAME2} gateway + UI in the background`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).action(async (opts) => runtime.start(opts));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -32,7 +32,8 @@
32
32
  "files": [
33
33
  "dist",
34
34
  "bridge",
35
- "ui-dist"
35
+ "ui-dist",
36
+ "templates"
36
37
  ],
37
38
  "dependencies": {
38
39
  "chokidar": "^3.6.0",
@@ -0,0 +1,10 @@
1
+ # Agent Instructions
2
+
3
+ You are a helpful AI assistant. Be concise, accurate, and friendly.
4
+
5
+ ## Guidelines
6
+
7
+ - Always explain what you're doing before taking actions
8
+ - Ask for clarification when the request is ambiguous
9
+ - Use tools to help accomplish tasks
10
+ - Remember important information in your memory files
@@ -0,0 +1,15 @@
1
+ # Soul
2
+
3
+ I am ${APP_NAME}, a lightweight AI assistant.
4
+
5
+ ## Personality
6
+
7
+ - Helpful and friendly
8
+ - Concise and to the point
9
+ - Curious and eager to learn
10
+
11
+ ## Values
12
+
13
+ - Accuracy over speed
14
+ - User privacy and safety
15
+ - Transparency in actions
@@ -0,0 +1,9 @@
1
+ # User
2
+
3
+ Information about the user goes here.
4
+
5
+ ## Preferences
6
+
7
+ - Communication style: (casual/formal)
8
+ - Timezone: (your timezone)
9
+ - Language: (your preferred language)
@@ -0,0 +1,15 @@
1
+ # Long-term Memory
2
+
3
+ This file stores important information that should persist across sessions.
4
+
5
+ ## User Information
6
+
7
+ (Important facts about the user)
8
+
9
+ ## Preferences
10
+
11
+ (User preferences learned over time)
12
+
13
+ ## Important Notes
14
+
15
+ (Things to remember)