@v587d/capital-generation 2.15.0 → 2.16.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/CHANGELOG.md +171 -0
- package/README.md +7 -12
- package/THIRD_PARTY_NOTICES.md +1 -0
- package/automation/TABLER-ICONS-LICENSE +21 -0
- package/automation/builtins.js +237 -10
- package/automation/client.js +79 -17
- package/automation/client.src.cjs +873 -210
- package/automation/contract.js +4 -0
- package/automation/defaults.js +6 -4
- package/automation/index.js +12 -7
- package/automation/package.json +5 -2
- package/automation/route.js +9 -2
- package/automation/runner.js +33 -6
- package/automation/scheduler.js +34 -29
- package/automation/schema.js +39 -5
- package/automation/service.js +102 -10
- package/automation/settings.js +6 -0
- package/automation/store.js +64 -21
- package/automation/task-icons.js +75 -0
- package/automation/workspaces.js +113 -13
- package/chart-ui/client.js +2 -2
- package/chart-ui/package.json +1 -1
- package/config/client.js +19 -5
- package/config/client.src.cjs +365 -44
- package/config/index.js +7 -5
- package/config/package.json +1 -1
- package/lib/agents/root-tool-policy.d.ts +3 -3
- package/lib/agents/root-tool-policy.js +4 -2
- package/lib/chart/runtime.d.ts +1 -1
- package/lib/chart/runtime.js +95 -0
- package/lib/chart/series.d.ts +4 -4
- package/lib/chart/series.js +44 -10
- package/lib/data-collector/dataset-tools.js +22 -0
- package/lib/data-collector/describe.js +1 -0
- package/lib/data-collector/hub.js +5 -0
- package/lib/data-collector/store.d.ts +5 -0
- package/lib/data-collector/store.js +17 -0
- package/lib/data-collector/time-axis.d.ts +15 -0
- package/lib/data-collector/time-axis.js +73 -0
- package/lib/data-collector/tools.d.ts +1 -1
- package/lib/data-collector/tools.js +12 -1
- package/lib/index.d.ts +5 -0
- package/lib/index.js +7 -5
- package/lib/sources/tencent-http.js +7 -2
- package/lib/sources/tencent-public-core.d.ts +2 -0
- package/lib/sources/tencent-public-core.js +5 -0
- package/lib/sources/wind-mcp.js +3 -3
- package/lib/sources-entry.d.ts +1 -1
- package/lib/web-retriever/local-fetch.d.ts +1 -1
- package/lib/web-retriever/local-fetch.js +1 -1
- package/lib/web-retriever/sources.d.ts +58 -0
- package/lib/web-retriever/sources.js +290 -0
- package/lib/web-retriever/tools.js +199 -8
- package/lib/web-retriever/wind-client.d.ts +1 -1
- package/lib/web-retriever/wind-client.js +1 -1
- package/package.json +1 -1
- package/preset/capital-generation/agent.patch.yml +20 -19
- package/preset/capital-generation/skills/capital-chart-protocol/SKILL.md +6 -3
- package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +9 -2
- package/preset/capital-generation/skills/capital-orchestration/SKILL.md +2 -1
- package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +2 -0
- package/preset/capital-generation/skills/capital-web-evidence/SKILL.md +18 -13
- package/preset/capital-generation/skills/capital-web-protocol/SKILL.md +30 -15
- package/watchlist/package.json +1 -1
package/automation/workspaces.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* sessions are grouped instead of landing in the ungrouped bucket.
|
|
5
5
|
*/
|
|
6
6
|
import { mkdir, realpath } from 'node:fs/promises'
|
|
7
|
+
import { join, sep } from 'node:path'
|
|
8
|
+
|
|
9
|
+
export const AUTOMATION_WORKSPACE_DIR = 'CapGen-automation-workspace'
|
|
7
10
|
|
|
8
11
|
export class WorkspaceError extends Error {
|
|
9
12
|
constructor(code, message) {
|
|
@@ -15,6 +18,7 @@ export class WorkspaceError extends Error {
|
|
|
15
18
|
|
|
16
19
|
const DEFAULT_REGISTRATIONS = new WeakMap()
|
|
17
20
|
const MAX_SESSIONS_TO_ADOPT = 500
|
|
21
|
+
const MAX_WORKSPACE_ID_CHARS = 200
|
|
18
22
|
|
|
19
23
|
function service(ctx, name) {
|
|
20
24
|
try {
|
|
@@ -24,15 +28,54 @@ function service(ctx, name) {
|
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
|
|
31
|
+
/** Directory segment safe on every platform; the raw profile name never becomes a path. */
|
|
32
|
+
export function safeSegment(value) {
|
|
33
|
+
return String(value).replace(/[^A-Za-z0-9._-]+/g, '_').slice(0, 120)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function defaultWorkspacePath(profile = {}) {
|
|
37
|
+
const home = profile.home ?? profile.dir ?? process.cwd()
|
|
38
|
+
return join(home, AUTOMATION_WORKSPACE_DIR, safeSegment(profile.name ?? 'default'))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function defaultWorkspaceTitle(displayName) {
|
|
42
|
+
return `CapGen 投研自动化(${displayName})`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `~` only for paths under the user's home; anything else stays absolute so it is unambiguous. */
|
|
46
|
+
export function workspaceDisplayPath(path, home) {
|
|
47
|
+
if (typeof path !== 'string' || typeof home !== 'string' || home.length === 0) return path
|
|
48
|
+
const prefix = home.endsWith(sep) ? home : `${home}${sep}`
|
|
49
|
+
return path.startsWith(prefix) ? `~${path.slice(home.length)}` : path
|
|
50
|
+
}
|
|
51
|
+
|
|
27
52
|
export function createWorkspaceCatalog(options) {
|
|
28
|
-
const { ctx, displayName, runDir, logger } = options
|
|
29
|
-
let
|
|
30
|
-
let
|
|
53
|
+
const { ctx, displayName, runDir, displayHome, getDefaultWorkspaceId, logger } = options
|
|
54
|
+
let dedicatedEntity
|
|
55
|
+
let dedicatedPromise
|
|
56
|
+
let warnedDefaultId
|
|
31
57
|
|
|
32
58
|
function registry() {
|
|
33
59
|
return service(ctx, 'workspaceRegistry')
|
|
34
60
|
}
|
|
35
61
|
|
|
62
|
+
function configuredDefaultId() {
|
|
63
|
+
let value
|
|
64
|
+
try {
|
|
65
|
+
value = typeof getDefaultWorkspaceId === 'function' ? getDefaultWorkspaceId() : getDefaultWorkspaceId
|
|
66
|
+
} catch {
|
|
67
|
+
value = undefined
|
|
68
|
+
}
|
|
69
|
+
if (typeof value !== 'string') return ''
|
|
70
|
+
return value.trim().slice(0, MAX_WORKSPACE_ID_CHARS)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function warnDefaultUnusable(id, reason) {
|
|
74
|
+
if (warnedDefaultId === id) return
|
|
75
|
+
warnedDefaultId = id
|
|
76
|
+
logger?.warn?.(`capital-automation: 默认工作区 ${id} ${reason},回退到专属默认工作区。`)
|
|
77
|
+
}
|
|
78
|
+
|
|
36
79
|
async function adoptSessions(entity) {
|
|
37
80
|
if (entity.sessionIds.length > 0) return
|
|
38
81
|
const persistence = service(ctx, 'sessionPersistence')
|
|
@@ -66,8 +109,8 @@ export function createWorkspaceCatalog(options) {
|
|
|
66
109
|
}
|
|
67
110
|
|
|
68
111
|
async function ensureDefault() {
|
|
69
|
-
if (
|
|
70
|
-
if (
|
|
112
|
+
if (dedicatedEntity !== undefined) return dedicatedEntity
|
|
113
|
+
if (dedicatedPromise !== undefined) return dedicatedPromise
|
|
71
114
|
const current = registry()
|
|
72
115
|
if (current === undefined) return undefined
|
|
73
116
|
let registrations = DEFAULT_REGISTRATIONS.get(current)
|
|
@@ -85,7 +128,7 @@ export function createWorkspaceCatalog(options) {
|
|
|
85
128
|
}
|
|
86
129
|
if (created === undefined) {
|
|
87
130
|
try {
|
|
88
|
-
created = await current.create(runDir,
|
|
131
|
+
created = await current.create(runDir, defaultWorkspaceTitle(displayName))
|
|
89
132
|
} catch (error) {
|
|
90
133
|
const recovered = typeof current.resolveByPath === 'function'
|
|
91
134
|
? await current.resolveByPath(runDir).catch(() => undefined)
|
|
@@ -94,35 +137,92 @@ export function createWorkspaceCatalog(options) {
|
|
|
94
137
|
created = recovered
|
|
95
138
|
}
|
|
96
139
|
}
|
|
97
|
-
|
|
140
|
+
dedicatedEntity = created
|
|
98
141
|
await adoptSessions(created)
|
|
99
142
|
return created
|
|
100
143
|
})()
|
|
101
144
|
registrations.set(runDir, sharedPromise)
|
|
102
145
|
}
|
|
103
|
-
|
|
146
|
+
dedicatedPromise = sharedPromise
|
|
104
147
|
try {
|
|
105
|
-
|
|
148
|
+
const created = await sharedPromise
|
|
149
|
+
if (created !== undefined) dedicatedEntity = created
|
|
150
|
+
return created
|
|
106
151
|
} catch (error) {
|
|
107
152
|
logger?.warn?.(`capital-automation: 无法注册默认工作区:${String(error)}`)
|
|
108
153
|
return undefined
|
|
109
154
|
} finally {
|
|
110
155
|
if (registrations.get(runDir) === sharedPromise) registrations.delete(runDir)
|
|
111
|
-
if (
|
|
156
|
+
if (dedicatedEntity === undefined) dedicatedPromise = undefined
|
|
112
157
|
}
|
|
113
158
|
}
|
|
114
159
|
|
|
160
|
+
/**
|
|
161
|
+
* A configured default is honoured only while it is registered and its directory is usable.
|
|
162
|
+
* A stale id must degrade to the dedicated workspace instead of breaking every empty task.
|
|
163
|
+
*/
|
|
164
|
+
async function configuredDefaultEntity() {
|
|
165
|
+
const id = configuredDefaultId()
|
|
166
|
+
if (id === '') return undefined
|
|
167
|
+
const entity = registry()?.get?.(id)
|
|
168
|
+
if (entity === undefined) {
|
|
169
|
+
warnDefaultUnusable(id, '不存在或已被移除')
|
|
170
|
+
return undefined
|
|
171
|
+
}
|
|
172
|
+
let status
|
|
173
|
+
try {
|
|
174
|
+
status = await entity.status?.()
|
|
175
|
+
} catch {
|
|
176
|
+
status = 'unavailable'
|
|
177
|
+
}
|
|
178
|
+
if (status !== undefined && status !== 'ok') {
|
|
179
|
+
warnDefaultUnusable(id, '目录不可用')
|
|
180
|
+
return undefined
|
|
181
|
+
}
|
|
182
|
+
warnedDefaultId = undefined
|
|
183
|
+
return entity
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function effectiveDefault() {
|
|
187
|
+
const configured = await configuredDefaultEntity()
|
|
188
|
+
if (configured !== undefined) return configured
|
|
189
|
+
return ensureDefault()
|
|
190
|
+
}
|
|
191
|
+
|
|
115
192
|
async function list() {
|
|
193
|
+
await ensureDefault()
|
|
116
194
|
const current = registry()
|
|
117
195
|
if (current === undefined) return []
|
|
118
|
-
const preferred = await
|
|
196
|
+
const preferred = await effectiveDefault()
|
|
197
|
+
const dedicatedId = dedicatedEntity?.id
|
|
119
198
|
return current.list().map((entity) => ({
|
|
120
199
|
id: entity.id,
|
|
121
200
|
title: entity.title,
|
|
122
201
|
default: preferred !== undefined && entity.id === preferred.id,
|
|
202
|
+
...(entity.id === dedicatedId ? { dedicated: true } : {}),
|
|
123
203
|
}))
|
|
124
204
|
}
|
|
125
205
|
|
|
206
|
+
/** Settings-card projection only: it carries paths, unlike the task page's `/meta`. */
|
|
207
|
+
async function details() {
|
|
208
|
+
await ensureDefault()
|
|
209
|
+
const current = registry()
|
|
210
|
+
if (current === undefined) return { workspaces: [], defaultWorkspaceId: null }
|
|
211
|
+
const preferred = await effectiveDefault()
|
|
212
|
+
const dedicatedId = dedicatedEntity?.id
|
|
213
|
+
return {
|
|
214
|
+
workspaces: current.list().map((entity) => ({
|
|
215
|
+
id: entity.id,
|
|
216
|
+
title: entity.title,
|
|
217
|
+
path: entity.path,
|
|
218
|
+
displayPath: workspaceDisplayPath(entity.path, displayHome),
|
|
219
|
+
default: preferred !== undefined && entity.id === preferred.id,
|
|
220
|
+
dedicated: entity.id === dedicatedId,
|
|
221
|
+
})),
|
|
222
|
+
defaultWorkspaceId: preferred?.id ?? null,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
126
226
|
async function validate(id) {
|
|
127
227
|
if (typeof id !== 'string' || id.length === 0) return
|
|
128
228
|
const current = registry()
|
|
@@ -145,10 +245,10 @@ export function createWorkspaceCatalog(options) {
|
|
|
145
245
|
const entity = registry().get(id)
|
|
146
246
|
return { workspaceId: entity.id, path: entity.path }
|
|
147
247
|
}
|
|
148
|
-
const preferred = await
|
|
248
|
+
const preferred = await effectiveDefault()
|
|
149
249
|
if (preferred !== undefined) return { workspaceId: preferred.id, path: preferred.path }
|
|
150
250
|
return { workspaceId: undefined, path: runDir }
|
|
151
251
|
}
|
|
152
252
|
|
|
153
|
-
return { list, validate, resolve, runDir }
|
|
253
|
+
return { list, details, validate, resolve, runDir }
|
|
154
254
|
}
|