zapmyco 0.16.0 → 0.17.2-beta.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 +53 -144
- package/esm/_dnt.polyfills.js +127 -0
- package/esm/_dnt.shims.js +61 -0
- package/esm/deno.js +65 -0
- package/esm/package.json +3 -0
- package/esm/src/ai-agent.js +138 -0
- package/esm/src/index.js +113 -0
- package/esm/src/text-line-stream.js +32 -0
- package/package.json +25 -91
- package/types/_dnt.polyfills.d.ts +101 -0
- package/types/_dnt.polyfills.d.ts.map +1 -0
- package/types/_dnt.shims.d.ts +6 -0
- package/types/_dnt.shims.d.ts.map +1 -0
- package/types/deno.d.ts +50 -0
- package/types/deno.d.ts.map +1 -0
- package/types/src/ai-agent.d.ts +48 -0
- package/types/src/ai-agent.d.ts.map +1 -0
- package/types/src/index.d.ts +74 -0
- package/types/src/index.d.ts.map +1 -0
- package/types/src/text-line-stream.d.ts +12 -0
- package/types/src/text-line-stream.d.ts.map +1 -0
- package/dist/agent-B6lIWQ5J.d.mts +0 -327
- package/dist/agent-B6lIWQ5J.d.mts.map +0 -1
- package/dist/cli/index.d.mts +0 -1
- package/dist/cli/index.mjs +0 -18243
- package/dist/cli/index.mjs.map +0 -1
- package/dist/index.d.mts +0 -3425
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -112
- package/dist/index.mjs.map +0 -1
- package/dist/loader-CWzMinwj.mjs +0 -6215
- package/dist/loader-CWzMinwj.mjs.map +0 -1
- package/dist/protocol/index.d.mts +0 -2
- package/dist/protocol/index.mjs +0 -1
- package/skills/code-review/SKILL.md +0 -73
- package/skills/commit/SKILL.md +0 -54
package/README.md
CHANGED
|
@@ -1,62 +1,47 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ai-typescript-starter
|
|
2
2
|
|
|
3
|
-
[](https://github.com/shenjingnan/ai-typescript-starter/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/ai-typescript-starter)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
AI
|
|
7
|
+
AI 原生的 TypeScript 启动模板,专为 AI 辅助开发时代打造。
|
|
8
8
|
|
|
9
9
|
## 特性
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- **
|
|
17
|
-
-
|
|
18
|
-
- **基础设施**: 事件总线、统一错误体系、结构化日志
|
|
11
|
+
- **现代技术栈**: TypeScript + Node.js 24+ + pnpm
|
|
12
|
+
- **构建工具**: tsdown - 基于 rolldown 的 TypeScript 打包器
|
|
13
|
+
- **测试框架**: Vitest - Vite 原生测试框架
|
|
14
|
+
- **代码质量**: Biome (Lint + Format) + cspell (拼写检查)
|
|
15
|
+
- **Git 工作流**: Husky + lint-staged + release-it
|
|
16
|
+
- **AI 集成**: 内置 CLAUDE.md 和 .claude/ 目录配置
|
|
17
|
+
- **CI/CD**: GitHub Actions 自动化测试和发布
|
|
19
18
|
|
|
20
19
|
## 快速开始
|
|
21
20
|
|
|
21
|
+
### 使用模板
|
|
22
|
+
|
|
23
|
+
点击仓库页面的 "Use this template" 按钮创建新项目。
|
|
24
|
+
|
|
22
25
|
### 安装
|
|
23
26
|
|
|
24
27
|
```bash
|
|
25
28
|
# 克隆项目
|
|
26
|
-
git clone https://github.com/
|
|
27
|
-
cd
|
|
29
|
+
git clone https://github.com/your-username/your-project.git
|
|
30
|
+
cd your-project
|
|
28
31
|
|
|
29
32
|
# 安装依赖
|
|
30
33
|
pnpm install
|
|
31
34
|
```
|
|
32
35
|
|
|
33
|
-
### 使用
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# 构建项目
|
|
37
|
-
pnpm run build
|
|
38
|
-
|
|
39
|
-
# 进入交互式 REPL 模式
|
|
40
|
-
pnpm run start
|
|
41
|
-
# 或直接运行 CLI
|
|
42
|
-
zapmyco
|
|
43
|
-
|
|
44
|
-
# 直接执行单次目标(非交互模式)
|
|
45
|
-
zapmyco run "重构用户认证模块"
|
|
46
|
-
|
|
47
|
-
# 列出可用 Agent
|
|
48
|
-
zapmyco agents
|
|
49
|
-
|
|
50
|
-
# 显示版本号
|
|
51
|
-
zapmyco version
|
|
52
|
-
```
|
|
53
|
-
|
|
54
36
|
### 开发
|
|
55
37
|
|
|
56
38
|
```bash
|
|
57
|
-
# 开发模式
|
|
39
|
+
# 开发模式
|
|
58
40
|
pnpm run dev
|
|
59
41
|
|
|
42
|
+
# 构建
|
|
43
|
+
pnpm run build
|
|
44
|
+
|
|
60
45
|
# 测试
|
|
61
46
|
pnpm run test
|
|
62
47
|
|
|
@@ -73,27 +58,16 @@ pnpm run check
|
|
|
73
58
|
## 项目结构
|
|
74
59
|
|
|
75
60
|
```
|
|
76
|
-
|
|
77
|
-
├── .
|
|
61
|
+
ai-typescript-starter/
|
|
62
|
+
├── .claude/ # Claude Code 配置
|
|
78
63
|
│ ├── commands/ # Slash 命令
|
|
79
64
|
│ └── skills/ # 技能定义
|
|
80
65
|
├── .github/ # GitHub 配置
|
|
81
|
-
│
|
|
66
|
+
│ ├── workflows/ # CI/CD 工作流
|
|
67
|
+
│ └── ISSUE_TEMPLATE/ # Issue 模板
|
|
82
68
|
├── docs/ # 文档
|
|
83
69
|
├── examples/ # 示例代码
|
|
84
|
-
├── src/
|
|
85
|
-
│ ├── cli/ # CLI 入口 & REPL 交互界面
|
|
86
|
-
│ │ └── repl/ # REPL 核心:命令注册、会话、渲染、历史、编辑器
|
|
87
|
-
│ ├── config/ # 配置加载与默认值
|
|
88
|
-
│ ├── core/ # 核心领域模型
|
|
89
|
-
│ │ ├── agent-runtime/# Agent 运行时 (pi-agent-core 适配层)
|
|
90
|
-
│ │ ├── aggregator/ # 结果聚合
|
|
91
|
-
│ │ ├── intent/ # 目标与意图
|
|
92
|
-
│ │ ├── result/ # 任务结果
|
|
93
|
-
│ │ └── task/ # 子任务与依赖图
|
|
94
|
-
│ ├── infra/ # 基础设施:常量、错误、事件总线、日志
|
|
95
|
-
│ ├── llm/ # LLM Provider 抽象 & Token 追踪
|
|
96
|
-
│ ├── protocol/ # Agent 协议接口定义
|
|
70
|
+
├── src/ # 源代码
|
|
97
71
|
│ └── __tests__/ # 测试文件
|
|
98
72
|
├── AGENTS.md # AI Agent 配置
|
|
99
73
|
└── dist/ # 构建产物
|
|
@@ -101,107 +75,41 @@ zapmyco/
|
|
|
101
75
|
|
|
102
76
|
## 可用脚本
|
|
103
77
|
|
|
104
|
-
| 命令
|
|
105
|
-
|
|
106
|
-
| `pnpm run build`
|
|
107
|
-
| `pnpm run dev`
|
|
108
|
-
| `pnpm run
|
|
109
|
-
| `pnpm run test`
|
|
110
|
-
| `pnpm run test:
|
|
111
|
-
| `pnpm run
|
|
112
|
-
| `pnpm run lint`
|
|
113
|
-
| `pnpm run
|
|
114
|
-
| `pnpm run
|
|
115
|
-
| `pnpm run
|
|
116
|
-
| `pnpm run check`
|
|
117
|
-
| `pnpm run
|
|
118
|
-
| `pnpm run
|
|
119
|
-
| `pnpm run release`
|
|
120
|
-
| `pnpm run release:
|
|
121
|
-
| `pnpm run release:
|
|
122
|
-
| `pnpm run release:
|
|
123
|
-
| `pnpm run release:
|
|
124
|
-
| `pnpm run release:major` | 直接发布 major 版本 |
|
|
125
|
-
|
|
126
|
-
## 公共 API
|
|
127
|
-
|
|
128
|
-
### 核心导出
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
import {
|
|
132
|
-
VERSION,
|
|
133
|
-
APP_NAME,
|
|
134
|
-
// 配置
|
|
135
|
-
loadConfig,
|
|
136
|
-
DEFAULT_CONFIG,
|
|
137
|
-
type ZapmycoConfig,
|
|
138
|
-
// Agent 运行时
|
|
139
|
-
createLlmBasedAgent,
|
|
140
|
-
createToolsFromCapabilities,
|
|
141
|
-
createToolFromCapability,
|
|
142
|
-
adaptAgentEvent,
|
|
143
|
-
createEventBridgeListener,
|
|
144
|
-
dispatchToEventBus,
|
|
145
|
-
LlmBasedAgent,
|
|
146
|
-
// LLM
|
|
147
|
-
CostTracker,
|
|
148
|
-
costTracker,
|
|
149
|
-
// 基础设施
|
|
150
|
-
eventBus,
|
|
151
|
-
Logger,
|
|
152
|
-
logger,
|
|
153
|
-
ZapmycoError,
|
|
154
|
-
} from 'zapmyco';
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Protocol 层类型
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
import type {
|
|
161
|
-
IAgent,
|
|
162
|
-
IStreamingAgent,
|
|
163
|
-
AgentExecuteRequest,
|
|
164
|
-
AgentExecuteOptions,
|
|
165
|
-
AgentStatus,
|
|
166
|
-
Capability,
|
|
167
|
-
CapabilityCategory,
|
|
168
|
-
Goal,
|
|
169
|
-
SubTask,
|
|
170
|
-
TaskGraph,
|
|
171
|
-
TaskResult,
|
|
172
|
-
FinalResult,
|
|
173
|
-
TokenUsage,
|
|
174
|
-
} from 'zapmyco';
|
|
175
|
-
|
|
176
|
-
// 或单独导入协议层
|
|
177
|
-
import type { IAgent, IStreamingAgent } from 'zapmyco/protocol';
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### 核心领域类型
|
|
181
|
-
|
|
182
|
-
| 模块 | 关键类型 | 说明 |
|
|
183
|
-
|------|---------|------|
|
|
184
|
-
| `protocol/agent` | `IAgent`, `IStreamingAgent` | Agent 统一接口 |
|
|
185
|
-
| `core/intent` | `Goal`, `GoalType`, `GoalConstraints` | 目标与意图定义 |
|
|
186
|
-
| `core/task` | `SubTask`, `TaskGraph`, `TaskStatus` | 子任务与依赖图 |
|
|
187
|
-
| `core/result` | `TaskResult`, `FinalResult`, `TokenUsage` | 执行结果与用量 |
|
|
188
|
-
| `core/aggregator` | `ProgressEvent`, `ProgressPayload` | 进度事件 |
|
|
189
|
-
| `core/agent-runtime` | `AgentRuntimeConfig`, `ToolRegistration` | 运行时配置 |
|
|
190
|
-
| `llm/types` | `ChatMessage`, `LlmResponse`, `StructuredOutputSchema` | LLM 交互类型 |
|
|
191
|
-
| `config/types` | `ZapmycoConfig` | 应用配置 |
|
|
78
|
+
| 命令 | 说明 |
|
|
79
|
+
| ------------------------ | --------------------------- |
|
|
80
|
+
| `pnpm run build` | 构建项目 |
|
|
81
|
+
| `pnpm run dev` | 开发模式 (watch) |
|
|
82
|
+
| `pnpm run test` | 运行测试 |
|
|
83
|
+
| `pnpm run test:watch` | 测试监听模式 |
|
|
84
|
+
| `pnpm run test:coverage` | 测试覆盖率报告 |
|
|
85
|
+
| `pnpm run lint` | 代码检查 |
|
|
86
|
+
| `pnpm run lint:fix` | 自动修复代码问题 |
|
|
87
|
+
| `pnpm run format` | 格式化代码 |
|
|
88
|
+
| `pnpm run typecheck` | TypeScript 类型检查 |
|
|
89
|
+
| `pnpm run check` | 完整检查 (typecheck + lint) |
|
|
90
|
+
| `pnpm run check:fix` | 检查并修复 |
|
|
91
|
+
| `pnpm run spellcheck` | 拼写检查 |
|
|
92
|
+
| `pnpm run release` | 创建发布 |
|
|
93
|
+
| `pnpm run release:beta` | 发布 beta 预发布版本 |
|
|
94
|
+
| `pnpm run release:dry` | 发布干运行 (不实际发布) |
|
|
95
|
+
| `pnpm run release:patch` | 直接发布 patch 版本 |
|
|
96
|
+
| `pnpm run release:minor` | 直接发布 minor 版本 |
|
|
97
|
+
| `pnpm run release:major` | 直接发布 major 版本 |
|
|
192
98
|
|
|
193
99
|
## AI 辅助开发
|
|
194
100
|
|
|
195
101
|
本项目专为 AI 辅助开发设计,内置了完善的 AI 工程约束:
|
|
196
102
|
|
|
197
|
-
###
|
|
103
|
+
### CLAUDE.md
|
|
198
104
|
|
|
199
105
|
为 Claude Code 提供项目上下文和开发规范。
|
|
200
106
|
|
|
201
|
-
### .
|
|
107
|
+
### .claude/ 目录
|
|
202
108
|
|
|
203
|
-
- `commands/` - 自定义 Slash 命令 (`/build`, `/test`, `/lint`, `/typecheck`, `/
|
|
204
|
-
|
|
109
|
+
- `commands/` - 自定义 Slash 命令 (`/build`, `/test`, `/lint`, `/typecheck`, `/spellcheck`,
|
|
110
|
+
`/release`, `/commit-push-pr`)
|
|
111
|
+
- `skills/` - 项目技能定义 (`resolve-git-conflicts`, `fix-audit`, `project-context`,
|
|
112
|
+
`update-readme`)
|
|
205
113
|
|
|
206
114
|
## 代码风格
|
|
207
115
|
|
|
@@ -226,6 +134,7 @@ pnpm run release
|
|
|
226
134
|
```
|
|
227
135
|
|
|
228
136
|
发布过程会自动:
|
|
137
|
+
|
|
229
138
|
1. 更新版本号
|
|
230
139
|
2. 更新 CHANGELOG.md
|
|
231
140
|
3. 创建 Git tag
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Based on [import-meta-ponyfill](https://github.com/gaubee/import-meta-ponyfill),
|
|
3
|
+
* but instead of using npm to install additional dependencies,
|
|
4
|
+
* this approach manually consolidates cjs/mjs/d.ts into a single file.
|
|
5
|
+
*
|
|
6
|
+
* Note that this code might be imported multiple times
|
|
7
|
+
* (for example, both dnt.test.polyfills.ts and dnt.polyfills.ts contain this code;
|
|
8
|
+
* or Node.js might dynamically clear the cache and then force a require).
|
|
9
|
+
* Therefore, it's important to avoid redundant writes to global objects.
|
|
10
|
+
* Additionally, consider that commonjs is used alongside esm,
|
|
11
|
+
* so the two ponyfill functions are stored independently in two separate global objects.
|
|
12
|
+
*/
|
|
13
|
+
//@ts-ignore
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
//@ts-ignore
|
|
16
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
17
|
+
//@ts-ignore
|
|
18
|
+
import { dirname } from "node:path";
|
|
19
|
+
const defineGlobalPonyfill = (symbolFor, fn) => {
|
|
20
|
+
if (!Reflect.has(globalThis, Symbol.for(symbolFor))) {
|
|
21
|
+
Object.defineProperty(globalThis, Symbol.for(symbolFor), {
|
|
22
|
+
configurable: true,
|
|
23
|
+
get() {
|
|
24
|
+
return fn;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export let import_meta_ponyfill_commonjs = (Reflect.get(globalThis, Symbol.for("import-meta-ponyfill-commonjs")) ??
|
|
30
|
+
(() => {
|
|
31
|
+
const moduleImportMetaWM = new WeakMap();
|
|
32
|
+
return (require, module) => {
|
|
33
|
+
let importMetaCache = moduleImportMetaWM.get(module);
|
|
34
|
+
if (importMetaCache == null) {
|
|
35
|
+
const importMeta = Object.assign(Object.create(null), {
|
|
36
|
+
url: pathToFileURL(module.filename).href,
|
|
37
|
+
main: require.main == module,
|
|
38
|
+
resolve: (specifier, parentURL = importMeta.url) => {
|
|
39
|
+
return pathToFileURL((importMeta.url === parentURL
|
|
40
|
+
? require
|
|
41
|
+
: createRequire(parentURL))
|
|
42
|
+
.resolve(specifier)).href;
|
|
43
|
+
},
|
|
44
|
+
filename: module.filename,
|
|
45
|
+
dirname: module.path,
|
|
46
|
+
});
|
|
47
|
+
moduleImportMetaWM.set(module, importMeta);
|
|
48
|
+
importMetaCache = importMeta;
|
|
49
|
+
}
|
|
50
|
+
return importMetaCache;
|
|
51
|
+
};
|
|
52
|
+
})());
|
|
53
|
+
defineGlobalPonyfill("import-meta-ponyfill-commonjs", import_meta_ponyfill_commonjs);
|
|
54
|
+
export let import_meta_ponyfill_esmodule = (Reflect.get(globalThis, Symbol.for("import-meta-ponyfill-esmodule")) ??
|
|
55
|
+
((importMeta) => {
|
|
56
|
+
const resolveFunStr = String(importMeta.resolve);
|
|
57
|
+
const shimWs = new WeakSet();
|
|
58
|
+
//@ts-ignore
|
|
59
|
+
const mainUrl = ("file:///" + process.argv[1].replace(/\\/g, "/"))
|
|
60
|
+
.replace(/\/{3,}/, "///");
|
|
61
|
+
const commonShim = (importMeta) => {
|
|
62
|
+
if (typeof importMeta.main !== "boolean") {
|
|
63
|
+
importMeta.main = importMeta.url === mainUrl;
|
|
64
|
+
}
|
|
65
|
+
if (typeof importMeta.filename !== "string") {
|
|
66
|
+
importMeta.filename = fileURLToPath(importMeta.url);
|
|
67
|
+
importMeta.dirname = dirname(importMeta.filename);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
if (
|
|
71
|
+
// v16.2.0+, v14.18.0+: Add support for WHATWG URL object to parentURL parameter.
|
|
72
|
+
resolveFunStr === "undefined" ||
|
|
73
|
+
// v20.0.0+, v18.19.0+"" This API now returns a string synchronously instead of a Promise.
|
|
74
|
+
resolveFunStr.startsWith("async")
|
|
75
|
+
// enable by --experimental-import-meta-resolve flag
|
|
76
|
+
) {
|
|
77
|
+
import_meta_ponyfill_esmodule = (importMeta) => {
|
|
78
|
+
if (!shimWs.has(importMeta)) {
|
|
79
|
+
shimWs.add(importMeta);
|
|
80
|
+
const importMetaUrlRequire = {
|
|
81
|
+
url: importMeta.url,
|
|
82
|
+
require: createRequire(importMeta.url),
|
|
83
|
+
};
|
|
84
|
+
importMeta.resolve = function resolve(specifier, parentURL = importMeta.url) {
|
|
85
|
+
return pathToFileURL((importMetaUrlRequire.url === parentURL
|
|
86
|
+
? importMetaUrlRequire.require
|
|
87
|
+
: createRequire(parentURL)).resolve(specifier)).href;
|
|
88
|
+
};
|
|
89
|
+
commonShim(importMeta);
|
|
90
|
+
}
|
|
91
|
+
return importMeta;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
/// native support
|
|
96
|
+
import_meta_ponyfill_esmodule = (importMeta) => {
|
|
97
|
+
if (!shimWs.has(importMeta)) {
|
|
98
|
+
shimWs.add(importMeta);
|
|
99
|
+
commonShim(importMeta);
|
|
100
|
+
}
|
|
101
|
+
return importMeta;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return import_meta_ponyfill_esmodule(importMeta);
|
|
105
|
+
}));
|
|
106
|
+
defineGlobalPonyfill("import-meta-ponyfill-esmodule", import_meta_ponyfill_esmodule);
|
|
107
|
+
export let import_meta_ponyfill = ((...args) => {
|
|
108
|
+
const _MODULE = (() => {
|
|
109
|
+
if (typeof require === "function" && typeof module === "object") {
|
|
110
|
+
return "commonjs";
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// eval("typeof import.meta");
|
|
114
|
+
return "esmodule";
|
|
115
|
+
}
|
|
116
|
+
})();
|
|
117
|
+
if (_MODULE === "commonjs") {
|
|
118
|
+
//@ts-ignore
|
|
119
|
+
import_meta_ponyfill = (r, m) => import_meta_ponyfill_commonjs(r, m);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
//@ts-ignore
|
|
123
|
+
import_meta_ponyfill = (im) => import_meta_ponyfill_esmodule(im);
|
|
124
|
+
}
|
|
125
|
+
//@ts-ignore
|
|
126
|
+
return import_meta_ponyfill(...args);
|
|
127
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Deno } from "@deno/shim-deno";
|
|
2
|
+
export { Deno } from "@deno/shim-deno";
|
|
3
|
+
const dntGlobals = {
|
|
4
|
+
Deno,
|
|
5
|
+
};
|
|
6
|
+
export const dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
|
|
7
|
+
function createMergeProxy(baseObj, extObj) {
|
|
8
|
+
return new Proxy(baseObj, {
|
|
9
|
+
get(_target, prop, _receiver) {
|
|
10
|
+
if (prop in extObj) {
|
|
11
|
+
return extObj[prop];
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return baseObj[prop];
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
set(_target, prop, value) {
|
|
18
|
+
if (prop in extObj) {
|
|
19
|
+
delete extObj[prop];
|
|
20
|
+
}
|
|
21
|
+
baseObj[prop] = value;
|
|
22
|
+
return true;
|
|
23
|
+
},
|
|
24
|
+
deleteProperty(_target, prop) {
|
|
25
|
+
let success = false;
|
|
26
|
+
if (prop in extObj) {
|
|
27
|
+
delete extObj[prop];
|
|
28
|
+
success = true;
|
|
29
|
+
}
|
|
30
|
+
if (prop in baseObj) {
|
|
31
|
+
delete baseObj[prop];
|
|
32
|
+
success = true;
|
|
33
|
+
}
|
|
34
|
+
return success;
|
|
35
|
+
},
|
|
36
|
+
ownKeys(_target) {
|
|
37
|
+
const baseKeys = Reflect.ownKeys(baseObj);
|
|
38
|
+
const extKeys = Reflect.ownKeys(extObj);
|
|
39
|
+
const extKeysSet = new Set(extKeys);
|
|
40
|
+
return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
|
|
41
|
+
},
|
|
42
|
+
defineProperty(_target, prop, desc) {
|
|
43
|
+
if (prop in extObj) {
|
|
44
|
+
delete extObj[prop];
|
|
45
|
+
}
|
|
46
|
+
Reflect.defineProperty(baseObj, prop, desc);
|
|
47
|
+
return true;
|
|
48
|
+
},
|
|
49
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
50
|
+
if (prop in extObj) {
|
|
51
|
+
return Reflect.getOwnPropertyDescriptor(extObj, prop);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return Reflect.getOwnPropertyDescriptor(baseObj, prop);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
has(_target, prop) {
|
|
58
|
+
return prop in extObj || prop in baseObj;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
package/esm/deno.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
"name": "@zapmyco/zapmyco",
|
|
3
|
+
"version": "0.17.2-beta.2",
|
|
4
|
+
"description": "AI 原生的 TypeScript 启动模板,专为 AI 辅助开发时代打造",
|
|
5
|
+
"exports": "./src/index.ts",
|
|
6
|
+
"tasks": {
|
|
7
|
+
"cli": "deno run --allow-env --allow-net src/index.ts",
|
|
8
|
+
"ai": "deno run --allow-env --allow-net src/index.ts ai",
|
|
9
|
+
"install:global": "deno install -g -n zapmyco --allow-env --allow-net src/index.ts",
|
|
10
|
+
"dev": "deno run --watch src/index.ts",
|
|
11
|
+
"test": "deno test --allow-env",
|
|
12
|
+
"test:coverage": "deno test --allow-env --coverage && deno coverage",
|
|
13
|
+
"lint": "deno lint",
|
|
14
|
+
"fmt": "deno fmt",
|
|
15
|
+
"fmt:check": "deno fmt --check",
|
|
16
|
+
"check": "deno check src/",
|
|
17
|
+
"check:all": "deno fmt --check && deno lint && deno check src/ && deno test --allow-env",
|
|
18
|
+
"release": "deno run -A tools/release.ts",
|
|
19
|
+
"release:dry": "deno run -A tools/release.ts --dry-run",
|
|
20
|
+
"build:npm": "deno run -A tools/build-npm.ts"
|
|
21
|
+
},
|
|
22
|
+
"nodeModulesDir": "auto",
|
|
23
|
+
"fmt": {
|
|
24
|
+
"exclude": [
|
|
25
|
+
"docs/"
|
|
26
|
+
],
|
|
27
|
+
"lineWidth": 100,
|
|
28
|
+
"indentWidth": 2,
|
|
29
|
+
"semiColons": true,
|
|
30
|
+
"singleQuote": true
|
|
31
|
+
},
|
|
32
|
+
"lint": {
|
|
33
|
+
"rules": {
|
|
34
|
+
"tags": [
|
|
35
|
+
"recommended"
|
|
36
|
+
],
|
|
37
|
+
"exclude": [
|
|
38
|
+
"no-explicit-any"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"publish": {
|
|
43
|
+
"exclude": [
|
|
44
|
+
".agents",
|
|
45
|
+
".claude",
|
|
46
|
+
".githooks",
|
|
47
|
+
".github",
|
|
48
|
+
"coverage",
|
|
49
|
+
"docs",
|
|
50
|
+
"examples",
|
|
51
|
+
"CHANGELOG.md",
|
|
52
|
+
"AGENTS.md",
|
|
53
|
+
"src/**/*_test.ts",
|
|
54
|
+
"tools",
|
|
55
|
+
"dist"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"compilerOptions": {
|
|
59
|
+
"strict": true,
|
|
60
|
+
"noUnusedLocals": true,
|
|
61
|
+
"noUnusedParameters": true,
|
|
62
|
+
"noImplicitReturns": true,
|
|
63
|
+
"noUncheckedIndexedAccess": true
|
|
64
|
+
}
|
|
65
|
+
};
|
package/esm/package.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Agent - 基于 @anthropic-ai/sdk 的 LLM 对话代理
|
|
3
|
+
*/
|
|
4
|
+
import * as dntShim from "../_dnt.shims.js";
|
|
5
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
6
|
+
import { TextLineStream } from './text-line-stream.js';
|
|
7
|
+
const DEFAULT_BASE_URL = 'https://api.deepseek.com/anthropic';
|
|
8
|
+
const DEFAULT_MODEL = 'deepseek-v4-flash';
|
|
9
|
+
const DEFAULT_SYSTEM_PROMPT = '你是一个 AI 编程助手,帮助用户解决编程问题。';
|
|
10
|
+
/**
|
|
11
|
+
* AI Agent 类 - 封装 LLM 对话功能
|
|
12
|
+
*/
|
|
13
|
+
export class AiAgent {
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
Object.defineProperty(this, "client", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: void 0
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "model", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: void 0
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "messages", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: []
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(this, "systemPrompt", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
value: void 0
|
|
38
|
+
});
|
|
39
|
+
const apiKey = options.apiKey ?? dntShim.Deno.env.get('DEEPSEEK_API_KEY');
|
|
40
|
+
if (!apiKey) {
|
|
41
|
+
throw new Error('DEEPSEEK_API_KEY 未设置。请通过环境变量 DEEPSEEK_API_KEY 设置 API Key。');
|
|
42
|
+
}
|
|
43
|
+
this.client = new Anthropic({
|
|
44
|
+
baseURL: options.baseURL ?? DEFAULT_BASE_URL,
|
|
45
|
+
apiKey,
|
|
46
|
+
});
|
|
47
|
+
this.model = options.model ?? DEFAULT_MODEL;
|
|
48
|
+
this.systemPrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 非流式对话 - 发送消息并获取完整回复
|
|
52
|
+
* @param input - 用户输入
|
|
53
|
+
* @returns 完整回复文本
|
|
54
|
+
*/
|
|
55
|
+
async chat(input) {
|
|
56
|
+
this.messages.push({ role: 'user', content: input });
|
|
57
|
+
const response = await this.client.messages.create({
|
|
58
|
+
model: this.model,
|
|
59
|
+
max_tokens: 4096,
|
|
60
|
+
system: this.systemPrompt,
|
|
61
|
+
messages: this.messages,
|
|
62
|
+
});
|
|
63
|
+
const firstBlock = response.content[0];
|
|
64
|
+
const content = firstBlock?.type === 'text' ? firstBlock.text : '';
|
|
65
|
+
this.messages.push({ role: 'assistant', content });
|
|
66
|
+
return content;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 流式对话 - 发送消息并通过回调逐块获取回复
|
|
70
|
+
* @param input - 用户输入
|
|
71
|
+
* @param onChunk - 每收到一个文本块的回调
|
|
72
|
+
* @returns 完整回复文本
|
|
73
|
+
*/
|
|
74
|
+
async chatStream(input, onChunk) {
|
|
75
|
+
this.messages.push({ role: 'user', content: input });
|
|
76
|
+
const stream = this.client.messages.stream({
|
|
77
|
+
model: this.model,
|
|
78
|
+
max_tokens: 4096,
|
|
79
|
+
system: this.systemPrompt,
|
|
80
|
+
messages: this.messages,
|
|
81
|
+
});
|
|
82
|
+
stream.on('text', (text) => {
|
|
83
|
+
onChunk(text);
|
|
84
|
+
});
|
|
85
|
+
const response = await stream.finalMessage();
|
|
86
|
+
const firstBlock = response.content[0];
|
|
87
|
+
const content = firstBlock?.type === 'text' ? firstBlock.text : '';
|
|
88
|
+
this.messages.push({ role: 'assistant', content });
|
|
89
|
+
return content;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 启动交互式对话 - 从 stdin 读取输入,流式输出到 stdout
|
|
93
|
+
*/
|
|
94
|
+
async startInteractiveChat() {
|
|
95
|
+
const encoder = new TextEncoder();
|
|
96
|
+
console.error('进入 AI 对话模式');
|
|
97
|
+
console.error(`模型: ${this.model}`);
|
|
98
|
+
console.error('输入 /exit 退出,/clear 清空上下文');
|
|
99
|
+
console.error('---');
|
|
100
|
+
const lines = dntShim.Deno.stdin.readable
|
|
101
|
+
.pipeThrough(new TextDecoderStream())
|
|
102
|
+
.pipeThrough(new TextLineStream());
|
|
103
|
+
for await (const line of lines) {
|
|
104
|
+
const trimmed = line.trim();
|
|
105
|
+
if (!trimmed)
|
|
106
|
+
continue;
|
|
107
|
+
if (trimmed === '/exit') {
|
|
108
|
+
console.error('\n再见!');
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
if (trimmed === '/clear') {
|
|
112
|
+
this.messages = [];
|
|
113
|
+
console.error('上下文已清空');
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
// 在 stderr 显示用户输入(不影响 stdout 的纯 AI 输出)
|
|
117
|
+
console.error(`\n❯ ${trimmed}\n`);
|
|
118
|
+
try {
|
|
119
|
+
await this.chatStream(trimmed, (chunk) => {
|
|
120
|
+
dntShim.Deno.stdout.writeSync(encoder.encode(chunk));
|
|
121
|
+
});
|
|
122
|
+
console.error('\n---');
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
126
|
+
console.error(`\n[错误] ${message}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** 清空对话上下文 */
|
|
131
|
+
clearContext() {
|
|
132
|
+
this.messages = [];
|
|
133
|
+
}
|
|
134
|
+
/** 获取当前对话历史 */
|
|
135
|
+
getMessages() {
|
|
136
|
+
return this.messages;
|
|
137
|
+
}
|
|
138
|
+
}
|