chainlesschain 0.45.75 → 0.45.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -15
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{Analytics-sBrYoc3A.js → Analytics-Dd2DjBH5.js} +2 -2
- package/src/assets/web-panel/assets/AppLayout-CP9fATUN.js +1 -0
- package/src/assets/web-panel/assets/AppLayout-cxfKLu-m.css +1 -0
- package/src/assets/web-panel/assets/Backup-D6Tc7sf3.js +1 -0
- package/src/assets/web-panel/assets/Chat-DDUJZJ9I.js +1 -0
- package/src/assets/web-panel/assets/Chat-DfR76jyX.css +1 -0
- package/src/assets/web-panel/assets/Cowork-CPqYhoMI.css +1 -0
- package/src/assets/web-panel/assets/Cowork-XRFqGfqJ.js +48 -0
- package/src/assets/web-panel/assets/{Cron-CNs03iHJ.js → Cron-BnWzy_ZB.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DanoHPSI.js → Dashboard-D2vCkoGu.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CCMVr3Y8.js → Git-DYlvK4sh.js} +2 -2
- package/src/assets/web-panel/assets/{Logs-BY6A0UNG.js → Logs-4VgUbfP0.js} +2 -2
- package/src/assets/web-panel/assets/{McpTools-CrBVYlg6.js → McpTools-ChaiHoWY.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-CWx3SpUt.js → Memory-PFtpuOwf.js} +2 -2
- package/src/assets/web-panel/assets/{Notes-1LcGD49x.js → Notes-wc_n6Rh1.js} +2 -2
- package/src/assets/web-panel/assets/{Organization-Dx2DhbkM.js → Organization-D1qUa8NQ.js} +4 -4
- package/src/assets/web-panel/assets/{P2P-B16fjqfJ.js → P2P-DIG2gnR8.js} +2 -2
- package/src/assets/web-panel/assets/{Permissions-BQbC9FzG.js → Permissions-CpE-Ar1e.js} +3 -3
- package/src/assets/web-panel/assets/{Projects-CjhZbNYm.js → Projects-GjuS-C6U.js} +2 -2
- package/src/assets/web-panel/assets/{Providers-ivOAQtHM.js → Providers-CCfGeqh_.js} +2 -2
- package/src/assets/web-panel/assets/{RssFeed-BrsErdrU.js → RssFeed-5TkrXK7Z.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DnEvJU5h.js → Security-CcfBWT1D.js} +3 -3
- package/src/assets/web-panel/assets/{Services-7jQywNbl.js → Services-Cnm5Zs5h.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CLlblJcG.js → Skills-BHapMb9h.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-CmJBC1cf.js → Tasks-DPb9OMck.js} +1 -1
- package/src/assets/web-panel/assets/Templates-Dij5t-rf.js +1 -0
- package/src/assets/web-panel/assets/{Wallet-3iYASEx_.js → Wallet-BJV5KmWA.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-s3Hzd9db.js → WebAuthn-DLkvYwSc.js} +5 -5
- package/src/assets/web-panel/assets/{antd-gZyc63Qr.js → antd-BQNxIyr-.js} +82 -82
- package/src/assets/web-panel/assets/github-dark-Dfs9RUU9.css +1 -0
- package/src/assets/web-panel/assets/index-CB5YlndO.js +2 -0
- package/src/assets/web-panel/assets/{markdown-Bv7nG63L.js → markdown-BeVIhIzs.js} +1 -1
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/learning.js +273 -0
- package/src/commands/lowcode.js +23 -8
- package/src/gateways/discord/discord-formatter.js +89 -0
- package/src/gateways/gateway-base.js +189 -0
- package/src/gateways/telegram/telegram-formatter.js +93 -0
- package/src/gateways/ws/action-protocol.js +54 -1
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/ws-server.js +10 -1
- package/src/index.js +2 -0
- package/src/lib/app-builder.js +136 -8
- package/src/lib/autonomous-agent.js +8 -1
- package/src/lib/cli-context-engineering.js +15 -0
- package/src/lib/cowork-task-runner.js +101 -0
- package/src/lib/cowork-task-templates.js +493 -0
- package/src/lib/execution-backend.js +239 -0
- package/src/lib/hook-manager.js +2 -0
- package/src/lib/iteration-budget.js +175 -0
- package/src/lib/learning/learning-hooks.js +117 -0
- package/src/lib/learning/learning-tables.js +66 -0
- package/src/lib/learning/outcome-feedback.js +243 -0
- package/src/lib/learning/reflection-engine.js +323 -0
- package/src/lib/learning/skill-improver.js +536 -0
- package/src/lib/learning/skill-synthesizer.js +315 -0
- package/src/lib/learning/trajectory-store.js +409 -0
- package/src/lib/plugin-autodiscovery.js +224 -0
- package/src/lib/session-search.js +193 -0
- package/src/lib/sub-agent-context.js +7 -2
- package/src/lib/user-profile.js +172 -0
- package/src/lib/web-ui-server.js +1 -1
- package/src/repl/agent-repl.js +109 -0
- package/src/runtime/agent-core.js +75 -4
- package/src/runtime/coding-agent-contract-shared.cjs +35 -0
- package/src/runtime/coding-agent-policy.cjs +10 -0
- package/src/assets/web-panel/assets/AppLayout-2RCrdXxl.js +0 -1
- package/src/assets/web-panel/assets/AppLayout-D9pBLPC3.css +0 -1
- package/src/assets/web-panel/assets/Backup-D68fenbD.js +0 -1
- package/src/assets/web-panel/assets/Chat-B2nB8o_F.js +0 -1
- package/src/assets/web-panel/assets/Chat-DB46afPg.css +0 -1
- package/src/assets/web-panel/assets/Templates-RXT8-DNk.js +0 -1
- package/src/assets/web-panel/assets/index-CyGtHm63.js +0 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram Formatter — converts agent responses to Telegram-compatible markup.
|
|
3
|
+
*
|
|
4
|
+
* Telegram uses a subset of Markdown (MarkdownV2) with different escaping rules.
|
|
5
|
+
*
|
|
6
|
+
* @module telegram-formatter
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Characters that must be escaped in MarkdownV2
|
|
10
|
+
const ESCAPE_CHARS = /([_*[\]()~`>#+\-=|{}.!])/g;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Escape text for Telegram MarkdownV2.
|
|
14
|
+
* @param {string} text
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
export function escapeMarkdownV2(text) {
|
|
18
|
+
if (!text) return "";
|
|
19
|
+
return text.replace(ESCAPE_CHARS, "\\$1");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Convert standard Markdown to Telegram MarkdownV2.
|
|
24
|
+
* Handles: bold, italic, code blocks, inline code, links.
|
|
25
|
+
* @param {string} markdown
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
export function toTelegramMarkdown(markdown) {
|
|
29
|
+
if (!markdown) return "";
|
|
30
|
+
|
|
31
|
+
let result = markdown;
|
|
32
|
+
|
|
33
|
+
// Preserve code blocks (don't escape inside them)
|
|
34
|
+
const codeBlocks = [];
|
|
35
|
+
result = result.replace(/```[\s\S]*?```/g, (match) => {
|
|
36
|
+
codeBlocks.push(match);
|
|
37
|
+
return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Preserve inline code
|
|
41
|
+
const inlineCode = [];
|
|
42
|
+
result = result.replace(/`[^`]+`/g, (match) => {
|
|
43
|
+
inlineCode.push(match);
|
|
44
|
+
return `__INLINE_CODE_${inlineCode.length - 1}__`;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Escape special characters in text
|
|
48
|
+
result = escapeMarkdownV2(result);
|
|
49
|
+
|
|
50
|
+
// Restore code blocks and inline code (unescaped)
|
|
51
|
+
for (let i = codeBlocks.length - 1; i >= 0; i--) {
|
|
52
|
+
result = result.replace(
|
|
53
|
+
`__CODE_BLOCK_${i}__`.replace(ESCAPE_CHARS, "\\$1"),
|
|
54
|
+
codeBlocks[i],
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
for (let i = inlineCode.length - 1; i >= 0; i--) {
|
|
58
|
+
result = result.replace(
|
|
59
|
+
`__INLINE_CODE_${i}__`.replace(ESCAPE_CHARS, "\\$1"),
|
|
60
|
+
inlineCode[i],
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Format an agent response for Telegram (plain text fallback).
|
|
69
|
+
* Strips complex markdown, keeps it readable.
|
|
70
|
+
* @param {string} response
|
|
71
|
+
* @param {object} [options]
|
|
72
|
+
* @param {number} [options.maxLength=4000]
|
|
73
|
+
* @returns {string}
|
|
74
|
+
*/
|
|
75
|
+
export function formatForTelegram(response, options = {}) {
|
|
76
|
+
if (!response) return "";
|
|
77
|
+
const maxLength = options.maxLength || 4000;
|
|
78
|
+
|
|
79
|
+
let text = response;
|
|
80
|
+
|
|
81
|
+
// Convert headers to bold
|
|
82
|
+
text = text.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
83
|
+
|
|
84
|
+
// Keep code blocks as-is (Telegram supports ```)
|
|
85
|
+
// Keep bold (**text** → *text*)
|
|
86
|
+
text = text.replace(/\*\*(.+?)\*\*/g, "*$1*");
|
|
87
|
+
|
|
88
|
+
if (text.length > maxLength) {
|
|
89
|
+
text = text.substring(0, maxLength - 3) + "...";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return text;
|
|
93
|
+
}
|
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
export async function handleCoworkTask(server, id, ws, message) {
|
|
2
|
+
const { templateId = null, userMessage, files = [] } = message;
|
|
3
|
+
|
|
4
|
+
if (!userMessage || typeof userMessage !== "string") {
|
|
5
|
+
server._send(ws, {
|
|
6
|
+
id,
|
|
7
|
+
type: "error",
|
|
8
|
+
code: "INVALID_MESSAGE",
|
|
9
|
+
message: "userMessage field required",
|
|
10
|
+
});
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const { runCoworkTask } = await import("../../lib/cowork-task-runner.js");
|
|
16
|
+
|
|
17
|
+
server._send(ws, {
|
|
18
|
+
id,
|
|
19
|
+
type: "cowork:started",
|
|
20
|
+
templateId,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const result = await runCoworkTask({
|
|
24
|
+
templateId,
|
|
25
|
+
userMessage,
|
|
26
|
+
files,
|
|
27
|
+
cwd: server.projectRoot || process.cwd(),
|
|
28
|
+
llmOptions: {},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
server._send(ws, {
|
|
32
|
+
id,
|
|
33
|
+
type: "cowork:done",
|
|
34
|
+
taskId: result.taskId,
|
|
35
|
+
status: result.status,
|
|
36
|
+
templateId: result.templateId,
|
|
37
|
+
templateName: result.templateName,
|
|
38
|
+
summary: result.result?.summary || "",
|
|
39
|
+
artifacts: result.result?.artifacts || [],
|
|
40
|
+
toolsUsed: result.result?.toolsUsed || [],
|
|
41
|
+
iterationCount: result.result?.iterationCount || 0,
|
|
42
|
+
});
|
|
43
|
+
} catch (err) {
|
|
44
|
+
server._send(ws, {
|
|
45
|
+
id,
|
|
46
|
+
type: "error",
|
|
47
|
+
code: "COWORK_FAILED",
|
|
48
|
+
message: err.message,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
1
53
|
export function handleSlashCommand(server, id, ws, message) {
|
|
2
54
|
const { sessionId, command } = message;
|
|
3
55
|
const handler = server.sessionHandlers.get(sessionId);
|
|
@@ -36,7 +88,8 @@ export async function handleOrchestrate(server, id, ws, message) {
|
|
|
36
88
|
}
|
|
37
89
|
|
|
38
90
|
try {
|
|
39
|
-
const { Orchestrator, TASK_SOURCE } =
|
|
91
|
+
const { Orchestrator, TASK_SOURCE } =
|
|
92
|
+
await import("../../lib/orchestrator.js");
|
|
40
93
|
|
|
41
94
|
const orch = new Orchestrator({
|
|
42
95
|
cwd: cwd || server.projectRoot || process.cwd(),
|
|
@@ -43,6 +43,7 @@ export function createWsMessageDispatcher(server) {
|
|
|
43
43
|
"session-answer": () => server._handleSessionAnswer(id, ws, message),
|
|
44
44
|
"host-tool-result": () => server._handleHostToolResult(id, ws, message),
|
|
45
45
|
orchestrate: () => server._handleOrchestrate(id, ws, message),
|
|
46
|
+
"cowork-task": () => server._handleCoworkTask(id, ws, message),
|
|
46
47
|
"tasks-list": () => server._handleTasksList(id, ws),
|
|
47
48
|
"tasks-stop": () => server._handleTasksStop(id, ws, message),
|
|
48
49
|
"tasks-detail": () => server._handleTaskDetail(id, ws, message),
|
|
@@ -48,7 +48,11 @@ import {
|
|
|
48
48
|
handleTaskGraphAdvance,
|
|
49
49
|
handleTaskGraphState,
|
|
50
50
|
} from "./session-protocol.js";
|
|
51
|
-
import {
|
|
51
|
+
import {
|
|
52
|
+
handleSlashCommand,
|
|
53
|
+
handleOrchestrate,
|
|
54
|
+
handleCoworkTask,
|
|
55
|
+
} from "./action-protocol.js";
|
|
52
56
|
import {
|
|
53
57
|
handleWorktreeDiff,
|
|
54
58
|
handleWorktreeMerge,
|
|
@@ -294,6 +298,11 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
294
298
|
return handleOrchestrate(this, id, ws, message);
|
|
295
299
|
}
|
|
296
300
|
|
|
301
|
+
/** @private — run a cowork daily task via SubAgentContext */
|
|
302
|
+
async _handleCoworkTask(id, ws, message) {
|
|
303
|
+
return handleCoworkTask(this, id, ws, message);
|
|
304
|
+
}
|
|
305
|
+
|
|
297
306
|
/** @private – list background tasks */
|
|
298
307
|
async _handleTasksList(id, ws) {
|
|
299
308
|
try {
|
package/src/index.js
CHANGED
|
@@ -47,6 +47,7 @@ import { registerA2aCommand } from "./commands/a2a.js";
|
|
|
47
47
|
// Phase 7: Security & Evolution
|
|
48
48
|
import { registerSandboxCommand } from "./commands/sandbox.js";
|
|
49
49
|
import { registerEvolutionCommand } from "./commands/evolution.js";
|
|
50
|
+
import { registerLearningCommand } from "./commands/learning.js";
|
|
50
51
|
|
|
51
52
|
// Phase 7: EvoMap Federation + DAO Governance
|
|
52
53
|
import { registerDaoCommand } from "./commands/dao.js";
|
|
@@ -168,6 +169,7 @@ export function createProgram() {
|
|
|
168
169
|
// Phase 7: Security & Evolution
|
|
169
170
|
registerSandboxCommand(program);
|
|
170
171
|
registerEvolutionCommand(program);
|
|
172
|
+
registerLearningCommand(program);
|
|
171
173
|
|
|
172
174
|
// Phase 7: EvoMap Federation + DAO Governance
|
|
173
175
|
registerDaoCommand(program);
|
package/src/lib/app-builder.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import crypto from "crypto";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
7
9
|
|
|
8
10
|
/** @type {Map<string, object>} In-memory app cache */
|
|
9
11
|
const _apps = new Map();
|
|
@@ -220,14 +222,12 @@ export function saveDesign(db, appId, design) {
|
|
|
220
222
|
).run(versionId, appId, newVersion, JSON.stringify(design));
|
|
221
223
|
|
|
222
224
|
if (!_versions.has(appId)) _versions.set(appId, []);
|
|
223
|
-
_versions
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
snapshot: design,
|
|
230
|
-
});
|
|
225
|
+
_versions.get(appId).push({
|
|
226
|
+
id: versionId,
|
|
227
|
+
app_id: appId,
|
|
228
|
+
version: newVersion,
|
|
229
|
+
snapshot: design,
|
|
230
|
+
});
|
|
231
231
|
|
|
232
232
|
if (_apps.has(appId)) {
|
|
233
233
|
_apps.get(appId).design = design;
|
|
@@ -375,3 +375,131 @@ export function listApps(db) {
|
|
|
375
375
|
updated_at: r.updated_at,
|
|
376
376
|
}));
|
|
377
377
|
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get a single application by ID from the database.
|
|
381
|
+
*
|
|
382
|
+
* @param {object} db
|
|
383
|
+
* @param {string} appId
|
|
384
|
+
* @returns {object|null}
|
|
385
|
+
*/
|
|
386
|
+
export function getApp(db, appId) {
|
|
387
|
+
const row = db.prepare(`SELECT * FROM lowcode_apps WHERE id = ?`).get(appId);
|
|
388
|
+
if (!row) return null;
|
|
389
|
+
return {
|
|
390
|
+
id: row.id,
|
|
391
|
+
name: row.name,
|
|
392
|
+
description: row.description,
|
|
393
|
+
design: row.design
|
|
394
|
+
? JSON.parse(row.design)
|
|
395
|
+
: { components: [], layout: {} },
|
|
396
|
+
status: row.status,
|
|
397
|
+
version: row.version,
|
|
398
|
+
platform: row.platform,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Generate a static HTML bundle string for an app's design.
|
|
404
|
+
*
|
|
405
|
+
* @param {object} app - App object with design
|
|
406
|
+
* @returns {{ "index.html": string, "app.js": string, "style.css": string }}
|
|
407
|
+
*/
|
|
408
|
+
function generateStaticBundle(app) {
|
|
409
|
+
const design = app.design || { components: [], layout: {} };
|
|
410
|
+
const components = design.components || [];
|
|
411
|
+
|
|
412
|
+
const componentHtml = components
|
|
413
|
+
.map(
|
|
414
|
+
(c, i) =>
|
|
415
|
+
` <div class="lc-component lc-${(c.type || c.name || "widget").toLowerCase()}" id="comp-${i}">${c.label || c.type || c.name || "Component"}</div>`,
|
|
416
|
+
)
|
|
417
|
+
.join("\n");
|
|
418
|
+
|
|
419
|
+
const html = `<!DOCTYPE html>
|
|
420
|
+
<html lang="en">
|
|
421
|
+
<head>
|
|
422
|
+
<meta charset="UTF-8">
|
|
423
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
424
|
+
<title>${app.name || "Low-Code App"}</title>
|
|
425
|
+
<link rel="stylesheet" href="style.css">
|
|
426
|
+
</head>
|
|
427
|
+
<body>
|
|
428
|
+
<div id="app">
|
|
429
|
+
<h1>${app.name || "Low-Code App"}</h1>
|
|
430
|
+
<p>${app.description || ""}</p>
|
|
431
|
+
<div class="lc-container">
|
|
432
|
+
${componentHtml || " <p>No components defined</p>"}
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
435
|
+
<script src="app.js"><\/script>
|
|
436
|
+
</body>
|
|
437
|
+
</html>`;
|
|
438
|
+
|
|
439
|
+
const css = `/* Generated by ChainlessChain Low-Code Platform */
|
|
440
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
441
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; padding: 24px; background: #f5f5f5; }
|
|
442
|
+
#app { max-width: 1200px; margin: 0 auto; }
|
|
443
|
+
h1 { margin-bottom: 8px; color: #1a1a1a; }
|
|
444
|
+
p { margin-bottom: 16px; color: #666; }
|
|
445
|
+
.lc-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
|
|
446
|
+
.lc-component { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; }
|
|
447
|
+
`;
|
|
448
|
+
|
|
449
|
+
const js = `// Generated by ChainlessChain Low-Code Platform
|
|
450
|
+
// App: ${app.name || "Untitled"} v${app.version || 1}
|
|
451
|
+
(function() {
|
|
452
|
+
console.log("Low-Code App initialized: ${app.name || "Untitled"}");
|
|
453
|
+
var config = ${JSON.stringify({ id: app.id, name: app.name, version: app.version, platform: app.platform })};
|
|
454
|
+
document.querySelectorAll(".lc-component").forEach(function(el) {
|
|
455
|
+
el.addEventListener("click", function() { el.classList.toggle("active"); });
|
|
456
|
+
});
|
|
457
|
+
})();
|
|
458
|
+
`;
|
|
459
|
+
|
|
460
|
+
return { "index.html": html, "app.js": js, "style.css": css };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Deploy an application by generating a static bundle and writing it to disk.
|
|
465
|
+
*
|
|
466
|
+
* @param {object} db
|
|
467
|
+
* @param {string} appId
|
|
468
|
+
* @param {{ outputDir?: string }} options
|
|
469
|
+
* @returns {{ appId: string, outputDir: string, files: string[], deployedAt: string }}
|
|
470
|
+
*/
|
|
471
|
+
export function deployApp(db, appId, options = {}) {
|
|
472
|
+
const app = getApp(db, appId);
|
|
473
|
+
if (!app) {
|
|
474
|
+
throw new Error(`App '${appId}' not found`);
|
|
475
|
+
}
|
|
476
|
+
if (app.status !== "published") {
|
|
477
|
+
throw new Error(
|
|
478
|
+
`App '${appId}' must be published before deploying (current status: ${app.status})`,
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const outputDir =
|
|
483
|
+
options.outputDir ||
|
|
484
|
+
path.join(process.cwd(), ".chainlesschain", "deploys", appId);
|
|
485
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
486
|
+
|
|
487
|
+
const bundle = generateStaticBundle(app);
|
|
488
|
+
const fileNames = [];
|
|
489
|
+
for (const [fileName, content] of Object.entries(bundle)) {
|
|
490
|
+
fs.writeFileSync(path.join(outputDir, fileName), content, "utf-8");
|
|
491
|
+
fileNames.push(fileName);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Update app status to deployed
|
|
495
|
+
db.prepare(
|
|
496
|
+
`UPDATE lowcode_apps SET status = ?, updated_at = datetime('now') WHERE id = ?`,
|
|
497
|
+
).run("deployed", appId);
|
|
498
|
+
|
|
499
|
+
if (_apps.has(appId)) {
|
|
500
|
+
_apps.get(appId).status = "deployed";
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const deployedAt = new Date().toISOString();
|
|
504
|
+
return { appId, outputDir, files: fileNames, deployedAt };
|
|
505
|
+
}
|
|
@@ -52,11 +52,18 @@ export class CLIAutonomousAgent extends EventEmitter {
|
|
|
52
52
|
/**
|
|
53
53
|
* Initialize with required dependencies.
|
|
54
54
|
*/
|
|
55
|
-
initialize({
|
|
55
|
+
initialize({
|
|
56
|
+
llmChat,
|
|
57
|
+
toolExecutor,
|
|
58
|
+
hookManager,
|
|
59
|
+
maxIterations,
|
|
60
|
+
iterationBudget,
|
|
61
|
+
} = {}) {
|
|
56
62
|
this._llmChat = llmChat || null;
|
|
57
63
|
this._toolExecutor = toolExecutor || null;
|
|
58
64
|
this._hookManager = hookManager || null;
|
|
59
65
|
if (maxIterations) this._maxIterations = maxIterations;
|
|
66
|
+
this._iterationBudget = iterationBudget || null; // shared budget from caller
|
|
60
67
|
this._initialized = true;
|
|
61
68
|
}
|
|
62
69
|
|
|
@@ -12,6 +12,7 @@ import { generateInstinctPrompt } from "./instinct-manager.js";
|
|
|
12
12
|
import { recallMemory } from "./hierarchical-memory.js";
|
|
13
13
|
import { BM25Search } from "./bm25-search.js";
|
|
14
14
|
import { createHash } from "crypto";
|
|
15
|
+
import { readUserProfile } from "./user-profile.js";
|
|
15
16
|
|
|
16
17
|
// Exported for test injection
|
|
17
18
|
export const _deps = {
|
|
@@ -19,6 +20,7 @@ export const _deps = {
|
|
|
19
20
|
recallMemory,
|
|
20
21
|
BM25Search,
|
|
21
22
|
createHash,
|
|
23
|
+
readUserProfile,
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
// ─── System prompt cleaning regexes (match desktop KV-Cache optimization) ───
|
|
@@ -105,6 +107,19 @@ export class CLIContextEngineering {
|
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
|
|
110
|
+
// 2b. User profile injection (USER.md)
|
|
111
|
+
try {
|
|
112
|
+
const profile = _deps.readUserProfile();
|
|
113
|
+
if (profile) {
|
|
114
|
+
result.push({
|
|
115
|
+
role: "system",
|
|
116
|
+
content: `## User Profile\n${profile}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
} catch (_err) {
|
|
120
|
+
// User profile injection failed — skip silently
|
|
121
|
+
}
|
|
122
|
+
|
|
108
123
|
// 3. Memory injection (scoped: higher threshold, namespace-aware)
|
|
109
124
|
if (this.db && userQuery) {
|
|
110
125
|
try {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cowork Task Runner — executes daily tasks using SubAgentContext.
|
|
3
|
+
*
|
|
4
|
+
* Creates an isolated sub-agent with a template-specific system prompt,
|
|
5
|
+
* runs the agent loop, and yields progress events for WS consumers.
|
|
6
|
+
*
|
|
7
|
+
* @module cowork-task-runner
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { SubAgentContext } from "./sub-agent-context.js";
|
|
11
|
+
import { getTemplate } from "./cowork-task-templates.js";
|
|
12
|
+
|
|
13
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const DEFAULT_MAX_ITERATIONS = 50;
|
|
16
|
+
const DEFAULT_TOKEN_BUDGET = 100_000;
|
|
17
|
+
|
|
18
|
+
// ─── Runner ───────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Run a cowork task using SubAgentContext.
|
|
22
|
+
*
|
|
23
|
+
* @param {object} options
|
|
24
|
+
* @param {string|null} options.templateId - Template ID (null = free mode)
|
|
25
|
+
* @param {string} options.userMessage - User's task description
|
|
26
|
+
* @param {string[]} [options.files] - File paths provided by user
|
|
27
|
+
* @param {string} [options.cwd] - Working directory
|
|
28
|
+
* @param {object} [options.db] - Database instance
|
|
29
|
+
* @param {object} [options.llmOptions] - LLM provider/model/key
|
|
30
|
+
* @param {number} [options.maxIterations] - Override iteration limit
|
|
31
|
+
* @param {number} [options.tokenBudget] - Override token budget
|
|
32
|
+
* @returns {Promise<{ taskId: string, status: string, result: object }>}
|
|
33
|
+
*/
|
|
34
|
+
export async function runCoworkTask(options = {}) {
|
|
35
|
+
const {
|
|
36
|
+
templateId = null,
|
|
37
|
+
userMessage,
|
|
38
|
+
files = [],
|
|
39
|
+
cwd = process.cwd(),
|
|
40
|
+
db = null,
|
|
41
|
+
llmOptions = {},
|
|
42
|
+
maxIterations = DEFAULT_MAX_ITERATIONS,
|
|
43
|
+
tokenBudget = DEFAULT_TOKEN_BUDGET,
|
|
44
|
+
} = options;
|
|
45
|
+
|
|
46
|
+
if (!userMessage || typeof userMessage !== "string") {
|
|
47
|
+
throw new Error("userMessage is required");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Resolve template
|
|
51
|
+
const template = getTemplate(templateId);
|
|
52
|
+
|
|
53
|
+
// Build the task prompt with template context + files
|
|
54
|
+
const taskParts = [template.systemPromptExtension];
|
|
55
|
+
|
|
56
|
+
if (files.length > 0) {
|
|
57
|
+
taskParts.push(`\n## 用户提供的文件\n${files.join("\n")}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const task = taskParts.join("\n");
|
|
61
|
+
|
|
62
|
+
// Create isolated sub-agent context
|
|
63
|
+
const subAgent = SubAgentContext.create({
|
|
64
|
+
role: `cowork-${template.id}`,
|
|
65
|
+
task,
|
|
66
|
+
inheritedContext: null,
|
|
67
|
+
maxIterations,
|
|
68
|
+
tokenBudget,
|
|
69
|
+
db,
|
|
70
|
+
llmOptions,
|
|
71
|
+
cwd,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const taskId = subAgent.id;
|
|
75
|
+
|
|
76
|
+
// Run the agent with the user's message
|
|
77
|
+
try {
|
|
78
|
+
const result = await subAgent.run(userMessage);
|
|
79
|
+
return {
|
|
80
|
+
taskId,
|
|
81
|
+
status: subAgent.status,
|
|
82
|
+
templateId: template.id,
|
|
83
|
+
templateName: template.name,
|
|
84
|
+
result,
|
|
85
|
+
};
|
|
86
|
+
} catch (err) {
|
|
87
|
+
return {
|
|
88
|
+
taskId,
|
|
89
|
+
status: "failed",
|
|
90
|
+
templateId: template.id,
|
|
91
|
+
templateName: template.name,
|
|
92
|
+
result: {
|
|
93
|
+
summary: `Task failed: ${err.message}`,
|
|
94
|
+
artifacts: [],
|
|
95
|
+
tokenCount: 0,
|
|
96
|
+
toolsUsed: [],
|
|
97
|
+
iterationCount: 0,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|