crewx 0.9.0-rc.2 → 0.9.0-rc.21
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/dist/assets/MarketPage-DDPL2d7x.js +36 -0
- package/dist/assets/{PromptTab-hdXDbbT6.js → PromptTab-UC3K4qx2.js} +3 -3
- package/dist/assets/{arc--CBVVcyH.js → arc-DdP3-fUR.js} +1 -1
- package/dist/assets/{architectureDiagram-UYN6MBPD-DUiYwqJn.js → architectureDiagram-UYN6MBPD-D16VON1i.js} +1 -1
- package/dist/assets/{blockDiagram-ZHA2E4KO-DV86vAgG.js → blockDiagram-ZHA2E4KO-qs1dIRkl.js} +4 -4
- package/dist/assets/{c4Diagram-6F5ED5ID-CvWE7Cx_.js → c4Diagram-6F5ED5ID-BeDy8akQ.js} +1 -1
- package/dist/assets/channel-DtrxBSkc.js +1 -0
- package/dist/assets/{chunk-5HRBRIJM-DAxM5Ul_.js → chunk-5HRBRIJM-BC1zIb11.js} +1 -1
- package/dist/assets/{chunk-7U56Z5CX-BuYaEj8L.js → chunk-7U56Z5CX-BuGil3QD.js} +1 -1
- package/dist/assets/{chunk-ASOPGD6M-2Kx0e45C.js → chunk-ASOPGD6M-DmKdDtBQ.js} +1 -1
- package/dist/assets/{chunk-KFBOBJHC-CR4QS6Rt.js → chunk-KFBOBJHC-D3BvHLPa.js} +1 -1
- package/dist/assets/{chunk-T2TOU4HS-CffcwNHx.js → chunk-T2TOU4HS-B5MoUp-N.js} +1 -1
- package/dist/assets/{chunk-TMUBEWPD-BGpYtekN.js → chunk-TMUBEWPD-AvWe_lsV.js} +1 -1
- package/dist/assets/classDiagram-LNE6IOMH-BMT5B_JB.js +1 -0
- package/dist/assets/classDiagram-v2-MQ7JQ4JX-BMT5B_JB.js +1 -0
- package/dist/assets/{dagre-4EVJKHTY-yBWukkrE.js → dagre-4EVJKHTY-B6DewFyM.js} +1 -1
- package/dist/assets/{diagram-QW4FP2JN-CIr1PLq3.js → diagram-QW4FP2JN-BTsQ8JSd.js} +1 -1
- package/dist/assets/{erDiagram-6RL3IURR-xG7SygyU.js → erDiagram-6RL3IURR-BM5nvgVR.js} +1 -1
- package/dist/assets/{flowDiagram-7ASYPVHJ-CKalfOqp.js → flowDiagram-7ASYPVHJ-D1UCCuOG.js} +1 -1
- package/dist/assets/{ganttDiagram-NTVNEXSI-Bnx7zrX4.js → ganttDiagram-NTVNEXSI-CNIGs7Cn.js} +1 -1
- package/dist/assets/{gitGraph-YCYPL57B-TQlF0fiA.js → gitGraph-YCYPL57B-DSLjx1yQ.js} +1 -1
- package/dist/assets/{gitGraphDiagram-NRZ2UAAF-DxlaFkwO.js → gitGraphDiagram-NRZ2UAAF-B11zX1Fa.js} +1 -1
- package/dist/assets/{infoDiagram-A4XQUW5V-B1-arkqa.js → infoDiagram-A4XQUW5V-DkjvODYl.js} +1 -1
- package/dist/assets/{journeyDiagram-G5WM74LC-Cj439GUX.js → journeyDiagram-G5WM74LC-BkCQPMn6.js} +1 -1
- package/dist/assets/{kanban-definition-QRCXZQQD-BvrIwEIc.js → kanban-definition-QRCXZQQD-_OX7pNfJ.js} +1 -1
- package/dist/assets/{linear-BKYNK0ri.js → linear-BYjwVAR6.js} +1 -1
- package/dist/assets/main-CZdKLdUl.css +10 -0
- package/dist/assets/main-CkkZNCy-.js +1561 -0
- package/dist/assets/{mindmap-definition-GWI6TPTV-BExfJY0G.js → mindmap-definition-GWI6TPTV-BzYpSnv8.js} +1 -1
- package/dist/assets/ort-wasm-simd-threaded.asyncify-DMmc6YqF.wasm +0 -0
- package/dist/assets/{pieDiagram-YF2LJOPJ-RPWpvrC8.js → pieDiagram-YF2LJOPJ-CEFg6ao0.js} +1 -1
- package/dist/assets/{quadrantDiagram-OS5C2QUG-DmbBzk5Q.js → quadrantDiagram-OS5C2QUG-_5w2x3VV.js} +1 -1
- package/dist/assets/{requirementDiagram-MIRIMTAZ-DFQuFXq3.js → requirementDiagram-MIRIMTAZ-B_VQYReZ.js} +1 -1
- package/dist/assets/{sankeyDiagram-Y46BX6SQ-p_bw56lJ.js → sankeyDiagram-Y46BX6SQ-CgmOlLhh.js} +1 -1
- package/dist/assets/{sequenceDiagram-G6AWOVSC-DTbBkLeD.js → sequenceDiagram-G6AWOVSC-MGVt0Ai2.js} +1 -1
- package/dist/assets/{stateDiagram-MAYHULR4-DBvC6UcF.js → stateDiagram-MAYHULR4-DaZjgTu-.js} +1 -1
- package/dist/assets/stateDiagram-v2-4JROLMXI-DN1wGYkV.js +1 -0
- package/dist/assets/{timeline-definition-U7ZMHBDA-B6utvIg1.js → timeline-definition-U7ZMHBDA-CusetmK6.js} +1 -1
- package/dist/assets/transformers.web-BN8Ug43_.js +45 -0
- package/dist/assets/{xychartDiagram-6QU3TZC5-BHG0s1Ye.js → xychartDiagram-6QU3TZC5-CTndf-if.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/app.module.js +4 -0
- package/dist-server/bootstrap/codex-writable-roots.js +88 -0
- package/dist-server/bootstrap/crewx-server.js +10 -2
- package/dist-server/common/decorator/skip-request-log.decorator.js +8 -0
- package/dist-server/common/interceptor/http-logging.interceptor.js +17 -4
- package/dist-server/common/task-log/stdout-json-fallback.js +200 -0
- package/dist-server/domain/agent/agent.controller.js +14 -0
- package/dist-server/domain/agent/agent.service.js +246 -18
- package/dist-server/domain/agent/dto/create-agent.dto.js +12 -0
- package/dist-server/domain/agent/dto/remote-provider.dto.js +82 -0
- package/dist-server/domain/agent/dto/reorder-agents.dto.js +51 -0
- package/dist-server/domain/agent/dto/update-agent.dto.js +3 -1
- package/dist-server/domain/agent/provider.controller.js +12 -1
- package/dist-server/domain/doc/doc.controller.js +43 -9
- package/dist-server/domain/doc/doc.service.js +80 -6
- package/dist-server/domain/doc/image-constants.js +11 -1
- package/dist-server/domain/events/workspace-events.controller.js +2 -0
- package/dist-server/domain/message/dto/send-message.dto.js +49 -1
- package/dist-server/domain/message/message.controller.js +1 -1
- package/dist-server/domain/message/message.module.js +2 -1
- package/dist-server/domain/message/message.service.js +83 -13
- package/dist-server/domain/settings/settings.service.js +188 -1
- package/dist-server/domain/system/system.controller.js +41 -0
- package/dist-server/domain/system/system.module.js +19 -0
- package/dist-server/domain/task/task.constants.js +8 -1
- package/dist-server/domain/task/task.service.js +59 -67
- package/dist-server/domain/thread/dto/list-threads.dto.js +18 -0
- package/dist-server/domain/thread/overdrive.types.js +38 -0
- package/dist-server/domain/thread/thread.service.js +83 -70
- package/dist-server/domain/usage/usage.controller.js +18 -0
- package/dist-server/domain/usage/usage.module.js +1 -0
- package/dist-server/domain/usage/usage.service.js +246 -4
- package/dist-server/domain/usage-report/dto/usage-report.dto.js +2 -0
- package/dist-server/domain/usage-report/usage-report.controller.js +72 -0
- package/dist-server/domain/usage-report/usage-report.module.js +23 -0
- package/dist-server/domain/usage-report/usage-report.service.js +135 -0
- package/dist-server/domain/wi/wi.service.js +45 -3
- package/dist-server/main.js +1 -0
- package/dist-server/repository/repository.module.js +2 -0
- package/dist-server/repository/task.repository.js +56 -0
- package/dist-server/repository/thread.repository.js +13 -0
- package/dist-server/repository/usage-report.repository.js +27 -0
- package/package.json +9 -9
- package/packages/cli/dist/bootstrap/codex-writable-roots.d.ts +45 -0
- package/packages/cli/dist/bootstrap/codex-writable-roots.js +88 -0
- package/packages/cli/dist/bootstrap/crewx-cli.js +2 -0
- package/packages/cli/dist/commands/execute.js +10 -2
- package/packages/cli/dist/commands/parse-common-flags.d.ts +5 -1
- package/packages/cli/dist/commands/parse-common-flags.js +9 -2
- package/packages/cli/dist/commands/ps.js +51 -2
- package/packages/cli/dist/commands/query.js +10 -2
- package/packages/cli/dist/commands/restart.js +20 -6
- package/packages/cli/dist/commands/write-output.d.ts +3 -0
- package/packages/cli/dist/commands/write-output.js +24 -0
- package/packages/cli/dist/main.js +7 -0
- package/packages/cli/package.json +1 -1
- package/dist/assets/MarketPage-T1o_oIrw.js +0 -41
- package/dist/assets/channel-7q16D7P9.js +0 -1
- package/dist/assets/classDiagram-LNE6IOMH-C6qjk4uc.js +0 -1
- package/dist/assets/classDiagram-v2-MQ7JQ4JX-C6qjk4uc.js +0 -1
- package/dist/assets/main-C5mwv79r.css +0 -10
- package/dist/assets/main-DmvFaz-d.js +0 -1486
- package/dist/assets/stateDiagram-v2-4JROLMXI-CCMApx_v.js +0 -1
|
@@ -44,11 +44,28 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.SettingsService = void 0;
|
|
46
46
|
const fs_1 = require("fs");
|
|
47
|
+
const node_path_1 = require("node:path");
|
|
47
48
|
const common_1 = require("@nestjs/common");
|
|
48
49
|
const yaml = __importStar(require("js-yaml"));
|
|
50
|
+
const knowledge_core_1 = require("@crewx/knowledge-core");
|
|
49
51
|
const analytics_client_js_1 = require("../../common/analytics.client.js");
|
|
50
52
|
const crewx_pool_service_js_1 = require("../../modules/crewx-pool.service.js");
|
|
51
53
|
const workspace_context_store_js_1 = require("../../common/workspace-context.store.js");
|
|
54
|
+
const DEFAULT_OVERDRIVE_TURNS = 3;
|
|
55
|
+
// wbs defaults — mirrors packages/built-in/wbs/src/engine.ts:58-78 (getSourceBranch/getTargetBranch/getMergeStrategy)
|
|
56
|
+
const DEFAULT_WBS_SOURCE_BRANCH = 'auto';
|
|
57
|
+
const DEFAULT_WBS_TARGET_BRANCH = 'auto';
|
|
58
|
+
const DEFAULT_WBS_MERGE_STRATEGY = 'local';
|
|
59
|
+
// memory defaults — mirrors packages/built-in/memory/src/engine.ts:130-163 (MemoryEngine constructor)
|
|
60
|
+
const DEFAULT_MEMORY_SUMMARY_DAYS = 7;
|
|
61
|
+
const DEFAULT_MEMORY_RECENT_DAYS = 30;
|
|
62
|
+
const DEFAULT_MEMORY_SHORT_TERM_HOURS = 24;
|
|
63
|
+
const DEFAULT_MEMORY_SUMMARIZER_AGENT = '@memory_summarizer';
|
|
64
|
+
const DEFAULT_MEMORY_SEARCHER_AGENT = '@memory_searcher';
|
|
65
|
+
const DEFAULT_MEMORY_SUMMARIZER_TIMEOUT = 60000;
|
|
66
|
+
const DEFAULT_MEMORY_SEARCHER_TIMEOUT = 300000;
|
|
67
|
+
// workflow defaults — mirrors packages/built-in/workflow/cli.ts:88-97 (getWorkflowConfig)
|
|
68
|
+
const DEFAULT_WORKFLOW_PATHS = ['workflows'];
|
|
52
69
|
let SettingsService = class SettingsService {
|
|
53
70
|
analyticsService;
|
|
54
71
|
pool;
|
|
@@ -57,17 +74,28 @@ let SettingsService = class SettingsService {
|
|
|
57
74
|
this.pool = pool;
|
|
58
75
|
}
|
|
59
76
|
get configPath() {
|
|
60
|
-
|
|
77
|
+
const workspacePath = (0, workspace_context_store_js_1.getWorkspacePath)();
|
|
78
|
+
return this.pool.resolveConfigPath(workspacePath) ?? (0, node_path_1.join)(workspacePath, 'crewx.yaml');
|
|
61
79
|
}
|
|
62
80
|
getSettings() {
|
|
63
81
|
const config = this.loadConfig();
|
|
64
82
|
const settings = (config.settings ?? {});
|
|
65
83
|
const dreaming = (settings.dreaming ?? {});
|
|
66
84
|
const continuity = (dreaming.continuity ?? {});
|
|
85
|
+
const overdrive = (settings.overdrive ?? {});
|
|
67
86
|
const template = (settings.template ?? {});
|
|
68
87
|
const exec = (template.exec ?? {});
|
|
88
|
+
const wbs = (settings.wbs ?? {});
|
|
89
|
+
const docs = (settings.docs ?? {});
|
|
90
|
+
const search = (settings.search ?? {});
|
|
91
|
+
const searchCache = (search.cache ?? {});
|
|
92
|
+
const memory = (settings.memory ?? {});
|
|
93
|
+
const workflow = (settings.workflow ?? {});
|
|
69
94
|
return {
|
|
70
95
|
analytics: settings.analytics !== false,
|
|
96
|
+
overdrive: {
|
|
97
|
+
defaultTurns: this.normalizeOverdriveTurns(overdrive.defaultTurns),
|
|
98
|
+
},
|
|
71
99
|
continuity: {
|
|
72
100
|
lookback: typeof continuity.lookback === 'number' ? continuity.lookback : 3,
|
|
73
101
|
reuseReadOnly: continuity.reuseReadOnly !== false,
|
|
@@ -86,6 +114,36 @@ let SettingsService = class SettingsService {
|
|
|
86
114
|
timeout: typeof exec.timeout === 'number' ? exec.timeout : 30,
|
|
87
115
|
allow: Array.isArray(exec.allow) ? exec.allow : [],
|
|
88
116
|
},
|
|
117
|
+
wbs: {
|
|
118
|
+
sourceBranch: typeof wbs.source_branch === 'string' ? wbs.source_branch : DEFAULT_WBS_SOURCE_BRANCH,
|
|
119
|
+
targetBranch: typeof wbs.target_branch === 'string' ? wbs.target_branch : DEFAULT_WBS_TARGET_BRANCH,
|
|
120
|
+
mergeStrategy: wbs.merge_strategy === 'pr' ? 'pr' : DEFAULT_WBS_MERGE_STRATEGY,
|
|
121
|
+
},
|
|
122
|
+
docs: {
|
|
123
|
+
extraRoots: Array.isArray(docs.extra_roots) ? docs.extra_roots : [],
|
|
124
|
+
rootFiles: Array.isArray(docs.root_files) ? docs.root_files : [...knowledge_core_1.DEFAULT_ROOT_FILES],
|
|
125
|
+
exclude: Array.isArray(docs.exclude) ? docs.exclude : [...knowledge_core_1.DEFAULT_EXCLUDE],
|
|
126
|
+
},
|
|
127
|
+
search: {
|
|
128
|
+
cache: {
|
|
129
|
+
ttl: typeof searchCache.ttl === 'number' ? searchCache.ttl : knowledge_core_1.DEFAULT_SEARCH_CONFIG.cache.ttl,
|
|
130
|
+
max: typeof searchCache.max === 'number' ? searchCache.max : knowledge_core_1.DEFAULT_SEARCH_CONFIG.cache.max,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
memory: {
|
|
134
|
+
summaryDays: typeof memory.summary_days === 'number' ? memory.summary_days : DEFAULT_MEMORY_SUMMARY_DAYS,
|
|
135
|
+
recentDays: typeof memory.recent_days === 'number' ? memory.recent_days : DEFAULT_MEMORY_RECENT_DAYS,
|
|
136
|
+
shortTermHours: typeof memory.short_term_hours === 'number' ? memory.short_term_hours : DEFAULT_MEMORY_SHORT_TERM_HOURS,
|
|
137
|
+
summarizerAgent: typeof memory.summarizer_agent === 'string' ? memory.summarizer_agent : DEFAULT_MEMORY_SUMMARIZER_AGENT,
|
|
138
|
+
searcherAgent: typeof memory.searcher_agent === 'string' ? memory.searcher_agent : DEFAULT_MEMORY_SEARCHER_AGENT,
|
|
139
|
+
summarizerTimeout: typeof memory.summarizer_timeout === 'number'
|
|
140
|
+
? memory.summarizer_timeout
|
|
141
|
+
: DEFAULT_MEMORY_SUMMARIZER_TIMEOUT,
|
|
142
|
+
searcherTimeout: typeof memory.searcher_timeout === 'number' ? memory.searcher_timeout : DEFAULT_MEMORY_SEARCHER_TIMEOUT,
|
|
143
|
+
},
|
|
144
|
+
workflow: {
|
|
145
|
+
paths: Array.isArray(workflow.paths) ? workflow.paths : [...DEFAULT_WORKFLOW_PATHS],
|
|
146
|
+
},
|
|
89
147
|
};
|
|
90
148
|
}
|
|
91
149
|
updateSettings(patch) {
|
|
@@ -160,6 +218,130 @@ let SettingsService = class SettingsService {
|
|
|
160
218
|
}
|
|
161
219
|
dirty = true;
|
|
162
220
|
}
|
|
221
|
+
if (patch.overdrive !== undefined) {
|
|
222
|
+
if (!config.settings || typeof config.settings !== 'object') {
|
|
223
|
+
config.settings = {};
|
|
224
|
+
}
|
|
225
|
+
const settings = config.settings;
|
|
226
|
+
if (!settings.overdrive || typeof settings.overdrive !== 'object') {
|
|
227
|
+
settings.overdrive = {};
|
|
228
|
+
}
|
|
229
|
+
const overdrive = settings.overdrive;
|
|
230
|
+
if (patch.overdrive.defaultTurns !== undefined) {
|
|
231
|
+
const val = patch.overdrive.defaultTurns;
|
|
232
|
+
if (Number.isInteger(val) && val > 0) {
|
|
233
|
+
overdrive.defaultTurns = val;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
dirty = true;
|
|
237
|
+
}
|
|
238
|
+
if (patch.wbs !== undefined) {
|
|
239
|
+
if (!config.settings || typeof config.settings !== 'object') {
|
|
240
|
+
config.settings = {};
|
|
241
|
+
}
|
|
242
|
+
const settings = config.settings;
|
|
243
|
+
if (!settings.wbs || typeof settings.wbs !== 'object') {
|
|
244
|
+
settings.wbs = {};
|
|
245
|
+
}
|
|
246
|
+
const wbs = settings.wbs;
|
|
247
|
+
if (patch.wbs.sourceBranch !== undefined) {
|
|
248
|
+
wbs.source_branch = patch.wbs.sourceBranch;
|
|
249
|
+
}
|
|
250
|
+
if (patch.wbs.targetBranch !== undefined) {
|
|
251
|
+
wbs.target_branch = patch.wbs.targetBranch;
|
|
252
|
+
}
|
|
253
|
+
if (patch.wbs.mergeStrategy !== undefined) {
|
|
254
|
+
wbs.merge_strategy = patch.wbs.mergeStrategy;
|
|
255
|
+
}
|
|
256
|
+
dirty = true;
|
|
257
|
+
}
|
|
258
|
+
if (patch.docs !== undefined) {
|
|
259
|
+
if (!config.settings || typeof config.settings !== 'object') {
|
|
260
|
+
config.settings = {};
|
|
261
|
+
}
|
|
262
|
+
const settings = config.settings;
|
|
263
|
+
if (!settings.docs || typeof settings.docs !== 'object') {
|
|
264
|
+
settings.docs = {};
|
|
265
|
+
}
|
|
266
|
+
const docs = settings.docs;
|
|
267
|
+
if (patch.docs.extraRoots !== undefined) {
|
|
268
|
+
docs.extra_roots = patch.docs.extraRoots;
|
|
269
|
+
}
|
|
270
|
+
if (patch.docs.rootFiles !== undefined) {
|
|
271
|
+
docs.root_files = patch.docs.rootFiles;
|
|
272
|
+
}
|
|
273
|
+
if (patch.docs.exclude !== undefined) {
|
|
274
|
+
docs.exclude = patch.docs.exclude;
|
|
275
|
+
}
|
|
276
|
+
dirty = true;
|
|
277
|
+
}
|
|
278
|
+
if (patch.search?.cache !== undefined) {
|
|
279
|
+
if (!config.settings || typeof config.settings !== 'object') {
|
|
280
|
+
config.settings = {};
|
|
281
|
+
}
|
|
282
|
+
const settings = config.settings;
|
|
283
|
+
if (!settings.search || typeof settings.search !== 'object') {
|
|
284
|
+
settings.search = {};
|
|
285
|
+
}
|
|
286
|
+
const search = settings.search;
|
|
287
|
+
if (!search.cache || typeof search.cache !== 'object') {
|
|
288
|
+
search.cache = {};
|
|
289
|
+
}
|
|
290
|
+
const cache = search.cache;
|
|
291
|
+
if (patch.search.cache.ttl !== undefined) {
|
|
292
|
+
cache.ttl = patch.search.cache.ttl;
|
|
293
|
+
}
|
|
294
|
+
if (patch.search.cache.max !== undefined) {
|
|
295
|
+
cache.max = patch.search.cache.max;
|
|
296
|
+
}
|
|
297
|
+
dirty = true;
|
|
298
|
+
}
|
|
299
|
+
if (patch.memory !== undefined) {
|
|
300
|
+
if (!config.settings || typeof config.settings !== 'object') {
|
|
301
|
+
config.settings = {};
|
|
302
|
+
}
|
|
303
|
+
const settings = config.settings;
|
|
304
|
+
if (!settings.memory || typeof settings.memory !== 'object') {
|
|
305
|
+
settings.memory = {};
|
|
306
|
+
}
|
|
307
|
+
const memory = settings.memory;
|
|
308
|
+
if (patch.memory.summaryDays !== undefined) {
|
|
309
|
+
memory.summary_days = patch.memory.summaryDays;
|
|
310
|
+
}
|
|
311
|
+
if (patch.memory.recentDays !== undefined) {
|
|
312
|
+
memory.recent_days = patch.memory.recentDays;
|
|
313
|
+
}
|
|
314
|
+
if (patch.memory.shortTermHours !== undefined) {
|
|
315
|
+
memory.short_term_hours = patch.memory.shortTermHours;
|
|
316
|
+
}
|
|
317
|
+
if (patch.memory.summarizerAgent !== undefined) {
|
|
318
|
+
memory.summarizer_agent = patch.memory.summarizerAgent;
|
|
319
|
+
}
|
|
320
|
+
if (patch.memory.searcherAgent !== undefined) {
|
|
321
|
+
memory.searcher_agent = patch.memory.searcherAgent;
|
|
322
|
+
}
|
|
323
|
+
if (patch.memory.summarizerTimeout !== undefined) {
|
|
324
|
+
memory.summarizer_timeout = patch.memory.summarizerTimeout;
|
|
325
|
+
}
|
|
326
|
+
if (patch.memory.searcherTimeout !== undefined) {
|
|
327
|
+
memory.searcher_timeout = patch.memory.searcherTimeout;
|
|
328
|
+
}
|
|
329
|
+
dirty = true;
|
|
330
|
+
}
|
|
331
|
+
if (patch.workflow !== undefined) {
|
|
332
|
+
if (!config.settings || typeof config.settings !== 'object') {
|
|
333
|
+
config.settings = {};
|
|
334
|
+
}
|
|
335
|
+
const settings = config.settings;
|
|
336
|
+
if (!settings.workflow || typeof settings.workflow !== 'object') {
|
|
337
|
+
settings.workflow = {};
|
|
338
|
+
}
|
|
339
|
+
const workflow = settings.workflow;
|
|
340
|
+
if (patch.workflow.paths !== undefined) {
|
|
341
|
+
workflow.paths = patch.workflow.paths;
|
|
342
|
+
}
|
|
343
|
+
dirty = true;
|
|
344
|
+
}
|
|
163
345
|
if (dirty) {
|
|
164
346
|
this.saveConfig(config);
|
|
165
347
|
if (analyticsValue !== undefined) {
|
|
@@ -168,6 +350,11 @@ let SettingsService = class SettingsService {
|
|
|
168
350
|
}
|
|
169
351
|
return this.getSettings();
|
|
170
352
|
}
|
|
353
|
+
normalizeOverdriveTurns(value) {
|
|
354
|
+
return Number.isInteger(value) && value > 0
|
|
355
|
+
? value
|
|
356
|
+
: DEFAULT_OVERDRIVE_TURNS;
|
|
357
|
+
}
|
|
171
358
|
loadConfig() {
|
|
172
359
|
if (!(0, fs_1.existsSync)(this.configPath))
|
|
173
360
|
return {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SystemController = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
15
|
+
let SystemController = class SystemController {
|
|
16
|
+
shutdown() {
|
|
17
|
+
// Delay the signal to the next tick so the 202 response reaches the
|
|
18
|
+
// client before shutdown begins. Send SIGTERM to self instead of
|
|
19
|
+
// process.exit(0) so Nest's shutdown hooks (enableShutdownHooks in
|
|
20
|
+
// main.ts) run and onApplicationShutdown -> crewx.close() can clean up
|
|
21
|
+
// active tasks gracefully. forceCloseConnections (see main.ts) forces
|
|
22
|
+
// any lingering keep-alive/SSE connections closed once the process exits.
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
process.kill(process.pid, 'SIGTERM');
|
|
25
|
+
}, 100);
|
|
26
|
+
return { success: true, data: { message: 'Server is shutting down' } };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
exports.SystemController = SystemController;
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, swagger_1.ApiOperation)({ operationId: 'SYS.SHUTDOWN', summary: 'Shut down the server' }),
|
|
32
|
+
(0, common_1.Post)('shutdown'),
|
|
33
|
+
(0, common_1.HttpCode)(202),
|
|
34
|
+
__metadata("design:type", Function),
|
|
35
|
+
__metadata("design:paramtypes", []),
|
|
36
|
+
__metadata("design:returntype", void 0)
|
|
37
|
+
], SystemController.prototype, "shutdown", null);
|
|
38
|
+
exports.SystemController = SystemController = __decorate([
|
|
39
|
+
(0, swagger_1.ApiTags)('system'),
|
|
40
|
+
(0, common_1.Controller)('system')
|
|
41
|
+
], SystemController);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SystemModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const system_controller_js_1 = require("./system.controller.js");
|
|
12
|
+
let SystemModule = class SystemModule {
|
|
13
|
+
};
|
|
14
|
+
exports.SystemModule = SystemModule;
|
|
15
|
+
exports.SystemModule = SystemModule = __decorate([
|
|
16
|
+
(0, common_1.Module)({
|
|
17
|
+
controllers: [system_controller_js_1.SystemController],
|
|
18
|
+
})
|
|
19
|
+
], SystemModule);
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MAX_TASK_LOG_LIMIT = exports.DEFAULT_TASK_LOG_LIMIT = void 0;
|
|
3
|
+
exports.OWNED_PROCESS_MARKERS = exports.MAX_TASK_LOG_LIMIT = exports.DEFAULT_TASK_LOG_LIMIT = void 0;
|
|
4
4
|
exports.DEFAULT_TASK_LOG_LIMIT = 1000;
|
|
5
5
|
exports.MAX_TASK_LOG_LIMIT = 1000;
|
|
6
|
+
/**
|
|
7
|
+
* Markers used to verify a PID is owned by a crewx-spawned process before
|
|
8
|
+
* sending it a kill signal. This is a safety check against PID reuse — it is
|
|
9
|
+
* NOT a provider whitelist. Any provider CLI that crewx can spawn must have
|
|
10
|
+
* its command name (or a wrapper token) listed here.
|
|
11
|
+
*/
|
|
12
|
+
exports.OWNED_PROCESS_MARKERS = ['crewx', 'claude', 'codex', 'opencode', 'node'];
|
|
@@ -22,6 +22,7 @@ const sdk_1 = require("@crewx/sdk");
|
|
|
22
22
|
const task_repository_js_1 = require("../../repository/task.repository.js");
|
|
23
23
|
const project_repository_js_1 = require("../../repository/project.repository.js");
|
|
24
24
|
const workspace_context_store_js_1 = require("../../common/workspace-context.store.js");
|
|
25
|
+
const stdout_json_fallback_js_1 = require("../../common/task-log/stdout-json-fallback.js");
|
|
25
26
|
const crewx_pool_service_js_1 = require("../../modules/crewx-pool.service.js");
|
|
26
27
|
const MAX_LOG_ENTRY_FIELD_LEN = 128 * 1024; // 128KB worth of UTF-16 code units
|
|
27
28
|
const RUNNING_INSTRUCTION_SYSTEM_MESSAGE = '<crewx_system_message type="running_instruction">\n' +
|
|
@@ -140,7 +141,7 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
140
141
|
// PID ownership verification: ensure PID belongs to a crewx-related process
|
|
141
142
|
try {
|
|
142
143
|
const cmdOutput = (0, child_process_1.execSync)(`ps -p ${task.pid} -o command=`, { encoding: 'utf-8', timeout: 3000 }).trim();
|
|
143
|
-
if (!
|
|
144
|
+
if (!this.isOwnedProcess(cmdOutput)) {
|
|
144
145
|
throw new common_1.HttpException({ code: 'PID_NOT_FOUND', message: 'Process ID not found' }, 422);
|
|
145
146
|
}
|
|
146
147
|
}
|
|
@@ -200,10 +201,12 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
200
201
|
}
|
|
201
202
|
const metadata = this.parseTaskMetadata(task.metadata);
|
|
202
203
|
const provider = this.extractProviderFromMeta(task.metadata);
|
|
204
|
+
const wasOverdrive = metadata.overdrive === true;
|
|
205
|
+
const overdriveState = metadata.overdriveState === 'latch' ? 'latch' : 'count';
|
|
203
206
|
const providerSessionId = this.readString(metadata.provider_session_id)
|
|
204
207
|
?? this.readString(metadata.providerSessionId)
|
|
205
208
|
?? this.extractProviderSessionIdFromLogs(task.logs);
|
|
206
|
-
if (!provider || (provider !== 'cli/codex' && provider !== 'cli/claude')) {
|
|
209
|
+
if (!provider || (provider !== 'cli/codex' && provider !== 'cli/claude' && provider !== 'cli/opencode')) {
|
|
207
210
|
throw new common_1.HttpException({ code: 'PROVIDER_UNSUPPORTED', message: 'Provider does not support running instructions' }, 422);
|
|
208
211
|
}
|
|
209
212
|
if (!providerSessionId) {
|
|
@@ -242,6 +245,7 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
242
245
|
threadId,
|
|
243
246
|
taskId,
|
|
244
247
|
provider,
|
|
248
|
+
model: task.model ?? undefined,
|
|
245
249
|
platform: 'cli',
|
|
246
250
|
resumeSessionId: providerSessionId,
|
|
247
251
|
metadata: {
|
|
@@ -250,6 +254,11 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
250
254
|
provider,
|
|
251
255
|
provider_session_id: providerSessionId,
|
|
252
256
|
runningInstruction: instruction,
|
|
257
|
+
...(wasOverdrive ? {
|
|
258
|
+
overdrive: true,
|
|
259
|
+
overdriveState,
|
|
260
|
+
overdriveMode: 'execute',
|
|
261
|
+
} : {}),
|
|
253
262
|
// Tags this run's task:end so finishTask only closes the matching
|
|
254
263
|
// generation, ignoring the killed prior run's stale task:end.
|
|
255
264
|
runEpoch,
|
|
@@ -257,6 +266,15 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
257
266
|
cwd: (0, workspace_context_store_js_1.getWorkspacePath)(),
|
|
258
267
|
}).catch((err) => {
|
|
259
268
|
this.logger.error(`Running instruction resume failed [task=${taskId}]: ${err.message}`, err.stack);
|
|
269
|
+
// Safety net: if execute() rejected before the new process ever reported
|
|
270
|
+
// its pid (task:start), the row would be a permanent zombie
|
|
271
|
+
// (status=running, pid=NULL). Only transition to failed if the row is
|
|
272
|
+
// still exactly in that pending-resume state — if a new process already
|
|
273
|
+
// reported its pid, or a later instruction bumped run_epoch again, this
|
|
274
|
+
// is a no-op so we never clobber a task that already recovered.
|
|
275
|
+
if (runEpoch != null) {
|
|
276
|
+
this.taskRepo.markTaskFailedIfResumePending(taskId, runEpoch, `Running instruction resume failed: ${err.message}`, workspaceId);
|
|
277
|
+
}
|
|
260
278
|
});
|
|
261
279
|
return { taskId, status: 'running', agentId: task.agent_id, resumedFromTaskId: taskId };
|
|
262
280
|
}
|
|
@@ -445,7 +463,7 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
445
463
|
}
|
|
446
464
|
const adapterKey = this.extractAdapterKey(row);
|
|
447
465
|
if (wantLogs) {
|
|
448
|
-
result.logs = this.parseLogs(row.logs, logLimit, adapterKey);
|
|
466
|
+
result.logs = this.parseLogs(row.logs, logLimit, adapterKey).logs;
|
|
449
467
|
}
|
|
450
468
|
result.toolUsage = this.aggregateToolUsage(row.logs, adapterKey);
|
|
451
469
|
if (wantChildren) {
|
|
@@ -493,7 +511,7 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
493
511
|
}
|
|
494
512
|
// --- TSK005 private helpers ---
|
|
495
513
|
toChildTaskStatus(row) {
|
|
496
|
-
const logs = this.parseLogs(row.logs, 1, this.extractAdapterKey(row));
|
|
514
|
+
const { logs } = this.parseLogs(row.logs, 1, this.extractAdapterKey(row));
|
|
497
515
|
return {
|
|
498
516
|
taskId: row.id,
|
|
499
517
|
agentId: row.agent_id,
|
|
@@ -515,19 +533,19 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
515
533
|
return undefined;
|
|
516
534
|
}
|
|
517
535
|
}
|
|
518
|
-
/** @see ThreadService.parseLogs — 동일 역할, ACP 파싱 로직 동기화 필요 */
|
|
536
|
+
/** @see ThreadService.parseLogs — 동일 역할, ACP 파싱 로직 동기화 필요 (TSK.GET 응답에는 progressSteps 미포함) */
|
|
519
537
|
parseLogs(logsJson, logLimit, providerId) {
|
|
520
538
|
if (!logsJson)
|
|
521
|
-
return [];
|
|
539
|
+
return { logs: [], progressSteps: [] };
|
|
522
540
|
let rawLogs;
|
|
523
541
|
try {
|
|
524
542
|
rawLogs = JSON.parse(logsJson);
|
|
525
543
|
}
|
|
526
544
|
catch {
|
|
527
|
-
return [];
|
|
545
|
+
return { logs: [], progressSteps: [] };
|
|
528
546
|
}
|
|
529
547
|
if (!Array.isArray(rawLogs))
|
|
530
|
-
return [];
|
|
548
|
+
return { logs: [], progressSteps: [] };
|
|
531
549
|
const entries = [];
|
|
532
550
|
for (const log of rawLogs) {
|
|
533
551
|
if (log.level === 'stdout') {
|
|
@@ -539,7 +557,7 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
539
557
|
}
|
|
540
558
|
// Parsed successfully but no displayable entries (e.g. thinking-only assistant message).
|
|
541
559
|
// Skip fallback if the raw message is a known metadata-only stream-json event type.
|
|
542
|
-
if (
|
|
560
|
+
if ((0, stdout_json_fallback_js_1.shouldSkipRawStdoutJsonFallback)(log.message, providerId))
|
|
543
561
|
continue;
|
|
544
562
|
}
|
|
545
563
|
catch { /* adapter parse failure — fallback to text */ }
|
|
@@ -555,18 +573,17 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
555
573
|
}
|
|
556
574
|
}
|
|
557
575
|
}
|
|
558
|
-
// Pipeline: merge consecutive text → deduplicate tool_use → truncate → logLimit slice
|
|
576
|
+
// Pipeline: merge consecutive text → deduplicate tool_use → truncate → [branch: text-only slice(-200) = progressSteps] → logLimit slice = logs
|
|
559
577
|
const merged = this.mergeConsecutiveText(entries);
|
|
560
578
|
const deduped = this.deduplicateToolUse(merged);
|
|
561
579
|
const truncated = deduped.map((e) => this.truncateEntry(e));
|
|
580
|
+
const progressSteps = truncated.filter((e) => e.type === 'text').slice(-200);
|
|
562
581
|
// Return the latest N entries (trim from the beginning)
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
return truncated;
|
|
582
|
+
const logs = truncated.length > logLimit ? truncated.slice(truncated.length - logLimit) : truncated;
|
|
583
|
+
return { logs, progressSteps };
|
|
567
584
|
}
|
|
568
585
|
aggregateToolUsage(logsJson, providerId) {
|
|
569
|
-
const entries = this.parseLogs(logsJson, task_constants_js_1.MAX_TASK_LOG_LIMIT, providerId);
|
|
586
|
+
const { logs: entries } = this.parseLogs(logsJson, task_constants_js_1.MAX_TASK_LOG_LIMIT, providerId);
|
|
570
587
|
const counts = new Map();
|
|
571
588
|
for (const entry of entries) {
|
|
572
589
|
if (entry.type === 'tool_use' && entry.toolName) {
|
|
@@ -639,6 +656,11 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
639
656
|
if (claudeSessionId) {
|
|
640
657
|
return claudeSessionId;
|
|
641
658
|
}
|
|
659
|
+
// OpenCode: every event carries a top-level `sessionID` (e.g. step_start/tool_use/text).
|
|
660
|
+
const opencodeSessionId = this.readString(message.sessionID);
|
|
661
|
+
if (opencodeSessionId) {
|
|
662
|
+
return opencodeSessionId;
|
|
663
|
+
}
|
|
642
664
|
}
|
|
643
665
|
catch {
|
|
644
666
|
// Ignore non-JSON log lines.
|
|
@@ -674,6 +696,9 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
674
696
|
if (providerKey === 'codex' && this.isCodexResumableEvent(message)) {
|
|
675
697
|
return true;
|
|
676
698
|
}
|
|
699
|
+
if (providerKey === 'opencode' && this.isOpencodeResumableEvent(message)) {
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
677
702
|
}
|
|
678
703
|
catch {
|
|
679
704
|
// Ignore non-JSON log lines.
|
|
@@ -681,6 +706,18 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
681
706
|
}
|
|
682
707
|
return false;
|
|
683
708
|
}
|
|
709
|
+
isOpencodeResumableEvent(message) {
|
|
710
|
+
const type = typeof message.type === 'string' ? message.type : '';
|
|
711
|
+
if (type === 'tool_use') {
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
if (type === 'text') {
|
|
715
|
+
const part = message.part;
|
|
716
|
+
const text = part?.text;
|
|
717
|
+
return typeof text === 'string' && text.trim().length > 0;
|
|
718
|
+
}
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
684
721
|
isClaudeResumableEvent(message) {
|
|
685
722
|
if (message.type !== 'assistant') {
|
|
686
723
|
return false;
|
|
@@ -717,13 +754,18 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
717
754
|
}
|
|
718
755
|
return false;
|
|
719
756
|
}
|
|
757
|
+
/** PID ownership check: is this `ps -o command=` output a process we're allowed to kill?
|
|
758
|
+
* Guards against PID reuse — NOT a provider whitelist (see OWNED_PROCESS_MARKERS doc). */
|
|
759
|
+
isOwnedProcess(cmdOutput) {
|
|
760
|
+
return task_constants_js_1.OWNED_PROCESS_MARKERS.some((marker) => cmdOutput.includes(marker));
|
|
761
|
+
}
|
|
720
762
|
terminateRunningProcess(task) {
|
|
721
763
|
if (task.pid == null) {
|
|
722
764
|
throw new common_1.HttpException({ code: 'PID_NOT_FOUND', message: 'Process ID not found' }, 422);
|
|
723
765
|
}
|
|
724
766
|
try {
|
|
725
767
|
const cmdOutput = (0, child_process_1.execSync)(`ps -p ${task.pid} -o command=`, { encoding: 'utf-8', timeout: 3000 }).trim();
|
|
726
|
-
if (!
|
|
768
|
+
if (!this.isOwnedProcess(cmdOutput)) {
|
|
727
769
|
throw new common_1.HttpException({ code: 'PID_NOT_FOUND', message: 'Process ID not found' }, 422);
|
|
728
770
|
}
|
|
729
771
|
}
|
|
@@ -868,7 +910,7 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
868
910
|
// Merge logs from all matching tasks
|
|
869
911
|
const allLogs = [];
|
|
870
912
|
for (const task of matchingTasks) {
|
|
871
|
-
const parsed = this.parseLogs(task.logs, 100, this.extractAdapterKey(task));
|
|
913
|
+
const { logs: parsed } = this.parseLogs(task.logs, 100, this.extractAdapterKey(task));
|
|
872
914
|
allLogs.push(...parsed);
|
|
873
915
|
}
|
|
874
916
|
// Sort by timestamp
|
|
@@ -971,56 +1013,6 @@ let TaskService = TaskService_1 = class TaskService {
|
|
|
971
1013
|
return text;
|
|
972
1014
|
return text.slice(0, maxLen) + '...';
|
|
973
1015
|
}
|
|
974
|
-
/**
|
|
975
|
-
* Returns true when the raw stdout line is a known metadata-only JSON event that
|
|
976
|
-
* should be silently dropped rather than shown as raw text.
|
|
977
|
-
*
|
|
978
|
-
* Covers Claude, Codex, and OpenCode stream-json protocols.
|
|
979
|
-
* Only called after parseStdoutEvent() returns [] (no displayable entries).
|
|
980
|
-
* Partial / truncated JSON → JSON.parse throws → returns false (keep raw text fallback).
|
|
981
|
-
*/
|
|
982
|
-
shouldSkipRawStdoutJsonFallback(message) {
|
|
983
|
-
const trimmed = message.trimStart();
|
|
984
|
-
if (!trimmed.startsWith('{'))
|
|
985
|
-
return false;
|
|
986
|
-
let obj;
|
|
987
|
-
try {
|
|
988
|
-
obj = JSON.parse(trimmed);
|
|
989
|
-
}
|
|
990
|
-
catch {
|
|
991
|
-
return false;
|
|
992
|
-
}
|
|
993
|
-
const type = obj.type;
|
|
994
|
-
if (typeof type !== 'string')
|
|
995
|
-
return false;
|
|
996
|
-
// Claude stream-json metadata events
|
|
997
|
-
if (type === 'assistant' ||
|
|
998
|
-
type === 'user' ||
|
|
999
|
-
type === 'system' ||
|
|
1000
|
-
type === 'result' ||
|
|
1001
|
-
type === 'rate_limit_event') {
|
|
1002
|
-
return true;
|
|
1003
|
-
}
|
|
1004
|
-
// Codex metadata-only events
|
|
1005
|
-
if (type === 'thread.started' ||
|
|
1006
|
-
type === 'turn.started' ||
|
|
1007
|
-
type === 'turn.completed' ||
|
|
1008
|
-
type === 'turn.failed' ||
|
|
1009
|
-
type === 'item.updated') {
|
|
1010
|
-
return true;
|
|
1011
|
-
}
|
|
1012
|
-
// Codex item.started/item.completed reach this function only after
|
|
1013
|
-
// parseStdoutEvent() returned no displayable entries. Skip raw fallback while
|
|
1014
|
-
// preserving the original line in tasks.logs for future reprocessing.
|
|
1015
|
-
if (type === 'item.started' || type === 'item.completed') {
|
|
1016
|
-
return true;
|
|
1017
|
-
}
|
|
1018
|
-
// OpenCode metadata-only events
|
|
1019
|
-
if (type === 'step_start' || type === 'step_finish') {
|
|
1020
|
-
return true;
|
|
1021
|
-
}
|
|
1022
|
-
return false;
|
|
1023
|
-
}
|
|
1024
1016
|
normalizeLimit(limit, fallback, max) {
|
|
1025
1017
|
const num = Number(limit);
|
|
1026
1018
|
if (!Number.isFinite(num) || num <= 0)
|
|
@@ -22,6 +22,7 @@ class ListThreadsDto {
|
|
|
22
22
|
order;
|
|
23
23
|
limit;
|
|
24
24
|
offset;
|
|
25
|
+
pinnedFirst;
|
|
25
26
|
}
|
|
26
27
|
exports.ListThreadsDto = ListThreadsDto;
|
|
27
28
|
__decorate([
|
|
@@ -68,3 +69,20 @@ __decorate([
|
|
|
68
69
|
(0, class_validator_1.IsNumber)(),
|
|
69
70
|
__metadata("design:type", Number)
|
|
70
71
|
], ListThreadsDto.prototype, "offset", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
74
|
+
description: 'Whether pinned threads are always shown first, unaffected by pagination (default: true)',
|
|
75
|
+
}),
|
|
76
|
+
(0, class_validator_1.IsOptional)(),
|
|
77
|
+
(0, class_transformer_1.Transform)(({ value }) => {
|
|
78
|
+
if (typeof value === 'boolean')
|
|
79
|
+
return value;
|
|
80
|
+
if (value === 'false')
|
|
81
|
+
return false;
|
|
82
|
+
if (value === 'true')
|
|
83
|
+
return true;
|
|
84
|
+
return value;
|
|
85
|
+
}),
|
|
86
|
+
(0, class_validator_1.IsBoolean)(),
|
|
87
|
+
__metadata("design:type", Boolean)
|
|
88
|
+
], ListThreadsDto.prototype, "pinnedFirst", void 0);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Overdrive (부스트/각성 모드) state model.
|
|
4
|
+
*
|
|
5
|
+
* User-facing term: Boost / 부스트 / 갉성 모드
|
|
6
|
+
* Internal key: overdrive
|
|
7
|
+
*
|
|
8
|
+
* The overdrive state is stored under `thread.metadata.overdrive`. Web chat
|
|
9
|
+
* uses the count state as a multi-request boost; CLI flags can still trigger a
|
|
10
|
+
* single boosted request without requiring a persistent UI session.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.OVERDRIVE_DEFAULT_TURNS = void 0;
|
|
14
|
+
exports.parseOverdriveSummary = parseOverdriveSummary;
|
|
15
|
+
const DEFAULT_TURNS = 3;
|
|
16
|
+
/** Parse a raw thread metadata blob into a normalized OverdriveSummary. */
|
|
17
|
+
function parseOverdriveSummary(metadataJson) {
|
|
18
|
+
if (!metadataJson) {
|
|
19
|
+
return { state: 'off', remaining: 0 };
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const meta = JSON.parse(metadataJson);
|
|
23
|
+
const od = meta?.overdrive;
|
|
24
|
+
if (!od || typeof od !== 'object') {
|
|
25
|
+
return { state: 'off', remaining: 0 };
|
|
26
|
+
}
|
|
27
|
+
const state = (od.state ?? 'off');
|
|
28
|
+
const remaining = typeof od.remaining === 'number' ? od.remaining : 0;
|
|
29
|
+
if (state === 'count' && remaining <= 0) {
|
|
30
|
+
return { state: 'off', remaining: 0 };
|
|
31
|
+
}
|
|
32
|
+
return { state, remaining };
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { state: 'off', remaining: 0 };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.OVERDRIVE_DEFAULT_TURNS = DEFAULT_TURNS;
|