@di-code/coding-agent 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +224 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/resources/index.d.ts +3 -0
- package/dist/core/resources/index.d.ts.map +1 -0
- package/dist/core/resources/index.js +2 -0
- package/dist/core/resources/index.js.map +1 -0
- package/dist/core/resources/loader.d.ts +8 -0
- package/dist/core/resources/loader.d.ts.map +1 -0
- package/dist/core/resources/loader.js +174 -0
- package/dist/core/resources/loader.js.map +1 -0
- package/dist/core/resources/skills.d.ts +10 -0
- package/dist/core/resources/skills.d.ts.map +1 -0
- package/dist/core/resources/skills.js +167 -0
- package/dist/core/resources/skills.js.map +1 -0
- package/dist/core/resources/types.d.ts +41 -0
- package/dist/core/resources/types.d.ts.map +1 -0
- package/dist/core/resources/types.js +2 -0
- package/dist/core/resources/types.js.map +1 -0
- package/dist/core/session.d.ts +7 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +23 -3
- package/dist/core/session.js.map +1 -1
- package/dist/core/skill-command.d.ts +3 -0
- package/dist/core/skill-command.d.ts.map +1 -0
- package/dist/core/skill-command.js +34 -0
- package/dist/core/skill-command.js.map +1 -0
- package/dist/core/system-prompt.d.ts +6 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +57 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/extensions/runtime.d.ts +7 -4
- package/dist/extensions/runtime.d.ts.map +1 -1
- package/dist/extensions/runtime.js +45 -10
- package/dist/extensions/runtime.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +85 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive-components.d.ts.map +1 -1
- package/dist/modes/interactive-components.js +4 -0
- package/dist/modes/interactive-components.js.map +1 -1
- package/dist/modes/interactive-state.js +1 -1
- package/dist/modes/interactive-state.js.map +1 -1
- package/dist/modes/interactive.d.ts +4 -0
- package/dist/modes/interactive.d.ts.map +1 -1
- package/dist/modes/interactive.js +26 -5
- package/dist/modes/interactive.js.map +1 -1
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/loader.d.ts +18 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +92 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manager.d.ts +23 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +152 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/manifest.d.ts +7 -0
- package/dist/plugins/manifest.d.ts.map +1 -0
- package/dist/plugins/manifest.js +116 -0
- package/dist/plugins/manifest.js.map +1 -0
- package/dist/plugins/types.d.ts +41 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/provider-onboarding.d.ts.map +1 -1
- package/dist/provider-onboarding.js +13 -1
- package/dist/provider-onboarding.js.map +1 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +37 -15
- package/dist/startup.js.map +1 -1
- package/package.json +24 -4
package/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# @di-code/coding-agent
|
|
2
|
+
|
|
3
|
+
`@di-code/coding-agent` 是 [di-code](https://github.com/qddidi/di-code) 的可安装终端 AI 编码代理。它包含 `di-code` CLI、本地 `read` / `write` / `edit` / `bash` 工具、会话管理、上下文压缩、交互式 ANSI UI、扩展系统和 JSONL RPC 服务端。
|
|
4
|
+
|
|
5
|
+
要求 Node.js `>= 22.19.0`。
|
|
6
|
+
|
|
7
|
+
## 快速安装启动
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
npm install @di-code/coding-agent -g
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
在需要 Agent 操作的项目目录启动交互式终端界面:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
di-code
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
没有 `DI_CODE_PROVIDER` 或 Provider 配置时,真实终端会启动首次配置向导。向导中输入的 API key 只保存在本次进程内存中。
|
|
20
|
+
|
|
21
|
+
## CLI 命令
|
|
22
|
+
|
|
23
|
+
完整用法:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
Usage: di-code [options] <prompt>
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
-p, --print 只输出最终 assistant 文本(默认)
|
|
30
|
+
--mode <mode> 输出模式:print、json 或 interactive
|
|
31
|
+
--interactive 启动交互式终端模式
|
|
32
|
+
--continue, -c 继续最近修改的会话
|
|
33
|
+
--session <path> 创建或恢复 JSONL 会话,路径相对于工作根目录
|
|
34
|
+
-h, --help 显示帮助
|
|
35
|
+
-v, --version 显示版本
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
常用命令:
|
|
39
|
+
|
|
40
|
+
```powershell
|
|
41
|
+
# 查看帮助和版本,不需要 Provider 或 API key
|
|
42
|
+
di-code --help
|
|
43
|
+
di-code --version
|
|
44
|
+
|
|
45
|
+
# 单次提问,默认是 print 模式
|
|
46
|
+
di-code "解释当前项目的目录结构"
|
|
47
|
+
di-code --print "找出项目中可能的 bug"
|
|
48
|
+
|
|
49
|
+
# JSON 模式:每行一个版本化事件,适合 PowerShell 或其他脚本消费
|
|
50
|
+
di-code --mode json "列出所有 TypeScript 文件"
|
|
51
|
+
|
|
52
|
+
# 交互模式:持续输入多个 prompt
|
|
53
|
+
di-code --interactive
|
|
54
|
+
|
|
55
|
+
# 保存到指定 JSONL 会话,后续可继续使用
|
|
56
|
+
di-code --session .di-code\sessions\review.jsonl "审查这个项目"
|
|
57
|
+
di-code --session .di-code\sessions\review.jsonl "检查测试覆盖率"
|
|
58
|
+
|
|
59
|
+
# 继续最近修改的会话
|
|
60
|
+
di-code --continue "继续上一次工作"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`--help` 和 `--version` 必须单独使用。非交互模式必须提供 prompt;`--continue` 不能和 `--session` 同时使用;`--print` 不能和 `--mode json` 或 `--interactive` 同时使用。
|
|
64
|
+
|
|
65
|
+
脚本中可以根据退出码判断结果:`0` 表示命令成功,`1` 表示参数错误、Provider 未配置或运行失败。错误文本写入 stderr,不会混入 `print` 模式的最终回答。
|
|
66
|
+
|
|
67
|
+
## 交互模式操作
|
|
68
|
+
|
|
69
|
+
运行 `di-code` 或 `di-code --interactive` 后,底部编辑器就是 prompt 输入框。输入内容后按 Enter 发送;模型生成期间再次输入的 prompt 会进入队列,按顺序执行。
|
|
70
|
+
|
|
71
|
+
### 斜杠命令
|
|
72
|
+
|
|
73
|
+
在输入框中输入 `/`,再按 Tab 可以打开命令补全菜单:
|
|
74
|
+
|
|
75
|
+
| 命令 | 作用 |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `/help` | 在状态区显示所有交互命令 |
|
|
78
|
+
| `/clear` | 清除当前屏幕上的可见消息,不删除 JSONL 会话历史 |
|
|
79
|
+
| `/model` | 打开模型选择器,切换当前 Provider 的模型 |
|
|
80
|
+
| `/session` | 打开会话选择器,切换或查看当前会话 |
|
|
81
|
+
| `/theme` | 在 dark 和 light 终端主题之间切换 |
|
|
82
|
+
| `/settings` | 打开设置,目前可切换上下文压缩 `on` / `off` |
|
|
83
|
+
| `/compact` | 立即压缩当前已持久化会话的上下文 |
|
|
84
|
+
| `/usage` | 显示请求数、输入/输出 token、总 token、费用和上下文占用 |
|
|
85
|
+
| `/retry` | 重试最近一次失败的 prompt |
|
|
86
|
+
|
|
87
|
+
例如:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
/help
|
|
91
|
+
/model
|
|
92
|
+
/usage
|
|
93
|
+
请检查刚才发现的问题
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
未知的 `/command` 会显示错误,不会发送给模型。`/clear` 只影响当前界面;想恢复之前的完整历史,应使用 `--session <path>` 或 `--continue` 打开会话。
|
|
97
|
+
|
|
98
|
+
### 快捷键
|
|
99
|
+
|
|
100
|
+
| 按键 | 作用 |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `Enter` | 发送当前 prompt |
|
|
103
|
+
| `Esc` | 取消正在进行的模型请求;没有请求时取消当前补全或关闭选择器 |
|
|
104
|
+
| `Ctrl+C` | 退出交互模式并恢复终端状态 |
|
|
105
|
+
| `Ctrl+O` | 打开模型选择器,与 `/model` 相同 |
|
|
106
|
+
| `Ctrl+L` | 打开会话选择器,与 `/session` 相同 |
|
|
107
|
+
| `Ctrl+T` | 打开主题选择器,与 `/theme` 相同 |
|
|
108
|
+
| `Ctrl+S` | 打开设置,与 `/settings` 相同 |
|
|
109
|
+
| `Ctrl+R` | 重试最近一次失败的 prompt,与 `/retry` 相同 |
|
|
110
|
+
| `Tab` | 补全斜杠命令;编辑普通文本时继续由编辑器处理 |
|
|
111
|
+
|
|
112
|
+
模型请求运行时按 `Esc` 会发送取消信号;取消后的 prompt 可以用 `/retry` 或 `Ctrl+R` 再次提交。退出只结束当前 CLI 进程,不会删除已经写入磁盘的会话文件。
|
|
113
|
+
|
|
114
|
+
## Provider 配置
|
|
115
|
+
|
|
116
|
+
全局安装的 CLI 启动前需要设置环境变量。不要把 API key 写入源代码或提交到 Git。
|
|
117
|
+
|
|
118
|
+
```powershell
|
|
119
|
+
$env:DI_CODE_PROVIDER = "openai"
|
|
120
|
+
$env:DI_CODE_MODEL = "gpt-4o" # 可选,不设置时使用默认模型
|
|
121
|
+
$env:OPENAI_API_KEY = "your-openai-api-key"
|
|
122
|
+
di-code --print "总结这个仓库"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
DeepSeek 使用 `$env:DI_CODE_PROVIDER = "deepseek"`、`$env:DEEPSEEK_API_KEY`,可选 `$env:DI_CODE_MODEL`。可选 endpoint 覆盖变量是 `OPENAI_BASE_URL` 和 `DEEPSEEK_BASE_URL`。设置 `DI_CODE_PROVIDER=faux` 可使用离线确定性 Provider。
|
|
126
|
+
|
|
127
|
+
## 自定义Provider settings
|
|
128
|
+
|
|
129
|
+
要使用自定义 OpenAI Responses 兼容网关,请在工作目录创建 `.di-code/settings.json`。凭据保存在环境变量中,文件只引用变量名,或者直接配置到apiKey中:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"providers": {
|
|
134
|
+
"company-gateway": {
|
|
135
|
+
"name": "Company Gateway",
|
|
136
|
+
"api": "openai-responses",
|
|
137
|
+
"baseUrl": "https://gateway.example.com/v1",
|
|
138
|
+
"apiKey": "$COMPANY_GATEWAY_API_KEY",
|
|
139
|
+
"models": [{
|
|
140
|
+
"id": "company-coder",//如gpt-5.5
|
|
141
|
+
"input": ["text"],
|
|
142
|
+
"reasoning": true,
|
|
143
|
+
"contextWindow": 200000,//可选,根据实际情况填写
|
|
144
|
+
"maxTokens": 32000 //可选
|
|
145
|
+
}]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
然后设置 `$env:COMPANY_GATEWAY_API_KEY`、`$env:DI_CODE_PROVIDER = "company-gateway"`,以及可选的 `$env:DI_CODE_MODEL = "company-coder"`。`apiKey` 支持 `$NAME` / `${NAME}` 引用。如果直接写入配置文件则无需设置环境变量。
|
|
152
|
+
|
|
153
|
+
### Provider 和模型字段
|
|
154
|
+
|
|
155
|
+
`.di-code/settings.json` 的根节点必须是 `providers` 对象。对象的 key 就是 Provider ID,用于 `DI_CODE_PROVIDER`。自定义 Provider 必须配置 `api` 和 `models`;内建 `openai`、`deepseek` 可以省略 `models`,使用内置模型目录。
|
|
156
|
+
|
|
157
|
+
Provider 字段:
|
|
158
|
+
|
|
159
|
+
| 字段 | 类型 | 说明 |
|
|
160
|
+
| --- | --- | --- |
|
|
161
|
+
| `name` | string | 可选的显示名称,省略时使用 Provider ID |
|
|
162
|
+
| `api` | string | `openai-responses` 或 `deepseek-responses` |
|
|
163
|
+
| `baseUrl` | string | Provider 默认 endpoint,必须是 `http` 或 `https` URL |
|
|
164
|
+
| `apiKey` | string | 推荐写 `$ENV_VAR` 或 `${ENV_VAR}`;也可直接写值,但不应提交到 Git |
|
|
165
|
+
| `models` | array | 自定义 Provider 必填;每项是一个模型对象 |
|
|
166
|
+
|
|
167
|
+
模型字段:
|
|
168
|
+
|
|
169
|
+
| 字段 | 类型 | 默认值或规则 |
|
|
170
|
+
| --- | --- | --- |
|
|
171
|
+
| `id` | string | 必填;也是 `DI_CODE_MODEL` 使用的模型 ID |
|
|
172
|
+
| `name` | string | 默认等于 `id` |
|
|
173
|
+
| `api` | string | 默认继承 Provider 的 `api`;模型值优先 |
|
|
174
|
+
| `baseUrl` | string | 默认继承 Provider 的 `baseUrl`;模型值优先 |
|
|
175
|
+
| `input` | array | 默认 `["text"]`;可填 `"text"`、`"image"` 或两者 |
|
|
176
|
+
| `reasoning` | boolean | 默认 `false`,表示模型是否支持思考内容 |
|
|
177
|
+
| `contextWindow` | 正整数 | 默认 `128000`,模型上下文 token 上限 |
|
|
178
|
+
| `maxTokens` | 正整数 | 默认 `16384`,单次最大输出 token;也支持 `maxOutputTokens` |
|
|
179
|
+
| `cost.input` | 非负数 | 默认 `0`,美元/百万输入 token |
|
|
180
|
+
| `cost.output` | 非负数 | 默认 `0`,美元/百万输出 token |
|
|
181
|
+
| `cost.cacheRead` | 非负数 | 默认 `0`,美元/百万缓存读取 token |
|
|
182
|
+
| `cost.cacheWrite` | 非负数 | 默认 `0`,美元/百万缓存写入 token |
|
|
183
|
+
|
|
184
|
+
完整示例:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"providers": {
|
|
189
|
+
"company-gateway": {
|
|
190
|
+
"name": "公司网关",
|
|
191
|
+
"api": "openai-responses",
|
|
192
|
+
"baseUrl": "https://gateway.example.com/v1",
|
|
193
|
+
"apiKey": "$COMPANY_GATEWAY_API_KEY",
|
|
194
|
+
"models": [
|
|
195
|
+
{
|
|
196
|
+
"id": "company-coder",
|
|
197
|
+
"name": "Company Coder",
|
|
198
|
+
"input": ["text", "image"],
|
|
199
|
+
"reasoning": true,
|
|
200
|
+
"contextWindow": 200000,
|
|
201
|
+
"maxTokens": 32000,
|
|
202
|
+
"cost": {
|
|
203
|
+
"input": 2.5,
|
|
204
|
+
"output": 10,
|
|
205
|
+
"cacheRead": 1.25,
|
|
206
|
+
"cacheWrite": 0
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
模型级 `baseUrl` 和 `api` 可以覆盖 Provider 级字段,模型级 `apiKey` 不存在,凭据始终从 Provider 级 `apiKey` 获取。`DI_CODE_MODEL` 必须匹配所选 Provider 的某个 `models[].id`;省略时使用该 Provider 的第一个模型。自定义模型只属于声明它的 Provider,不会自动出现在其他 Provider 的列表中。
|
|
216
|
+
|
|
217
|
+
## RPC 集成
|
|
218
|
+
|
|
219
|
+
该包还安装 `di-code-rpc`,这是供宿主程序使用的 JSONL 子进程入口,不是交互式终端命令。Node.js 宿主程序从 `@di-code/coding-agent/rpc` 导入 RPC API;需要监管子进程时使用 `@di-code/orchestrator`。
|
|
220
|
+
|
|
221
|
+
## 链接
|
|
222
|
+
|
|
223
|
+
- 源码和完整配置说明:<https://github.com/qddidi/di-code>
|
|
224
|
+
- 提交问题:<https://github.com/qddidi/di-code/issues>
|
package/dist/cli.d.ts
CHANGED
|
@@ -3,12 +3,20 @@ export type CliCommand = {
|
|
|
3
3
|
kind: "help";
|
|
4
4
|
} | {
|
|
5
5
|
kind: "version";
|
|
6
|
+
} | {
|
|
7
|
+
kind: "plugin";
|
|
8
|
+
action: "install" | "list" | "enable" | "disable" | "update" | "remove";
|
|
9
|
+
argument?: string;
|
|
6
10
|
} | {
|
|
7
11
|
kind: "run";
|
|
8
12
|
mode: OutputMode;
|
|
9
13
|
prompt: string;
|
|
10
14
|
sessionPath?: string;
|
|
11
15
|
continueSession?: true;
|
|
16
|
+
noSkills?: true;
|
|
17
|
+
noContextFiles?: true;
|
|
18
|
+
skillPaths?: readonly string[];
|
|
19
|
+
projectTrust?: boolean;
|
|
12
20
|
};
|
|
13
21
|
export declare class CliUsageError extends Error {
|
|
14
22
|
constructor(message: string);
|
|
@@ -20,6 +28,9 @@ export interface CliDependencies {
|
|
|
20
28
|
run(command: Extract<CliCommand, {
|
|
21
29
|
kind: "run";
|
|
22
30
|
}>): Promise<number>;
|
|
31
|
+
plugin?(command: Extract<CliCommand, {
|
|
32
|
+
kind: "plugin";
|
|
33
|
+
}>): Promise<number>;
|
|
23
34
|
readonly version: string;
|
|
24
35
|
}
|
|
25
36
|
export declare function runCli(args: readonly string[], dependencies: CliDependencies): Promise<number>;
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAE1D,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAE1D,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9G;IACA,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEL,qBAAa,aAAc,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAoIhE;AAoBD,MAAM,WAAW,eAAe;IAC/B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBpG"}
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,22 @@ export class CliUsageError extends Error {
|
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
export function parseCliArgs(args) {
|
|
8
|
+
if (args[0] === "plugin") {
|
|
9
|
+
const action = args[1];
|
|
10
|
+
if (action !== "install" &&
|
|
11
|
+
action !== "list" &&
|
|
12
|
+
action !== "enable" &&
|
|
13
|
+
action !== "disable" &&
|
|
14
|
+
action !== "update" &&
|
|
15
|
+
action !== "remove")
|
|
16
|
+
throw new CliUsageError("Plugin command must be install, list, enable, disable, update, or remove.");
|
|
17
|
+
const argument = args[2];
|
|
18
|
+
if (args.length > 3 ||
|
|
19
|
+
(action !== "list" && (argument === undefined || argument.trim() === "")) ||
|
|
20
|
+
(action === "list" && argument !== undefined))
|
|
21
|
+
throw new CliUsageError("Plugin command has invalid arguments.");
|
|
22
|
+
return { kind: "plugin", action, ...(argument ? { argument } : {}) };
|
|
23
|
+
}
|
|
8
24
|
const staticOption = args.find((argument) => ["-h", "--help", "-v", "--version"].includes(argument));
|
|
9
25
|
if (staticOption !== undefined) {
|
|
10
26
|
const kind = staticOption === "-h" || staticOption === "--help" ? "help" : "version";
|
|
@@ -17,6 +33,10 @@ export function parseCliArgs(args) {
|
|
|
17
33
|
let printAlias = false;
|
|
18
34
|
let sessionPath;
|
|
19
35
|
let continueSession = false;
|
|
36
|
+
let noSkills = false;
|
|
37
|
+
let noContextFiles = false;
|
|
38
|
+
let projectTrust;
|
|
39
|
+
const skillPaths = [];
|
|
20
40
|
const promptParts = [];
|
|
21
41
|
for (let index = 0; index < args.length; index++) {
|
|
22
42
|
const argument = args[index];
|
|
@@ -32,6 +52,31 @@ export function parseCliArgs(args) {
|
|
|
32
52
|
continueSession = true;
|
|
33
53
|
continue;
|
|
34
54
|
}
|
|
55
|
+
if (argument === "--no-skills") {
|
|
56
|
+
noSkills = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (argument === "--no-context-files") {
|
|
60
|
+
noContextFiles = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (argument === "--trust-project" || argument === "--untrust-project") {
|
|
64
|
+
const nextTrust = argument === "--trust-project";
|
|
65
|
+
if (projectTrust !== undefined && projectTrust !== nextTrust) {
|
|
66
|
+
throw new CliUsageError("Cannot combine --trust-project with --untrust-project.");
|
|
67
|
+
}
|
|
68
|
+
projectTrust = nextTrust;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (argument === "--skill") {
|
|
72
|
+
const value = args[index + 1];
|
|
73
|
+
if (value === undefined || value.trim().length === 0) {
|
|
74
|
+
throw new CliUsageError("Option --skill requires a non-empty value.");
|
|
75
|
+
}
|
|
76
|
+
skillPaths.push(value);
|
|
77
|
+
index++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
35
80
|
if (argument === "--mode") {
|
|
36
81
|
const value = args[index + 1];
|
|
37
82
|
if (value === undefined) {
|
|
@@ -78,6 +123,10 @@ export function parseCliArgs(args) {
|
|
|
78
123
|
prompt: promptParts.join(" "),
|
|
79
124
|
...(sessionPath ? { sessionPath } : {}),
|
|
80
125
|
...(continueSession ? { continueSession: true } : {}),
|
|
126
|
+
...(noSkills ? { noSkills: true } : {}),
|
|
127
|
+
...(noContextFiles ? { noContextFiles: true } : {}),
|
|
128
|
+
...(skillPaths.length > 0 ? { skillPaths } : {}),
|
|
129
|
+
...(projectTrust === undefined ? {} : { projectTrust }),
|
|
81
130
|
};
|
|
82
131
|
}
|
|
83
132
|
const HELP_TEXT = `Usage: di-code [options] <prompt>
|
|
@@ -88,6 +137,12 @@ Options:
|
|
|
88
137
|
--interactive Start interactive terminal mode
|
|
89
138
|
--continue, -c Continue the most recently modified session
|
|
90
139
|
--session <path> Create or resume a JSONL session (relative to the work root)
|
|
140
|
+
--skill <path> Add a SKILL.md file or skill directory (repeatable)
|
|
141
|
+
--no-skills Disable all Skill loading
|
|
142
|
+
--no-context-files Disable AGENTS.md discovery and loading
|
|
143
|
+
--trust-project Persist trust for project-local Skill discovery
|
|
144
|
+
--untrust-project Persist denial for project-local Skill discovery
|
|
145
|
+
plugin <action> Install, list, enable, disable, update, or remove a plugin
|
|
91
146
|
-h, --help Show help
|
|
92
147
|
-v, --version Show version
|
|
93
148
|
`;
|
|
@@ -107,6 +162,10 @@ export async function runCli(args, dependencies) {
|
|
|
107
162
|
case "help":
|
|
108
163
|
dependencies.stdout(HELP_TEXT);
|
|
109
164
|
return 0;
|
|
165
|
+
case "plugin":
|
|
166
|
+
if (!dependencies.plugin)
|
|
167
|
+
throw new Error("Plugin command handler is unavailable.");
|
|
168
|
+
return dependencies.plugin(command);
|
|
110
169
|
case "version":
|
|
111
170
|
dependencies.stdout(`${dependencies.version}\n`);
|
|
112
171
|
return 0;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputMode = \"print\" | \"json\" | \"interactive\";\n\nexport type CliCommand =\n\t| { kind: \"help\" }\n\t| { kind: \"version\" }\n\t| { kind: \"run\"; mode: OutputMode; prompt: string; sessionPath?: string; continueSession?: true };\n\nexport class CliUsageError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CliUsageError\";\n\t}\n}\n\nexport function parseCliArgs(args: readonly string[]): CliCommand {\n\tconst staticOption = args.find((argument) => [\"-h\", \"--help\", \"-v\", \"--version\"].includes(argument));\n\tif (staticOption !== undefined) {\n\t\tconst kind = staticOption === \"-h\" || staticOption === \"--help\" ? \"help\" : \"version\";\n\t\tif (args.length !== 1) {\n\t\t\tthrow new CliUsageError(`--${kind} must be used on its own.`);\n\t\t}\n\t\treturn { kind };\n\t}\n\n\tlet mode: OutputMode = \"print\";\n\tlet printAlias = false;\n\tlet sessionPath: string | undefined;\n\tlet continueSession = false;\n\tconst promptParts: string[] = [];\n\n\tfor (let index = 0; index < args.length; index++) {\n\t\tconst argument = args[index];\n\t\tif (argument === \"-p\" || argument === \"--print\") {\n\t\t\tprintAlias = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--interactive\") {\n\t\t\tmode = \"interactive\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"-c\" || argument === \"--continue\") {\n\t\t\tcontinueSession = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--mode\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --mode requires a value.\");\n\t\t\t}\n\t\t\tif (value !== \"print\" && value !== \"json\" && value !== \"interactive\") {\n\t\t\t\tthrow new CliUsageError(`Unsupported mode \"${value}\". Expected print, json, or interactive.`);\n\t\t\t}\n\t\t\tmode = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--session\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a value.\");\n\t\t\t}\n\t\t\tif (value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a non-empty value.\");\n\t\t\t}\n\t\t\tsessionPath = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument?.startsWith(\"-\")) {\n\t\t\tthrow new CliUsageError(`Unknown option \"${argument}\".`);\n\t\t}\n\t\tif (argument !== undefined) {\n\t\t\tpromptParts.push(argument);\n\t\t}\n\t}\n\n\tif (printAlias && mode !== \"print\") {\n\t\tthrow new CliUsageError(`Cannot combine --print with --mode ${mode}.`);\n\t}\n\tif (continueSession && sessionPath !== undefined) {\n\t\tthrow new CliUsageError(\"Cannot combine --continue with --session.\");\n\t}\n\tif (promptParts.length === 0 && mode !== \"interactive\") {\n\t\tthrow new CliUsageError(\"A prompt is required.\");\n\t}\n\n\treturn {\n\t\tkind: \"run\",\n\t\tmode,\n\t\tprompt: promptParts.join(\" \"),\n\t\t...(sessionPath ? { sessionPath } : {}),\n\t\t...(continueSession ? { continueSession: true as const } : {}),\n\t};\n}\n\nconst HELP_TEXT = `Usage: di-code [options] <prompt>\n\nOptions:\n -p, --print Print only the final assistant text (default)\n --mode <mode> Output mode: print, json, or interactive\n --interactive Start interactive terminal mode\n --continue, -c Continue the most recently modified session\n --session <path> Create or resume a JSONL session (relative to the work root)\n -h, --help Show help\n -v, --version Show version\n`;\n\nexport interface CliDependencies {\n\tstdout(text: string): void;\n\tstderr(text: string): void;\n\trun(command: Extract<CliCommand, { kind: \"run\" }>): Promise<number>;\n\treadonly version: string;\n}\n\nexport async function runCli(args: readonly string[], dependencies: CliDependencies): Promise<number> {\n\tlet command: CliCommand;\n\ttry {\n\t\tcommand = parseCliArgs(args);\n\t} catch (cause) {\n\t\tif (cause instanceof CliUsageError) {\n\t\t\tdependencies.stderr(`${cause.message}\\n`);\n\t\t\treturn 1;\n\t\t}\n\t\tthrow cause;\n\t}\n\n\tswitch (command.kind) {\n\t\tcase \"help\":\n\t\t\tdependencies.stdout(HELP_TEXT);\n\t\t\treturn 0;\n\t\tcase \"version\":\n\t\t\tdependencies.stdout(`${dependencies.version}\\n`);\n\t\t\treturn 0;\n\t\tcase \"run\":\n\t\t\treturn dependencies.run(command);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputMode = \"print\" | \"json\" | \"interactive\";\n\nexport type CliCommand =\n\t| { kind: \"help\" }\n\t| { kind: \"version\" }\n\t| { kind: \"plugin\"; action: \"install\" | \"list\" | \"enable\" | \"disable\" | \"update\" | \"remove\"; argument?: string }\n\t| {\n\t\t\tkind: \"run\";\n\t\t\tmode: OutputMode;\n\t\t\tprompt: string;\n\t\t\tsessionPath?: string;\n\t\t\tcontinueSession?: true;\n\t\t\tnoSkills?: true;\n\t\t\tnoContextFiles?: true;\n\t\t\tskillPaths?: readonly string[];\n\t\t\tprojectTrust?: boolean;\n\t };\n\nexport class CliUsageError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CliUsageError\";\n\t}\n}\n\nexport function parseCliArgs(args: readonly string[]): CliCommand {\n\tif (args[0] === \"plugin\") {\n\t\tconst action = args[1];\n\t\tif (\n\t\t\taction !== \"install\" &&\n\t\t\taction !== \"list\" &&\n\t\t\taction !== \"enable\" &&\n\t\t\taction !== \"disable\" &&\n\t\t\taction !== \"update\" &&\n\t\t\taction !== \"remove\"\n\t\t)\n\t\t\tthrow new CliUsageError(\"Plugin command must be install, list, enable, disable, update, or remove.\");\n\t\tconst argument = args[2];\n\t\tif (\n\t\t\targs.length > 3 ||\n\t\t\t(action !== \"list\" && (argument === undefined || argument.trim() === \"\")) ||\n\t\t\t(action === \"list\" && argument !== undefined)\n\t\t)\n\t\t\tthrow new CliUsageError(\"Plugin command has invalid arguments.\");\n\t\treturn { kind: \"plugin\", action, ...(argument ? { argument } : {}) };\n\t}\n\tconst staticOption = args.find((argument) => [\"-h\", \"--help\", \"-v\", \"--version\"].includes(argument));\n\tif (staticOption !== undefined) {\n\t\tconst kind = staticOption === \"-h\" || staticOption === \"--help\" ? \"help\" : \"version\";\n\t\tif (args.length !== 1) {\n\t\t\tthrow new CliUsageError(`--${kind} must be used on its own.`);\n\t\t}\n\t\treturn { kind };\n\t}\n\n\tlet mode: OutputMode = \"print\";\n\tlet printAlias = false;\n\tlet sessionPath: string | undefined;\n\tlet continueSession = false;\n\tlet noSkills = false;\n\tlet noContextFiles = false;\n\tlet projectTrust: boolean | undefined;\n\tconst skillPaths: string[] = [];\n\tconst promptParts: string[] = [];\n\n\tfor (let index = 0; index < args.length; index++) {\n\t\tconst argument = args[index];\n\t\tif (argument === \"-p\" || argument === \"--print\") {\n\t\t\tprintAlias = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--interactive\") {\n\t\t\tmode = \"interactive\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"-c\" || argument === \"--continue\") {\n\t\t\tcontinueSession = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--no-skills\") {\n\t\t\tnoSkills = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--no-context-files\") {\n\t\t\tnoContextFiles = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--trust-project\" || argument === \"--untrust-project\") {\n\t\t\tconst nextTrust = argument === \"--trust-project\";\n\t\t\tif (projectTrust !== undefined && projectTrust !== nextTrust) {\n\t\t\t\tthrow new CliUsageError(\"Cannot combine --trust-project with --untrust-project.\");\n\t\t\t}\n\t\t\tprojectTrust = nextTrust;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--skill\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined || value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --skill requires a non-empty value.\");\n\t\t\t}\n\t\t\tskillPaths.push(value);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--mode\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --mode requires a value.\");\n\t\t\t}\n\t\t\tif (value !== \"print\" && value !== \"json\" && value !== \"interactive\") {\n\t\t\t\tthrow new CliUsageError(`Unsupported mode \"${value}\". Expected print, json, or interactive.`);\n\t\t\t}\n\t\t\tmode = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--session\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a value.\");\n\t\t\t}\n\t\t\tif (value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a non-empty value.\");\n\t\t\t}\n\t\t\tsessionPath = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument?.startsWith(\"-\")) {\n\t\t\tthrow new CliUsageError(`Unknown option \"${argument}\".`);\n\t\t}\n\t\tif (argument !== undefined) {\n\t\t\tpromptParts.push(argument);\n\t\t}\n\t}\n\n\tif (printAlias && mode !== \"print\") {\n\t\tthrow new CliUsageError(`Cannot combine --print with --mode ${mode}.`);\n\t}\n\tif (continueSession && sessionPath !== undefined) {\n\t\tthrow new CliUsageError(\"Cannot combine --continue with --session.\");\n\t}\n\tif (promptParts.length === 0 && mode !== \"interactive\") {\n\t\tthrow new CliUsageError(\"A prompt is required.\");\n\t}\n\n\treturn {\n\t\tkind: \"run\",\n\t\tmode,\n\t\tprompt: promptParts.join(\" \"),\n\t\t...(sessionPath ? { sessionPath } : {}),\n\t\t...(continueSession ? { continueSession: true as const } : {}),\n\t\t...(noSkills ? { noSkills: true as const } : {}),\n\t\t...(noContextFiles ? { noContextFiles: true as const } : {}),\n\t\t...(skillPaths.length > 0 ? { skillPaths } : {}),\n\t\t...(projectTrust === undefined ? {} : { projectTrust }),\n\t};\n}\n\nconst HELP_TEXT = `Usage: di-code [options] <prompt>\n\nOptions:\n -p, --print Print only the final assistant text (default)\n --mode <mode> Output mode: print, json, or interactive\n --interactive Start interactive terminal mode\n --continue, -c Continue the most recently modified session\n --session <path> Create or resume a JSONL session (relative to the work root)\n --skill <path> Add a SKILL.md file or skill directory (repeatable)\n --no-skills Disable all Skill loading\n --no-context-files Disable AGENTS.md discovery and loading\n --trust-project Persist trust for project-local Skill discovery\n --untrust-project Persist denial for project-local Skill discovery\n plugin <action> Install, list, enable, disable, update, or remove a plugin\n -h, --help Show help\n -v, --version Show version\n`;\n\nexport interface CliDependencies {\n\tstdout(text: string): void;\n\tstderr(text: string): void;\n\trun(command: Extract<CliCommand, { kind: \"run\" }>): Promise<number>;\n\tplugin?(command: Extract<CliCommand, { kind: \"plugin\" }>): Promise<number>;\n\treadonly version: string;\n}\n\nexport async function runCli(args: readonly string[], dependencies: CliDependencies): Promise<number> {\n\tlet command: CliCommand;\n\ttry {\n\t\tcommand = parseCliArgs(args);\n\t} catch (cause) {\n\t\tif (cause instanceof CliUsageError) {\n\t\t\tdependencies.stderr(`${cause.message}\\n`);\n\t\t\treturn 1;\n\t\t}\n\t\tthrow cause;\n\t}\n\n\tswitch (command.kind) {\n\t\tcase \"help\":\n\t\t\tdependencies.stdout(HELP_TEXT);\n\t\t\treturn 0;\n\t\tcase \"plugin\":\n\t\t\tif (!dependencies.plugin) throw new Error(\"Plugin command handler is unavailable.\");\n\t\t\treturn dependencies.plugin(command);\n\t\tcase \"version\":\n\t\t\tdependencies.stdout(`${dependencies.version}\\n`);\n\t\t\treturn 0;\n\t\tcase \"run\":\n\t\t\treturn dependencies.run(command);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DefaultResourceLoader, loadResources } from "./loader.ts";
|
|
2
|
+
export type { ContextFile, ResourceDiagnostic, ResourceDiagnosticStage, ResourceLoader, ResourceLoaderOptions, ResourceScope, ResourceSnapshot, SkillResource, } from "./types.ts";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACX,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,aAAa,GACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export { DefaultResourceLoader, loadResources } from \"./loader.ts\";\nexport type {\n\tContextFile,\n\tResourceDiagnostic,\n\tResourceDiagnosticStage,\n\tResourceLoader,\n\tResourceLoaderOptions,\n\tResourceScope,\n\tResourceSnapshot,\n\tSkillResource,\n} from \"./types.ts\";\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ResourceLoader, ResourceLoaderOptions, ResourceSnapshot } from "./types.ts";
|
|
2
|
+
export declare class DefaultResourceLoader implements ResourceLoader {
|
|
3
|
+
private readonly options;
|
|
4
|
+
constructor(options: ResourceLoaderOptions);
|
|
5
|
+
load(): Promise<ResourceSnapshot>;
|
|
6
|
+
}
|
|
7
|
+
export declare function loadResources(options: ResourceLoaderOptions): Promise<ResourceSnapshot>;
|
|
8
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/resources/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGX,cAAc,EACd,qBAAqB,EAErB,gBAAgB,EAEhB,MAAM,YAAY,CAAC;AAyFpB,qBAAa,qBAAsB,YAAW,cAAc;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;gBAEpC,OAAO,EAAE,qBAAqB;IAIpC,IAAI,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAmEvC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAE7F"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { access, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, parse, resolve } from "node:path";
|
|
3
|
+
import { discoverSkills, loadSkill } from "./skills.js";
|
|
4
|
+
const MAX_CONTEXT_FILE_BYTES = 256 * 1024;
|
|
5
|
+
function isMissingPath(cause) {
|
|
6
|
+
return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
7
|
+
}
|
|
8
|
+
function contextDiagnostic(path, stage, message) {
|
|
9
|
+
return { path, kind: "agents", stage, severity: "warning", message };
|
|
10
|
+
}
|
|
11
|
+
async function locateAgentsFile(directory) {
|
|
12
|
+
for (const name of ["AGENTS.md", "AGENTS.MD"]) {
|
|
13
|
+
const path = join(directory, name);
|
|
14
|
+
try {
|
|
15
|
+
if ((await stat(path)).isFile())
|
|
16
|
+
return path;
|
|
17
|
+
}
|
|
18
|
+
catch (cause) {
|
|
19
|
+
if (!isMissingPath(cause))
|
|
20
|
+
throw cause;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
async function loadContextFile(path, scope) {
|
|
26
|
+
try {
|
|
27
|
+
const metadata = await stat(path);
|
|
28
|
+
if (metadata.size > MAX_CONTEXT_FILE_BYTES) {
|
|
29
|
+
return { diagnostic: contextDiagnostic(path, "read", `AGENTS.md exceeds ${MAX_CONTEXT_FILE_BYTES} byte limit`) };
|
|
30
|
+
}
|
|
31
|
+
return { file: { kind: "agents", path: resolve(path), scope, content: await readFile(path, "utf8") } };
|
|
32
|
+
}
|
|
33
|
+
catch (cause) {
|
|
34
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
35
|
+
return { diagnostic: contextDiagnostic(path, "read", `Failed to read AGENTS.md: ${message}`) };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function loadContextFiles(options) {
|
|
39
|
+
if (options.noContextFiles)
|
|
40
|
+
return { contextFiles: [], diagnostics: [] };
|
|
41
|
+
const contextFiles = [];
|
|
42
|
+
const diagnostics = [];
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
const add = async (directory, scope) => {
|
|
45
|
+
let path;
|
|
46
|
+
try {
|
|
47
|
+
path = await locateAgentsFile(directory);
|
|
48
|
+
}
|
|
49
|
+
catch (cause) {
|
|
50
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
51
|
+
diagnostics.push(contextDiagnostic(directory, "discover", `Failed to discover AGENTS.md: ${message}`));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!path)
|
|
55
|
+
return;
|
|
56
|
+
const absolutePath = resolve(path);
|
|
57
|
+
if (seen.has(absolutePath))
|
|
58
|
+
return;
|
|
59
|
+
seen.add(absolutePath);
|
|
60
|
+
const loaded = await loadContextFile(absolutePath, scope);
|
|
61
|
+
if (loaded.file)
|
|
62
|
+
contextFiles.push(loaded.file);
|
|
63
|
+
if (loaded.diagnostic)
|
|
64
|
+
diagnostics.push(loaded.diagnostic);
|
|
65
|
+
};
|
|
66
|
+
await add(resolve(options.agentDir), "global");
|
|
67
|
+
const ancestors = [];
|
|
68
|
+
let current = resolve(options.cwd);
|
|
69
|
+
while (true) {
|
|
70
|
+
ancestors.unshift(current);
|
|
71
|
+
const parent = dirname(current);
|
|
72
|
+
if (parent === current || parse(current).root === current)
|
|
73
|
+
break;
|
|
74
|
+
current = parent;
|
|
75
|
+
}
|
|
76
|
+
for (const directory of ancestors)
|
|
77
|
+
await add(directory, directory === resolve(options.cwd) ? "project" : "ancestor");
|
|
78
|
+
return { contextFiles, diagnostics };
|
|
79
|
+
}
|
|
80
|
+
async function exists(directory) {
|
|
81
|
+
try {
|
|
82
|
+
await access(directory);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
catch (cause) {
|
|
86
|
+
if (isMissingPath(cause))
|
|
87
|
+
return false;
|
|
88
|
+
throw cause;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export class DefaultResourceLoader {
|
|
92
|
+
options;
|
|
93
|
+
constructor(options) {
|
|
94
|
+
this.options = options;
|
|
95
|
+
}
|
|
96
|
+
async load() {
|
|
97
|
+
const context = await loadContextFiles(this.options);
|
|
98
|
+
const diagnostics = [...context.diagnostics];
|
|
99
|
+
const skills = new Map();
|
|
100
|
+
const add = (candidate, candidateDiagnostics) => {
|
|
101
|
+
diagnostics.push(...candidateDiagnostics);
|
|
102
|
+
const existing = skills.get(candidate.name);
|
|
103
|
+
if (existing) {
|
|
104
|
+
diagnostics.push({
|
|
105
|
+
path: candidate.filePath,
|
|
106
|
+
kind: "skill",
|
|
107
|
+
stage: "collision",
|
|
108
|
+
severity: "warning",
|
|
109
|
+
message: `Skill name collision: "${candidate.name}"; using ${existing.filePath}`,
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
skills.set(candidate.name, candidate);
|
|
114
|
+
};
|
|
115
|
+
const addResults = (results) => {
|
|
116
|
+
for (const result of results) {
|
|
117
|
+
if (result.skill)
|
|
118
|
+
add(result.skill, result.diagnostics);
|
|
119
|
+
else
|
|
120
|
+
diagnostics.push(...result.diagnostics);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
if (!this.options.noSkills) {
|
|
124
|
+
for (const rawPath of this.options.skillPaths ?? []) {
|
|
125
|
+
const path = resolve(this.options.cwd, rawPath);
|
|
126
|
+
try {
|
|
127
|
+
const metadata = await stat(path);
|
|
128
|
+
if (metadata.isDirectory())
|
|
129
|
+
addResults(await discoverSkills(path, "explicit"));
|
|
130
|
+
else {
|
|
131
|
+
const result = await loadSkill(path, "explicit");
|
|
132
|
+
if (result.skill)
|
|
133
|
+
add(result.skill, result.diagnostics);
|
|
134
|
+
else
|
|
135
|
+
diagnostics.push(...result.diagnostics);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (cause) {
|
|
139
|
+
const message = isMissingPath(cause)
|
|
140
|
+
? "Skill path does not exist"
|
|
141
|
+
: `Failed to discover skill path: ${String(cause)}`;
|
|
142
|
+
diagnostics.push({ path, kind: "skill", stage: "discover", severity: "warning", message });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const projectDirectories = [
|
|
146
|
+
join(this.options.cwd, ".di-code", "skills"),
|
|
147
|
+
join(this.options.cwd, ".pi", "skills"),
|
|
148
|
+
];
|
|
149
|
+
if (this.options.projectTrusted === true) {
|
|
150
|
+
for (const directory of projectDirectories)
|
|
151
|
+
addResults(await discoverSkills(directory, "project"));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
for (const directory of projectDirectories) {
|
|
155
|
+
if (await exists(directory)) {
|
|
156
|
+
diagnostics.push({
|
|
157
|
+
path: resolve(directory),
|
|
158
|
+
kind: "skill",
|
|
159
|
+
stage: "trust",
|
|
160
|
+
severity: "warning",
|
|
161
|
+
message: "Project skill skipped because project trust is not granted",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
addResults(await discoverSkills(join(this.options.agentDir, "skills"), "global"));
|
|
167
|
+
}
|
|
168
|
+
return { contextFiles: context.contextFiles, skills: [...skills.values()], diagnostics };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function loadResources(options) {
|
|
172
|
+
return new DefaultResourceLoader(options).load();
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/resources/loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { access, readFile, stat } from \"node:fs/promises\";\nimport { dirname, join, parse, resolve } from \"node:path\";\nimport { discoverSkills, loadSkill } from \"./skills.ts\";\nimport type {\n\tContextFile,\n\tResourceDiagnostic,\n\tResourceLoader,\n\tResourceLoaderOptions,\n\tResourceScope,\n\tResourceSnapshot,\n\tSkillResource,\n} from \"./types.ts\";\n\nconst MAX_CONTEXT_FILE_BYTES = 256 * 1024;\n\nfunction isMissingPath(cause: unknown): boolean {\n\treturn cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\";\n}\n\nfunction contextDiagnostic(path: string, stage: ResourceDiagnostic[\"stage\"], message: string): ResourceDiagnostic {\n\treturn { path, kind: \"agents\", stage, severity: \"warning\", message };\n}\n\nasync function locateAgentsFile(directory: string): Promise<string | undefined> {\n\tfor (const name of [\"AGENTS.md\", \"AGENTS.MD\"]) {\n\t\tconst path = join(directory, name);\n\t\ttry {\n\t\t\tif ((await stat(path)).isFile()) return path;\n\t\t} catch (cause) {\n\t\t\tif (!isMissingPath(cause)) throw cause;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nasync function loadContextFile(\n\tpath: string,\n\tscope: ResourceScope,\n): Promise<{ file?: ContextFile; diagnostic?: ResourceDiagnostic }> {\n\ttry {\n\t\tconst metadata = await stat(path);\n\t\tif (metadata.size > MAX_CONTEXT_FILE_BYTES) {\n\t\t\treturn { diagnostic: contextDiagnostic(path, \"read\", `AGENTS.md exceeds ${MAX_CONTEXT_FILE_BYTES} byte limit`) };\n\t\t}\n\t\treturn { file: { kind: \"agents\", path: resolve(path), scope, content: await readFile(path, \"utf8\") } };\n\t} catch (cause) {\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\treturn { diagnostic: contextDiagnostic(path, \"read\", `Failed to read AGENTS.md: ${message}`) };\n\t}\n}\n\nasync function loadContextFiles(options: ResourceLoaderOptions): Promise<{\n\tcontextFiles: ContextFile[];\n\tdiagnostics: ResourceDiagnostic[];\n}> {\n\tif (options.noContextFiles) return { contextFiles: [], diagnostics: [] };\n\tconst contextFiles: ContextFile[] = [];\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\tconst seen = new Set<string>();\n\tconst add = async (directory: string, scope: ResourceScope): Promise<void> => {\n\t\tlet path: string | undefined;\n\t\ttry {\n\t\t\tpath = await locateAgentsFile(directory);\n\t\t} catch (cause) {\n\t\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\t\tdiagnostics.push(contextDiagnostic(directory, \"discover\", `Failed to discover AGENTS.md: ${message}`));\n\t\t\treturn;\n\t\t}\n\t\tif (!path) return;\n\t\tconst absolutePath = resolve(path);\n\t\tif (seen.has(absolutePath)) return;\n\t\tseen.add(absolutePath);\n\t\tconst loaded = await loadContextFile(absolutePath, scope);\n\t\tif (loaded.file) contextFiles.push(loaded.file);\n\t\tif (loaded.diagnostic) diagnostics.push(loaded.diagnostic);\n\t};\n\n\tawait add(resolve(options.agentDir), \"global\");\n\tconst ancestors: string[] = [];\n\tlet current = resolve(options.cwd);\n\twhile (true) {\n\t\tancestors.unshift(current);\n\t\tconst parent = dirname(current);\n\t\tif (parent === current || parse(current).root === current) break;\n\t\tcurrent = parent;\n\t}\n\tfor (const directory of ancestors) await add(directory, directory === resolve(options.cwd) ? \"project\" : \"ancestor\");\n\treturn { contextFiles, diagnostics };\n}\n\nasync function exists(directory: string): Promise<boolean> {\n\ttry {\n\t\tawait access(directory);\n\t\treturn true;\n\t} catch (cause) {\n\t\tif (isMissingPath(cause)) return false;\n\t\tthrow cause;\n\t}\n}\n\nexport class DefaultResourceLoader implements ResourceLoader {\n\tprivate readonly options: ResourceLoaderOptions;\n\n\tconstructor(options: ResourceLoaderOptions) {\n\t\tthis.options = options;\n\t}\n\n\tasync load(): Promise<ResourceSnapshot> {\n\t\tconst context = await loadContextFiles(this.options);\n\t\tconst diagnostics = [...context.diagnostics];\n\t\tconst skills = new Map<string, SkillResource>();\n\t\tconst add = (candidate: SkillResource, candidateDiagnostics: readonly ResourceDiagnostic[]): void => {\n\t\t\tdiagnostics.push(...candidateDiagnostics);\n\t\t\tconst existing = skills.get(candidate.name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tpath: candidate.filePath,\n\t\t\t\t\tkind: \"skill\",\n\t\t\t\t\tstage: \"collision\",\n\t\t\t\t\tseverity: \"warning\",\n\t\t\t\t\tmessage: `Skill name collision: \"${candidate.name}\"; using ${existing.filePath}`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tskills.set(candidate.name, candidate);\n\t\t};\n\t\tconst addResults = (results: Awaited<ReturnType<typeof discoverSkills>>): void => {\n\t\t\tfor (const result of results) {\n\t\t\t\tif (result.skill) add(result.skill, result.diagnostics);\n\t\t\t\telse diagnostics.push(...result.diagnostics);\n\t\t\t}\n\t\t};\n\n\t\tif (!this.options.noSkills) {\n\t\t\tfor (const rawPath of this.options.skillPaths ?? []) {\n\t\t\t\tconst path = resolve(this.options.cwd, rawPath);\n\t\t\t\ttry {\n\t\t\t\t\tconst metadata = await stat(path);\n\t\t\t\t\tif (metadata.isDirectory()) addResults(await discoverSkills(path, \"explicit\"));\n\t\t\t\t\telse {\n\t\t\t\t\t\tconst result = await loadSkill(path, \"explicit\");\n\t\t\t\t\t\tif (result.skill) add(result.skill, result.diagnostics);\n\t\t\t\t\t\telse diagnostics.push(...result.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t} catch (cause) {\n\t\t\t\t\tconst message = isMissingPath(cause)\n\t\t\t\t\t\t? \"Skill path does not exist\"\n\t\t\t\t\t\t: `Failed to discover skill path: ${String(cause)}`;\n\t\t\t\t\tdiagnostics.push({ path, kind: \"skill\", stage: \"discover\", severity: \"warning\", message });\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst projectDirectories = [\n\t\t\t\tjoin(this.options.cwd, \".di-code\", \"skills\"),\n\t\t\t\tjoin(this.options.cwd, \".pi\", \"skills\"),\n\t\t\t];\n\t\t\tif (this.options.projectTrusted === true) {\n\t\t\t\tfor (const directory of projectDirectories) addResults(await discoverSkills(directory, \"project\"));\n\t\t\t} else {\n\t\t\t\tfor (const directory of projectDirectories) {\n\t\t\t\t\tif (await exists(directory)) {\n\t\t\t\t\t\tdiagnostics.push({\n\t\t\t\t\t\t\tpath: resolve(directory),\n\t\t\t\t\t\t\tkind: \"skill\",\n\t\t\t\t\t\t\tstage: \"trust\",\n\t\t\t\t\t\t\tseverity: \"warning\",\n\t\t\t\t\t\t\tmessage: \"Project skill skipped because project trust is not granted\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\taddResults(await discoverSkills(join(this.options.agentDir, \"skills\"), \"global\"));\n\t\t}\n\t\treturn { contextFiles: context.contextFiles, skills: [...skills.values()], diagnostics };\n\t}\n}\n\nexport async function loadResources(options: ResourceLoaderOptions): Promise<ResourceSnapshot> {\n\treturn new DefaultResourceLoader(options).load();\n}\n"]}
|