claude-coder 1.7.0 → 1.8.0
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 +177 -125
- package/bin/cli.js +159 -161
- package/package.json +52 -47
- package/src/commands/auth.js +294 -0
- package/src/commands/setup-modules/helpers.js +105 -0
- package/src/commands/setup-modules/index.js +26 -0
- package/src/commands/setup-modules/mcp.js +95 -0
- package/src/commands/setup-modules/provider.js +261 -0
- package/src/commands/setup-modules/safety.js +62 -0
- package/src/commands/setup-modules/simplify.js +53 -0
- package/src/commands/setup.js +172 -0
- package/src/common/assets.js +192 -0
- package/src/{config.js → common/config.js} +138 -201
- package/src/common/constants.js +57 -0
- package/src/{indicator.js → common/indicator.js} +222 -217
- package/src/common/interaction.js +170 -0
- package/src/common/logging.js +77 -0
- package/src/common/sdk.js +51 -0
- package/src/{tasks.js → common/tasks.js} +157 -172
- package/src/common/utils.js +147 -0
- package/src/core/base.js +54 -0
- package/src/core/coding.js +55 -0
- package/src/core/context.js +132 -0
- package/src/core/hooks.js +529 -0
- package/src/{init.js → core/init.js} +163 -144
- package/src/core/plan.js +318 -0
- package/src/core/prompts.js +253 -0
- package/src/core/query.js +48 -0
- package/src/core/repair.js +58 -0
- package/src/{runner.js → core/runner.js} +352 -420
- package/src/core/scan.js +89 -0
- package/src/core/simplify.js +59 -0
- package/src/core/validator.js +138 -0
- package/{prompts/ADD_GUIDE.md → templates/addGuide.md} +98 -98
- package/templates/addUser.md +26 -0
- package/{prompts/CLAUDE.md → templates/agentProtocol.md} +195 -199
- package/templates/bash-process.md +5 -0
- package/{prompts/coding_user.md → templates/codingUser.md} +31 -23
- package/templates/guidance.json +35 -0
- package/templates/playwright.md +17 -0
- package/templates/requirements.example.md +56 -56
- package/{prompts/SCAN_PROTOCOL.md → templates/scanProtocol.md} +118 -118
- package/{prompts/scan_user.md → templates/scanUser.md} +17 -17
- package/templates/test_rule.md +194 -194
- package/prompts/add_user.md +0 -24
- package/src/auth.js +0 -245
- package/src/hooks.js +0 -160
- package/src/prompts.js +0 -295
- package/src/scanner.js +0 -62
- package/src/session.js +0 -352
- package/src/setup.js +0 -579
- package/src/validator.js +0 -181
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { runSession } = require("./base");
|
|
4
|
+
const { buildQueryOptions } = require("./query");
|
|
5
|
+
const { buildSystemPrompt, buildCodingPrompt } = require("./prompts");
|
|
6
|
+
const { extractResult } = require("../common/logging");
|
|
7
|
+
const { log } = require("../common/config");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 内部:运行编码 Session
|
|
11
|
+
*/
|
|
12
|
+
async function runCodingSession(sessionNum, opts = {}) {
|
|
13
|
+
const taskId = opts.taskId || "unknown";
|
|
14
|
+
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
15
|
+
|
|
16
|
+
return runSession("coding", {
|
|
17
|
+
opts,
|
|
18
|
+
sessionNum,
|
|
19
|
+
logFileName: `${taskId}_session_${sessionNum}_${dateStr}.log`,
|
|
20
|
+
label: `coding task=${taskId}`,
|
|
21
|
+
|
|
22
|
+
async execute(sdk, ctx) {
|
|
23
|
+
const prompt = buildCodingPrompt(sessionNum, opts);
|
|
24
|
+
const queryOpts = buildQueryOptions(ctx.config, opts);
|
|
25
|
+
queryOpts.systemPrompt = buildSystemPrompt(false);
|
|
26
|
+
queryOpts.hooks = ctx.hooks;
|
|
27
|
+
queryOpts.abortController = ctx.abortController;
|
|
28
|
+
queryOpts.disallowedTools = ['askUserQuestion'];
|
|
29
|
+
|
|
30
|
+
const collected = await ctx.runQuery(sdk, prompt, queryOpts);
|
|
31
|
+
const result = extractResult(collected);
|
|
32
|
+
const subtype = result?.subtype || "unknown";
|
|
33
|
+
|
|
34
|
+
if (subtype !== "success" && subtype !== "unknown") {
|
|
35
|
+
log(
|
|
36
|
+
"warn",
|
|
37
|
+
`session 结束原因: ${subtype} (turns: ${result?.num_turns ?? "?"})`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (ctx.logStream.writable) {
|
|
41
|
+
ctx.logStream.write(
|
|
42
|
+
`[${new Date().toISOString()}] SESSION_END subtype=${subtype} turns=${result?.num_turns ?? "?"} cost=${result?.total_cost_usd ?? "?"}\n`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
cost: result?.total_cost_usd ?? null,
|
|
48
|
+
tokenUsage: result?.usage ?? null,
|
|
49
|
+
subtype,
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { runCodingSession };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { loadConfig, buildEnvVars, log } = require('../common/config');
|
|
6
|
+
const { Indicator } = require('../common/indicator');
|
|
7
|
+
const { logMessage: baseLogMessage } = require('../common/logging');
|
|
8
|
+
const { createHooks } = require('./hooks');
|
|
9
|
+
const { assets } = require('../common/assets');
|
|
10
|
+
|
|
11
|
+
class SessionContext {
|
|
12
|
+
constructor(type, opts = {}) {
|
|
13
|
+
this.type = type;
|
|
14
|
+
this.opts = opts;
|
|
15
|
+
assets.init(opts.projectRoot || process.cwd());
|
|
16
|
+
this.config = loadConfig();
|
|
17
|
+
this._applyEnvConfig();
|
|
18
|
+
this.indicator = new Indicator();
|
|
19
|
+
this.logStream = null;
|
|
20
|
+
this.logFile = null;
|
|
21
|
+
this.hooks = null;
|
|
22
|
+
this.cleanup = null;
|
|
23
|
+
this._isStalled = () => false;
|
|
24
|
+
this.abortController = new AbortController();
|
|
25
|
+
this._lastStatusKey = '';
|
|
26
|
+
this._needsNewline = false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_applyEnvConfig() {
|
|
30
|
+
Object.assign(process.env, buildEnvVars(this.config));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
initLogging(logFileName, externalLogStream) {
|
|
34
|
+
if (externalLogStream) {
|
|
35
|
+
this.logStream = externalLogStream;
|
|
36
|
+
this._externalLogStream = true;
|
|
37
|
+
} else {
|
|
38
|
+
const logsDir = assets.dir('logs');
|
|
39
|
+
this.logFile = path.join(logsDir, logFileName);
|
|
40
|
+
this.logStream = fs.createWriteStream(this.logFile, { flags: 'a' });
|
|
41
|
+
this._externalLogStream = false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
initHooks(hookType) {
|
|
46
|
+
const stallTimeoutMs = this.config.stallTimeout * 1000;
|
|
47
|
+
const completionTimeoutMs = this.config.completionTimeout * 1000;
|
|
48
|
+
const result = createHooks(hookType, this.indicator, this.logStream, {
|
|
49
|
+
stallTimeoutMs,
|
|
50
|
+
abortController: this.abortController,
|
|
51
|
+
editThreshold: this.config.editThreshold,
|
|
52
|
+
completionTimeoutMs,
|
|
53
|
+
});
|
|
54
|
+
this.hooks = result.hooks;
|
|
55
|
+
this.cleanup = result.cleanup;
|
|
56
|
+
this._isStalled = result.isStalled;
|
|
57
|
+
return Math.floor(stallTimeoutMs / 60000);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
startIndicator(sessionNum, stallTimeoutMin) {
|
|
61
|
+
this.indicator.start(sessionNum, stallTimeoutMin);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
isStalled() {
|
|
65
|
+
return this._isStalled();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async runQuery(sdk, prompt, queryOpts) {
|
|
69
|
+
const collected = [];
|
|
70
|
+
const session = sdk.query({ prompt, options: queryOpts });
|
|
71
|
+
|
|
72
|
+
for await (const message of session) {
|
|
73
|
+
if (this._isStalled()) {
|
|
74
|
+
log('warn', '停顿超时,中断消息循环');
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
collected.push(message);
|
|
78
|
+
this._logMessage(message);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return collected;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
_logMessage(message) {
|
|
85
|
+
const hasText = message.type === 'assistant'
|
|
86
|
+
&& message.message?.content?.some(b => b.type === 'text' && b.text);
|
|
87
|
+
|
|
88
|
+
if (hasText && this.indicator) {
|
|
89
|
+
this.indicator.pauseRendering();
|
|
90
|
+
process.stderr.write('\r\x1b[K');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
baseLogMessage(message, this.logStream, this.indicator);
|
|
94
|
+
|
|
95
|
+
if (hasText) {
|
|
96
|
+
const textBlocks = message.message.content.filter(b => b.type === 'text' && b.text);
|
|
97
|
+
const lastText = textBlocks[textBlocks.length - 1];
|
|
98
|
+
this._needsNewline = lastText && !lastText.text.endsWith('\n');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (hasText && this.indicator) {
|
|
102
|
+
if (this._needsNewline) {
|
|
103
|
+
process.stdout.write('\n');
|
|
104
|
+
this._needsNewline = false;
|
|
105
|
+
}
|
|
106
|
+
const contentKey = `${this.indicator.phase}|${this.indicator.step}|${this.indicator.toolTarget}`;
|
|
107
|
+
if (contentKey !== this._lastStatusKey) {
|
|
108
|
+
this._lastStatusKey = contentKey;
|
|
109
|
+
const statusLine = this.indicator.getStatusLine();
|
|
110
|
+
if (statusLine) process.stderr.write(statusLine + '\n');
|
|
111
|
+
}
|
|
112
|
+
this.indicator.resumeRendering();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
finish() {
|
|
117
|
+
if (this._needsNewline) {
|
|
118
|
+
process.stdout.write('\n');
|
|
119
|
+
this._needsNewline = false;
|
|
120
|
+
}
|
|
121
|
+
if (this.cleanup) this.cleanup();
|
|
122
|
+
if (this.logStream && !this._externalLogStream) this.logStream.end();
|
|
123
|
+
this.indicator.stop();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
errorFinish(err) {
|
|
127
|
+
this.finish();
|
|
128
|
+
log('error', err.message);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = { SessionContext };
|