@travisennis/acai 0.0.11 → 0.0.12

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 (110) hide show
  1. package/README.md +2 -3
  2. package/dist/commands/init-project/utils.d.ts.map +1 -1
  3. package/dist/commands/init-project/utils.js +0 -11
  4. package/dist/commands/manager.d.ts.map +1 -1
  5. package/dist/commands/manager.js +6 -1
  6. package/dist/commands/resources/index.d.ts.map +1 -1
  7. package/dist/commands/resources/index.js +4 -1
  8. package/dist/commands/session/index.d.ts.map +1 -1
  9. package/dist/commands/session/index.js +6 -0
  10. package/dist/commands/session/types.d.ts +1 -0
  11. package/dist/commands/session/types.d.ts.map +1 -1
  12. package/dist/commands/tools/index.d.ts +3 -0
  13. package/dist/commands/tools/index.d.ts.map +1 -0
  14. package/dist/commands/tools/index.js +190 -0
  15. package/dist/commands/tools/templates.d.ts +6 -0
  16. package/dist/commands/tools/templates.d.ts.map +1 -0
  17. package/dist/commands/tools/templates.js +97 -0
  18. package/dist/config/index.d.ts +5 -0
  19. package/dist/config/index.d.ts.map +1 -1
  20. package/dist/config/index.js +41 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +15 -3
  23. package/dist/models/anthropic-provider.d.ts +1 -1
  24. package/dist/models/deepseek-provider.d.ts +3 -3
  25. package/dist/models/deepseek-provider.js +17 -17
  26. package/dist/models/google-provider.d.ts +2 -4
  27. package/dist/models/google-provider.d.ts.map +1 -1
  28. package/dist/models/google-provider.js +2 -17
  29. package/dist/models/groq-provider.d.ts +2 -4
  30. package/dist/models/groq-provider.d.ts.map +1 -1
  31. package/dist/models/groq-provider.js +3 -21
  32. package/dist/models/opencode-go-provider.d.ts +11 -1
  33. package/dist/models/opencode-go-provider.d.ts.map +1 -1
  34. package/dist/models/opencode-go-provider.js +136 -0
  35. package/dist/models/opencode-zen-provider.d.ts +3 -3
  36. package/dist/models/opencode-zen-provider.d.ts.map +1 -1
  37. package/dist/models/opencode-zen-provider.js +26 -32
  38. package/dist/models/openrouter-provider.d.ts +4 -15
  39. package/dist/models/openrouter-provider.d.ts.map +1 -1
  40. package/dist/models/openrouter-provider.js +26 -169
  41. package/dist/models/providers.d.ts +1 -1
  42. package/dist/models/providers.d.ts.map +1 -1
  43. package/dist/models/xai-provider.d.ts +1 -2
  44. package/dist/models/xai-provider.d.ts.map +1 -1
  45. package/dist/models/xai-provider.js +0 -13
  46. package/dist/prompts/manager.d.ts.map +1 -1
  47. package/dist/prompts/manager.js +5 -1
  48. package/dist/prompts/system-prompt.d.ts +1 -0
  49. package/dist/prompts/system-prompt.d.ts.map +1 -1
  50. package/dist/prompts/system-prompt.js +20 -5
  51. package/dist/repl/index.d.ts +1 -2
  52. package/dist/repl/index.d.ts.map +1 -1
  53. package/dist/repl/index.js +5 -52
  54. package/dist/skills/activated-tracker.d.ts +11 -0
  55. package/dist/skills/activated-tracker.d.ts.map +1 -0
  56. package/dist/skills/activated-tracker.js +16 -0
  57. package/dist/skills/index.d.ts +1 -1
  58. package/dist/skills/index.d.ts.map +1 -1
  59. package/dist/skills/index.js +7 -1
  60. package/dist/tools/bash.d.ts +4 -4
  61. package/dist/tools/bash.d.ts.map +1 -1
  62. package/dist/tools/bash.js +17 -6
  63. package/dist/tools/directory-tree.d.ts +4 -4
  64. package/dist/tools/directory-tree.d.ts.map +1 -1
  65. package/dist/tools/directory-tree.js +2 -0
  66. package/dist/tools/dynamic-tool-loader.d.ts +11 -2
  67. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  68. package/dist/tools/dynamic-tool-loader.js +299 -39
  69. package/dist/tools/edit-file.d.ts +2 -2
  70. package/dist/tools/glob.d.ts +16 -16
  71. package/dist/tools/glob.d.ts.map +1 -1
  72. package/dist/tools/glob.js +9 -1
  73. package/dist/tools/grep.d.ts +14 -14
  74. package/dist/tools/grep.d.ts.map +1 -1
  75. package/dist/tools/grep.js +7 -0
  76. package/dist/tools/index.d.ts +42 -36
  77. package/dist/tools/index.d.ts.map +1 -1
  78. package/dist/tools/index.js +16 -1
  79. package/dist/tools/ls.d.ts +2 -2
  80. package/dist/tools/ls.d.ts.map +1 -1
  81. package/dist/tools/ls.js +1 -0
  82. package/dist/tools/read-file.d.ts +8 -8
  83. package/dist/tools/save-file.d.ts +4 -4
  84. package/dist/tools/skill.d.ts +2 -1
  85. package/dist/tools/skill.d.ts.map +1 -1
  86. package/dist/tools/skill.js +55 -12
  87. package/dist/tools/types.d.ts +8 -2
  88. package/dist/tools/types.d.ts.map +1 -1
  89. package/dist/tools/web-fetch.d.ts +6 -6
  90. package/dist/tools/web-fetch.d.ts.map +1 -1
  91. package/dist/tools/web-fetch.js +27 -8
  92. package/dist/tools/web-search.d.ts +4 -4
  93. package/dist/tools/web-search.js +1 -1
  94. package/dist/tui/components/footer.d.ts +0 -2
  95. package/dist/tui/components/footer.d.ts.map +1 -1
  96. package/dist/tui/components/footer.js +1 -17
  97. package/dist/utils/binary-output.d.ts +32 -0
  98. package/dist/utils/binary-output.d.ts.map +1 -0
  99. package/dist/utils/binary-output.js +127 -0
  100. package/dist/utils/command-protection.d.ts.map +1 -1
  101. package/dist/utils/command-protection.js +92 -9
  102. package/dist/utils/parsing.d.ts +1 -1
  103. package/dist/utils/parsing.d.ts.map +1 -1
  104. package/package.json +27 -25
  105. package/dist/modes/manager.d.ts +0 -24
  106. package/dist/modes/manager.d.ts.map +0 -1
  107. package/dist/modes/manager.js +0 -77
  108. package/dist/modes/prompts.d.ts +0 -2
  109. package/dist/modes/prompts.d.ts.map +0 -1
  110. package/dist/modes/prompts.js +0 -142
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Acai: AI-Powered Software Development Assistant
1
+ # acai
2
2
 
