jinzd-ai-cli 0.4.207 → 0.4.208

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.
Files changed (26) hide show
  1. package/dist/{batch-6PORMJWT.js → batch-3T44NFLG.js} +2 -2
  2. package/dist/{chunk-QQYSZMET.js → chunk-2OVMMSGQ.js} +3 -3
  3. package/dist/{chunk-2WV6AGHM.js → chunk-J22B3OSQ.js} +1 -1
  4. package/dist/{chunk-QNUVZO5X.js → chunk-KV4GYNEA.js} +1 -1
  5. package/dist/{chunk-KJHMRAJU.js → chunk-P7JY3SWA.js} +1 -1
  6. package/dist/{chunk-BQIV4ZQT.js → chunk-QDY72ABW.js} +1 -1
  7. package/dist/{chunk-KOU4KX7J.js → chunk-TD7JEHCR.js} +2 -2
  8. package/dist/{chunk-TW47X5AO.js → chunk-TM4MS63K.js} +1 -1
  9. package/dist/{chunk-SFCNFX42.js → chunk-VWYUB22Y.js} +1 -1
  10. package/dist/{ci-AYMV66P3.js → ci-6QWBVRJX.js} +2 -2
  11. package/dist/{constants-NHGTSHKT.js → constants-SZTQNN7K.js} +1 -1
  12. package/dist/{doctor-cli-WKH7T4AW.js → doctor-cli-I2Y2YR4V.js} +4 -4
  13. package/dist/electron-server.js +2 -2
  14. package/dist/{hub-6R3M3NTC.js → hub-XVPFBODB.js} +1 -1
  15. package/dist/index.js +16 -16
  16. package/dist/{run-tests-5F2OBWIK.js → run-tests-D5SNUBYX.js} +2 -2
  17. package/dist/{run-tests-NBCA4KEG.js → run-tests-HZ2CRCTZ.js} +1 -1
  18. package/dist/{server-L2MXWYF7.js → server-4EFTRFTN.js} +7 -7
  19. package/dist/{server-37EXC4EB.js → server-PVKLPRUP.js} +4 -4
  20. package/dist/{task-orchestrator-2DTDVCMR.js → task-orchestrator-2A5VCFLS.js} +4 -4
  21. package/dist/{usage-SZWZFX3T.js → usage-Q24E5636.js} +2 -2
  22. package/dist/web/client/actions.js +78 -78
  23. package/dist/web/client/app.js +5 -5
  24. package/dist/web/client/index.html +1 -1
  25. package/dist/web/client/templates.js +188 -188
  26. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-TW47X5AO.js";
4
+ } from "./chunk-TM4MS63K.js";
5
5
  import "./chunk-TZQHYZKT.js";
6
- import "./chunk-QNUVZO5X.js";
6
+ import "./chunk-KV4GYNEA.js";
7
7
  import {
8
8
  atomicWriteFileSync
9
9
  } from "./chunk-IW3Q7AE5.js";
@@ -5,10 +5,10 @@ import {
5
5
  } from "./chunk-T2NL5ZIA.js";
6
6
  import {
7
7
  runTestsTool
8
- } from "./chunk-SFCNFX42.js";
8
+ } from "./chunk-VWYUB22Y.js";
9
9
  import {
10
10
  runTool
11
- } from "./chunk-2WV6AGHM.js";
11
+ } from "./chunk-J22B3OSQ.js";
12
12
  import {
13
13
  getDangerLevel,
14
14
  isFileWriteTool,
@@ -26,7 +26,7 @@ import {
26
26
  SUBAGENT_ALLOWED_TOOLS,
27
27
  SUBAGENT_DEFAULT_MAX_ROUNDS,
28
28
  SUBAGENT_MAX_ROUNDS_LIMIT
29
- } from "./chunk-QNUVZO5X.js";
29
+ } from "./chunk-KV4GYNEA.js";
30
30
  import {
31
31
  fileCheckpoints
32
32
  } from "./chunk-4BKXL7SM.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CONFIG_DIR_NAME
4
- } from "./chunk-QNUVZO5X.js";
4
+ } from "./chunk-KV4GYNEA.js";
5
5
  import {
6
6
  atomicWriteFileSync
7
7
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.206";
4
+ var VERSION = "0.4.208";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  VERSION
5
- } from "./chunk-QNUVZO5X.js";
5
+ } from "./chunk-KV4GYNEA.js";
6
6
 
7
7
  // src/diagnostics/crash-log.ts
8
8
  import {
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.206";
9
+ var VERSION = "0.4.208";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  truncateForPersist
4
- } from "./chunk-QQYSZMET.js";
4
+ } from "./chunk-2OVMMSGQ.js";
5
5
  import {
6
6
  APP_NAME,
7
7
  CONFIG_DIR_NAME,
@@ -11,7 +11,7 @@ import {
11
11
  MCP_PROTOCOL_VERSION,
12
12
  MCP_TOOL_PREFIX,
13
13
  VERSION
14
- } from "./chunk-QNUVZO5X.js";
14
+ } from "./chunk-KV4GYNEA.js";
15
15
 
16
16
  // src/mcp/client.ts
17
17
  import { spawn } from "child_process";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-QNUVZO5X.js";
11
+ } from "./chunk-KV4GYNEA.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-QNUVZO5X.js";
4
+ } from "./chunk-KV4GYNEA.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -10,11 +10,11 @@ import {
10
10
  import "./chunk-XPBEJB27.js";
11
11
  import {
12
12
  ConfigManager
13
- } from "./chunk-TW47X5AO.js";
13
+ } from "./chunk-TM4MS63K.js";
14
14
  import "./chunk-TZQHYZKT.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-QNUVZO5X.js";
