@jcheesepkg/nanobot 0.7.5 → 0.7.6
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.
|
@@ -114,7 +114,6 @@ var ExecTool = class extends Tool {
|
|
|
114
114
|
env
|
|
115
115
|
}, (error, stdout, stderr) => {
|
|
116
116
|
const parts = [];
|
|
117
|
-
console.log(`Exec: command=${command}, env=${JSON.stringify(env)}, stdout=${stdout}, stderr=${stderr}, error=${error}`);
|
|
118
117
|
if (stdout) parts.push(stdout);
|
|
119
118
|
if (stderr) parts.push(`[stderr]\n${stderr}`);
|
|
120
119
|
if (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.mjs","names":[],"sources":["../../../src/agent/tools/shell.ts"],"sourcesContent":["import { exec, spawn } from \"node:child_process\";\nimport { Tool } from \"./base.js\";\n\n/** Env var patterns that should never leak to user-invoked commands. */\nconst SENSITIVE_ENV_PATTERNS = [\n /api[_-]?key/i,\n /api[_-]?token/i,\n /api[_-]?secret/i,\n /secret/i,\n /token/i,\n /password/i,\n /credential/i,\n /^LLM_/i,\n /^OPENROUTER_/i,\n /^OPENAI_/i,\n /^ANTHROPIC_/i,\n /^STRIPE_/i,\n /^LINE_CHANNEL/i,\n /^APIFY_/i,\n /^Z_AI_/i,\n /^BRAVE_/i,\n /^AWS_/i,\n /^GOOGLE_/i,\n /^AZURE_/i,\n /^NANOBOT_/i,\n];\n\n/**\n * Trusted commands that receive skill-specific env vars.\n * Only the first word (binary name) of the command is matched.\n * These commands still do NOT get the core LLM/channel secrets.\n */\nconst TRUSTED_COMMANDS = [\"summarize\"];\n\n/** Env vars injected for trusted commands only. */\nconst SKILL_ENV_KEYS = [\n \"LLM_API_KEY\",\n \"LLM_API_BASE\",\n \"APIFY_API_TOKEN\",\n];\n\n/** Build a sanitized env for child processes — strips all secrets. */\nfunction buildSafeEnv(): Record<string, string> {\n const safe: Record<string, string> = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (!value) continue;\n if (SENSITIVE_ENV_PATTERNS.some((re) => re.test(key))) continue;\n safe[key] = value;\n }\n return safe;\n}\n\n/** Build env for trusted skill commands — safe env + skill-specific keys. */\nfunction buildSkillEnv(): Record<string, string> {\n const env = buildSafeEnv();\n for (const key of SKILL_ENV_KEYS) {\n const value = process.env[key];\n if (value) env[key] = value;\n }\n return env;\n}\n\n/** Check if a command starts with a trusted binary. */\nfunction isTrustedCommand(command: string): boolean {\n // Extract the first word, stripping common prefixes like timeout, env, etc.\n const stripped = command.replace(/^\\s*(timeout\\s+\\d+\\s+|env\\s+\\S+=\\S+\\s+)*/, \"\");\n const firstWord = stripped.trim().split(/\\s+/)[0];\n return TRUSTED_COMMANDS.includes(firstWord);\n}\n\nexport class ExecTool extends Tool {\n readonly name = \"exec\";\n readonly description =\n \"Execute a shell command and return its output. Use for running programs, scripts, git, etc.\";\n readonly parameters = {\n type: \"object\",\n properties: {\n command: { type: \"string\", description: \"Shell command to execute\" },\n timeout: {\n type: \"integer\",\n description: \"Timeout in seconds (default: 60)\",\n },\n },\n required: [\"command\"],\n };\n\n private workingDir: string;\n private defaultTimeout: number;\n private restrictToWorkspace: boolean;\n\n constructor(params?: {\n workingDir?: string;\n timeout?: number;\n restrictToWorkspace?: boolean;\n }) {\n super();\n this.workingDir = params?.workingDir ?? process.cwd();\n this.defaultTimeout = params?.timeout ?? 60;\n this.restrictToWorkspace = params?.restrictToWorkspace ?? false;\n }\n\n async execute(args: Record<string, unknown>): Promise<string> {\n const command = String(args.command);\n const timeout = args.timeout ? Number(args.timeout) : this.defaultTimeout;\n\n if (!command.trim()) {\n return \"Error: Empty command\";\n }\n\n // Safety checks when restricted to workspace\n if (this.restrictToWorkspace) {\n const dangerous = [\"rm -rf /\", \"mkfs\", \"dd if=\", \"> /dev/\"];\n for (const pattern of dangerous) {\n if (command.includes(pattern)) {\n return `Error: Command blocked for safety: ${pattern}`;\n }\n }\n }\n\n // Build env: scrub secrets when restricted, pass through when unrestricted\n let env: Record<string, string>;\n if (!this.restrictToWorkspace) {\n env = { ...process.env, HOME: process.env.HOME ?? \"\" } as Record<string, string>;\n } else if (isTrustedCommand(command)) {\n env = buildSkillEnv();\n // DEBUG: echo the key so we can verify it reaches the child process\n } else {\n env = buildSafeEnv();\n }\n\n return new Promise<string>((resolve) => {\n exec(\n command,\n {\n cwd: this.workingDir,\n timeout: timeout * 1000,\n maxBuffer: 1024 * 1024, // 1MB\n env,\n },\n (error, stdout, stderr) => {\n const parts: string[] = [];\n\n
|
|
1
|
+
{"version":3,"file":"shell.mjs","names":[],"sources":["../../../src/agent/tools/shell.ts"],"sourcesContent":["import { exec, spawn } from \"node:child_process\";\nimport { Tool } from \"./base.js\";\n\n/** Env var patterns that should never leak to user-invoked commands. */\nconst SENSITIVE_ENV_PATTERNS = [\n /api[_-]?key/i,\n /api[_-]?token/i,\n /api[_-]?secret/i,\n /secret/i,\n /token/i,\n /password/i,\n /credential/i,\n /^LLM_/i,\n /^OPENROUTER_/i,\n /^OPENAI_/i,\n /^ANTHROPIC_/i,\n /^STRIPE_/i,\n /^LINE_CHANNEL/i,\n /^APIFY_/i,\n /^Z_AI_/i,\n /^BRAVE_/i,\n /^AWS_/i,\n /^GOOGLE_/i,\n /^AZURE_/i,\n /^NANOBOT_/i,\n];\n\n/**\n * Trusted commands that receive skill-specific env vars.\n * Only the first word (binary name) of the command is matched.\n * These commands still do NOT get the core LLM/channel secrets.\n */\nconst TRUSTED_COMMANDS = [\"summarize\"];\n\n/** Env vars injected for trusted commands only. */\nconst SKILL_ENV_KEYS = [\n \"LLM_API_KEY\",\n \"LLM_API_BASE\",\n \"APIFY_API_TOKEN\",\n];\n\n/** Build a sanitized env for child processes — strips all secrets. */\nfunction buildSafeEnv(): Record<string, string> {\n const safe: Record<string, string> = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (!value) continue;\n if (SENSITIVE_ENV_PATTERNS.some((re) => re.test(key))) continue;\n safe[key] = value;\n }\n return safe;\n}\n\n/** Build env for trusted skill commands — safe env + skill-specific keys. */\nfunction buildSkillEnv(): Record<string, string> {\n const env = buildSafeEnv();\n for (const key of SKILL_ENV_KEYS) {\n const value = process.env[key];\n if (value) env[key] = value;\n }\n return env;\n}\n\n/** Check if a command starts with a trusted binary. */\nfunction isTrustedCommand(command: string): boolean {\n // Extract the first word, stripping common prefixes like timeout, env, etc.\n const stripped = command.replace(/^\\s*(timeout\\s+\\d+\\s+|env\\s+\\S+=\\S+\\s+)*/, \"\");\n const firstWord = stripped.trim().split(/\\s+/)[0];\n return TRUSTED_COMMANDS.includes(firstWord);\n}\n\nexport class ExecTool extends Tool {\n readonly name = \"exec\";\n readonly description =\n \"Execute a shell command and return its output. Use for running programs, scripts, git, etc.\";\n readonly parameters = {\n type: \"object\",\n properties: {\n command: { type: \"string\", description: \"Shell command to execute\" },\n timeout: {\n type: \"integer\",\n description: \"Timeout in seconds (default: 60)\",\n },\n },\n required: [\"command\"],\n };\n\n private workingDir: string;\n private defaultTimeout: number;\n private restrictToWorkspace: boolean;\n\n constructor(params?: {\n workingDir?: string;\n timeout?: number;\n restrictToWorkspace?: boolean;\n }) {\n super();\n this.workingDir = params?.workingDir ?? process.cwd();\n this.defaultTimeout = params?.timeout ?? 60;\n this.restrictToWorkspace = params?.restrictToWorkspace ?? false;\n }\n\n async execute(args: Record<string, unknown>): Promise<string> {\n const command = String(args.command);\n const timeout = args.timeout ? Number(args.timeout) : this.defaultTimeout;\n\n if (!command.trim()) {\n return \"Error: Empty command\";\n }\n\n // Safety checks when restricted to workspace\n if (this.restrictToWorkspace) {\n const dangerous = [\"rm -rf /\", \"mkfs\", \"dd if=\", \"> /dev/\"];\n for (const pattern of dangerous) {\n if (command.includes(pattern)) {\n return `Error: Command blocked for safety: ${pattern}`;\n }\n }\n }\n\n // Build env: scrub secrets when restricted, pass through when unrestricted\n let env: Record<string, string>;\n if (!this.restrictToWorkspace) {\n env = { ...process.env, HOME: process.env.HOME ?? \"\" } as Record<string, string>;\n } else if (isTrustedCommand(command)) {\n env = buildSkillEnv();\n // DEBUG: echo the key so we can verify it reaches the child process\n } else {\n env = buildSafeEnv();\n }\n\n return new Promise<string>((resolve) => {\n exec(\n command,\n {\n cwd: this.workingDir,\n timeout: timeout * 1000,\n maxBuffer: 1024 * 1024, // 1MB\n env,\n },\n (error, stdout, stderr) => {\n const parts: string[] = [];\n\n if (stdout) parts.push(stdout);\n if (stderr) parts.push(`[stderr]\\n${stderr}`);\n\n if (error) {\n if (error.killed) {\n parts.push(`\\n[Timed out after ${timeout}s]`);\n } else if (error.code !== undefined) {\n parts.push(`\\n[Exit code: ${error.code}]`);\n }\n }\n\n const output = parts.join(\"\\n\").trim();\n // Truncate large output\n if (output.length > 50000) {\n resolve(\n output.slice(0, 50000) + \"\\n... (truncated, output too large)\",\n );\n } else {\n resolve(output || \"(no output)\");\n }\n },\n );\n\n });\n }\n}\n"],"mappings":";;;;;AAIA,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;AAOD,MAAM,mBAAmB,CAAC,YAAY;;AAGtC,MAAM,iBAAiB;CACrB;CACA;CACA;CACD;;AAGD,SAAS,eAAuC;CAC9C,MAAM,OAA+B,EAAE;AACvC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,IAAI,EAAE;AACtD,MAAI,CAAC,MAAO;AACZ,MAAI,uBAAuB,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,CAAE;AACvD,OAAK,OAAO;;AAEd,QAAO;;;AAIT,SAAS,gBAAwC;CAC/C,MAAM,MAAM,cAAc;AAC1B,MAAK,MAAM,OAAO,gBAAgB;EAChC,MAAM,QAAQ,QAAQ,IAAI;AAC1B,MAAI,MAAO,KAAI,OAAO;;AAExB,QAAO;;;AAIT,SAAS,iBAAiB,SAA0B;CAGlD,MAAM,YADW,QAAQ,QAAQ,4CAA4C,GAAG,CACrD,MAAM,CAAC,MAAM,MAAM,CAAC;AAC/C,QAAO,iBAAiB,SAAS,UAAU;;AAG7C,IAAa,WAAb,cAA8B,KAAK;CACjC,AAAS,OAAO;CAChB,AAAS,cACP;CACF,AAAS,aAAa;EACpB,MAAM;EACN,YAAY;GACV,SAAS;IAAE,MAAM;IAAU,aAAa;IAA4B;GACpE,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACF;EACD,UAAU,CAAC,UAAU;EACtB;CAED,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YAAY,QAIT;AACD,SAAO;AACP,OAAK,aAAa,QAAQ,cAAc,QAAQ,KAAK;AACrD,OAAK,iBAAiB,QAAQ,WAAW;AACzC,OAAK,sBAAsB,QAAQ,uBAAuB;;CAG5D,MAAM,QAAQ,MAAgD;EAC5D,MAAM,UAAU,OAAO,KAAK,QAAQ;EACpC,MAAM,UAAU,KAAK,UAAU,OAAO,KAAK,QAAQ,GAAG,KAAK;AAE3D,MAAI,CAAC,QAAQ,MAAM,CACjB,QAAO;AAIT,MAAI,KAAK,qBAEP;QAAK,MAAM,WADO;IAAC;IAAY;IAAQ;IAAU;IAAU,CAEzD,KAAI,QAAQ,SAAS,QAAQ,CAC3B,QAAO,sCAAsC;;EAMnD,IAAI;AACJ,MAAI,CAAC,KAAK,oBACR,OAAM;GAAE,GAAG,QAAQ;GAAK,MAAM,QAAQ,IAAI,QAAQ;GAAI;WAC7C,iBAAiB,QAAQ,CAClC,OAAM,eAAe;MAGrB,OAAM,cAAc;AAGtB,SAAO,IAAI,SAAiB,YAAY;AACtC,QACE,SACA;IACE,KAAK,KAAK;IACV,SAAS,UAAU;IACnB,WAAW,OAAO;IAClB;IACD,GACA,OAAO,QAAQ,WAAW;IACzB,MAAM,QAAkB,EAAE;AAE1B,QAAI,OAAQ,OAAM,KAAK,OAAO;AAC9B,QAAI,OAAQ,OAAM,KAAK,aAAa,SAAS;AAE7C,QAAI,OACF;SAAI,MAAM,OACR,OAAM,KAAK,sBAAsB,QAAQ,IAAI;cACpC,MAAM,SAAS,OACxB,OAAM,KAAK,iBAAiB,MAAM,KAAK,GAAG;;IAI9C,MAAM,SAAS,MAAM,KAAK,KAAK,CAAC,MAAM;AAEtC,QAAI,OAAO,SAAS,IAClB,SACE,OAAO,MAAM,GAAG,IAAM,GAAG,sCAC1B;QAED,SAAQ,UAAU,cAAc;KAGrC;IAED"}
|
package/dist/config/schema.d.mts
CHANGED
|
@@ -70,31 +70,31 @@ declare const ChannelsConfigSchema: z.ZodObject<{
|
|
|
70
70
|
channelAccessToken?: string | undefined;
|
|
71
71
|
}>>;
|
|
72
72
|
}, "strip", z.ZodTypeAny, {
|
|
73
|
-
line: {
|
|
74
|
-
enabled: boolean;
|
|
75
|
-
allowFrom: string[];
|
|
76
|
-
channelSecret: string;
|
|
77
|
-
channelAccessToken: string;
|
|
78
|
-
};
|
|
79
73
|
telegram: {
|
|
80
74
|
enabled: boolean;
|
|
81
75
|
token: string;
|
|
82
76
|
allowFrom: string[];
|
|
83
77
|
proxy?: string | null | undefined;
|
|
84
78
|
};
|
|
79
|
+
line: {
|
|
80
|
+
enabled: boolean;
|
|
81
|
+
allowFrom: string[];
|
|
82
|
+
channelSecret: string;
|
|
83
|
+
channelAccessToken: string;
|
|
84
|
+
};
|
|
85
85
|
}, {
|
|
86
|
-
line?: {
|
|
87
|
-
enabled?: boolean | undefined;
|
|
88
|
-
allowFrom?: string[] | undefined;
|
|
89
|
-
channelSecret?: string | undefined;
|
|
90
|
-
channelAccessToken?: string | undefined;
|
|
91
|
-
} | undefined;
|
|
92
86
|
telegram?: {
|
|
93
87
|
enabled?: boolean | undefined;
|
|
94
88
|
token?: string | undefined;
|
|
95
89
|
allowFrom?: string[] | undefined;
|
|
96
90
|
proxy?: string | null | undefined;
|
|
97
91
|
} | undefined;
|
|
92
|
+
line?: {
|
|
93
|
+
enabled?: boolean | undefined;
|
|
94
|
+
allowFrom?: string[] | undefined;
|
|
95
|
+
channelSecret?: string | undefined;
|
|
96
|
+
channelAccessToken?: string | undefined;
|
|
97
|
+
} | undefined;
|
|
98
98
|
}>;
|
|
99
99
|
type ChannelsConfig = z.infer<typeof ChannelsConfigSchema>;
|
|
100
100
|
declare const AgentDefaultsSchema: z.ZodObject<{
|
|
@@ -648,31 +648,31 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
648
648
|
channelAccessToken?: string | undefined;
|
|
649
649
|
}>>;
|
|
650
650
|
}, "strip", z.ZodTypeAny, {
|
|
651
|
-
line: {
|
|
652
|
-
enabled: boolean;
|
|
653
|
-
allowFrom: string[];
|
|
654
|
-
channelSecret: string;
|
|
655
|
-
channelAccessToken: string;
|
|
656
|
-
};
|
|
657
651
|
telegram: {
|
|
658
652
|
enabled: boolean;
|
|
659
653
|
token: string;
|
|
660
654
|
allowFrom: string[];
|
|
661
655
|
proxy?: string | null | undefined;
|
|
662
656
|
};
|
|
657
|
+
line: {
|
|
658
|
+
enabled: boolean;
|
|
659
|
+
allowFrom: string[];
|
|
660
|
+
channelSecret: string;
|
|
661
|
+
channelAccessToken: string;
|
|
662
|
+
};
|
|
663
663
|
}, {
|
|
664
|
-
line?: {
|
|
665
|
-
enabled?: boolean | undefined;
|
|
666
|
-
allowFrom?: string[] | undefined;
|
|
667
|
-
channelSecret?: string | undefined;
|
|
668
|
-
channelAccessToken?: string | undefined;
|
|
669
|
-
} | undefined;
|
|
670
664
|
telegram?: {
|
|
671
665
|
enabled?: boolean | undefined;
|
|
672
666
|
token?: string | undefined;
|
|
673
667
|
allowFrom?: string[] | undefined;
|
|
674
668
|
proxy?: string | null | undefined;
|
|
675
669
|
} | undefined;
|
|
670
|
+
line?: {
|
|
671
|
+
enabled?: boolean | undefined;
|
|
672
|
+
allowFrom?: string[] | undefined;
|
|
673
|
+
channelSecret?: string | undefined;
|
|
674
|
+
channelAccessToken?: string | undefined;
|
|
675
|
+
} | undefined;
|
|
676
676
|
}>>;
|
|
677
677
|
providers: z.ZodDefault<z.ZodObject<{
|
|
678
678
|
anthropic: z.ZodDefault<z.ZodObject<{
|
|
@@ -1035,18 +1035,18 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
1035
1035
|
};
|
|
1036
1036
|
};
|
|
1037
1037
|
channels: {
|
|
1038
|
-
line: {
|
|
1039
|
-
enabled: boolean;
|
|
1040
|
-
allowFrom: string[];
|
|
1041
|
-
channelSecret: string;
|
|
1042
|
-
channelAccessToken: string;
|
|
1043
|
-
};
|
|
1044
1038
|
telegram: {
|
|
1045
1039
|
enabled: boolean;
|
|
1046
1040
|
token: string;
|
|
1047
1041
|
allowFrom: string[];
|
|
1048
1042
|
proxy?: string | null | undefined;
|
|
1049
1043
|
};
|
|
1044
|
+
line: {
|
|
1045
|
+
enabled: boolean;
|
|
1046
|
+
allowFrom: string[];
|
|
1047
|
+
channelSecret: string;
|
|
1048
|
+
channelAccessToken: string;
|
|
1049
|
+
};
|
|
1050
1050
|
};
|
|
1051
1051
|
providers: {
|
|
1052
1052
|
anthropic: {
|
|
@@ -1139,18 +1139,18 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
1139
1139
|
} | undefined;
|
|
1140
1140
|
} | undefined;
|
|
1141
1141
|
channels?: {
|
|
1142
|
-
line?: {
|
|
1143
|
-
enabled?: boolean | undefined;
|
|
1144
|
-
allowFrom?: string[] | undefined;
|
|
1145
|
-
channelSecret?: string | undefined;
|
|
1146
|
-
channelAccessToken?: string | undefined;
|
|
1147
|
-
} | undefined;
|
|
1148
1142
|
telegram?: {
|
|
1149
1143
|
enabled?: boolean | undefined;
|
|
1150
1144
|
token?: string | undefined;
|
|
1151
1145
|
allowFrom?: string[] | undefined;
|
|
1152
1146
|
proxy?: string | null | undefined;
|
|
1153
1147
|
} | undefined;
|
|
1148
|
+
line?: {
|
|
1149
|
+
enabled?: boolean | undefined;
|
|
1150
|
+
allowFrom?: string[] | undefined;
|
|
1151
|
+
channelSecret?: string | undefined;
|
|
1152
|
+
channelAccessToken?: string | undefined;
|
|
1153
|
+
} | undefined;
|
|
1154
1154
|
} | undefined;
|
|
1155
1155
|
providers?: {
|
|
1156
1156
|
anthropic?: {
|