3
3
  ![Project Status](https://img.shields.io/badge/Status-Active-brightgreen)
4
4
  ![License](https://img.shields.io/badge/License-MIT-blue.svg)
@@ -87,7 +87,6 @@ Reference files directly with `@filename`, directories with `@dirname`, or run s
87
87
  │ ├── execution/ # Command execution utilities
88
88
  │ ├── middleware/ # AI request/response middleware
89
89
  │ ├── models/ # AI model providers and management
90
- │ ├── modes/ # Agent mode management
91
90
  │ ├── prompts/ # Prompt generation and management
92
91
  │ ├── repl/ # REPL utilities
93
92
  │ ├── sessions/ # Session persistence and management
@@ -108,7 +107,7 @@ Reference files directly with `@filename`, directories with `@dirname`, or run s
108
107
  - [Usage Guide](docs/usage.md) - Commands, keyboard shortcuts, piped input, and prompt syntax
109
108
  - [Configuration](docs/configuration.md) - Environment variables, project and global settings
110
109
  - [Skills System](docs/skills.md) - Creating and using specialized instruction files
111
- - [Dynamic Tools](docs/dynamic-tools.md) - Creating custom tools to extend acai
110
+ - [Dynamic Tools](docs/dynamic-tools.md) - Creating custom tools to extend acai (supports bash, python, and other languages; Amp-compatible text schema format; `/tools make` scaffolding command)
112
111
  - [Architecture](ARCHITECTURE.md) - Internal architecture and flow diagrams
113
112
  - [Contributing](CONTRIBUTING.md) - Development setup, scripts, and code style
114
113
 
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/commands/init-project/utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,sCAAsC,CAAC;AAEzE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GACjB,oBAAoB,CAmCtB;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAazE;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE3D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/commands/init-project/utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,sCAAsC,CAAC;AAEzE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GACjB,oBAAoB,CAwBtB;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAazE;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE3D"}
@@ -12,17 +12,6 @@ export function ensureProjectDirectory(projectDir) {
12
12
  else {
13
13
  existing.push(".acai/");
14
14
  }
15
- const subdirs = ["rules"];
16
- for (const subdir of subdirs) {
17
- const dirPath = path.join(projectDir, subdir);
18
- if (!existsSync(dirPath)) {
19
- mkdirSync(dirPath, { recursive: true });
20
- created.push(`.acai/${subdir}/`);
21
- }
22
- else {
23
- existing.push(`.acai/${subdir}/`);
24
- }
25
- }
26
15
  const agentsSkillsDir = path.join(path.dirname(projectDir), ".agents", "skills");
27
16
  if (!existsSync(agentsSkillsDir)) {
28
17
  mkdirSync(agentsSkillsDir, { recursive: true });
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../source/commands/manager.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,SAAS,EACT,MAAM,EACN,YAAY,EACZ,GAAG,EACJ,MAAM,iBAAiB,CAAC;AA2BzB,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,YAAY,CAAC;AAE9D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,WAAW,CAAU;gBAEjB,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,MAAM,EACN,YAAY,EACZ,aAAa,EACb,SAAS,GACV,EAAE,cAAc;IAaX,mBAAmB;YA0DX,qBAAqB;IA0EnC,OAAO,CAAC,iBAAiB;IAQnB,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAuB/C,WAAW;IAKL,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAKlD,MAAM,CACV,EAAE,SAAS,EAAE,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,EACpC,OAAO,EAAE;QACP,GAAG,EAAE,GAAG,CAAC;QACT,SAAS,EAAE,SAAS,CAAC;QACrB,cAAc,EAAE,SAAS,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;KAChB;;;CAsBJ"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../source/commands/manager.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,SAAS,EACT,MAAM,EACN,YAAY,EACZ,GAAG,EACJ,MAAM,iBAAiB,CAAC;AA4BzB,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,YAAY,CAAC;AAE9D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,WAAW,CAAU;gBAEjB,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,MAAM,EACN,YAAY,EACZ,aAAa,EACb,SAAS,GACV,EAAE,cAAc;IAaX,mBAAmB;YA2DX,qBAAqB;IA4EnC,OAAO,CAAC,iBAAiB;IAQnB,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAuB/C,WAAW;IAKL,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAKlD,MAAM,CACV,EAAE,SAAS,EAAE,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,EACpC,OAAO,EAAE;QACP,GAAG,EAAE,GAAG,CAAC;QACT,SAAS,EAAE,SAAS,CAAC;QACrB,cAAc,EAAE,SAAS,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;KAChB;;;CAsBJ"}
@@ -1,4 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
+ import { parseSkillsPath } from "../config/index.js";
2
3
  import { processPrompt } from "../prompts/mentions.js";
3
4
  import { loadSkills } from "../skills/index.js";
4
5
  import style from "../terminal/style.js";
@@ -27,6 +28,7 @@ import { reviewCommand } from "./review/index.js";
27
28
  import { sessionCommand } from "./session/index.js";
28
29
  import { shareCommand } from "./share/index.js";
29
30
  import { shellCommand } from "./shell/index.js";
31
+ import { toolsCommand } from "./tools/index.js";
30
32
  export class CommandManager {
31
33
  commands;
32
34
  promptManager;
@@ -87,6 +89,7 @@ export class CommandManager {
87
89
  resourcesCommand(options),
88
90
  shareCommand(options),
89
91
  shellCommand(options),
92
+ toolsCommand(options),
90
93
  ];
91
94
  // Add help command with access to all commands
92
95
  const helpCmd = helpCommand(options, this.commands);
@@ -103,7 +106,9 @@ export class CommandManager {
103
106
  this.initialized = true;
104
107
  }
105
108
  async registerSkillCommands(options) {
106
- const skills = await loadSkills();
109
+ const appConfig = await this.config.getConfig();
110
+ const skillPaths = parseSkillsPath(appConfig.skills.path);
111
+ const skills = await loadSkills(skillPaths);
107
112
  const userInvocableSkills = skills.getUserInvocable();
108
113
  for (const skill of userInvocableSkills) {
109
114
  const commandName = `/${skill.name}`;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/resources/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkC/D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,WAAW,CAmErE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/resources/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkC/D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,WAAW,CAqErE"}
@@ -1,3 +1,4 @@
1
+ import { parseSkillsPath } from "../../config/index.js";
1
2
  import { loadSkills } from "../../skills/index.js";
2
3
  import style from "../../terminal/style.js";
3
4
  import { Modal, Container as ModalContainer, ModalText, } from "../../tui/index.js";
@@ -30,7 +31,9 @@ export function resourcesCommand(options) {
30
31
  getSubCommands: async () => [],
31
32
  async handle(_args, { tui, editor }) {
32
33
  try {
33
- const skills = await loadSkills();
34
+ const appConfig = await options.config.getConfig();
35
+ const skillPaths = parseSkillsPath(appConfig.skills.path);
36
+ const skills = await loadSkills(skillPaths);
34
37
  const allSkills = skills.getAll();
35
38
  const agentsFiles = await options.config.readAgentsFiles();
36
39
  const projectSkills = allSkills.filter((s) => s.source === "project");
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/session/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAoH/D,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,GACb,EAAE,cAAc,GAAG,WAAW,CAgK9B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/session/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAyH/D,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,GACb,EAAE,cAAc,GAAG,WAAW,CAiK9B"}
@@ -44,6 +44,11 @@ function buildContextTable(breakdown, window) {
44
44
  formatNumber(breakdown.systemPromptBreakdown.userAgentsMd),
45
45
  formatPercentage(breakdown.systemPromptBreakdown.userAgentsMd, window),
46
46
  ],
47
+ [
48
+ " ~/.config/AGENTS.md",
49
+ formatNumber(breakdown.systemPromptBreakdown.configAgentsMd),
50
+ formatPercentage(breakdown.systemPromptBreakdown.configAgentsMd, window),
51
+ ],
47
52
  [
48
53
  " ./AGENTS.md",
49
54
  formatNumber(breakdown.systemPromptBreakdown.cwdAgentsMd),
@@ -126,6 +131,7 @@ export function sessionCommand({ config, tokenCounter, modelManager, sessionMana
126
131
  const systemPromptBreakdown = {
127
132
  core: tokenCounter.count(sysResult.components.core),
128
133
  userAgentsMd: tokenCounter.count(sysResult.components.userAgentsMd),
134
+ configAgentsMd: tokenCounter.count(sysResult.components.configAgentsMd),
129
135
  cwdAgentsMd: tokenCounter.count(sysResult.components.cwdAgentsMd),
130
136
  learnedRules: tokenCounter.count(sysResult.components.learnedRules),
131
137
  skills: tokenCounter.count(sysResult.components.skills),
@@ -4,6 +4,7 @@ export type Breakdown = {
4
4
  systemPromptBreakdown: {
5
5
  core: number;
6
6
  userAgentsMd: number;
7
+ configAgentsMd: number;
7
8
  cwdAgentsMd: number;
8
9
  learnedRules: number;
9
10
  skills: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../source/commands/session/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAEvC,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,EAAE;IAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GACxC,MAAM,CAOR"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../source/commands/session/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAEvC,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,EAAE;IAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GACxC,MAAM,CAOR"}
@@ -0,0 +1,3 @@
1
+ import type { CommandOptions, ReplCommand } from "../types.ts";
2
+ export declare function toolsCommand(options: CommandOptions): ReplCommand;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/tools/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAa/D,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,WAAW,CA6CjE"}
@@ -0,0 +1,190 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import style from "../../terminal/style.js";
4
+ import { Text } from "../../tui/index.js";
5
+ import { bashTemplate, nodeTemplate, textCompanionTemplate, textSchemaTemplate, zshTemplate, } from "./templates.js";
6
+ const TOOL_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
7
+ export function toolsCommand(options) {
8
+ return {
9
+ command: "/tools",
10
+ description: "Manage dynamic tools (make, list)",
11
+ aliases: [],
12
+ getSubCommands: async () => ["make", "list"],
13
+ async handle(args, { tui, container, editor, }) {
14
+ const subCommand = args[0];
15
+ if (subCommand === "make") {
16
+ return handleToolMake(args.slice(1), options, container, editor, tui);
17
+ }
18
+ if (subCommand === "list") {
19
+ return handleToolList(options, container, editor, tui);
20
+ }
21
+ // Default: show help
22
+ container.addChild(new Text(style.dim("Usage: /tools make <name> [--bash|--zsh|--node|--text] [--description <desc>] [--dir <path>]"), 0, 1));
23
+ container.addChild(new Text(style.dim(" /tools list"), 0, 1));
24
+ return "continue";
25
+ },
26
+ };
27
+ }
28
+ function writeToolFile(filePath, content, makeExecutable) {
29
+ const files = [];
30
+ fs.writeFileSync(filePath, content, "utf8");
31
+ if (makeExecutable) {
32
+ fs.chmodSync(filePath, 0o755);
33
+ }
34
+ files.push(filePath);
35
+ return files;
36
+ }
37
+ function createToolFiles(toolName, description, toolType, outputDir) {
38
+ const files = [];
39
+ const typeConfig = {
40
+ node: {
41
+ ext: ".mjs",
42
+ template: () => nodeTemplate(toolName, description),
43
+ executable: true,
44
+ },
45
+ bash: {
46
+ ext: ".sh",
47
+ template: () => bashTemplate(toolName, description),
48
+ executable: true,
49
+ },
50
+ zsh: {
51
+ ext: ".zsh",
52
+ template: () => zshTemplate(toolName, description),
53
+ executable: true,
54
+ },
55
+ text: { ext: ".sh", template: () => "", executable: true }, // handled separately
56
+ };
57
+ if (toolType === "text") {
58
+ const toolFilePath = path.join(outputDir, `${toolName}.tool`);
59
+ const companionFilePath = path.join(outputDir, `${toolName}.sh`);
60
+ if (fs.existsSync(toolFilePath))
61
+ return toolFilePath;
62
+ if (fs.existsSync(companionFilePath))
63
+ return companionFilePath;
64
+ files.push(...writeToolFile(toolFilePath, textSchemaTemplate(toolName, description), false));
65
+ files.push(...writeToolFile(companionFilePath, textCompanionTemplate(toolName), true));
66
+ return files;
67
+ }
68
+ const config = typeConfig[toolType];
69
+ const filePath = path.join(outputDir, `${toolName}${config.ext}`);
70
+ if (fs.existsSync(filePath))
71
+ return filePath;
72
+ files.push(...writeToolFile(filePath, config.template(), config.executable));
73
+ return files;
74
+ }
75
+ function handleToolMake(args, options, container, editor, tui) {
76
+ // Parse arguments
77
+ let toolName = "";
78
+ let toolType = "bash";
79
+ let description = "";
80
+ let customDir = "";
81
+ for (let i = 0; i < args.length; i++) {
82
+ const arg = args[i];
83
+ if (arg === "--bash") {
84
+ toolType = "bash";
85
+ }
86
+ else if (arg === "--zsh") {
87
+ toolType = "zsh";
88
+ }
89
+ else if (arg === "--node") {
90
+ toolType = "node";
91
+ }
92
+ else if (arg === "--text") {
93
+ toolType = "text";
94
+ }
95
+ else if (arg === "--description" || arg === "-d") {
96
+ description = args[++i] || "";
97
+ }
98
+ else if (arg === "--dir") {
99
+ customDir = args[++i] || "";
100
+ }
101
+ else if (!arg.startsWith("-")) {
102
+ toolName = arg;
103
+ }
104
+ }
105
+ if (!toolName) {
106
+ container.addChild(new Text(style.red("Error: Tool name is required"), 0, 1));
107
+ container.addChild(new Text(style.dim("Usage: /tools make <name> [--bash|--zsh|--node|--text] [--description <desc>] [--dir <path>]"), 0, 1));
108
+ tui.requestRender();
109
+ editor.setText("");
110
+ return "continue";
111
+ }
112
+ if (!TOOL_NAME_REGEX.test(toolName)) {
113
+ container.addChild(new Text(style.red(`Error: Tool name must match ${TOOL_NAME_REGEX.source}`), 0, 1));
114
+ tui.requestRender();
115
+ editor.setText("");
116
+ return "continue";
117
+ }
118
+ if (!description) {
119
+ description = `Dynamic tool: ${toolName}`;
120
+ }
121
+ // Determine output directory
122
+ const outputDir = customDir || path.join(options.workspace.primaryDir, ".acai", "tools");
123
+ // Create directory if it doesn't exist
124
+ if (!fs.existsSync(outputDir)) {
125
+ fs.mkdirSync(outputDir, { recursive: true });
126
+ }
127
+ try {
128
+ const result = createToolFiles(toolName, description, toolType, outputDir);
129
+ if (typeof result === "string") {
130
+ // A file already exists
131
+ container.addChild(new Text(style.red(`Error: File already exists: ${result}`), 0, 1));
132
+ tui.requestRender();
133
+ editor.setText("");
134
+ return "continue";
135
+ }
136
+ container.addChild(new Text(style.green(`Created tool: ${toolName}`), 0, 1));
137
+ for (const filePath of result) {
138
+ container.addChild(new Text(style.dim(` ${filePath}`), 0, 1));
139
+ }
140
+ container.addChild(new Text(style.dim("Restart acai or reload tools to use the new tool."), 0, 1));
141
+ }
142
+ catch (e) {
143
+ container.addChild(new Text(style.red(`Error creating tool: ${e.message}`), 0, 1));
144
+ }
145
+ tui.requestRender();
146
+ editor.setText("");
147
+ return "continue";
148
+ }
149
+ async function handleToolList(options, container, editor, tui) {
150
+ const projectDir = path.join(options.workspace.primaryDir, ".acai", "tools");
151
+ const userDir = path.join(process.env["HOME"] || process.env["USERPROFILE"] || "", ".acai", "tools");
152
+ const dirs = [
153
+ { label: "User tools", dirPath: userDir },
154
+ { label: "Project tools", dirPath: projectDir },
155
+ ];
156
+ let foundAny = false;
157
+ for (const dir of dirs) {
158
+ if (!fs.existsSync(dir.dirPath)) {
159
+ container.addChild(new Text(style.dim(`${dir.label}: directory not found (${dir.dirPath})`), 0, 1));
160
+ continue;
161
+ }
162
+ const files = fs.readdirSync(dir.dirPath);
163
+ const toolFiles = files.filter((f) => f.endsWith(".js") ||
164
+ f.endsWith(".mjs") ||
165
+ f.endsWith(".cjs") ||
166
+ f.endsWith(".sh") ||
167
+ f.endsWith(".bash") ||
168
+ f.endsWith(".zsh") ||
169
+ f.endsWith(".py") ||
170
+ f.endsWith(".rb") ||
171
+ f.endsWith(".tool") ||
172
+ (!path.extname(f) &&
173
+ fs.statSync(path.join(dir.dirPath, f)).mode & 0o111));
174
+ if (toolFiles.length === 0) {
175
+ container.addChild(new Text(style.dim(`${dir.label}: no tools found`), 0, 1));
176
+ continue;
177
+ }
178
+ foundAny = true;
179
+ container.addChild(new Text(style.bold(dir.label), 0, 1));
180
+ for (const file of toolFiles) {
181
+ container.addChild(new Text(style.dim(` ${file}`), 0, 1));
182
+ }
183
+ }
184
+ if (!foundAny) {
185
+ container.addChild(new Text(style.dim("No dynamic tools found."), 0, 1));
186
+ }
187
+ tui.requestRender();
188
+ editor.setText("");
189
+ return "continue";
190
+ }
@@ -0,0 +1,6 @@
1
+ export declare function nodeTemplate(name: string, description: string): string;
2
+ export declare function bashTemplate(name: string, description: string): string;
3
+ export declare function zshTemplate(name: string, description: string): string;
4
+ export declare function textSchemaTemplate(name: string, description: string): string;
5
+ export declare function textCompanionTemplate(name: string): string;
6
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../source/commands/tools/templates.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CA2BtE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAuBtE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAuBrE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAe1D"}
@@ -0,0 +1,97 @@
1
+ export function nodeTemplate(name, description) {
2
+ return `#!/usr/bin/env node
3
+
4
+ const TOOL_ACTION = process.env.TOOL_ACTION;
5
+
6
+ if (TOOL_ACTION === 'describe') {
7
+ console.log(JSON.stringify({
8
+ name: '${name}',
9
+ description: '${description}',
10
+ parameters: [],
11
+ needsApproval: false,
12
+ }, null, 2));
13
+ process.exit(0);
14
+ }
15
+
16
+ if (TOOL_ACTION === 'execute') {
17
+ let data = '';
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.on('data', (chunk) => { data += chunk; });
20
+ process.stdin.on('end', () => {
21
+ const params = JSON.parse(data);
22
+ // Your tool logic here
23
+ console.log('Hello from ${name}');
24
+ process.exit(0);
25
+ });
26
+ }
27
+ `;
28
+ }
29
+ export function bashTemplate(name, description) {
30
+ return `#!/bin/bash
31
+
32
+ action="\${TOOL_ACTION}"
33
+
34
+ if [ "$action" = "describe" ]; then
35
+ cat << 'EOF'
36
+ name: ${name}
37
+ description: ${description}
38
+ EOF
39
+ exit 0
40
+ fi
41
+
42
+ if [ "$action" = "execute" ]; then
43
+ # Read key-value params from stdin
44
+ while IFS='=' read -r key value; do
45
+ declare "$key"="$value"
46
+ done
47
+ # Your tool logic here
48
+ echo "Hello from ${name}"
49
+ exit 0
50
+ fi
51
+ `;
52
+ }
53
+ export function zshTemplate(name, description) {
54
+ return `#!/bin/zsh
55
+
56
+ action="\${TOOL_ACTION}"
57
+
58
+ if [ "$action" = "describe" ]; then
59
+ cat << 'EOF'
60
+ name: ${name}
61
+ description: ${description}
62
+ EOF
63
+ exit 0
64
+ fi
65
+
66
+ if [ "$action" = "execute" ]; then
67
+ # Read key-value params from stdin
68
+ while IFS='=' read -r key value; do
69
+ declare "$key"="$value"
70
+ done
71
+ # Your tool logic here
72
+ echo "Hello from ${name}"
73
+ exit 0
74
+ fi
75
+ `;
76
+ }
77
+ export function textSchemaTemplate(name, description) {
78
+ return `name: ${name}
79
+ description: ${description}
80
+ `;
81
+ }
82
+ export function textCompanionTemplate(name) {
83
+ return `#!/bin/bash
84
+ # Companion script for ${name}.tool
85
+ # Modify this script to implement your tool logic
86
+
87
+ action="\${TOOL_ACTION}"
88
+
89
+ if [ "$action" = "execute" ]; then
90
+ while IFS='=' read -r key value; do
91
+ declare "$key"="$value"
92
+ done
93
+ echo "Hello from ${name}"
94
+ exit 0
95
+ fi
96
+ `;
97
+ }
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ export declare function parseSkillsPath(skillsPath: string): string[];
2
3
  export declare const defaultConfig: {
3
4
  readonly loop: {
4
5
  readonly maxIterations: 200;
@@ -16,11 +17,13 @@ export declare const defaultConfig: {
16
17
  readonly readOnlyFiles: string[];
17
18
  readonly skills: {
18
19
  readonly enabled: true;
20
+ readonly path: "";
19
21
  };
20
22
  readonly devtools: {
21
23
  readonly enabled: false;
22
24
  };
23
25
  readonly autoGenerateRules: false;
26
+ readonly allowedDirs: string[];
24
27
  readonly env: Record<string, string>;
25
28
  };
26
29
  declare const ConfigSchema: z.ZodObject<{
@@ -43,8 +46,10 @@ declare const ConfigSchema: z.ZodObject<{
43
46
  readOnlyFiles: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;
44
47
  skills: z.ZodDefault<z.ZodOptional<z.ZodObject<{
45
48
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
49
+ path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
46
50
  }, z.core.$strip>>>;
47
51
  autoGenerateRules: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
52
+ allowedDirs: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;
48
53
  devtools: z.ZodDefault<z.ZodOptional<z.ZodObject<{
49
54
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
50
55
  }, z.core.$strip>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/config/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,aAAa;;;;;8BAKI,MAAM,EAAE,GAAG,SAAS;;;;;;;;;4BAS3B,MAAM,EAAE;;;;;;;;kBAQlB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAGX,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqDhB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM;IAI3B,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAK1B,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOlD,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAOjC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW/C,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;CAIrC;AAED,qBAAa,aAAa;IACxB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,cAAc,CAAS;;YAOjB,WAAW;IAanB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IA8B5B,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAKpC,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBjD,eAAe,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IA4B/D,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7C,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAYvC,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAc3C,cAAc;IActB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAexD,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC;CAKjB;AAGD,eAAO,MAAM,MAAM,eAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/config/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAa5D;AAED,eAAO,MAAM,aAAa;;;;;8BAKI,MAAM,EAAE,GAAG,SAAS;;;;;;;;;4BAS3B,MAAM,EAAE;;;;;;;;;0BASV,MAAM,EAAE;kBAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAGX,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0DhB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM;IAI3B,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAK1B,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOlD,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAOjC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW/C,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;CAIrC;AAED,qBAAa,aAAa;IACxB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,cAAc,CAAS;;YAOjB,WAAW;IAanB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IA6C5B,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAKpC,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBjD,eAAe,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAgC/D,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7C,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAYvC,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAc3C,cAAc;IActB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAexD,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC;CAKjB;AAGD,eAAO,MAAM,MAAM,eAAsB,CAAC"}
@@ -4,6 +4,22 @@ import { homedir } from "node:os";
4
4
  import path from "node:path";
5
5
  import { z } from "zod";
6
6
  import { jsonParser } from "../utils/parsing.js";
7
+ const PATH_SEPARATOR = process.platform === "win32" ? ";" : ":";
8
+ export function parseSkillsPath(skillsPath) {
9
+ if (!skillsPath)
10
+ return [];
11
+ const paths = skillsPath
12
+ .split(PATH_SEPARATOR)
13
+ .map((p) => p.trim())
14
+ .filter((p) => p.length > 0)
15
+ .map((p) => {
16
+ if (p.startsWith("~")) {
17
+ return path.join(homedir(), p.slice(1));
18
+ }
19
+ return path.resolve(p);
20
+ });
21
+ return [...new Set(paths)];
22
+ }
7
23
  export const defaultConfig = {
8
24
  loop: {
9
25
  maxIterations: 200,
@@ -21,11 +37,13 @@ export const defaultConfig = {
21
37
  readOnlyFiles: [],
22
38
  skills: {
23
39
  enabled: true,
40
+ path: "",
24
41
  },
25
42
  devtools: {
26
43
  enabled: false,
27
44
  },
28
45
  autoGenerateRules: false,
46
+ allowedDirs: [],
29
47
  env: {},
30
48
  };
31
49
  // Type definitions
@@ -68,6 +86,7 @@ const ConfigSchema = z.object({
68
86
  skills: z
69
87
  .object({
70
88
  enabled: z.boolean().optional().default(defaultConfig.skills.enabled),
89
+ path: z.string().optional().default(defaultConfig.skills.path),
71
90
  })
72
91
  .optional()
73
92
  .default(defaultConfig.skills),
@@ -75,6 +94,10 @@ const ConfigSchema = z.object({
75
94
  .boolean()
76
95
  .optional()
77
96
  .default(defaultConfig.autoGenerateRules),
97
+ allowedDirs: z
98
+ .array(z.string())
99
+ .optional()
100
+ .default(defaultConfig.allowedDirs),
78
101
  devtools: z
79
102
  .object({
80
103
  enabled: z.boolean().optional().default(defaultConfig.devtools.enabled),
@@ -156,10 +179,23 @@ export class ConfigManager {
156
179
  ...appConfig.env,
157
180
  ...projectConfig.env,
158
181
  };
182
+ const mergedAllowedDirs = [
183
+ ...(appConfig.allowedDirs ?? []),
184
+ ...(projectConfig.allowedDirs ?? []),
185
+ ];
186
+ const mergedSkills = {
187
+ ...appConfig.skills,
188
+ ...projectConfig.skills,
189
+ path: [appConfig.skills?.path, projectConfig.skills?.path]
190
+ .filter((p) => !!p)
191
+ .join(PATH_SEPARATOR),
192
+ };
159
193
  const mergedConfig = {
160
194
  ...appConfig,
161
195
  ...projectConfig,
162
196
  env: mergedEnv,
197
+ allowedDirs: mergedAllowedDirs,
198
+ skills: mergedSkills,
163
199
  };
164
200
  const result = ConfigSchema.parse(mergedConfig);
165
201
  this.cachedConfig = result;
@@ -184,7 +220,7 @@ export class ConfigManager {
184
220
  }
185
221
  }
186
222
  if (!configData.skills) {
187
- configData.skills = { enabled: true };
223
+ configData.skills = { enabled: true, path: "" };
188
224
  }
189
225
  configData.skills.enabled = enabled;
190
226
  await this.app.ensurePath();
@@ -197,6 +233,10 @@ export class ConfigManager {
197
233
  absolute: path.join(this.app.getPath(), "AGENTS.md"),
198
234
  relative: "~/.acai/AGENTS.md",
199
235
  },
236
+ {
237
+ absolute: path.join(homedir(), ".config", "AGENTS.md"),
238
+ relative: "~/.config/AGENTS.md",
239
+ },
200
240
  {
201
241
  absolute: path.join(process.cwd(), "AGENTS.md"),
202
242
  relative: "./AGENTS.md",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";AA6BA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAGD,wBAAgB,sBAAsB,CACpC,UAAU,GAAE,MAAM,EAAO,GACxB,gBAAgB,CAsBlB;AAoDD,QAAA,MAAM,KAAK;;;;;;;;;;CAAyB,CAAC;AAMrC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAE9C;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";AAiCA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAGD,wBAAgB,sBAAsB,CACpC,UAAU,GAAE,MAAM,EAAO,GACxB,gBAAgB,CAsBlB;AAoDD,QAAA,MAAM,KAAK;;;;;;;;;;CAAyB,CAAC;AAMrC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAE9C;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC"}
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import { setTerminalTitle } from "./terminal/control.js";
22
22
  import { select } from "./terminal/select-prompt.js";
23
23
  import { TokenCounter } from "./tokens/counter.js";
24
24
  import { TokenTracker } from "./tokens/tracker.js";
25
- import { initTools } from "./tools/index.js";
25
+ import { getActivatedSkillsTracker, initTools, } from "./tools/index.js";
26
26
  import { logger } from "./utils/logger.js";
27
27
  import { getPackageVersion } from "./utils/version.js";
28
28
  // Create workspace context from CLI arguments
@@ -221,7 +221,7 @@ async function determineInitialPrompt() {
221
221
  async function initializeModelManager(appDir) {
222
222
  const chosenModel = isSupportedModel(flags.model)
223
223
  ? flags.model
224
- : "opencode-go:kimi-k2-5";
224
+ : "opencode-go:glm-5-1"; // DEFAULT MODEL
225
225
  const projectConfig = await config.getConfig();
226
226
  const devtoolsEnabled = projectConfig.devtools?.enabled ?? false;
227
227
  const modelManager = new ModelManager({
@@ -232,7 +232,7 @@ async function initializeModelManager(appDir) {
232
232
  modelManager.setModel("cli", chosenModel);
233
233
  modelManager.setModel("title-conversation", chosenModel);
234
234
  modelManager.setModel("conversation-summarizer", chosenModel);
235
- modelManager.setModel("tool-repair", "openai:gpt-5.1-codex-mini");
235
+ modelManager.setModel("tool-repair", "openai:gpt-5.4-mini");
236
236
  modelManager.setModel("conversation-analyzer", chosenModel);
237
237
  modelManager.setModel("init-project", chosenModel);
238
238
  modelManager.setModel("handoff-agent", chosenModel);
@@ -337,6 +337,7 @@ function setupReplEventHandlers(repl, agent, sessionManager, noSession) {
337
337
  logger.info("Resetting agent state.");
338
338
  agent.resetState();
339
339
  agent.setConfig(await config.getConfig());
340
+ getActivatedSkillsTracker().reset();
340
341
  void repl.rerender();
341
342
  });
342
343
  repl.setInterruptCallback(async () => {
@@ -462,6 +463,17 @@ async function main() {
462
463
  const { initialPromptInput, stdinContent, hasContinueOrResume, resumeSessionId, } = await determineInitialPrompt();
463
464
  // Initialize application state
464
465
  const state = await initializeAppState(appConfig, initialPromptInput, stdinContent, hasContinueOrResume, resumeSessionId);
466
+ // Add config-sourced allowed directories
467
+ const configAllowedDirs = appConfig.allowedDirs ?? [];
468
+ for (const dir of configAllowedDirs) {
469
+ const expandedDir = dir.startsWith("~/") || dir === "~"
470
+ ? path.join(os.homedir(), dir.slice(1))
471
+ : dir;
472
+ const resolvedDir = path.resolve(expandedDir);
473
+ if (!workspace.allowedDirs.includes(resolvedDir)) {
474
+ workspace.allowedDirs.push(resolvedDir);
475
+ }
476
+ }
465
477
  // Add logs directory to allowed directories if configured
466
478
  const logsPath = (await config.getConfig()).logs?.path;
467
479
  if (logsPath) {