17
+ } from "./chunk-KV4GYNEA.js";
18
18
 
19
19
  // src/cli/ci.ts
20
20
  import { execFileSync } from "child_process";
@@ -36,7 +36,7 @@ import {
36
36
  TEST_TIMEOUT,
37
37
  VERSION,
38
38
  buildUserIdentityPrompt
39
- } from "./chunk-QNUVZO5X.js";
39
+ } from "./chunk-KV4GYNEA.js";
40
40
  export {
41
41
  AGENTIC_BEHAVIOR_GUIDELINE,
42
42
  APP_NAME,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getConfigDirUsage,
4
4
  listRecentCrashes
5
- } from "./chunk-KJHMRAJU.js";
5
+ } from "./chunk-P7JY3SWA.js";
6
6
  import {
7
7
  ProviderRegistry
8
8
  } from "./chunk-QMXC327F.js";
@@ -11,17 +11,17 @@ import {
11
11
  getTopFailingTools,
12
12
  getTopUsedTools,
13
13
  resetStats
14
- } from "./chunk-2WV6AGHM.js";
14
+ } from "./chunk-J22B3OSQ.js";
15
15
  import "./chunk-XPBEJB27.js";
16
16
  import {
17
17
  ConfigManager
18
- } from "./chunk-TW47X5AO.js";
18
+ } from "./chunk-TM4MS63K.js";
19
19
  import "./chunk-TZQHYZKT.js";
20
20
  import {
21
21
  DEV_STATE_FILE_NAME,
22
22
  MEMORY_FILE_NAME,
23
23
  VERSION
24
- } from "./chunk-QNUVZO5X.js";
24
+ } from "./chunk-KV4GYNEA.js";
25
25
  import "./chunk-IW3Q7AE5.js";
26
26
 
27
27
  // src/diagnostics/doctor-cli.ts
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-BQIV4ZQT.js";
39
+ } from "./chunk-QDY72ABW.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -14373,7 +14373,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
14373
14373
  case "test": {
14374
14374
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
14375
14375
  try {
14376
- const { executeTests } = await import("./run-tests-NBCA4KEG.js");
14376
+ const { executeTests } = await import("./run-tests-HZ2CRCTZ.js");
14377
14377
  const argStr = args.join(" ").trim();
14378
14378
  let testArgs = {};
14379
14379
  if (argStr) {
@@ -154,7 +154,7 @@ ${content}`);
154
154
  }
155
155
  }
156
156
  async function runTaskMode(config, providers, configManager, topic) {
157
- const { TaskOrchestrator } = await import("./task-orchestrator-2DTDVCMR.js");
157
+ const { TaskOrchestrator } = await import("./task-orchestrator-2A5VCFLS.js");
158
158
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
159
159
  let interrupted = false;
160
160
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  saveDevState,
16
16
  sessionHasMeaningfulContent,
17
17
  setupProxy
18
- } from "./chunk-KOU4KX7J.js";
18
+ } from "./chunk-TD7JEHCR.js";
19
19
  import {
20
20
  ToolExecutor,
21
21
  ToolRegistry,
@@ -35,10 +35,10 @@ import {
35
35
  spawnAgentContext,
36
36
  theme,
37
37
  undoStack
38
- } from "./chunk-QQYSZMET.js";
38
+ } from "./chunk-2OVMMSGQ.js";
39
39
  import "./chunk-T2NL5ZIA.js";
40
40
  import "./chunk-BXP6YZ2P.js";
41
- import "./chunk-SFCNFX42.js";
41
+ import "./chunk-VWYUB22Y.js";
42
42
  import {
43
43
  SessionManager,
44
44
  getContentText
@@ -55,7 +55,7 @@ import {
55
55
  getConfigDirUsage,
56
56
  listRecentCrashes,
57
57
  writeCrashLog
58
- } from "./chunk-KJHMRAJU.js";
58
+ } from "./chunk-P7JY3SWA.js";
59
59
  import {
60
60
  ProviderRegistry
61
61
  } from "./chunk-QMXC327F.js";
@@ -64,7 +64,7 @@ import {
64
64
  getTopFailingTools,
65
65
  getTopUsedTools,
66
66
  installFlushOnExit
67
- } from "./chunk-2WV6AGHM.js";
67
+ } from "./chunk-J22B3OSQ.js";
68
68
  import {
69
69
  CONTENT_ONLY_STREAM_REMINDER,
70
70
  TEE_FINAL_USER_NUDGE,
@@ -86,7 +86,7 @@ import {
86
86
  } from "./chunk-XPBEJB27.js";
87
87
  import {
88
88
  ConfigManager
89
- } from "./chunk-TW47X5AO.js";
89
+ } from "./chunk-TM4MS63K.js";
90
90
  import {
91
91
  AuthError,
92
92
  ProviderError,
@@ -113,7 +113,7 @@ import {
113
113
  SKILLS_DIR_NAME,
114
114
  VERSION,
115
115
  buildUserIdentityPrompt
116
- } from "./chunk-QNUVZO5X.js";
116
+ } from "./chunk-KV4GYNEA.js";
117
117
  import {
118
118
  formatGitContextForPrompt,
119
119
  getGitContext,
@@ -1832,7 +1832,7 @@ No tools match "${filter}".
1832
1832
  const { join: join6 } = await import("path");
1833
1833
  const { existsSync: existsSync6 } = await import("fs");
1834
1834
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1835
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-NHGTSHKT.js");
1835
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-SZTQNN7K.js");
1836
1836
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1837
1837
  const cwd = process.cwd();
1838
1838
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2893,7 +2893,7 @@ ${hint}` : "")
2893
2893
  usage: "/test [command|filter]",
2894
2894
  async execute(args, ctx) {
2895
2895
  try {
2896
- const { executeTests } = await import("./run-tests-5F2OBWIK.js");
2896
+ const { executeTests } = await import("./run-tests-D5SNUBYX.js");
2897
2897
  const argStr = args.join(" ").trim();
2898
2898
  let testArgs = {};
2899
2899
  if (argStr) {
@@ -7271,7 +7271,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7271
7271
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7272
7272
  process.exit(1);
7273
7273
  }
7274
- const { startWebServer } = await import("./server-L2MXWYF7.js");
7274
+ const { startWebServer } = await import("./server-4EFTRFTN.js");
7275
7275
  await startWebServer({ port, host: options.host });
7276
7276
  });
7277
7277
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -7438,16 +7438,16 @@ program.command("sessions").description("List recent conversation sessions").opt
7438
7438
  console.log(footer + "\n");
7439
7439
  });
