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.
Files changed (52) hide show
  1. package/README.md +177 -125
  2. package/bin/cli.js +159 -161
  3. package/package.json +52 -47
  4. package/src/commands/auth.js +294 -0
  5. package/src/commands/setup-modules/helpers.js +105 -0
  6. package/src/commands/setup-modules/index.js +26 -0
  7. package/src/commands/setup-modules/mcp.js +95 -0
  8. package/src/commands/setup-modules/provider.js +261 -0
  9. package/src/commands/setup-modules/safety.js +62 -0
  10. package/src/commands/setup-modules/simplify.js +53 -0
  11. package/src/commands/setup.js +172 -0
  12. package/src/common/assets.js +192 -0
  13. package/src/{config.js → common/config.js} +138 -201
  14. package/src/common/constants.js +57 -0
  15. package/src/{indicator.js → common/indicator.js} +222 -217
  16. package/src/common/interaction.js +170 -0
  17. package/src/common/logging.js +77 -0
  18. package/src/common/sdk.js +51 -0
  19. package/src/{tasks.js → common/tasks.js} +157 -172
  20. package/src/common/utils.js +147 -0
  21. package/src/core/base.js +54 -0
  22. package/src/core/coding.js +55 -0
  23. package/src/core/context.js +132 -0
  24. package/src/core/hooks.js +529 -0
  25. package/src/{init.js → core/init.js} +163 -144
  26. package/src/core/plan.js +318 -0
  27. package/src/core/prompts.js +253 -0
  28. package/src/core/query.js +48 -0
  29. package/src/core/repair.js +58 -0
  30. package/src/{runner.js → core/runner.js} +352 -420
  31. package/src/core/scan.js +89 -0
  32. package/src/core/simplify.js +59 -0
  33. package/src/core/validator.js +138 -0
  34. package/{prompts/ADD_GUIDE.md → templates/addGuide.md} +98 -98
  35. package/templates/addUser.md +26 -0
  36. package/{prompts/CLAUDE.md → templates/agentProtocol.md} +195 -199
  37. package/templates/bash-process.md +5 -0
  38. package/{prompts/coding_user.md → templates/codingUser.md} +31 -23
  39. package/templates/guidance.json +35 -0
  40. package/templates/playwright.md +17 -0
  41. package/templates/requirements.example.md +56 -56
  42. package/{prompts/SCAN_PROTOCOL.md → templates/scanProtocol.md} +118 -118
  43. package/{prompts/scan_user.md → templates/scanUser.md} +17 -17
  44. package/templates/test_rule.md +194 -194
  45. package/prompts/add_user.md +0 -24
  46. package/src/auth.js +0 -245
  47. package/src/hooks.js +0 -160
  48. package/src/prompts.js +0 -295
  49. package/src/scanner.js +0 -62
  50. package/src/session.js +0 -352
  51. package/src/setup.js +0 -579
  52. 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 };