nextclaw 0.3.1 → 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 +93 -64
- package/package.json +3 -2
- package/templates/AGENTS.md +10 -0
- package/templates/SOUL.md +15 -0
- package/templates/USER.md +9 -0
- package/templates/memory/MEMORY.md +15 -0
- package/ui-dist/assets/{index-BIesvTqn.js → index-BivRvIey.js} +45 -45
- package/ui-dist/index.html +1 -1
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";
|
|
@@ -80,19 +83,7 @@ async function findAvailablePort(port, host, attempts = 20) {
|
|
|
80
83
|
}
|
|
81
84
|
async function isPortAvailable(port, host) {
|
|
82
85
|
const checkHost = normalizeHostForPortCheck(host);
|
|
83
|
-
|
|
84
|
-
if (checkHost === "127.0.0.1") {
|
|
85
|
-
hostsToCheck.push("::1");
|
|
86
|
-
} else if (checkHost === "::1") {
|
|
87
|
-
hostsToCheck.push("127.0.0.1");
|
|
88
|
-
}
|
|
89
|
-
for (const candidate of hostsToCheck) {
|
|
90
|
-
const ok = await canBindPort(port, candidate);
|
|
91
|
-
if (ok) {
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return false;
|
|
86
|
+
return await canBindPort(port, checkHost);
|
|
96
87
|
}
|
|
97
88
|
async function canBindPort(port, host) {
|
|
98
89
|
return await new Promise((resolve3) => {
|
|
@@ -306,21 +297,46 @@ var CliRuntime = class {
|
|
|
306
297
|
return getPackageVersion();
|
|
307
298
|
}
|
|
308
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";
|
|
309
306
|
const configPath = getConfigPath();
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
+
}
|
|
324
340
|
}
|
|
325
341
|
async gateway(opts) {
|
|
326
342
|
const uiOverrides = {};
|
|
@@ -352,6 +368,7 @@ ${this.logo} ${APP_NAME} is ready!`);
|
|
|
352
368
|
await this.startGateway({ uiOverrides, allowMissingProvider: true });
|
|
353
369
|
}
|
|
354
370
|
async start(opts) {
|
|
371
|
+
await this.init({ source: "start", auto: true });
|
|
355
372
|
const uiOverrides = {
|
|
356
373
|
enabled: true,
|
|
357
374
|
open: false
|
|
@@ -942,44 +959,55 @@ ${this.logo} ${APP_NAME} is ready!`);
|
|
|
942
959
|
});
|
|
943
960
|
}
|
|
944
961
|
createWorkspaceTemplates(workspace) {
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
## Personality
|
|
952
|
-
|
|
953
|
-
- Helpful and friendly
|
|
954
|
-
- Concise and to the point
|
|
955
|
-
- Curious and eager to learn
|
|
956
|
-
|
|
957
|
-
## Values
|
|
958
|
-
|
|
959
|
-
- Accuracy over speed
|
|
960
|
-
- User privacy and safety
|
|
961
|
-
- Transparency in actions
|
|
962
|
-
|
|
963
|
-
`,
|
|
964
|
-
"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"
|
|
965
|
-
};
|
|
966
|
-
for (const [filename, content] of Object.entries(templates)) {
|
|
967
|
-
const filePath = join2(workspace, filename);
|
|
968
|
-
if (!existsSync2(filePath)) {
|
|
969
|
-
writeFileSync2(filePath, content);
|
|
970
|
-
}
|
|
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 };
|
|
971
967
|
}
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
);
|
|
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);
|
|
980
989
|
}
|
|
981
990
|
const skillsDir = join2(workspace, "skills");
|
|
982
|
-
|
|
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;
|
|
983
1011
|
}
|
|
984
1012
|
getBridgeDir() {
|
|
985
1013
|
const userBridge = join2(getDataDir2(), "bridge");
|
|
@@ -1039,6 +1067,7 @@ var program = new Command();
|
|
|
1039
1067
|
var runtime = new CliRuntime({ logo: LOGO });
|
|
1040
1068
|
program.name(APP_NAME2).description(`${LOGO} ${APP_NAME2} - ${APP_TAGLINE}`).version(getPackageVersion(), "-v, --version", "show version");
|
|
1041
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());
|
|
1042
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));
|
|
1043
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));
|
|
1044
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.
|
|
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,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)
|