7440
7440
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
7441
- const { runUsageCli } = await import("./usage-SZWZFX3T.js");
7441
+ const { runUsageCli } = await import("./usage-Q24E5636.js");
7442
7442
  await runUsageCli(options);
7443
7443
  });
7444
7444
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
7445
- const { runDoctorCli } = await import("./doctor-cli-WKH7T4AW.js");
7445
+ const { runDoctorCli } = await import("./doctor-cli-I2Y2YR4V.js");
7446
7446
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7447
7447
  });
7448
7448
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
7449
7449
  try {
7450
- const batch = await import("./batch-6PORMJWT.js");
7450
+ const batch = await import("./batch-3T44NFLG.js");
7451
7451
  switch (action) {
7452
7452
  case "submit":
7453
7453
  if (!arg) {
@@ -7490,7 +7490,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7490
7490
  }
7491
7491
  });
7492
7492
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
7493
- const { startMcpServer } = await import("./server-37EXC4EB.js");
7493
+ const { startMcpServer } = await import("./server-PVKLPRUP.js");
7494
7494
  await startMcpServer({
7495
7495
  allowDestructive: !!options.allowDestructive,
7496
7496
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7499,7 +7499,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
7499
7499
  });
7500
7500
  });
7501
7501
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).option("--base <ref>", "Base ref for `git diff <ref>...HEAD` (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").action(async (options) => {
7502
- const { runCi } = await import("./ci-AYMV66P3.js");
7502
+ const { runCi } = await import("./ci-6QWBVRJX.js");
7503
7503
  const result = await runCi({
7504
7504
  pr: options.pr,
7505
7505
  base: options.base,
@@ -7645,7 +7645,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7645
7645
  }),
7646
7646
  config.get("customProviders")
7647
7647
  );
7648
- const { startHub } = await import("./hub-6R3M3NTC.js");
7648
+ const { startHub } = await import("./hub-XVPFBODB.js");
7649
7649
  await startHub(
7650
7650
  {
7651
7651
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-SFCNFX42.js";
6
- import "./chunk-QNUVZO5X.js";
5
+ } from "./chunk-VWYUB22Y.js";
6
+ import "./chunk-KV4GYNEA.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-BQIV4ZQT.js";
4
+ } from "./chunk-QDY72ABW.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -19,7 +19,7 @@ import {
19
19
  loadDevState,
20
20
  persistToolRound,
21
21
  setupProxy
22
- } from "./chunk-KOU4KX7J.js";
22
+ } from "./chunk-TD7JEHCR.js";
23
23
  import {
24
24
  ToolExecutor,
25
25
  ToolRegistry,
@@ -38,10 +38,10 @@ import {
38
38
  spawnAgentContext,
39
39
  truncateOutput,
40
40
  undoStack
41
- } from "./chunk-QQYSZMET.js";
41
+ } from "./chunk-2OVMMSGQ.js";
42
42
  import "./chunk-T2NL5ZIA.js";
43
43
  import "./chunk-BXP6YZ2P.js";
44
- import "./chunk-SFCNFX42.js";
44
+ import "./chunk-VWYUB22Y.js";
45
45
  import {
46
46
  SessionManager,
47
47
  getContentText
@@ -55,7 +55,7 @@ import {
55
55
  } from "./chunk-QMXC327F.js";
56
56
  import {
57
57
  runTool
58
- } from "./chunk-2WV6AGHM.js";
58
+ } from "./chunk-J22B3OSQ.js";
59
59
  import {
60
60
  CONTENT_ONLY_STREAM_REMINDER,
61
61
  TEE_FINAL_USER_NUDGE,
@@ -74,7 +74,7 @@ import {
74
74
  } from "./chunk-XPBEJB27.js";
75
75
  import {
76
76
  ConfigManager
77
- } from "./chunk-TW47X5AO.js";
77
+ } from "./chunk-TM4MS63K.js";
78
78
  import "./chunk-TZQHYZKT.js";
