@changw98ic/cli 1.0.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/LICENSE +674 -0
- package/README.md +57 -0
- package/dist/commands/adapt.d.ts +8 -0
- package/dist/commands/adapt.d.ts.map +1 -0
- package/dist/commands/adapt.js +108 -0
- package/dist/commands/adapt.js.map +1 -0
- package/dist/commands/archive.d.ts +6 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +66 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/backup.d.ts +6 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +151 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/context.d.ts +9 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +203 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/dashboard.d.ts +6 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +27 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/entity.d.ts +6 -0
- package/dist/commands/entity.d.ts.map +1 -0
- package/dist/commands/entity.js +173 -0
- package/dist/commands/entity.js.map +1 -0
- package/dist/commands/extract-context.d.ts +9 -0
- package/dist/commands/extract-context.d.ts.map +1 -0
- package/dist/commands/extract-context.js +135 -0
- package/dist/commands/extract-context.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +69 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +37 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate.d.ts +6 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +67 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/plan.d.ts +6 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +35 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/preflight.d.ts +6 -0
- package/dist/commands/preflight.d.ts.map +1 -0
- package/dist/commands/preflight.js +80 -0
- package/dist/commands/preflight.js.map +1 -0
- package/dist/commands/query.d.ts +6 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +82 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/rag.d.ts +6 -0
- package/dist/commands/rag.d.ts.map +1 -0
- package/dist/commands/rag.js +113 -0
- package/dist/commands/rag.js.map +1 -0
- package/dist/commands/review.d.ts +6 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +38 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/state.d.ts +6 -0
- package/dist/commands/state.d.ts.map +1 -0
- package/dist/commands/state.js +64 -0
- package/dist/commands/state.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +49 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/style.d.ts +9 -0
- package/dist/commands/style.d.ts.map +1 -0
- package/dist/commands/style.js +120 -0
- package/dist/commands/style.js.map +1 -0
- package/dist/commands/update-state.d.ts +6 -0
- package/dist/commands/update-state.d.ts.map +1 -0
- package/dist/commands/update-state.js +92 -0
- package/dist/commands/update-state.js.map +1 -0
- package/dist/commands/use.d.ts +5 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +33 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/commands/where.d.ts +2 -0
- package/dist/commands/where.d.ts.map +1 -0
- package/dist/commands/where.js +13 -0
- package/dist/commands/where.js.map +1 -0
- package/dist/commands/workflow.d.ts +6 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +155 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/commands/write.d.ts +7 -0
- package/dist/commands/write.d.ts.map +1 -0
- package/dist/commands/write.js +33 -0
- package/dist/commands/write.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/api-client.d.ts +61 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +390 -0
- package/dist/utils/api-client.js.map +1 -0
- package/dist/utils/api-client.types.d.ts +42 -0
- package/dist/utils/api-client.types.d.ts.map +1 -0
- package/dist/utils/api-client.types.js +5 -0
- package/dist/utils/api-client.types.js.map +1 -0
- package/dist/utils/archive-manager.d.ts +72 -0
- package/dist/utils/archive-manager.d.ts.map +1 -0
- package/dist/utils/archive-manager.js +449 -0
- package/dist/utils/archive-manager.js.map +1 -0
- package/dist/utils/backup-manager.d.ts +65 -0
- package/dist/utils/backup-manager.d.ts.map +1 -0
- package/dist/utils/backup-manager.js +266 -0
- package/dist/utils/backup-manager.js.map +1 -0
- package/dist/utils/chapter-context.d.ts +77 -0
- package/dist/utils/chapter-context.d.ts.map +1 -0
- package/dist/utils/chapter-context.js +280 -0
- package/dist/utils/chapter-context.js.map +1 -0
- package/dist/utils/entity-linker.d.ts +74 -0
- package/dist/utils/entity-linker.d.ts.map +1 -0
- package/dist/utils/entity-linker.js +208 -0
- package/dist/utils/entity-linker.js.map +1 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +22 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/observability.d.ts +145 -0
- package/dist/utils/observability.d.ts.map +1 -0
- package/dist/utils/observability.js +298 -0
- package/dist/utils/observability.js.map +1 -0
- package/dist/utils/output.d.ts +45 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +60 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/path-compat.d.ts +63 -0
- package/dist/utils/path-compat.d.ts.map +1 -0
- package/dist/utils/path-compat.js +128 -0
- package/dist/utils/path-compat.js.map +1 -0
- package/dist/utils/project-locator.d.ts +47 -0
- package/dist/utils/project-locator.d.ts.map +1 -0
- package/dist/utils/project-locator.js +372 -0
- package/dist/utils/project-locator.js.map +1 -0
- package/dist/utils/runtime-compat.d.ts +39 -0
- package/dist/utils/runtime-compat.d.ts.map +1 -0
- package/dist/utils/runtime-compat.js +113 -0
- package/dist/utils/runtime-compat.js.map +1 -0
- package/dist/utils/security.d.ts +74 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +291 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/status-reporter.d.ts +66 -0
- package/dist/utils/status-reporter.d.ts.map +1 -0
- package/dist/utils/status-reporter.js +309 -0
- package/dist/utils/status-reporter.js.map +1 -0
- package/dist/utils/style-sampler.d.ts +69 -0
- package/dist/utils/style-sampler.d.ts.map +1 -0
- package/dist/utils/style-sampler.js +206 -0
- package/dist/utils/style-sampler.js.map +1 -0
- package/dist/utils/workflow-manager.d.ts +104 -0
- package/dist/utils/workflow-manager.d.ts.map +1 -0
- package/dist/utils/workflow-manager.js +462 -0
- package/dist/utils/workflow-manager.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-locator.d.ts","sourceRoot":"","sources":["../../src/utils/project-locator.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,yBAAyB,+BAAgC,CAAC;AACvE,eAAO,MAAM,2BAA2B,QAA+C,CAAC;AACxF,eAAO,MAAM,mBAAmB,QAA6C,CAAC;AAE9E,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAC3D,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAC/D,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAMjE;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAStD;AAuOD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,mBAAmB,CAAC,EAAE,MAAM,EAC5B,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,MAAM,CAuER;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,EAAE;IAC1D,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,GAAG,IAAI,CAiChB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACnC,MAAM,GAAG,IAAI,CA+Cf;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,iBAAiB,CAAC,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE;IACR,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GACA,MAAM,CAaR"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Locator - 项目根目录解析器
|
|
3
|
+
*
|
|
4
|
+
* 迁移自 Python project_locator.py,保持完全兼容
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
7
|
+
import { join, resolve, dirname } from 'path';
|
|
8
|
+
import { platform } from 'os';
|
|
9
|
+
import { getStatePath, isProjectRoot, isExplicitProjectRoot, normalizePath, getGlobalRegistryPath, makePathKey, nowIso, } from './path-compat.js';
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Constants
|
|
12
|
+
// ============================================================================
|
|
13
|
+
export const DEFAULT_PROJECT_DIR_NAMES = ['webnovel-project'];
|
|
14
|
+
export const CURRENT_PROJECT_POINTER_REL = join('.claude', '.webnovel-current-project');
|
|
15
|
+
export const GLOBAL_REGISTRY_REL = join('webnovel-writer', 'workspaces.json');
|
|
16
|
+
export const ENV_CLAUDE_PROJECT_DIR = 'CLAUDE_PROJECT_DIR';
|
|
17
|
+
export const ENV_CLAUDE_HOME = 'CLAUDE_HOME';
|
|
18
|
+
export const ENV_WEBNOVEL_CLAUDE_HOME = 'WEBNOVEL_CLAUDE_HOME';
|
|
19
|
+
export const ENV_WEBNOVEL_PROJECT_ROOT = 'WEBNOVEL_PROJECT_ROOT';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Git Root Detection
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* 查找最近的 Git 根目录
|
|
25
|
+
*/
|
|
26
|
+
export function findGitRoot(cwd) {
|
|
27
|
+
const parts = resolve(cwd).split(/[/\\]/);
|
|
28
|
+
for (let i = parts.length; i > 0; i--) {
|
|
29
|
+
const candidate = parts.slice(0, i).join(sep());
|
|
30
|
+
if (existsSync(join(candidate, '.git'))) {
|
|
31
|
+
return candidate || '/';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
function sep() {
|
|
37
|
+
return platform() === 'win32' ? '\\' : '/';
|
|
38
|
+
}
|
|
39
|
+
function defaultRegistry() {
|
|
40
|
+
return {
|
|
41
|
+
schema_version: 1,
|
|
42
|
+
workspaces: {},
|
|
43
|
+
last_used_project_root: '',
|
|
44
|
+
updated_at: nowIso(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function loadGlobalRegistry(path) {
|
|
48
|
+
if (!existsSync(path)) {
|
|
49
|
+
return defaultRegistry();
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const content = readFileSync(path, 'utf-8');
|
|
53
|
+
const data = JSON.parse(content || '{}');
|
|
54
|
+
if (typeof data !== 'object' || data === null) {
|
|
55
|
+
return defaultRegistry();
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
schema_version: data.schema_version ?? 1,
|
|
59
|
+
workspaces: data.workspaces ?? {},
|
|
60
|
+
last_used_project_root: data.last_used_project_root ?? '',
|
|
61
|
+
updated_at: data.updated_at ?? nowIso(),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return defaultRegistry();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function saveGlobalRegistry(path, data) {
|
|
69
|
+
try {
|
|
70
|
+
const dir = dirname(path);
|
|
71
|
+
if (!existsSync(dir)) {
|
|
72
|
+
mkdirSync(dir, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
data.updated_at = nowIso();
|
|
75
|
+
writeFileSync(path, JSON.stringify(data, null, 2), 'utf-8');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// best-effort, 非阻断
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 从用户级 registry 解析 project_root
|
|
83
|
+
*/
|
|
84
|
+
function resolveProjectRootFromGlobalRegistry(base, options) {
|
|
85
|
+
const regPath = getGlobalRegistryPath();
|
|
86
|
+
const reg = loadGlobalRegistry(regPath);
|
|
87
|
+
const workspaces = reg.workspaces;
|
|
88
|
+
if (Object.keys(workspaces).length === 0) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const hints = [];
|
|
92
|
+
const envWs = process.env[ENV_CLAUDE_PROJECT_DIR];
|
|
93
|
+
if (envWs) {
|
|
94
|
+
hints.push(normalizePath(envWs));
|
|
95
|
+
}
|
|
96
|
+
if (options?.workspaceHint) {
|
|
97
|
+
hints.push(normalizePath(options.workspaceHint));
|
|
98
|
+
}
|
|
99
|
+
hints.push(normalizePath(base));
|
|
100
|
+
// 1) 精确匹配
|
|
101
|
+
for (const hint of hints) {
|
|
102
|
+
const key = makePathKey(hint);
|
|
103
|
+
const entry = workspaces[key];
|
|
104
|
+
if (entry && entry.current_project_root) {
|
|
105
|
+
const target = resolve(normalizePath(entry.current_project_root));
|
|
106
|
+
if (isProjectRoot(target)) {
|
|
107
|
+
return target;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// 2) 前缀匹配
|
|
112
|
+
for (const hint of hints) {
|
|
113
|
+
const hintKey = makePathKey(hint);
|
|
114
|
+
let bestKey = null;
|
|
115
|
+
let bestLen = -1;
|
|
116
|
+
for (const wsKey of Object.keys(workspaces)) {
|
|
117
|
+
if (hintKey === wsKey || hintKey.startsWith(wsKey + sep())) {
|
|
118
|
+
if (wsKey.length > bestLen) {
|
|
119
|
+
bestKey = wsKey;
|
|
120
|
+
bestLen = wsKey.length;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (bestKey) {
|
|
125
|
+
const entry = workspaces[bestKey];
|
|
126
|
+
if (entry && entry.current_project_root) {
|
|
127
|
+
const target = resolve(normalizePath(entry.current_project_root));
|
|
128
|
+
if (isProjectRoot(target)) {
|
|
129
|
+
return target;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// 3) last_used fallback
|
|
135
|
+
if (options?.allowLastUsedFallback) {
|
|
136
|
+
const lastUsed = reg.last_used_project_root;
|
|
137
|
+
if (lastUsed) {
|
|
138
|
+
const target = resolve(normalizePath(lastUsed));
|
|
139
|
+
if (isProjectRoot(target)) {
|
|
140
|
+
return target;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Pointer File
|
|
148
|
+
// ============================================================================
|
|
149
|
+
/**
|
|
150
|
+
* 查找包含 .claude/ 的最近祖先目录
|
|
151
|
+
*/
|
|
152
|
+
function findWorkspaceRootWithClaude(start) {
|
|
153
|
+
const parts = resolve(start).split(/[/\\]/);
|
|
154
|
+
for (let i = parts.length; i > 0; i--) {
|
|
155
|
+
const candidate = parts.slice(0, i).join(sep());
|
|
156
|
+
if (existsSync(join(candidate, '.claude'))) {
|
|
157
|
+
return candidate || '/';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 从 workspace 指针文件解析 project_root
|
|
164
|
+
*/
|
|
165
|
+
function resolveProjectRootFromPointer(cwd, stopAt) {
|
|
166
|
+
const parts = resolve(cwd).split(/[/\\]/);
|
|
167
|
+
for (let i = parts.length; i > 0; i--) {
|
|
168
|
+
const candidate = parts.slice(0, i).join(sep());
|
|
169
|
+
const pointerFile = join(candidate, CURRENT_PROJECT_POINTER_REL);
|
|
170
|
+
if (existsSync(pointerFile)) {
|
|
171
|
+
const raw = readFileSync(pointerFile, 'utf-8').trim();
|
|
172
|
+
if (!raw)
|
|
173
|
+
continue;
|
|
174
|
+
let target = normalizePath(raw);
|
|
175
|
+
if (!resolve(target).startsWith('/')) {
|
|
176
|
+
// 相对路径,相对于指针文件所在目录
|
|
177
|
+
target = resolve(join(dirname(pointerFile), raw));
|
|
178
|
+
}
|
|
179
|
+
if (isProjectRoot(target)) {
|
|
180
|
+
return resolve(target);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (stopAt && candidate === stopAt) {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
// ============================================================================
|
|
190
|
+
// Candidate Roots
|
|
191
|
+
// ============================================================================
|
|
192
|
+
function* candidateRoots(cwd, stopAt) {
|
|
193
|
+
const resolved = resolve(cwd);
|
|
194
|
+
yield resolved;
|
|
195
|
+
for (const name of DEFAULT_PROJECT_DIR_NAMES) {
|
|
196
|
+
yield join(resolved, name);
|
|
197
|
+
}
|
|
198
|
+
const parts = resolved.split(/[/\\]/);
|
|
199
|
+
for (let i = parts.length - 1; i > 0; i--) {
|
|
200
|
+
const parent = parts.slice(0, i).join(sep());
|
|
201
|
+
yield parent;
|
|
202
|
+
for (const name of DEFAULT_PROJECT_DIR_NAMES) {
|
|
203
|
+
yield join(parent, name);
|
|
204
|
+
}
|
|
205
|
+
if (stopAt && parent === stopAt) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// ============================================================================
|
|
211
|
+
// Main API
|
|
212
|
+
// ============================================================================
|
|
213
|
+
/**
|
|
214
|
+
* 解析项目根目录
|
|
215
|
+
*
|
|
216
|
+
* 解析优先级:
|
|
217
|
+
* 1) 显式传入的 project_root
|
|
218
|
+
* 2) 环境变量 WEBNOVEL_PROJECT_ROOT
|
|
219
|
+
* 3) workspace 指针文件
|
|
220
|
+
* 4) 用户级 registry (前缀匹配)
|
|
221
|
+
* 5) 从 CWD 向上搜索 .webnovel/state.json
|
|
222
|
+
*
|
|
223
|
+
* @throws Error 如果无法找到有效的项目根目录
|
|
224
|
+
*/
|
|
225
|
+
export function resolveProjectRoot(explicitProjectRoot, options) {
|
|
226
|
+
const cwd = resolve(options?.cwd || process.cwd());
|
|
227
|
+
// 1) 显式传入
|
|
228
|
+
if (explicitProjectRoot) {
|
|
229
|
+
const root = resolve(normalizePath(explicitProjectRoot));
|
|
230
|
+
if (isExplicitProjectRoot(root)) {
|
|
231
|
+
return root;
|
|
232
|
+
}
|
|
233
|
+
// 兼容:显式传入工作区根目录(含指针文件)
|
|
234
|
+
const pointerRoot = resolveProjectRootFromPointer(root, findGitRoot(root));
|
|
235
|
+
if (pointerRoot) {
|
|
236
|
+
return pointerRoot;
|
|
237
|
+
}
|
|
238
|
+
// 兼容:从用户级 registry 查找
|
|
239
|
+
const regRoot = resolveProjectRootFromGlobalRegistry(root, {
|
|
240
|
+
workspaceHint: root,
|
|
241
|
+
allowLastUsedFallback: false,
|
|
242
|
+
});
|
|
243
|
+
if (regRoot) {
|
|
244
|
+
return regRoot;
|
|
245
|
+
}
|
|
246
|
+
throw new Error(`Not a webnovel project root (missing .webnovel/state.json): ${root}`);
|
|
247
|
+
}
|
|
248
|
+
// 2) 环境变量
|
|
249
|
+
const envRoot = process.env[ENV_WEBNOVEL_PROJECT_ROOT];
|
|
250
|
+
if (envRoot) {
|
|
251
|
+
const root = resolve(normalizePath(envRoot));
|
|
252
|
+
if (isProjectRoot(root)) {
|
|
253
|
+
return root;
|
|
254
|
+
}
|
|
255
|
+
throw new Error(`WEBNOVEL_PROJECT_ROOT is set but invalid (missing .webnovel/state.json): ${root}`);
|
|
256
|
+
}
|
|
257
|
+
const gitRoot = findGitRoot(cwd);
|
|
258
|
+
// 3) workspace 指针文件
|
|
259
|
+
const pointerRoot = resolveProjectRootFromPointer(cwd, gitRoot);
|
|
260
|
+
if (pointerRoot) {
|
|
261
|
+
return pointerRoot;
|
|
262
|
+
}
|
|
263
|
+
// 4) 用户级 registry
|
|
264
|
+
const allowLastUsed = Boolean(process.env[ENV_CLAUDE_PROJECT_DIR]);
|
|
265
|
+
const regRoot = resolveProjectRootFromGlobalRegistry(cwd, {
|
|
266
|
+
allowLastUsedFallback: allowLastUsed,
|
|
267
|
+
});
|
|
268
|
+
if (regRoot) {
|
|
269
|
+
return regRoot;
|
|
270
|
+
}
|
|
271
|
+
// 5) 从 CWD 向上搜索
|
|
272
|
+
for (const candidate of candidateRoots(cwd, gitRoot)) {
|
|
273
|
+
if (isProjectRoot(candidate)) {
|
|
274
|
+
return resolve(candidate);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
throw new Error('Unable to locate webnovel project root. Expected `.webnovel/state.json` under the current directory, ' +
|
|
278
|
+
'a parent directory, or `webnovel-project/`. Run /webnovel-init first or pass --project-root / set ' +
|
|
279
|
+
'WEBNOVEL_PROJECT_ROOT.');
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* 更新用户级 registry:workspace -> current_project_root 映射
|
|
283
|
+
*/
|
|
284
|
+
export function updateGlobalRegistryCurrentProject(options) {
|
|
285
|
+
const root = resolve(normalizePath(options.projectRoot));
|
|
286
|
+
if (!isProjectRoot(root)) {
|
|
287
|
+
throw new Error(`Not a webnovel project root (missing .webnovel/state.json): ${root}`);
|
|
288
|
+
}
|
|
289
|
+
let ws = options.workspaceRoot;
|
|
290
|
+
if (!ws) {
|
|
291
|
+
const envWs = process.env[ENV_CLAUDE_PROJECT_DIR];
|
|
292
|
+
if (envWs) {
|
|
293
|
+
ws = normalizePath(envWs);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (!ws) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
ws = resolve(normalizePath(ws));
|
|
300
|
+
const regPath = getGlobalRegistryPath();
|
|
301
|
+
const reg = loadGlobalRegistry(regPath);
|
|
302
|
+
const workspaces = reg.workspaces;
|
|
303
|
+
workspaces[makePathKey(ws)] = {
|
|
304
|
+
workspace_root: ws,
|
|
305
|
+
current_project_root: root,
|
|
306
|
+
updated_at: nowIso(),
|
|
307
|
+
};
|
|
308
|
+
reg.last_used_project_root = root;
|
|
309
|
+
saveGlobalRegistry(regPath, reg);
|
|
310
|
+
return regPath;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* 写入 workspace 级当前项目指针
|
|
314
|
+
*/
|
|
315
|
+
export function writeCurrentProjectPointer(projectRoot, options) {
|
|
316
|
+
const root = resolve(normalizePath(projectRoot));
|
|
317
|
+
if (!isProjectRoot(root)) {
|
|
318
|
+
throw new Error(`Not a webnovel project root (missing .webnovel/state.json): ${root}`);
|
|
319
|
+
}
|
|
320
|
+
let wsRoot = options?.workspaceRoot
|
|
321
|
+
? resolve(normalizePath(options.workspaceRoot))
|
|
322
|
+
: findWorkspaceRootWithClaude(root);
|
|
323
|
+
if (!wsRoot) {
|
|
324
|
+
wsRoot = findWorkspaceRootWithClaude(resolve(process.cwd()));
|
|
325
|
+
}
|
|
326
|
+
if (!wsRoot) {
|
|
327
|
+
// 兜底:使用项目父目录
|
|
328
|
+
wsRoot = dirname(root);
|
|
329
|
+
}
|
|
330
|
+
let pointerFile = null;
|
|
331
|
+
// 仅当工作区内已存在 .claude/ 时才写入指针
|
|
332
|
+
if (existsSync(join(wsRoot, '.claude'))) {
|
|
333
|
+
try {
|
|
334
|
+
pointerFile = join(wsRoot, CURRENT_PROJECT_POINTER_REL);
|
|
335
|
+
const pointerDir = dirname(pointerFile);
|
|
336
|
+
if (!existsSync(pointerDir)) {
|
|
337
|
+
mkdirSync(pointerDir, { recursive: true });
|
|
338
|
+
}
|
|
339
|
+
writeFileSync(pointerFile, root, 'utf-8');
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
pointerFile = null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// best-effort 更新用户级 registry
|
|
346
|
+
try {
|
|
347
|
+
updateGlobalRegistryCurrentProject({
|
|
348
|
+
workspaceRoot: wsRoot,
|
|
349
|
+
projectRoot: root,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
// 非阻断
|
|
354
|
+
}
|
|
355
|
+
return pointerFile;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* 解析 state.json 文件路径
|
|
359
|
+
*/
|
|
360
|
+
export function resolveStateFile(explicitStateFile, options) {
|
|
361
|
+
const cwd = resolve(options?.cwd || process.cwd());
|
|
362
|
+
if (explicitStateFile) {
|
|
363
|
+
const p = resolve(normalizePath(explicitStateFile));
|
|
364
|
+
if (!p.startsWith('/')) {
|
|
365
|
+
return resolve(join(cwd, p));
|
|
366
|
+
}
|
|
367
|
+
return p;
|
|
368
|
+
}
|
|
369
|
+
const root = resolveProjectRoot(options?.explicitProjectRoot, { cwd });
|
|
370
|
+
return getStatePath(root);
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=project-locator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-locator.js","sourceRoot":"","sources":["../../src/utils/project-locator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 在 Windows 上启用 UTF-8 stdio
|
|
3
|
+
*
|
|
4
|
+
* Node.js 默认在 Windows 上使用 UTF-8,但控制台可能需要设置
|
|
5
|
+
* 此函数主要用于打印前的编码确保
|
|
6
|
+
*/
|
|
7
|
+
export declare function setupWindowsUtf8(): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* 规范化 Windows 上的 POSIX 风格路径
|
|
10
|
+
*
|
|
11
|
+
* 处理以下格式:
|
|
12
|
+
* - Git Bash / MSYS: /d/desktop/... => D:/desktop/...
|
|
13
|
+
* - WSL: /mnt/d/desktop/... => D:/desktop/...
|
|
14
|
+
*
|
|
15
|
+
* @param path 原始路径
|
|
16
|
+
* @returns 规范化后的路径
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeWindowsPath(path: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* 跨平台路径规范化
|
|
21
|
+
*
|
|
22
|
+
* 统一处理不同来源的路径格式
|
|
23
|
+
*/
|
|
24
|
+
export declare function normalizePathCrossPlatform(path: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* 获取安全的 stdio 编码
|
|
27
|
+
*
|
|
28
|
+
* Node.js 默认 UTF-8,此函数返回编码名称供参考
|
|
29
|
+
*/
|
|
30
|
+
export declare function getStdioEncoding(): string;
|
|
31
|
+
/**
|
|
32
|
+
* 检测是否在 WSL 环境中运行
|
|
33
|
+
*/
|
|
34
|
+
export declare function isWsl(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* 获取平台特定的换行符
|
|
37
|
+
*/
|
|
38
|
+
export declare function getNewline(): string;
|
|
39
|
+
//# sourceMappingURL=runtime-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-compat.d.ts","sourceRoot":"","sources":["../../src/utils/runtime-compat.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAgB1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA2BzD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;GAEG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAY/B;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时兼容性工具
|
|
3
|
+
*
|
|
4
|
+
* 迁移自 Python runtime_compat.py
|
|
5
|
+
* 处理 Windows UTF-8 stdio 和跨平台路径规范化
|
|
6
|
+
*/
|
|
7
|
+
import { platform } from 'os';
|
|
8
|
+
import { normalize, resolve } from 'path';
|
|
9
|
+
const isWindows = platform() === 'win32';
|
|
10
|
+
// Windows POSIX 风格路径正则(Git Bash / MSYS 风格)
|
|
11
|
+
const WIN_POSIX_DRIVE_RE = /^\/([a-zA-Z])\/(.*)$/;
|
|
12
|
+
// WSL 挂载路径正则
|
|
13
|
+
const WIN_WSL_MNT_DRIVE_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/;
|
|
14
|
+
/**
|
|
15
|
+
* 在 Windows 上启用 UTF-8 stdio
|
|
16
|
+
*
|
|
17
|
+
* Node.js 默认在 Windows 上使用 UTF-8,但控制台可能需要设置
|
|
18
|
+
* 此函数主要用于打印前的编码确保
|
|
19
|
+
*/
|
|
20
|
+
export function setupWindowsUtf8() {
|
|
21
|
+
if (!isWindows) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
// Node.js 在 Windows 上默认使用 UTF-8,无需额外设置
|
|
25
|
+
// 但可以设置控制台代码页为 UTF-8
|
|
26
|
+
try {
|
|
27
|
+
// 通过环境变量抑制编码警告
|
|
28
|
+
if (!process.env.NODE_OPTIONS?.includes('--no-warnings')) {
|
|
29
|
+
process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + ' --no-warnings';
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 规范化 Windows 上的 POSIX 风格路径
|
|
39
|
+
*
|
|
40
|
+
* 处理以下格式:
|
|
41
|
+
* - Git Bash / MSYS: /d/desktop/... => D:/desktop/...
|
|
42
|
+
* - WSL: /mnt/d/desktop/... => D:/desktop/...
|
|
43
|
+
*
|
|
44
|
+
* @param path 原始路径
|
|
45
|
+
* @returns 规范化后的路径
|
|
46
|
+
*/
|
|
47
|
+
export function normalizeWindowsPath(path) {
|
|
48
|
+
if (!isWindows) {
|
|
49
|
+
return normalize(path);
|
|
50
|
+
}
|
|
51
|
+
const raw = path.trim();
|
|
52
|
+
if (!raw) {
|
|
53
|
+
return raw;
|
|
54
|
+
}
|
|
55
|
+
// WSL 挂载路径: /mnt/d/... => D:/...
|
|
56
|
+
let match = raw.match(WIN_WSL_MNT_DRIVE_RE);
|
|
57
|
+
if (match) {
|
|
58
|
+
const drive = match[1].toUpperCase();
|
|
59
|
+
const rest = match[2];
|
|
60
|
+
return normalize(`${drive}:/${rest}`);
|
|
61
|
+
}
|
|
62
|
+
// Git Bash / MSYS 路径: /d/... => D:/...
|
|
63
|
+
match = raw.match(WIN_POSIX_DRIVE_RE);
|
|
64
|
+
if (match) {
|
|
65
|
+
const drive = match[1].toUpperCase();
|
|
66
|
+
const rest = match[2];
|
|
67
|
+
return normalize(`${drive}:/${rest}`);
|
|
68
|
+
}
|
|
69
|
+
return normalize(path);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 跨平台路径规范化
|
|
73
|
+
*
|
|
74
|
+
* 统一处理不同来源的路径格式
|
|
75
|
+
*/
|
|
76
|
+
export function normalizePathCrossPlatform(path) {
|
|
77
|
+
// 先处理 Windows 特殊格式
|
|
78
|
+
let normalized = normalizeWindowsPath(path);
|
|
79
|
+
// 再规范化
|
|
80
|
+
return resolve(normalized);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 获取安全的 stdio 编码
|
|
84
|
+
*
|
|
85
|
+
* Node.js 默认 UTF-8,此函数返回编码名称供参考
|
|
86
|
+
*/
|
|
87
|
+
export function getStdioEncoding() {
|
|
88
|
+
return 'utf-8';
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 检测是否在 WSL 环境中运行
|
|
92
|
+
*/
|
|
93
|
+
export function isWsl() {
|
|
94
|
+
if (!isWindows && process.platform === 'linux') {
|
|
95
|
+
// 检测 WSL 环境
|
|
96
|
+
try {
|
|
97
|
+
const fs = require('fs');
|
|
98
|
+
const release = fs.readFileSync('/proc/version', 'utf-8');
|
|
99
|
+
return release.toLowerCase().includes('microsoft');
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 获取平台特定的换行符
|
|
109
|
+
*/
|
|
110
|
+
export function getNewline() {
|
|
111
|
+
return isWindows ? '\r\n' : '\n';
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=runtime-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-compat.js","sourceRoot":"","sources":["../../src/utils/runtime-compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 清理文件名,防止路径遍历攻击 (CWE-22)
|
|
3
|
+
*
|
|
4
|
+
* @param name 原始文件名(可能包含路径遍历字符)
|
|
5
|
+
* @param maxLength 文件名最大长度(默认 100 字符)
|
|
6
|
+
* @returns 安全的文件名
|
|
7
|
+
*/
|
|
8
|
+
export declare function sanitizeFilename(name: string, maxLength?: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* 清理 Git 提交消息,防止命令注入 (CWE-77)
|
|
11
|
+
*
|
|
12
|
+
* @param message 原始提交消息
|
|
13
|
+
* @param maxLength 消息最大长度(默认 200 字符)
|
|
14
|
+
* @returns 安全的提交消息
|
|
15
|
+
*/
|
|
16
|
+
export declare function sanitizeCommitMessage(message: string, maxLength?: number): string;
|
|
17
|
+
/**
|
|
18
|
+
* 检测 Git 是否可用
|
|
19
|
+
*/
|
|
20
|
+
export declare function isGitAvailable(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* 检测指定目录是否是 Git 仓库
|
|
23
|
+
*/
|
|
24
|
+
export declare function isGitRepo(path: string): boolean;
|
|
25
|
+
interface GitOperationResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
output: string;
|
|
28
|
+
wasSkipped: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 优雅执行 Git 操作
|
|
32
|
+
*/
|
|
33
|
+
export declare function gitGracefulOperation(args: string[], cwd: string, fallbackMsg?: string): Promise<GitOperationResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Git add
|
|
36
|
+
*/
|
|
37
|
+
export declare function gitAdd(files: string[], cwd: string): Promise<GitOperationResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Git commit
|
|
40
|
+
*/
|
|
41
|
+
export declare function gitCommit(message: string, cwd: string): Promise<GitOperationResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Git status
|
|
44
|
+
*/
|
|
45
|
+
export declare function gitStatus(cwd: string): Promise<string[]>;
|
|
46
|
+
export declare class AtomicWriteError extends Error {
|
|
47
|
+
constructor(message: string);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 原子化写入 JSON 文件
|
|
51
|
+
*
|
|
52
|
+
* 实现策略:
|
|
53
|
+
* 1. 写入临时文件(同目录)
|
|
54
|
+
* 2. 可选:备份原文件
|
|
55
|
+
* 3. 原子重命名
|
|
56
|
+
*/
|
|
57
|
+
export declare function writeJsonAtomic(filePath: string, data: unknown, options?: {
|
|
58
|
+
backup?: boolean;
|
|
59
|
+
indent?: number;
|
|
60
|
+
}): void;
|
|
61
|
+
/**
|
|
62
|
+
* 安全读取 JSON 文件
|
|
63
|
+
*/
|
|
64
|
+
export declare function readJsonSafe<T = Record<string, unknown>>(filePath: string, defaultValue?: T): T;
|
|
65
|
+
/**
|
|
66
|
+
* 从备份恢复文件
|
|
67
|
+
*/
|
|
68
|
+
export declare function restoreFromBackup(filePath: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* 验证并转换整数输入
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateIntegerInput(value: string, fieldName: string): number;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":"AAeA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,MAAM,CA4BtE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,MAAM,CA8B9E;AAQD;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAiBxC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAK/C;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,WAAW,SAAqB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0C7B;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAEtF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAGzF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAM9D;AAMD,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,IAAI,CAuDN;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,CAAC,GACf,CAAC,CAcH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAgB3D;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAU7E"}
|