agency-orchestrator 0.8.0 → 0.8.1
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/cli.js +31 -1
- package/dist/export/convert.d.ts +17 -0
- package/dist/export/convert.js +125 -0
- package/package.json +6 -3
- package/web/server.js +18 -0
- package/website/dist/assets/{Changelog-C-2NwXOa.js → Changelog-C6gJ8sN7.js} +1 -1
- package/website/dist/assets/{CreativeLibrary-ByU75zJj.js → CreativeLibrary-B_8O1s2c.js} +1 -1
- package/website/dist/assets/{Docs-upfORkRh.js → Docs-DU2N3IS_.js} +1 -1
- package/website/dist/assets/{Experts-DZcMYT0N.js → Experts-C9z5y2rm.js} +1 -1
- package/website/dist/assets/{Home-C1iExJ44.js → Home-BWGkGVMU.js} +1 -1
- package/website/dist/assets/{Markdown-Du-_jWYV.js → Markdown-C0L6FhCW.js} +1 -1
- package/website/dist/assets/{NotFound-DFOhxeLB.js → NotFound-xNtHHfkV.js} +1 -1
- package/website/dist/assets/{PromptStudio-CtdWODfK.js → PromptStudio-17TeFAQ8.js} +1 -1
- package/website/dist/assets/{SiteFooter-CsQnpWsM.js → SiteFooter-DR4eH-53.js} +1 -1
- package/website/dist/assets/{Sponsors-Wm7wOV0d.js → Sponsors-BMRgur4p.js} +1 -1
- package/website/dist/assets/{Studio-Db7R3YwK.js → Studio-yUpOYHMn.js} +34 -29
- package/website/dist/assets/{TutorialDetail-VrrsTGTl.js → TutorialDetail-BrfVjMLZ.js} +1 -1
- package/website/dist/assets/{Tutorials-DGzE4QCM.js → Tutorials-DC9c2EvF.js} +1 -1
- package/website/dist/assets/{UsagePanel-_z-wE9kf.js → UsagePanel-CzoMRrg1.js} +1 -1
- package/website/dist/assets/{arrow-left-LNFkvuFe.js → arrow-left-RD0wK_Iq.js} +1 -1
- package/website/dist/assets/{arrow-up-right-DUa0xHYF.js → arrow-up-right-BuwIRRU6.js} +1 -1
- package/website/dist/assets/{badge-DnXqkHQO.js → badge-DfAy_y5P.js} +1 -1
- package/website/dist/assets/{clock-DeAEswbe.js → clock-Cy6q8QUy.js} +1 -1
- package/website/dist/assets/{copy-CEowRexz.js → copy-DyTNyX56.js} +1 -1
- package/website/dist/assets/{copy-button-eOlzSbi7.js → copy-button-DC6rEWiP.js} +1 -1
- package/website/dist/assets/{download-CdAgc0a_.js → download-DIXKHBqo.js} +1 -1
- package/website/dist/assets/{external-link-g9VqtAuI.js → external-link-CjdD4QgR.js} +1 -1
- package/website/dist/assets/{index-D4qIfjfN.js → index-CrZmwA66.js} +2 -2
- package/website/dist/assets/index-qTaRmBkE.css +1 -0
- package/website/dist/assets/{mail-BQb9aJdA.js → mail-YfVJ15xh.js} +1 -1
- package/website/dist/assets/{search-ouXlHBRS.js → search-WlZrNuJy.js} +1 -1
- package/website/dist/assets/{sparkles-FGrgtgsi.js → sparkles-C5b30t-L.js} +1 -1
- package/website/dist/assets/{sponsors-DeXMAzHe.js → sponsors-DcILXsjq.js} +1 -1
- package/website/dist/assets/useBackend-_4T8SBzA.js +30 -0
- package/website/dist/assets/{workflow-BvnziOG8.js → workflow-C-Cq5FbH.js} +1 -1
- package/website/dist/index.html +2 -2
- package/website/dist/assets/index-CA4ERbPo.css +0 -1
- package/website/dist/assets/useBackend-DZu6HpVx.js +0 -30
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* ao plan workflow.yaml
|
|
9
9
|
* ao roles --agents-dir ./agents
|
|
10
10
|
*/
|
|
11
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
11
|
+
import { readFileSync, existsSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { resolve, join, dirname } from 'node:path';
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
14
|
import { execSync, spawn } from 'node:child_process';
|
|
@@ -125,6 +125,7 @@ async function handleRun() {
|
|
|
125
125
|
console.error('用法: ao run <workflow.yaml> [--input key=value ...]');
|
|
126
126
|
console.error(' 或: ao run --team <名字> "你的任务" # 用已保存的团队跑新任务');
|
|
127
127
|
console.error(' --materialize <目录> 把开发步产出的「### 路径 + 代码围栏」文件块落盘成真实项目脚手架');
|
|
128
|
+
console.error(' --export <格式> 把本次产出导出:docx/pdf/xlsx(给人)或 skill/plan(给编码 agent 执行)');
|
|
128
129
|
console.error(' --compare 跑完后再跑单次基线 + 盲评,并排对比多智能体 vs 单次');
|
|
129
130
|
console.error(' --judge-provider/--judge-model --compare 时指定评审模型(默认用生成模型)');
|
|
130
131
|
process.exit(1);
|
|
@@ -231,6 +232,35 @@ async function handleRun() {
|
|
|
231
232
|
if (mat.skipped.length)
|
|
232
233
|
console.log(` ⛔ 跳过 ${mat.skipped.length} 个不安全路径: ${mat.skipped.slice(0, 5).join(', ')}`);
|
|
233
234
|
}
|
|
235
|
+
// --export <fmt>:把本次产出导出成 Word/PDF/Excel,或 Skill/可执行计划(给编码 agent 跑)
|
|
236
|
+
const exportFmt = getArgValue('--export');
|
|
237
|
+
if (exportFmt) {
|
|
238
|
+
const allowed = ['docx', 'pdf', 'xlsx', 'skill', 'plan'];
|
|
239
|
+
if (!allowed.includes(exportFmt)) {
|
|
240
|
+
console.error(`\n ⚠️ --export 仅支持: ${allowed.join(' / ')}`);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const md = result.steps
|
|
244
|
+
.filter(s => s.status === 'completed' && s.output)
|
|
245
|
+
.map(s => `## ${s.agentName || s.role || s.id}\n\n${s.output}`)
|
|
246
|
+
.join('\n\n---\n\n');
|
|
247
|
+
if (!md) {
|
|
248
|
+
console.log(`\n ⚠️ --export:本次运行没有可导出的产出。`);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
// 懒加载转换器(xlsx/marked/html-to-docx 较重,仅用到时才载)
|
|
252
|
+
const { exportMarkdown } = await import('./export/convert.js');
|
|
253
|
+
const r = await exportMarkdown(md, exportFmt, { name: result.name });
|
|
254
|
+
const safe = (result.name || 'report').replace(/[^一-鿿a-zA-Z0-9_-]+/g, '-').replace(/-+/g, '-').slice(0, 60) || 'report';
|
|
255
|
+
const out = resolve(`${safe}.${r.ext}`);
|
|
256
|
+
writeFileSync(out, r.buffer);
|
|
257
|
+
console.log(`\n 📤 已导出 → ${out}(${r.engine})`);
|
|
258
|
+
if (r.ext === 'html' && exportFmt === 'pdf') {
|
|
259
|
+
console.log(` (未检测到 pandoc+LaTeX,已输出打印就绪 HTML;浏览器打开 Ctrl-P 存 PDF,或装 pandoc 获更佳排版)`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
234
264
|
process.exit(result.success ? 0 : 1);
|
|
235
265
|
}
|
|
236
266
|
catch (err) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ExportFormat = 'docx' | 'pdf' | 'xlsx' | 'skill' | 'plan';
|
|
2
|
+
export interface ExportResult {
|
|
3
|
+
buffer: Buffer;
|
|
4
|
+
ext: string;
|
|
5
|
+
mime: string;
|
|
6
|
+
engine: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function hasPandoc(): boolean;
|
|
9
|
+
/** 解析 markdown 表格(连续的 | … | 行),标题取表格上方最近的标题行。 */
|
|
10
|
+
export declare function extractMarkdownTables(md: string): Array<{
|
|
11
|
+
title?: string;
|
|
12
|
+
rows: string[][];
|
|
13
|
+
}>;
|
|
14
|
+
export declare function exportMarkdown(md: string, format: ExportFormat, opts?: {
|
|
15
|
+
name?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
}): Promise<ExportResult>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// 把工作流产出的 Markdown 报告转成可用格式。
|
|
2
|
+
// 给人:Word(.docx)/ PDF / Excel(.xlsx,从 Markdown 表格抽)
|
|
3
|
+
// 给机器:Skill(.md + frontmatter,可复用方法论)/ 可执行计划(plan.md,交 Claude Code 执行)
|
|
4
|
+
//
|
|
5
|
+
// 设计(对齐 AO「零配置探测」):有 pandoc 就用它出最好看的 docx/pdf(pdf 走 xelatex 排版最佳);
|
|
6
|
+
// 没 pandoc 则用纯 JS 兜底(marked + html-to-docx)。Excel 一律用 SheetJS(不依赖 pandoc)。
|
|
7
|
+
// n8n 同款思路——转文件是确定性的库调用,不是 LLM。
|
|
8
|
+
import { spawnSync } from 'node:child_process';
|
|
9
|
+
import { marked } from 'marked';
|
|
10
|
+
import * as XLSX from 'xlsx';
|
|
11
|
+
import { isOnPath } from '../providers/detect.js';
|
|
12
|
+
export function hasPandoc() {
|
|
13
|
+
return isOnPath('pandoc');
|
|
14
|
+
}
|
|
15
|
+
/** Markdown → HTML(给 docx/pdf 兜底用),套一层基础打印样式。 */
|
|
16
|
+
function mdToHtml(md, title = 'Report') {
|
|
17
|
+
const body = marked.parse(md, { async: false });
|
|
18
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title>
|
|
19
|
+
<style>body{font-family:system-ui,"PingFang SC","Microsoft YaHei",sans-serif;line-height:1.7;max-width:820px;margin:24px auto;padding:0 16px;color:#1a1a1a}
|
|
20
|
+
h1,h2,h3{line-height:1.3}table{border-collapse:collapse;width:100%}th,td{border:1px solid #ccc;padding:6px 10px}
|
|
21
|
+
pre{background:#f5f5f5;padding:12px;border-radius:6px;overflow:auto}code{font-family:ui-monospace,monospace}
|
|
22
|
+
@media print{body{margin:0}}</style></head><body>${body}</body></html>`;
|
|
23
|
+
}
|
|
24
|
+
/** 用 pandoc 把 markdown 转成指定目标(stdout 二进制)。失败/无 pandoc 返回 null。 */
|
|
25
|
+
function pandocConvert(md, to, extraArgs = []) {
|
|
26
|
+
if (!hasPandoc())
|
|
27
|
+
return null;
|
|
28
|
+
const r = spawnSync('pandoc', ['-f', 'markdown', '-t', to, ...extraArgs], {
|
|
29
|
+
input: md,
|
|
30
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
31
|
+
});
|
|
32
|
+
if (r.status !== 0 || !r.stdout || r.stdout.length === 0)
|
|
33
|
+
return null;
|
|
34
|
+
return Buffer.from(r.stdout);
|
|
35
|
+
}
|
|
36
|
+
async function toDocx(md) {
|
|
37
|
+
const viaPandoc = pandocConvert(md, 'docx');
|
|
38
|
+
if (viaPandoc)
|
|
39
|
+
return { buffer: viaPandoc, ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', engine: 'pandoc' };
|
|
40
|
+
// JS 兜底:marked → html → html-to-docx
|
|
41
|
+
// @ts-expect-error html-to-docx 无类型声明文件
|
|
42
|
+
const HTMLtoDOCX = (await import('html-to-docx')).default;
|
|
43
|
+
const out = await HTMLtoDOCX(mdToHtml(md), null, { table: { row: { cantSplit: true } } });
|
|
44
|
+
const buffer = Buffer.isBuffer(out) ? out : Buffer.from(out);
|
|
45
|
+
return { buffer, ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', engine: 'html-to-docx' };
|
|
46
|
+
}
|
|
47
|
+
function toPdf(md) {
|
|
48
|
+
// PDF 排版最好看的是 pandoc + xelatex;无 pandoc 时不硬出丑 PDF,改给打印就绪的 HTML(浏览器 Ctrl-P 存 PDF)。
|
|
49
|
+
const viaPandoc = pandocConvert(md, 'pdf', ['--pdf-engine=xelatex', '-V', 'CJKmainfont=PingFang SC']);
|
|
50
|
+
if (viaPandoc)
|
|
51
|
+
return { buffer: viaPandoc, ext: 'pdf', mime: 'application/pdf', engine: 'pandoc+xelatex' };
|
|
52
|
+
return { buffer: Buffer.from(mdToHtml(md), 'utf-8'), ext: 'html', mime: 'text/html', engine: 'html-fallback' };
|
|
53
|
+
}
|
|
54
|
+
/** 从 Markdown 里的表格抽成 xlsx(每个表格一个 sheet)。没有表格则把全文放一个 sheet 的首列。 */
|
|
55
|
+
function toXlsx(md) {
|
|
56
|
+
const wb = XLSX.utils.book_new();
|
|
57
|
+
const tables = extractMarkdownTables(md);
|
|
58
|
+
if (tables.length === 0) {
|
|
59
|
+
const ws = XLSX.utils.aoa_to_sheet(md.split('\n').map((line) => [line]));
|
|
60
|
+
XLSX.utils.book_append_sheet(wb, ws, 'Report');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
tables.forEach((t, i) => {
|
|
64
|
+
const ws = XLSX.utils.aoa_to_sheet(t.rows);
|
|
65
|
+
XLSX.utils.book_append_sheet(wb, ws, (t.title || `Table${i + 1}`).slice(0, 28));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' });
|
|
69
|
+
return { buffer, ext: 'xlsx', mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', engine: 'sheetjs' };
|
|
70
|
+
}
|
|
71
|
+
/** 解析 markdown 表格(连续的 | … | 行),标题取表格上方最近的标题行。 */
|
|
72
|
+
export function extractMarkdownTables(md) {
|
|
73
|
+
const lines = md.split('\n');
|
|
74
|
+
const tables = [];
|
|
75
|
+
let lastHeading;
|
|
76
|
+
let i = 0;
|
|
77
|
+
const splitRow = (line) => line.trim().replace(/^\||\|$/g, '').split('|').map((c) => c.trim());
|
|
78
|
+
while (i < lines.length) {
|
|
79
|
+
const line = lines[i];
|
|
80
|
+
const h = line.match(/^#{1,6}\s+(.+)/);
|
|
81
|
+
if (h) {
|
|
82
|
+
lastHeading = h[1].trim();
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const isRow = /^\s*\|.*\|\s*$/.test(line);
|
|
87
|
+
const isSep = i + 1 < lines.length && /^\s*\|[\s:|-]+\|\s*$/.test(lines[i + 1]);
|
|
88
|
+
if (isRow && isSep) {
|
|
89
|
+
const rows = [splitRow(line)];
|
|
90
|
+
i += 2; // 跳过表头 + 分隔行
|
|
91
|
+
while (i < lines.length && /^\s*\|.*\|\s*$/.test(lines[i])) {
|
|
92
|
+
rows.push(splitRow(lines[i]));
|
|
93
|
+
i++;
|
|
94
|
+
}
|
|
95
|
+
tables.push({ title: lastHeading, rows });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
i++;
|
|
99
|
+
}
|
|
100
|
+
return tables;
|
|
101
|
+
}
|
|
102
|
+
/** 把报告包成可复用 Skill(.md + frontmatter)或可执行计划(交 Claude Code 跑)。 */
|
|
103
|
+
function toSkillOrPlan(md, format, opts) {
|
|
104
|
+
const name = (opts?.name || 'generated-plan').replace(/[^一-鿿a-zA-Z0-9_-]/g, '-').replace(/-+/g, '-').toLowerCase();
|
|
105
|
+
const desc = opts?.description || '由 Agency Orchestrator 多智能体协作生成的方法论 / 计划';
|
|
106
|
+
let content;
|
|
107
|
+
if (format === 'skill') {
|
|
108
|
+
content = `---\nname: ${name}\ndescription: ${desc}\n---\n\n${md}\n`;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// 可执行计划:给 Claude Code 等编码 agent 的执行说明(把"看的报告"变成"做的指令")
|
|
112
|
+
content = `# 执行计划(由 Agency Orchestrator 生成)\n\n> 你是编码执行 agent。请**严格按下面的计划自动执行直到完成**,对不明确处用合理默认值,不要反问。完成后自检是否满足计划目标。\n\n---\n\n${md}\n`;
|
|
113
|
+
}
|
|
114
|
+
return { buffer: Buffer.from(content, 'utf-8'), ext: 'md', mime: 'text/markdown', engine: 'wrap' };
|
|
115
|
+
}
|
|
116
|
+
export async function exportMarkdown(md, format, opts) {
|
|
117
|
+
switch (format) {
|
|
118
|
+
case 'docx': return toDocx(md);
|
|
119
|
+
case 'pdf': return toPdf(md);
|
|
120
|
+
case 'xlsx': return toXlsx(md);
|
|
121
|
+
case 'skill': return toSkillOrPlan(md, 'skill', opts);
|
|
122
|
+
case 'plan': return toSkillOrPlan(md, 'plan', opts);
|
|
123
|
+
default: throw new Error(`不支持的导出格式: ${format}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agency-orchestrator",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Multi-agent YAML workflow engine — 216 AI roles, auto DAG parallelism, zero code. One sentence → multiple AI roles collaborate → complete plan in minutes. 10 LLM providers, 7 need no API key.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"multi-agent",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"eval:baseline": "npx tsx eval/run-eval.ts --save-baseline",
|
|
70
70
|
"build:studio": "npm --prefix website install && npm --prefix website run build",
|
|
71
71
|
"verify:release": "node scripts/verify-cli.mjs && node scripts/verify-frontend.mjs",
|
|
72
|
-
"test": "npx tsx test/run.ts && npx tsx test/condition.ts && npx tsx test/cli.ts && npx tsx test/cli-base.ts && npx tsx test/parse-inputs.ts && npx tsx test/compose.ts && npx tsx test/demo.ts && npx tsx test/factory-custom.ts && npx tsx test/azure-compat.ts && npx tsx test/connector-continuation.ts && npx tsx test/connector-stall.ts && npx tsx test/compare-lib.ts && npx tsx test/install.ts && npx tsx test/materialize.ts && npx tsx test/paths.ts && npx tsx test/skills.ts && npx tsx test/step-llm.ts && npx tsx test/step-llm-yaml.ts && npx tsx test/stdin-limit.ts && npx tsx test/compose-name.ts && npx tsx test/team.ts && npx tsx test/prompt.ts && npx tsx test/upgrade.ts && npx tsx test/resume.ts && npx tsx test/feedback.ts && npx tsx test/human-input.ts && npx tsx test/init.ts && npx tsx test/roles.ts && npx tsx test/eval-gate.ts && npx tsx test/validate-report.ts && npx tsx test/workflows.ts && npx tsx test/timeout.ts && npx tsx test/inputs.ts && npx tsx test/e2e.ts && npx tsx test/e2e-condition.ts && npx tsx test/e2e-loop.ts && npx tsx test/detect-providers.ts && npx tsx test/canvas-graph.ts && npx tsx test/creative-prompts.ts && npx tsx test/web-server.ts && npx tsx test/mcp.ts",
|
|
72
|
+
"test": "npx tsx test/run.ts && npx tsx test/condition.ts && npx tsx test/cli.ts && npx tsx test/cli-base.ts && npx tsx test/parse-inputs.ts && npx tsx test/compose.ts && npx tsx test/demo.ts && npx tsx test/factory-custom.ts && npx tsx test/azure-compat.ts && npx tsx test/connector-continuation.ts && npx tsx test/connector-stall.ts && npx tsx test/compare-lib.ts && npx tsx test/install.ts && npx tsx test/materialize.ts && npx tsx test/paths.ts && npx tsx test/skills.ts && npx tsx test/step-llm.ts && npx tsx test/step-llm-yaml.ts && npx tsx test/stdin-limit.ts && npx tsx test/compose-name.ts && npx tsx test/team.ts && npx tsx test/prompt.ts && npx tsx test/upgrade.ts && npx tsx test/resume.ts && npx tsx test/feedback.ts && npx tsx test/human-input.ts && npx tsx test/init.ts && npx tsx test/roles.ts && npx tsx test/eval-gate.ts && npx tsx test/validate-report.ts && npx tsx test/workflows.ts && npx tsx test/timeout.ts && npx tsx test/inputs.ts && npx tsx test/e2e.ts && npx tsx test/e2e-condition.ts && npx tsx test/e2e-loop.ts && npx tsx test/detect-providers.ts && npx tsx test/canvas-graph.ts && npx tsx test/creative-prompts.ts && npx tsx test/export-convert.ts && npx tsx test/web-server.ts && npx tsx test/mcp.ts",
|
|
73
73
|
"prepublishOnly": "npm run build && npm run build:studio && npm run verify:release"
|
|
74
74
|
},
|
|
75
75
|
"files": [
|
|
@@ -90,8 +90,11 @@
|
|
|
90
90
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
91
91
|
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
92
92
|
"agency-agents-zh": "^1.2.2",
|
|
93
|
+
"html-to-docx": "^1.8.0",
|
|
93
94
|
"js-yaml": "^4.1.0",
|
|
94
|
-
"
|
|
95
|
+
"marked": "^18.0.5",
|
|
96
|
+
"superpowers-zh": "^1.5.0",
|
|
97
|
+
"xlsx": "^0.18.5"
|
|
95
98
|
},
|
|
96
99
|
"devDependencies": {
|
|
97
100
|
"@types/js-yaml": "^4.0.9",
|
package/web/server.js
CHANGED
|
@@ -796,6 +796,24 @@ app.post('/api/workflows/graph', async (req, res) => {
|
|
|
796
796
|
} catch (err) { res.status(500).json({ error: err?.message || String(err) }); }
|
|
797
797
|
});
|
|
798
798
|
|
|
799
|
+
// ── 报告导出:Markdown → Word / PDF / Excel / Skill / 可执行计划(确定性转换,见 src/export/convert.ts) ──
|
|
800
|
+
app.post('/api/export', async (req, res) => {
|
|
801
|
+
const { markdown, format, name } = req.body || {};
|
|
802
|
+
if (!markdown || typeof markdown !== 'string') return res.status(400).json({ error: 'markdown required' });
|
|
803
|
+
const allowed = ['docx', 'pdf', 'xlsx', 'skill', 'plan'];
|
|
804
|
+
if (!allowed.includes(format)) return res.status(400).json({ error: `format must be one of ${allowed.join('/')}` });
|
|
805
|
+
try {
|
|
806
|
+
const { exportMarkdown } = await import('../dist/export/convert.js');
|
|
807
|
+
const r = await exportMarkdown(markdown, format, { name: typeof name === 'string' ? name : undefined });
|
|
808
|
+
const safe = (typeof name === 'string' && name.trim() ? name : 'report').replace(/[^一-鿿a-zA-Z0-9_-]+/g, '-').replace(/-+/g, '-').slice(0, 60) || 'report';
|
|
809
|
+
res.setHeader('Content-Type', r.mime);
|
|
810
|
+
// 中文文件名用 RFC 5987 编码,避免 header 非法字符
|
|
811
|
+
res.setHeader('Content-Disposition', `attachment; filename="export.${r.ext}"; filename*=UTF-8''${encodeURIComponent(safe)}.${r.ext}`);
|
|
812
|
+
res.setHeader('X-Export-Engine', r.engine);
|
|
813
|
+
res.send(r.buffer);
|
|
814
|
+
} catch (err) { res.status(500).json({ error: err?.message || String(err) }); }
|
|
815
|
+
});
|
|
816
|
+
|
|
799
817
|
// ── Teams / Loadouts: reusable role line-ups, shared with the `ao team` CLI ──
|
|
800
818
|
// Stored in ~/.ao/teams (or AO_TEAMS_DIR) so CLI-saved and Studio-saved teams interoperate.
|
|
801
819
|
app.get('/api/teams', async (_req, res) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{u as p,r as d,j as n}from"./vendor-react-BYpU7-8G.js";import{S as m}from"./SiteFooter-
|
|
1
|
+
import{u as p,r as d,j as n}from"./vendor-react-BYpU7-8G.js";import{S as m}from"./SiteFooter-DR4eH-53.js";import{B as c}from"./badge-DfAy_y5P.js";import{M as u}from"./Markdown-C0L6FhCW.js";import{c as g,u as A,S as h}from"./index-CrZmwA66.js";import{A as L}from"./arrow-up-right-BuwIRRU6.js";import"./vendor-radix-5dK8e-Nk.js";import"./vendor-charts-EdNYpIP7.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as m,j as e}from"./vendor-react-BYpU7-8G.js";import{S as j}from"./SiteFooter-
|
|
1
|
+
import{r as m,j as e}from"./vendor-react-BYpU7-8G.js";import{S as j}from"./SiteFooter-DR4eH-53.js";import{c as y,u as w,a as h}from"./index-CrZmwA66.js";import{u as A}from"./useSeo-_9wpTevc.js";import{t as H}from"./track-UypTCFjF.js";import{S as U}from"./search-WlZrNuJy.js";import{E as v}from"./external-link-CjdD4QgR.js";import{C as M,a as k}from"./copy-DyTNyX56.js";import"./vendor-radix-5dK8e-Nk.js";import"./vendor-charts-EdNYpIP7.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{h as b,r as u,j as e,i as k,L as w}from"./vendor-react-BYpU7-8G.js";import{C as x}from"./copy-button-
|
|
1
|
+
import{h as b,r as u,j as e,i as k,L as w}from"./vendor-react-BYpU7-8G.js";import{C as x}from"./copy-button-DC6rEWiP.js";import{S as A}from"./SiteFooter-DR4eH-53.js";import{M as v}from"./Markdown-C0L6FhCW.js";import{u as z,a as O}from"./index-CrZmwA66.js";import{u as I}from"./useSeo-_9wpTevc.js";import{S}from"./search-WlZrNuJy.js";import"./copy-DyTNyX56.js";import"./vendor-radix-5dK8e-Nk.js";import"./vendor-charts-EdNYpIP7.js";const i=[{icon:"🚀",label:{zh:"快速入门",en:"Getting started"},pages:[{slug:"intro",title:{zh:"软件介绍",en:"Introduction"},sections:[{heading:{zh:"什么是 Agency Orchestrator",en:"What is Agency Orchestrator"},body:{zh:`Agency Orchestrator(\`ao\`)是 **agency-agents 专家角色库的编排器**。
|
|
2
2
|
|
|
3
3
|
agency-agents 里有 216 位打磨好的 AI 专家——营销、工程、设计、产品、财务、法律、销售、学术……每一位都是一段精调过的系统提示词,让模型稳定地以该领域专家的身份输出。但单独一位专家只能解决一个环节;真实任务往往要**多位专家分工协作**:研究员先调研、分析师再拆解、撰稿人成文、收口角色把关。
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as n,j as e}from"./vendor-react-BYpU7-8G.js";import{S as I}from"./SiteFooter-
|
|
1
|
+
import{r as n,j as e}from"./vendor-react-BYpU7-8G.js";import{S as I}from"./SiteFooter-DR4eH-53.js";import{u as R,a as p,S as F,X as D}from"./index-CrZmwA66.js";import{u as K}from"./useSeo-_9wpTevc.js";import O from"./experts-Dg_8n5tZ.js";import{S as q}from"./search-WlZrNuJy.js";import{C as A,a as E}from"./copy-DyTNyX56.js";import{A as B}from"./arrow-up-right-BuwIRRU6.js";import"./vendor-radix-5dK8e-Nk.js";import"./vendor-charts-EdNYpIP7.js";const z=O;async function H(l){try{return await navigator.clipboard.writeText(l),!0}catch{try{const s=document.createElement("textarea");s.value=l,s.style.position="fixed",s.style.opacity="0",document.body.appendChild(s),s.select();const a=document.execCommand("copy");return document.body.removeChild(s),a}catch{return!1}}}function M({e:l,className:s}){return e.jsx("span",{className:p("grid size-10 shrink-0 place-items-center rounded-xl text-lg font-bold text-white",s),style:{background:l.color||"#888"},children:l.emoji||l.name.slice(0,1)})}function ee(){const{t:l,lang:s}=R();K(s==="en"?"216 AI Expert Roles — Engineering / Design / Product / Marketing | Agency Orchestrator":"216 个 AI 专家角色库 — 工程 / 设计 / 产品 / 营销 | Agency Orchestrator",s==="en"?"Browse 216 orchestratable AI expert roles. One sentence → AI auto-assembles a team to collaborate.":"浏览 216 个可编排的 AI 专家角色,一句话让系统自动组队协作完成任务。");const a=l.experts,m=z[s]??z.zh,[f,P]=n.useState(""),[c,y]=n.useState("all"),b=n.useRef(new Map),[x,j]=n.useState(null),[d,u]=n.useState(null),[N,g]=n.useState(""),[v,w]=n.useState(!1),k=n.useCallback(async t=>{const r=`${s}/${t.category}/${t.id}`;if(b.current.has(r))return b.current.get(r);const o=await fetch(`/prompts/${s}/${t.category}/${t.id}.md`);if(!o.ok)throw new Error("fetch failed");const i=await o.text();return b.current.set(r,i),i},[s]),C=t=>{j(t),setTimeout(()=>j(r=>r===t?null:r),1800)},$=async t=>{const r=`${t.category}/${t.id}`;try{const o=await H(await k(t));C(o?r:`fail:${r}`)}catch{C(`fail:${r}`)}};n.useEffect(()=>{if(!d)return;const t=r=>{r.key==="Escape"&&u(null)};return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[d]);const S=async t=>{u(t),g(""),w(!0);try{g(await k(t))}catch{g("")}w(!1)},T=n.useMemo(()=>{const t=new Map;return m.forEach(r=>t.set(r.category,r.categoryName)),Array.from(t,([r,o])=>({id:r,name:o}))},[m]),h=n.useMemo(()=>{const t=f.trim().toLowerCase();return m.filter(r=>c!=="all"&&r.category!==c?!1:t?(r.name+r.description+r.categoryName).toLowerCase().includes(t):!0)},[m,f,c]);return e.jsxs(e.Fragment,{children:[e.jsx("main",{className:"pt-24",children:e.jsxs("div",{className:"container-page pb-20",children:[e.jsxs("div",{className:"mx-auto max-w-2xl text-center",children:[e.jsx("h1",{className:"text-3xl font-extrabold tracking-tight sm:text-4xl md:text-5xl",children:a.title}),e.jsx("p",{className:"mx-auto mt-4 text-pretty leading-relaxed text-muted-foreground",children:a.subtitle})]}),e.jsx("div",{className:"mx-auto mt-8 max-w-xl",children:e.jsxs("div",{className:"relative",children:[e.jsx(q,{className:"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground"}),e.jsx("input",{value:f,onChange:t=>P(t.target.value),placeholder:a.searchPlaceholder,className:"w-full rounded-xl border border-border/70 bg-card/60 py-2.5 pl-10 pr-3 text-sm outline-none focus:border-primary/40"})]})}),e.jsxs("div",{className:"mt-5 flex flex-wrap items-center justify-center gap-2",children:[e.jsx(L,{active:c==="all",onClick:()=>y("all"),children:a.all}),T.map(t=>e.jsx(L,{active:c===t.id,onClick:()=>y(t.id),children:t.name},t.id))]}),e.jsxs("p",{className:"mt-4 text-center text-sm text-muted-foreground",children:[h.length," ",a.countSuffix]}),h.length===0?e.jsx("p",{className:"mt-16 text-center text-sm text-muted-foreground",children:a.empty}):e.jsx("div",{className:"mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3",children:h.map(t=>{const r=`${t.category}/${t.id}`,o=x===r,i=x===`fail:${r}`;return e.jsxs("div",{className:"flex flex-col rounded-2xl border border-border/70 bg-card/60 p-5 transition-colors hover:border-primary/40",children:[e.jsxs("button",{type:"button",onClick:()=>S(t),className:"flex items-center gap-3 text-left",children:[e.jsx(M,{e:t}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate text-[11px] font-medium text-primary",children:t.categoryName}),e.jsx("h3",{className:"truncate font-semibold",children:t.name})]})]}),e.jsx("p",{className:"mt-3 line-clamp-4 flex-1 text-sm leading-relaxed text-muted-foreground",children:t.description}),e.jsxs("div",{className:"mt-4 flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:()=>S(t),className:"rounded-lg border border-border/70 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:border-primary/40 hover:text-foreground",children:a.viewPrompt}),e.jsxs("button",{type:"button",onClick:()=>$(t),className:p("inline-flex flex-1 items-center justify-center gap-1.5 rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",o?"border-emerald-500/40 bg-emerald-500/10 text-emerald-500":i?"border-red-500/40 bg-red-500/10 text-red-500":"border-primary/40 bg-primary/10 text-primary hover:bg-primary/15"),children:[o?e.jsx(A,{className:"size-3.5"}):e.jsx(E,{className:"size-3.5"}),o?a.copied:i?a.copyFailed:a.copyPrompt]})]})]},r)})}),e.jsx("div",{className:"mt-12 text-center",children:e.jsxs("a",{href:F.rolesRepo,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1.5 rounded-xl border border-border/70 bg-card/60 px-4 py-3 text-sm font-medium hover:border-primary/40",children:[a.repoCta,e.jsx(B,{className:"size-4 text-primary"})]})})]})}),e.jsx(I,{}),d&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-end justify-center bg-black/60 p-0 backdrop-blur-sm sm:items-center sm:p-6",onClick:()=>u(null),children:e.jsxs("div",{role:"dialog","aria-modal":"true","aria-label":d.name,className:"flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-t-2xl border border-border/70 bg-card shadow-2xl sm:rounded-2xl",onClick:t=>t.stopPropagation(),children:[e.jsxs("div",{className:"flex items-center gap-3 border-b border-border/70 p-4",children:[e.jsx(M,{e:d}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"truncate text-[11px] font-medium text-primary",children:d.categoryName}),e.jsx("h3",{className:"truncate font-semibold",children:d.name})]}),e.jsx("button",{type:"button",onClick:()=>u(null),"aria-label":a.close,className:"rounded-lg p-1.5 text-muted-foreground hover:bg-muted hover:text-foreground",children:e.jsx(D,{className:"size-5"})})]}),e.jsx("p",{className:"px-4 pt-3 text-xs text-muted-foreground",children:a.promptHint}),e.jsx("div",{className:"m-4 flex-1 overflow-auto rounded-xl border border-border/60 bg-background/60 p-4",children:v?e.jsx("p",{className:"text-sm text-muted-foreground",children:a.loading}):e.jsx("pre",{className:"whitespace-pre-wrap break-words font-mono text-xs leading-relaxed text-foreground",children:N})}),e.jsx("div",{className:"flex items-center justify-end gap-2 border-t border-border/70 p-4",children:(()=>{const t=`${d.category}/${d.id}`,r=x===t,o=x===`fail:${t}`;return e.jsxs("button",{type:"button",onClick:()=>$(d),disabled:v||!N,className:p("inline-flex items-center gap-1.5 rounded-lg border px-4 py-2 text-sm font-medium transition-colors disabled:opacity-50",r?"border-emerald-500/40 bg-emerald-500/10 text-emerald-500":o?"border-red-500/40 bg-red-500/10 text-red-500":"border-primary/40 bg-primary/10 text-primary hover:bg-primary/15"),children:[r?e.jsx(A,{className:"size-4"}):e.jsx(E,{className:"size-4"}),r?a.copied:o?a.copyFailed:a.copyPrompt]})})()})]})})]})}function L({active:l,onClick:s,children:a}){return e.jsx("button",{type:"button",onClick:s,className:p("rounded-full border px-3 py-1 text-sm font-medium transition-colors",l?"border-primary/40 bg-primary/10 text-primary":"border-border/70 text-muted-foreground hover:text-foreground"),children:a})}export{ee as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{j as e,L as c}from"./vendor-react-BYpU7-8G.js";import{c as d,u as o,S as r,B as i,G as x}from"./index-
|
|
1
|
+
import{j as e,L as c}from"./vendor-react-BYpU7-8G.js";import{c as d,u as o,S as r,B as i,G as x}from"./index-CrZmwA66.js";import{B as g,U as j,W as m,T as b,K as f}from"./workflow-C-Cq5FbH.js";import{m as n}from"./vendor-framer-motion-HzmZRvhs.js";import{C as p}from"./copy-button-DC6rEWiP.js";import{B as y}from"./badge-DfAy_y5P.js";import{D as N}from"./download-DIXKHBqo.js";import{C as v}from"./copy-DyTNyX56.js";import{S as w}from"./SiteFooter-DR4eH-53.js";import"./vendor-radix-5dK8e-Nk.js";import"./vendor-charts-EdNYpIP7.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|