79
79
  import {
80
80
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -94,7 +94,7 @@ import {
94
94
  SKILLS_DIR_NAME,
95
95
  VERSION,
96
96
  buildUserIdentityPrompt
97
- } from "./chunk-QNUVZO5X.js";
97
+ } from "./chunk-KV4GYNEA.js";
98
98
  import {
99
99
  formatGitContextForPrompt,
100
100
  getGitContext,
@@ -2458,7 +2458,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2458
2458
  case "test": {
2459
2459
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2460
2460
  try {
2461
- const { executeTests } = await import("./run-tests-5F2OBWIK.js");
2461
+ const { executeTests } = await import("./run-tests-D5SNUBYX.js");
2462
2462
  const argStr = args.join(" ").trim();
2463
2463
  let testArgs = {};
2464
2464
  if (argStr) {
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-QQYSZMET.js";
4
+ } from "./chunk-2OVMMSGQ.js";
5
5
  import "./chunk-T2NL5ZIA.js";
6
6
  import "./chunk-BXP6YZ2P.js";
7
- import "./chunk-SFCNFX42.js";
7
+ import "./chunk-VWYUB22Y.js";
8
8
  import {
9
9
  runTool
10
- } from "./chunk-2WV6AGHM.js";
10
+ } from "./chunk-J22B3OSQ.js";
11
11
  import {
12
12
  getDangerLevel,
13
13
  schemaToJsonSchema
@@ -15,7 +15,7 @@ import {
15
15
  import "./chunk-TZQHYZKT.js";
16
16
  import {
17
17
  VERSION
18
- } from "./chunk-QNUVZO5X.js";
18
+ } from "./chunk-KV4GYNEA.js";
19
19
  import "./chunk-4BKXL7SM.js";
20
20
  import "./chunk-TB4W4Y4T.js";
21
21
  import "./chunk-KHYD3WXE.js";
@@ -3,13 +3,13 @@ import {
3
3
  ToolRegistry,
4
4
  googleSearchContext,
5
5
  truncateOutput
6
- } from "./chunk-QQYSZMET.js";
6
+ } from "./chunk-2OVMMSGQ.js";
7
7
  import "./chunk-T2NL5ZIA.js";
8
8
  import "./chunk-BXP6YZ2P.js";
9
- import "./chunk-SFCNFX42.js";
9
+ import "./chunk-VWYUB22Y.js";
10
10
  import {
11
11
  runTool
12
- } from "./chunk-2WV6AGHM.js";
12
+ } from "./chunk-J22B3OSQ.js";
13
13
  import {
14
14
  getDangerLevel,
15
15
  runLeanAgentLoop
@@ -17,7 +17,7 @@ import {
17
17
  import "./chunk-TZQHYZKT.js";
18
18
  import {
19
19
  SUBAGENT_ALLOWED_TOOLS
20
- } from "./chunk-QNUVZO5X.js";
20
+ } from "./chunk-KV4GYNEA.js";
21
21
  import "./chunk-4BKXL7SM.js";
22
22
  import "./chunk-TB4W4Y4T.js";
23
23
  import "./chunk-KHYD3WXE.js";
@@ -8,9 +8,9 @@ import {
8
8
  } from "./chunk-E44DTERW.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-TW47X5AO.js";
11
+ } from "./chunk-TM4MS63K.js";
12
12
  import "./chunk-TZQHYZKT.js";
13
- import "./chunk-QNUVZO5X.js";
13
+ import "./chunk-KV4GYNEA.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
15
 
16
16
  // src/cli/usage.ts
@@ -3,82 +3,82 @@
3
3
  * Kept separate from app.js so static and dynamic UI markup can avoid inline handlers.
4
4
  */
5
5
 
6
- function handleDeclarativeAction(action, el) {
7
- switch (action) {
8
- case 'toggle-auth-mode': toggleAuthMode(); break;
9
- case 'show-enable-auth': showEnableAuthDialog(); break;
10
- case 'logout': handleLogout(); break;
11
- case 'toggle-batch-select': toggleBatchSelect(); break;
12
- case 'select-all-sessions': selectAllSessions(); break;
13
- case 'batch-delete-selected': batchDeleteSelected(); break;
14
- case 'start-hub': window.startHub(); break;
15
- case 'abort-hub': window.abortHub(); break;
16
- case 'close-sidebar': closeSidebar(); break;
17
- case 'import-templates': importTemplates(); break;
18
- case 'export-templates': exportTemplates(); break;
19
- case 'show-add-template': showAddTemplate(); break;
20
- case 'cancel-template-form': cancelTemplateForm(); break;
21
- case 'save-template-form': saveTemplateForm(); break;
22
- case 'confirm-response': window.respondConfirm(el.dataset.requestId, el.dataset.approved === 'true'); break;
23
- case 'batch-confirm-response': window.respondBatchConfirm(el.dataset.requestId, el); break;
24
- case 'batch-deny-response': window.respondBatchDeny(el.dataset.requestId, el); break;
25
- case 'ask-user-response': window.respondAskUser(el.dataset.requestId); break;
26
- case 'auto-pause-response': window.respondAutoPause(el.dataset.requestId, el.dataset.pauseAction); break;
27
- case 'use-template': useTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
28
- case 'edit-template': editTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
29
- case 'delete-template': deleteTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
30
- case 'insert-file-ref': insertFileRef(el.dataset.filePath || ''); break;
31
- case 'show-full-preview':
32
- if (el.previousElementSibling) el.previousElementSibling.style.maxHeight = 'none';
33
- el.remove();
34
- break;
35
- case 'load-session': send({ type: 'command', name: 'session', args: ['load', el.dataset.sessionId] }); break;
36
- }
37
- }
38
-
39
- document.addEventListener('click', (event) => {
40
- const themeEl = event.target.closest('[data-theme-choice]');
41
- if (themeEl) {
42
- event.preventDefault();
43
- window.setTheme(themeEl.dataset.themeChoice);
44
- return;
45
- }
46
-
47
- const actionEl = event.target.closest('[data-action]');
48
- if (!actionEl) return;
49
- event.preventDefault();
50
- handleDeclarativeAction(actionEl.dataset.action, actionEl);
51
- });
52
-
53
- document.addEventListener('keydown', (event) => {
54
- if (event.key !== 'Enter') return;
55
- const actionEl = event.target.closest('[data-enter-action]');
56
- if (!actionEl) return;
57
- event.preventDefault();
58
- handleDeclarativeAction(actionEl.dataset.enterAction, actionEl);
59
- });
60
-
61
- document.getElementById('auth-form')?.addEventListener('submit', handleAuth);
62
-
63
- function registerServiceWorker() {
64
- // Self-updating service worker (v0.4.159). A new SW postMessages
65
- // 'sw-updated' (and triggers controllerchange) when it takes over; reload
66
- // once so users do not stay on stale index.html/app.js after an upgrade.
67
- if (!('serviceWorker' in navigator)) return;
68
- let swReloaded = false;
69
- const reloadOnce = () => {
70
- if (!swReloaded) {
71
- swReloaded = true;
72
- location.reload();
73
- }
74
- };
75
- navigator.serviceWorker.addEventListener('message', (e) => {
76
- if (e.data && e.data.type === 'sw-updated') reloadOnce();
77
- });
78
- navigator.serviceWorker.addEventListener('controllerchange', reloadOnce);
79
- navigator.serviceWorker.register('sw.js').then((reg) => {
80
- reg.update();
81
- }).catch(() => {});
82
- }
83
-
6
+ function handleDeclarativeAction(action, el) {
7
+ switch (action) {
8
+ case 'toggle-auth-mode': toggleAuthMode(); break;
9
+ case 'show-enable-auth': showEnableAuthDialog(); break;
10
+ case 'logout': handleLogout(); break;
11
+ case 'toggle-batch-select': toggleBatchSelect(); break;
12
+ case 'select-all-sessions': selectAllSessions(); break;
13
+ case 'batch-delete-selected': batchDeleteSelected(); break;
14
+ case 'start-hub': window.startHub(); break;
15
+ case 'abort-hub': window.abortHub(); break;
16
+ case 'close-sidebar': closeSidebar(); break;
17
+ case 'import-templates': importTemplates(); break;
18
+ case 'export-templates': exportTemplates(); break;
19
+ case 'show-add-template': showAddTemplate(); break;
20
+ case 'cancel-template-form': cancelTemplateForm(); break;
21
+ case 'save-template-form': saveTemplateForm(); break;
22
+ case 'confirm-response': window.respondConfirm(el.dataset.requestId, el.dataset.approved === 'true'); break;
23
+ case 'batch-confirm-response': window.respondBatchConfirm(el.dataset.requestId, el); break;
24
+ case 'batch-deny-response': window.respondBatchDeny(el.dataset.requestId, el); break;
25
+ case 'ask-user-response': window.respondAskUser(el.dataset.requestId); break;
26
+ case 'auto-pause-response': window.respondAutoPause(el.dataset.requestId, el.dataset.pauseAction); break;
27
+ case 'use-template': useTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
28
+ case 'edit-template': editTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
29
+ case 'delete-template': deleteTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
30
+ case 'insert-file-ref': insertFileRef(el.dataset.filePath || ''); break;
31
+ case 'show-full-preview':
32
+ if (el.previousElementSibling) el.previousElementSibling.style.maxHeight = 'none';
33
+ el.remove();
34
+ break;
35
+ case 'load-session': send({ type: 'command', name: 'session', args: ['load', el.dataset.sessionId] }); break;
36
+ }
37
+ }
38
+
39
+ document.addEventListener('click', (event) => {
40
+ const themeEl = event.target.closest('[data-theme-choice]');
41
+ if (themeEl) {
42
+ event.preventDefault();
43
+ window.setTheme(themeEl.dataset.themeChoice);
44
+ return;
45
+ }
46
+
47
+ const actionEl = event.target.closest('[data-action]');
48
+ if (!actionEl) return;
49
+ event.preventDefault();
50
+ handleDeclarativeAction(actionEl.dataset.action, actionEl);
51
+ });
52
+
53
+ document.addEventListener('keydown', (event) => {
54
+ if (event.key !== 'Enter') return;
55
+ const actionEl = event.target.closest('[data-enter-action]');
56
+ if (!actionEl) return;
57
+ event.preventDefault();
58
+ handleDeclarativeAction(actionEl.dataset.enterAction, actionEl);
59
+ });
60
+
61
+ document.getElementById('auth-form')?.addEventListener('submit', handleAuth);
62
+
63
+ function registerServiceWorker() {
64
+ // Self-updating service worker (v0.4.159). A new SW postMessages
65
+ // 'sw-updated' (and triggers controllerchange) when it takes over; reload
66
+ // once so users do not stay on stale index.html/app.js after an upgrade.
67
+ if (!('serviceWorker' in navigator)) return;
68
+ let swReloaded = false;
69
+ const reloadOnce = () => {
70
+ if (!swReloaded) {
71
+ swReloaded = true;
72
+ location.reload();
73
+ }
74
+ };
75
+ navigator.serviceWorker.addEventListener('message', (e) => {
76
+ if (e.data && e.data.type === 'sw-updated') reloadOnce();
77
+ });
78
+ navigator.serviceWorker.addEventListener('controllerchange', reloadOnce);
79
+ navigator.serviceWorker.register('sw.js').then((reg) => {
80
+ reg.update();
81
+ }).catch(() => {});
82
+ }
83
+
84
84
  registerServiceWorker();
@@ -666,7 +666,7 @@ window.setTheme = function(theme) {
666
666
 
667
667
  // ── UI helpers ─────────────────────────────────────────────────────
668
668
 
669
-
669
+
670
670
  function createAssistantMessage() {
671
671
  const el = document.createElement('div');
672
672
  el.className = 'msg-assistant';
@@ -715,10 +715,10 @@ function renderMarkdown(el, text) {
715
715
  const btn = document.createElement('button');
716
716
  btn.className = 'copy-code-btn btn btn-ghost btn-xs';
717
717
  btn.textContent = '📋 Copy';
718
- btn.addEventListener('click', () => {
719
- navigator.clipboard.writeText(block.textContent || '');
720
- btn.textContent = 'Copied';
721
- setTimeout(() => btn.textContent = 'Copy', 1500);
718
+ btn.addEventListener('click', () => {
719
+ navigator.clipboard.writeText(block.textContent || '');
720
+ btn.textContent = 'Copied';
721
+ setTimeout(() => btn.textContent = 'Copy', 1500);
722
722
  });
723
723
  pre.style.position = 'relative';
724
724
  pre.appendChild(btn);
@@ -338,7 +338,7 @@
338
338
  <form method="dialog" class="modal-backdrop"><button>close</button></form>
339
339
  </dialog>
340
340
 
341
- <script src="app.js"></script>
341
+ <script src="app.js"></script>
342
342
  <script src="templates.js"></script>
343
343
  <script src="actions.js"></script>
344
344
  </body>
@@ -1,188 +1,188 @@
1
- /**
2
- * Prompt template modal and import/export helpers.
3
- * Loaded after app.js so it can use shared UI helpers.
4
- */
5
-
6
- const TEMPLATES_KEY = 'aicli-templates';
7
-
8
- function loadTemplates() {
9
- try {
10
- return JSON.parse(localStorage.getItem(TEMPLATES_KEY) || '[]');
11
- } catch {
12
- return [];
13
- }
14
- }
15
-
16
- function saveTemplatesToStorage(templates) {
17
- localStorage.setItem(TEMPLATES_KEY, JSON.stringify(templates));
18
- }
19
-
20
- function openTemplatesModal() {
21
- const modal = document.getElementById('templates-modal');
22
- if (!modal) return;
23
- cancelTemplateForm();
24
- renderTemplateList();
25
- document.getElementById('template-search').value = '';
26
- modal.showModal();
27
- }
28
-
29
- function renderTemplateList(filter) {
30
- const listEl = document.getElementById('template-list');
31
- if (!listEl) return;
32
- const templates = loadTemplates();
33
- const q = (filter || '').toLowerCase();
34
- const filtered = q
35
- ? templates.filter(t => t.name.toLowerCase().includes(q) || (t.tags || []).some(tag => tag.toLowerCase().includes(q)) || t.content.toLowerCase().includes(q))
36
- : templates;
37
-
38
- if (filtered.length === 0) {
39
- listEl.innerHTML = `<div class="template-empty">${q ? 'No matching templates' : 'No templates yet. Click + New to create one.'}</div>`;
40
- return;
41
- }
42
-
43
- listEl.innerHTML = filtered.map(t => {
44
- const preview = t.content.length > 80 ? t.content.slice(0, 80) + '...' : t.content;
45
- const tagsHtml = (t.tags || []).map(tag => `<span class="template-item-tag">${escapeHtml(tag)}</span>`).join('');
46
- return `
47
- <div class="template-item" data-tpl-id="${t.id}" data-action="use-template">
48
- <div class="template-item-body">
49
- <div class="template-item-name">${escapeHtml(t.name)}</div>
50
- <div class="template-item-preview">${escapeHtml(preview)}</div>
51
- ${tagsHtml ? `<div class="template-item-tags">${tagsHtml}</div>` : ''}
52
- </div>
53
- <div class="template-item-actions">
54
- <button class="btn btn-xs btn-ghost" data-action="edit-template" title="Edit">Edit</button>
55
- <button class="btn btn-xs btn-ghost" data-action="delete-template" title="Delete">Delete</button>
56
- </div>
57
- </div>`;
58
- }).join('');
59
- }
60
-
61
- function useTemplate(id) {
62
- const templates = loadTemplates();
63
- const tpl = templates.find(t => t.id === id);
64
- if (!tpl) return;
65
- const input = document.getElementById('user-input');
66
- if (!input) return;
67
- input.value = tpl.content;
68
- input.focus();
69
- input.style.height = 'auto';
70
- input.style.height = Math.min(input.scrollHeight, 200) + 'px';
71
- document.getElementById('templates-modal')?.close();
72
- }
73
-
74
- function showAddTemplate() {
75
- const form = document.getElementById('template-form');
76
- form.classList.remove('hidden');
77
- document.getElementById('tpl-edit-id').value = '';
78
- document.getElementById('tpl-name').value = '';
79
- document.getElementById('tpl-content').value = '';
80
- document.getElementById('tpl-tags').value = '';
81
- document.getElementById('tpl-name').focus();
82
- }
83
-
84
- function editTemplate(id) {
85
- const templates = loadTemplates();
86
- const tpl = templates.find(t => t.id === id);
87
- if (!tpl) return;
88
- const form = document.getElementById('template-form');
89
- form.classList.remove('hidden');
90
- document.getElementById('tpl-edit-id').value = tpl.id;
91
- document.getElementById('tpl-name').value = tpl.name;
92
- document.getElementById('tpl-content').value = tpl.content;
93
- document.getElementById('tpl-tags').value = (tpl.tags || []).join(', ');
94
- document.getElementById('tpl-name').focus();
95
- }
96
-
97
- function cancelTemplateForm() {
98
- document.getElementById('template-form')?.classList.add('hidden');
99
- }
100
-
101
- function saveTemplateForm() {
102
- const name = document.getElementById('tpl-name').value.trim();
103
- const content = document.getElementById('tpl-content').value.trim();
104
- const tagsRaw = document.getElementById('tpl-tags').value.trim();
105
- const editId = document.getElementById('tpl-edit-id').value;
106
-
107
- if (!name || !content) return;
108
-
109
- const tags = tagsRaw ? tagsRaw.split(',').map(s => s.trim()).filter(Boolean) : [];
110
- const templates = loadTemplates();
111
-
112
- if (editId) {
113
- const idx = templates.findIndex(t => t.id === editId);
114
- if (idx >= 0) {
115
- templates[idx].name = name;
116
- templates[idx].content = content;
117
- templates[idx].tags = tags;
118
- }
119
- } else {
120
- templates.unshift({
121
- id: 'tpl-' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
122
- name,
123
- content,
124
- tags,
125
- createdAt: new Date().toISOString(),
126
- });
127
- }
128
-
129
- saveTemplatesToStorage(templates);
130
- cancelTemplateForm();
131
- renderTemplateList();
132
- }
133
-
134
- function deleteTemplate(id) {
135
- const templates = loadTemplates().filter(t => t.id !== id);
136
- saveTemplatesToStorage(templates);
137
- renderTemplateList(document.getElementById('template-search')?.value);
138
- }
139
-
140
- function exportTemplates() {
141
- const templates = loadTemplates();
142
- if (templates.length === 0) return;
143
- const blob = new Blob([JSON.stringify(templates, null, 2)], { type: 'application/json' });
144
- const url = URL.createObjectURL(blob);
145
- const a = document.createElement('a');
146
- a.href = url;
147
- a.download = `aicli-templates-${new Date().toISOString().slice(0, 10)}.json`;
148
- a.click();
149
- URL.revokeObjectURL(url);
150
- }
151
-
152
- function importTemplates() {
153
- const input = document.createElement('input');
154
- input.type = 'file';
155
- input.accept = '.json';
156
- input.addEventListener('change', () => {
157
- const file = input.files[0];
158
- if (!file) return;
159
- const reader = new FileReader();
160
- reader.addEventListener('load', () => {
161
- try {
162
- const imported = JSON.parse(reader.result);
163
- if (!Array.isArray(imported)) throw new Error('Not an array');
164
- const existing = loadTemplates();
165
- const existingIds = new Set(existing.map(t => t.id));
166
- let added = 0;
167
- for (const t of imported) {
168
- if (t.id && t.name && t.content && !existingIds.has(t.id)) {
169
- existing.push(t);
170
- added++;
171
- }
172
- }
173
- saveTemplatesToStorage(existing);
174
- renderTemplateList();
175
- addInfoMessage(`Imported ${added} template(s).`);
176
- } catch {
177
- addErrorMessage('Failed to import templates: invalid JSON format.');
178
- }
179
- });
180
- reader.readAsText(file);
181
- });
182
- input.click();
183
- }
184
-
185
- document.getElementById('btn-templates')?.addEventListener('click', openTemplatesModal);
186
- document.getElementById('template-search')?.addEventListener('input', (e) => {
187
- renderTemplateList(e.target.value);
188
- });
1
+ /**
2
+ * Prompt template modal and import/export helpers.
3
+ * Loaded after app.js so it can use shared UI helpers.
4
+ */
5
+
6
+ const TEMPLATES_KEY = 'aicli-templates';
7
+
8
+ function loadTemplates() {
9
+ try {
10
+ return JSON.parse(localStorage.getItem(TEMPLATES_KEY) || '[]');
11
+ } catch {
12
+ return [];
13
+ }
14
+ }
15
+
16
+ function saveTemplatesToStorage(templates) {
17
+ localStorage.setItem(TEMPLATES_KEY, JSON.stringify(templates));
18
+ }
19
+
20
+ function openTemplatesModal() {
21
+ const modal = document.getElementById('templates-modal');
22
+ if (!modal) return;
23
+ cancelTemplateForm();
24
+ renderTemplateList();
25
+ document.getElementById('template-search').value = '';
26
+ modal.showModal();
27
+ }
28
+
29
+ function renderTemplateList(filter) {
30
+ const listEl = document.getElementById('template-list');
31
+ if (!listEl) return;
32
+ const templates = loadTemplates();
33
+ const q = (filter || '').toLowerCase();
34
+ const filtered = q
35
+ ? templates.filter(t => t.name.toLowerCase().includes(q) || (t.tags || []).some(tag => tag.toLowerCase().includes(q)) || t.content.toLowerCase().includes(q))
36
+ : templates;
37
+
38
+ if (filtered.length === 0) {
39
+ listEl.innerHTML = `<div class="template-empty">${q ? 'No matching templates' : 'No templates yet. Click + New to create one.'}</div>`;
40
+ return;
41
+ }
42
+
43
+ listEl.innerHTML = filtered.map(t => {
44
+ const preview = t.content.length > 80 ? t.content.slice(0, 80) + '...' : t.content;
45
+ const tagsHtml = (t.tags || []).map(tag => `<span class="template-item-tag">${escapeHtml(tag)}</span>`).join('');
46
+ return `
47
+ <div class="template-item" data-tpl-id="${t.id}" data-action="use-template">
48
+ <div class="template-item-body">
49
+ <div class="template-item-name">${escapeHtml(t.name)}</div>
50
+ <div class="template-item-preview">${escapeHtml(preview)}</div>
51
+ ${tagsHtml ? `<div class="template-item-tags">${tagsHtml}</div>` : ''}
52
+ </div>
53
+ <div class="template-item-actions">
54
+ <button class="btn btn-xs btn-ghost" data-action="edit-template" title="Edit">Edit</button>
55
+ <button class="btn btn-xs btn-ghost" data-action="delete-template" title="Delete">Delete</button>
56
+ </div>
57
+ </div>`;
58
+ }).join('');
59
+ }
60
+
61
+ function useTemplate(id) {
62
+ const templates = loadTemplates();
63
+ const tpl = templates.find(t => t.id === id);
64
+ if (!tpl) return;
65
+ const input = document.getElementById('user-input');
66
+ if (!input) return;
67
+ input.value = tpl.content;
68
+ input.focus();
69
+ input.style.height = 'auto';
70
+ input.style.height = Math.min(input.scrollHeight, 200) + 'px';
71
+ document.getElementById('templates-modal')?.close();
72
+ }
73
+
74
+ function showAddTemplate() {
75
+ const form = document.getElementById('template-form');
76
+ form.classList.remove('hidden');
77
+ document.getElementById('tpl-edit-id').value = '';
78
+ document.getElementById('tpl-name').value = '';
79
+ document.getElementById('tpl-content').value = '';
80
+ document.getElementById('tpl-tags').value = '';
81
+ document.getElementById('tpl-name').focus();
82
+ }
83
+
84
+ function editTemplate(id) {
85
+ const templates = loadTemplates();
86
+ const tpl = templates.find(t => t.id === id);
87
+ if (!tpl) return;
88
+ const form = document.getElementById('template-form');
89
+ form.classList.remove('hidden');
90
+ document.getElementById('tpl-edit-id').value = tpl.id;
91
+ document.getElementById('tpl-name').value = tpl.name;
92
+ document.getElementById('tpl-content').value = tpl.content;
93
+ document.getElementById('tpl-tags').value = (tpl.tags || []).join(', ');
94
+ document.getElementById('tpl-name').focus();
95
+ }
96
+
97
+ function cancelTemplateForm() {
98
+ document.getElementById('template-form')?.classList.add('hidden');
99
+ }
100
+
101
+ function saveTemplateForm() {
102
+ const name = document.getElementById('tpl-name').value.trim();
103
+ const content = document.getElementById('tpl-content').value.trim();
104
+ const tagsRaw = document.getElementById('tpl-tags').value.trim();
105
+ const editId = document.getElementById('tpl-edit-id').value;
106
+
107
+ if (!name || !content) return;
108
+
109
+ const tags = tagsRaw ? tagsRaw.split(',').map(s => s.trim()).filter(Boolean) : [];
110
+ const templates = loadTemplates();
111
+
112
+ if (editId) {
113
+ const idx = templates.findIndex(t => t.id === editId);
114
+ if (idx >= 0) {
115
+ templates[idx].name = name;
116
+ templates[idx].content = content;
117
+ templates[idx].tags = tags;
118
+ }
119
+ } else {
120
+ templates.unshift({
121
+ id: 'tpl-' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
122
+ name,
123
+ content,
124
+ tags,
125
+ createdAt: new Date().toISOString(),
126
+ });
127
+ }
128
+
129
+ saveTemplatesToStorage(templates);
130
+ cancelTemplateForm();
131
+ renderTemplateList();
132
+ }
133
+
134
+ function deleteTemplate(id) {
135
+ const templates = loadTemplates().filter(t => t.id !== id);
136
+ saveTemplatesToStorage(templates);
137
+ renderTemplateList(document.getElementById('template-search')?.value);
138
+ }
139
+
140
+ function exportTemplates() {
141
+ const templates = loadTemplates();
142
+ if (templates.length === 0) return;
143
+ const blob = new Blob([JSON.stringify(templates, null, 2)], { type: 'application/json' });
144
+ const url = URL.createObjectURL(blob);
145
+ const a = document.createElement('a');
146
+ a.href = url;
147
+ a.download = `aicli-templates-${new Date().toISOString().slice(0, 10)}.json`;
148
+ a.click();
149
+ URL.revokeObjectURL(url);
150
+ }
151
+
152
+ function importTemplates() {
153
+ const input = document.createElement('input');
154
+ input.type = 'file';
155
+ input.accept = '.json';
156
+ input.addEventListener('change', () => {
157
+ const file = input.files[0];
158
+ if (!file) return;
159
+ const reader = new FileReader();
160
+ reader.addEventListener('load', () => {
161
+ try {
162
+ const imported = JSON.parse(reader.result);
163
+ if (!Array.isArray(imported)) throw new Error('Not an array');
164
+ const existing = loadTemplates();
165
+ const existingIds = new Set(existing.map(t => t.id));
166
+ let added = 0;
167
+ for (const t of imported) {
168
+ if (t.id && t.name && t.content && !existingIds.has(t.id)) {
169
+ existing.push(t);
170
+ added++;
171
+ }
172
+ }
173
+ saveTemplatesToStorage(existing);
174
+ renderTemplateList();
175
+ addInfoMessage(`Imported ${added} template(s).`);
176
+ } catch {
177
+ addErrorMessage('Failed to import templates: invalid JSON format.');
178
+ }
179
+ });
180
+ reader.readAsText(file);
181
+ });
182
+ input.click();
183
+ }
184
+
185
+ document.getElementById('btn-templates')?.addEventListener('click', openTemplatesModal);
186
+ document.getElementById('template-search')?.addEventListener('input', (e) => {
187
+ renderTemplateList(e.target.value);
188
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.207",
3
+ "version": "0.4.208",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",