@tbox.cn/app-template-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +13 -0
- package/.nvmrc +1 -0
- package/.tbox/app.json +4 -0
- package/AGENTS.md +101 -0
- package/ENV.md +77 -0
- package/LEGAL.md +7 -0
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/apps/client/STYLE_GUIDE.md +81 -0
- package/apps/client/VISUAL_RESTORE.md +90 -0
- package/apps/client/assets/copy@2x.png +0 -0
- package/apps/client/assets/debug.png +0 -0
- package/apps/client/assets/dislike@2x.png +0 -0
- package/apps/client/assets/keyboard-circle.svg +12 -0
- package/apps/client/assets/like@2x.png +0 -0
- package/apps/client/assets/more-circle.svg +3 -0
- package/apps/client/assets/new-chat.svg +3 -0
- package/apps/client/assets/quick-command-star.svg +3 -0
- package/apps/client/assets/send-gradient.svg +14 -0
- package/apps/client/assets/speaker@2x.png +0 -0
- package/apps/client/assets/stop@2x.png +0 -0
- package/apps/client/assets/voice-circle.svg +3 -0
- package/apps/client/babel-plugins/code-inspect.cjs +110 -0
- package/apps/client/index.html +36 -0
- package/apps/client/package.json +34 -0
- package/apps/client/src/app.tsx +5 -0
- package/apps/client/src/business/App.tsx +11 -0
- package/apps/client/src/business/README.md +82 -0
- package/apps/client/src/cards/CardRenderer.tsx +10 -0
- package/apps/client/src/cards/registry.ts +22 -0
- package/apps/client/src/components/ActionBar/DebugButton.tsx +49 -0
- package/apps/client/src/components/ActionBar/index.less +120 -0
- package/apps/client/src/components/ActionBar/index.tsx +157 -0
- package/apps/client/src/components/ChatHeader/index.less +104 -0
- package/apps/client/src/components/ChatHeader/index.tsx +63 -0
- package/apps/client/src/components/ChatInput/index.less +332 -0
- package/apps/client/src/components/ChatInput/index.tsx +251 -0
- package/apps/client/src/components/ChatInput/voice/VoicePressField.tsx +34 -0
- package/apps/client/src/components/ChatInput/voice/VoiceRecordingOverlay.tsx +51 -0
- package/apps/client/src/components/ChatInput/voice/machine.ts +27 -0
- package/apps/client/src/components/ChatInput/voice/useVoicePress.ts +188 -0
- package/apps/client/src/components/ErrorBoundary.tsx +2 -0
- package/apps/client/src/components/MediaList/index.less +241 -0
- package/apps/client/src/components/MediaList/index.tsx +256 -0
- package/apps/client/src/components/MessageBubble/index.less +309 -0
- package/apps/client/src/components/MessageBubble/index.tsx +163 -0
- package/apps/client/src/components/PullDownIndicator/index.less +32 -0
- package/apps/client/src/components/PullDownIndicator/index.tsx +33 -0
- package/apps/client/src/components/QuickCommands/index.less +48 -0
- package/apps/client/src/components/QuickCommands/index.tsx +22 -0
- package/apps/client/src/components/ReasoningBlock/index.less +90 -0
- package/apps/client/src/components/ReasoningBlock/index.tsx +56 -0
- package/apps/client/src/components/ScrollToBottomButton/index.less +32 -0
- package/apps/client/src/components/ScrollToBottomButton/index.tsx +10 -0
- package/apps/client/src/components/ToolCallBlock/index.less +91 -0
- package/apps/client/src/components/ToolCallBlock/index.tsx +63 -0
- package/apps/client/src/examples/tourism/TourismLanding.tsx +96 -0
- package/apps/client/src/examples/tourism/index.less +192 -0
- package/apps/client/src/hooks/useMediaUpload.ts +237 -0
- package/apps/client/src/hooks/usePullDownHistory.ts +97 -0
- package/apps/client/src/hooks/useTTSAutoPlay.ts +80 -0
- package/apps/client/src/main.tsx +17 -0
- package/apps/client/src/modules.ts +30 -0
- package/apps/client/src/pages/index/index.less +43 -0
- package/apps/client/src/pages/index/index.tsx +145 -0
- package/apps/client/src/platform/AgentChatApp.tsx +39 -0
- package/apps/client/src/platform/agent-runtime.ts +15 -0
- package/apps/client/src/platform/state/createPersistedStore.ts +19 -0
- package/apps/client/src/shims/node-stub.ts +14 -0
- package/apps/client/src/store/chat-config.ts +29 -0
- package/apps/client/src/store/chat.ts +201 -0
- package/apps/client/src/styles/global.less +60 -0
- package/apps/client/src/styles/tokens.less +60 -0
- package/apps/client/src/types/chat.ts +29 -0
- package/apps/client/src/utils/copyText.ts +11 -0
- package/apps/client/src/utils/imagePreview.ts +10 -0
- package/apps/client/src/utils/session-error.ts +5 -0
- package/apps/client/src/utils/toast.ts +15 -0
- package/apps/client/src/vite-env.d.ts +3 -0
- package/apps/client/tsconfig.json +11 -0
- package/apps/client/vite.config.ts +40 -0
- package/apps/server/package.json +40 -0
- package/apps/server/src/cli/collect-registry.ts +26 -0
- package/apps/server/src/cli/plugin-doctor.ts +89 -0
- package/apps/server/src/cli/plugin-inspect.ts +49 -0
- package/apps/server/src/index.ts +230 -0
- package/apps/server/src/intent-routes.ts +23 -0
- package/apps/server/src/modules.ts +31 -0
- package/apps/server/src/tools/translate.ts +41 -0
- package/apps/server/tests/cards-registry.test.ts +55 -0
- package/apps/server/tests/tool-runtime.test.ts +49 -0
- package/apps/server/tsconfig.json +5 -0
- package/apps/server/tsup.config.ts +25 -0
- package/apps/server/vitest.config.ts +8 -0
- package/config/chat.json +8 -0
- package/config/llm_provider.json +3 -0
- package/config/plugins.json +3 -0
- package/eslint.config.mjs +41 -0
- package/package.json +51 -0
- package/packages/module-weather/package.json +35 -0
- package/packages/module-weather/src/client/cards/weather/index.less +22 -0
- package/packages/module-weather/src/client/cards/weather/index.tsx +14 -0
- package/packages/module-weather/src/client/index.ts +19 -0
- package/packages/module-weather/src/index.ts +2 -0
- package/packages/module-weather/src/server/cards/weather/meta.ts +28 -0
- package/packages/module-weather/src/server/index.ts +19 -0
- package/packages/module-weather/src/server/tool.ts +29 -0
- package/packages/module-weather/tbox.component.json +27 -0
- package/packages/module-weather/tsconfig.json +14 -0
- package/pnpm-workspace.template.yaml +60 -0
- package/scripts/build.sh +39 -0
- package/scripts/check-inspector.sh +91 -0
- package/scripts/check-workspace.mjs +164 -0
- package/scripts/dev.sh +15 -0
- package/scripts/prepare.sh +11 -0
- package/scripts/start.sh +11 -0
- package/scripts/stop.sh +26 -0
- package/scripts/verify-generated.mjs +142 -0
- package/tsconfig.base.json +20 -0
package/scripts/stop.sh
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
4
|
+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
5
|
+
cd "$PROJECT_DIR"
|
|
6
|
+
|
|
7
|
+
PORT=${PORT:-8000}
|
|
8
|
+
|
|
9
|
+
echo "=== Stopping server on port $PORT ==="
|
|
10
|
+
if lsof -i :"$PORT" > /dev/null 2>&1; then
|
|
11
|
+
for PID in $(lsof -t -i :"$PORT"); do
|
|
12
|
+
echo "Killing process $PID..."
|
|
13
|
+
kill -9 "$PID" 2>/dev/null || true
|
|
14
|
+
done
|
|
15
|
+
sleep 1
|
|
16
|
+
lsof -i :"$PORT" > /dev/null 2>&1 && echo "Warning: Port $PORT still in use" || echo "Port $PORT is now free"
|
|
17
|
+
else
|
|
18
|
+
echo "Port $PORT is not in use"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "=== Cleaning up residual processes ==="
|
|
22
|
+
pkill -f "tsx watch src/index.ts" 2>/dev/null || true
|
|
23
|
+
pkill -f "node.*dist/index.js" 2>/dev/null || true
|
|
24
|
+
pkill -f "vite" 2>/dev/null || true
|
|
25
|
+
|
|
26
|
+
echo "=== All services stopped ==="
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* verify:generated 守卫(003 D5,三项内容):
|
|
4
|
+
* ① 装配文件与模块声明一致(漂移 = 0,服务端 modules.ts)
|
|
5
|
+
* ② 2 装配文件双锚点完整(imports + register 标记齐全)
|
|
6
|
+
* ③ 装配文件无裸露 import(全部 import 行在锚区内;import type 豁免)
|
|
7
|
+
* 自包含实现(模板独立于 CLI 包),全量校验以 `tbox-app module doctor` / `tbox-app module diff` 为准。
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
10
|
+
import { readdir } from 'node:fs/promises';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import process from 'node:process';
|
|
13
|
+
|
|
14
|
+
const appDir = path.resolve(process.argv[2] ?? path.join(import.meta.dirname, '..'));
|
|
15
|
+
const failures = [];
|
|
16
|
+
const warnings = [];
|
|
17
|
+
|
|
18
|
+
const ASSEMBLY_FILES = [
|
|
19
|
+
{ path: 'apps/server/src/modules.ts', markers: ['imports', 'register'] },
|
|
20
|
+
{ path: 'apps/client/src/modules.ts', markers: ['imports', 'register'] },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const IMPORT_LINE = /^import\s+.+from\s+['"][^'"]+['"];\s*$/;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 锚点行判定:必须为独立注释行(精确匹配),避免文件头注释中出现
|
|
27
|
+
* "@tbox:imports-begin" 字样时把锚区状态机提前置 true,导致"无裸露 import"检查失效。
|
|
28
|
+
*/
|
|
29
|
+
function isAnchorBegin(line) {
|
|
30
|
+
return line.trim() === '// @tbox:imports-begin';
|
|
31
|
+
}
|
|
32
|
+
function isAnchorEnd(line) {
|
|
33
|
+
return line.trim() === '// @tbox:imports-end';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 读取 .tbox/app.json 的 npm 模块清单 */
|
|
37
|
+
function readManifestModules() {
|
|
38
|
+
try {
|
|
39
|
+
const raw = JSON.parse(readFileSync(path.join(appDir, '.tbox/app.json'), 'utf8'));
|
|
40
|
+
return Array.isArray(raw?.npmModules) ? raw.npmModules : [];
|
|
41
|
+
} catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 收集 packages/* 下本地模块 id(有 tbox.component.json) */
|
|
47
|
+
async function listLocalModuleIds() {
|
|
48
|
+
const packagesDir = path.join(appDir, 'packages');
|
|
49
|
+
if (!existsSync(packagesDir)) return [];
|
|
50
|
+
const entries = await readdir(packagesDir, { withFileTypes: true });
|
|
51
|
+
const ids = [];
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
if (!entry.isDirectory()) continue;
|
|
54
|
+
if (existsSync(path.join(packagesDir, entry.name, 'tbox.component.json'))) {
|
|
55
|
+
ids.push(entry.name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return ids;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function extractBlock(content, marker) {
|
|
62
|
+
const begin = `// @tbox:${marker}-begin`;
|
|
63
|
+
const end = `// @tbox:${marker}-end`;
|
|
64
|
+
const b = content.indexOf(begin);
|
|
65
|
+
if (b === -1) return null;
|
|
66
|
+
const e = content.indexOf(end, b);
|
|
67
|
+
if (e === -1) return null;
|
|
68
|
+
return content.slice(b + begin.length, e);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function idFromPkg(pkg) {
|
|
72
|
+
return pkg.replace(/^@[^/]+\//, '').replace(/\/(server|client)$/, '');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function main() {
|
|
76
|
+
// ② 锚点完整 + ③ 无裸露 import
|
|
77
|
+
for (const file of ASSEMBLY_FILES) {
|
|
78
|
+
const full = path.join(appDir, file.path);
|
|
79
|
+
if (!existsSync(full)) {
|
|
80
|
+
failures.push(`${file.path}: 缺失`);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const content = readFileSync(full, 'utf8');
|
|
84
|
+
for (const marker of file.markers) {
|
|
85
|
+
const block = extractBlock(content, marker);
|
|
86
|
+
if (block === null) {
|
|
87
|
+
failures.push(`${file.path}: 缺 ${marker} 锚区`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const lines = content.split(/\r?\n/);
|
|
91
|
+
let inAnchor = false;
|
|
92
|
+
lines.forEach((line, i) => {
|
|
93
|
+
if (isAnchorBegin(line)) inAnchor = true;
|
|
94
|
+
else if (isAnchorEnd(line)) inAnchor = false;
|
|
95
|
+
// import type 属类型导入(非模块装配),锚区外合法,不视为裸露
|
|
96
|
+
else if (IMPORT_LINE.test(line.trim()) && !line.trim().startsWith('import type') && !inAnchor) {
|
|
97
|
+
failures.push(`${file.path}:${i + 1} 裸露 import(不在 imports 锚区内): ${line.trim()}`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ① 漂移 = 0:声明(manifest + 本地模块)vs 服务端 modules.ts 实际装配
|
|
103
|
+
// 契约包(无 tbox.component.json / 无 serverModule)不参与 modules.ts 装配,不计入声明
|
|
104
|
+
// (客户端 modules.ts 装配漂移由 tbox-app module doctor 全量校验兜底)
|
|
105
|
+
const npmModules = readManifestModules();
|
|
106
|
+
const declared = new Set([
|
|
107
|
+
...npmModules
|
|
108
|
+
.filter((m) => existsSync(path.join(appDir, 'packages', m.id, 'tbox.component.json')))
|
|
109
|
+
.map((m) => m.id),
|
|
110
|
+
...(await listLocalModuleIds()),
|
|
111
|
+
]);
|
|
112
|
+
const modulesTs = existsSync(path.join(appDir, 'apps/server/src/modules.ts'))
|
|
113
|
+
? readFileSync(path.join(appDir, 'apps/server/src/modules.ts'), 'utf8')
|
|
114
|
+
: '';
|
|
115
|
+
const importsBlock = extractBlock(modulesTs, 'imports') ?? '';
|
|
116
|
+
const actual = new Set(
|
|
117
|
+
[...importsBlock.matchAll(/from\s+['"]([^'"]+)['"]/g)].map((m) => idFromPkg(m[1])),
|
|
118
|
+
);
|
|
119
|
+
for (const id of declared) {
|
|
120
|
+
if (!actual.has(id)) failures.push(`模块 ${id} 已声明未装配(modules.ts imports 锚区)`);
|
|
121
|
+
}
|
|
122
|
+
for (const id of actual) {
|
|
123
|
+
if (!declared.has(id)) warnings.push(`模块 ${id} 已装配未声明(仅告警,可能为手接)`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (warnings.length > 0) {
|
|
127
|
+
console.warn('[verify:generated] 告警:');
|
|
128
|
+
for (const w of warnings) console.warn(` - ${w}`);
|
|
129
|
+
}
|
|
130
|
+
if (failures.length > 0) {
|
|
131
|
+
console.error('[verify:generated] 校验失败:');
|
|
132
|
+
for (const f of failures) console.error(` - ${f}`);
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
} else {
|
|
135
|
+
console.log('[verify:generated] 通过(装配一致 + 锚点完整 + 无裸露 import)');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
main().catch((err) => {
|
|
140
|
+
console.error('[verify:generated] 执行失败:', err);
|
|
141
|
+
process.exitCode = 1;
|
|
142
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"useDefineForClassFields": true,
|
|
16
|
+
"noUnusedLocals": true,
|
|
17
|
+
"noUnusedParameters": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true
|
|
19
|
+
}
|
|
20
|
+
}
|