work-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/README.md +234 -0
- package/app/(admin)/approvals/page.tsx +16 -0
- package/app/(admin)/audit/page.tsx +18 -0
- package/app/(admin)/layout.tsx +47 -0
- package/app/(admin)/scheduled-tasks/page.tsx +17 -0
- package/app/(admin)/settings/page.tsx +46 -0
- package/app/(admin)/skills/[name]/page.tsx +378 -0
- package/app/(admin)/skills/page.tsx +406 -0
- package/app/(admin)/statistics/page.tsx +416 -0
- package/app/(admin)/tickets/[id]/page.tsx +348 -0
- package/app/(admin)/tickets/new/page.tsx +309 -0
- package/app/(admin)/tickets/page.tsx +27 -0
- package/app/api/audit/route.ts +30 -0
- package/app/api/auth/feishu/callback/route.ts +72 -0
- package/app/api/auth/feishu/login/route.ts +17 -0
- package/app/api/auth/feishu/sso/route.ts +78 -0
- package/app/api/auth/login/route.ts +85 -0
- package/app/api/auth/oauth/route.ts +168 -0
- package/app/api/config/providers/route.ts +105 -0
- package/app/api/config/route.ts +115 -0
- package/app/api/config/status/route.ts +56 -0
- package/app/api/config/test/route.ts +212 -0
- package/app/api/documents/[id]/route.ts +88 -0
- package/app/api/documents/route.ts +53 -0
- package/app/api/health/route.ts +32 -0
- package/app/api/knowledge/[id]/route.ts +152 -0
- package/app/api/knowledge/from-session/route.ts +27 -0
- package/app/api/knowledge/route.ts +100 -0
- package/app/api/market/knowledge/[id]/route.ts +92 -0
- package/app/api/market/knowledge/route.ts +130 -0
- package/app/api/marketplace/skills/[id]/approve/route.ts +68 -0
- package/app/api/marketplace/skills/[id]/certify/route.ts +54 -0
- package/app/api/marketplace/skills/[id]/install/route.ts +180 -0
- package/app/api/marketplace/skills/[id]/promote-to-system/route.ts +219 -0
- package/app/api/marketplace/skills/[id]/rate/route.ts +90 -0
- package/app/api/marketplace/skills/[id]/ratings/route.ts +55 -0
- package/app/api/marketplace/skills/[id]/reject/route.ts +68 -0
- package/app/api/marketplace/skills/[id]/route.ts +177 -0
- package/app/api/marketplace/skills/route.ts +235 -0
- package/app/api/memory/route.ts +40 -0
- package/app/api/my/files/[id]/route.ts +52 -0
- package/app/api/my/files/route.ts +230 -0
- package/app/api/my/knowledge/route.ts +36 -0
- package/app/api/pi-chat/route.ts +443 -0
- package/app/api/recommend/route.ts +38 -0
- package/app/api/scheduled-tasks/[id]/execute/route.ts +132 -0
- package/app/api/scheduled-tasks/[id]/route.ts +165 -0
- package/app/api/scheduled-tasks/[id]/toggle/route.ts +53 -0
- package/app/api/scheduled-tasks/route.ts +101 -0
- package/app/api/sessions/[id]/messages/route.ts +212 -0
- package/app/api/sessions/route.ts +101 -0
- package/app/api/share/file/[id]/route.ts +37 -0
- package/app/api/skills/[name]/execute/route.ts +121 -0
- package/app/api/skills/[name]/route.ts +167 -0
- package/app/api/skills/create/route.ts +65 -0
- package/app/api/skills/generate/route.ts +405 -0
- package/app/api/skills/installed/route.ts +151 -0
- package/app/api/skills/route.ts +174 -0
- package/app/api/skills/translate/route.ts +40 -0
- package/app/api/skills/user/[name]/route.ts +159 -0
- package/app/api/skills/user/route.ts +90 -0
- package/app/api/statistics/route.ts +94 -0
- package/app/api/task-executions/[id]/route.ts +34 -0
- package/app/api/task-executions/route.ts +29 -0
- package/app/api/tickets/[id]/approve/route.ts +129 -0
- package/app/api/tickets/[id]/execute/route.ts +201 -0
- package/app/api/tickets/[id]/route.ts +127 -0
- package/app/api/tickets/route.ts +103 -0
- package/app/api/user/skills/route.ts +175 -0
- package/app/api/users/route.ts +80 -0
- package/app/chat/page.tsx +5 -0
- package/app/globals.css +84 -0
- package/app/h5/layout.tsx +5 -0
- package/app/h5/mobile-approvals-page.tsx +167 -0
- package/app/h5/mobile-chat-page.tsx +951 -0
- package/app/h5/mobile-profile-page.tsx +147 -0
- package/app/h5/mobile-tickets-page.tsx +121 -0
- package/app/h5/page.tsx +23 -0
- package/app/h5/ticket-action-buttons.tsx +80 -0
- package/app/layout.tsx +26 -0
- package/app/login/page.tsx +318 -0
- package/app/market/knowledge/[id]/page.tsx +77 -0
- package/app/market/knowledge/page.tsx +358 -0
- package/app/market/layout.tsx +29 -0
- package/app/market/page.tsx +18 -0
- package/app/market/skills/page.tsx +397 -0
- package/app/my/files/page.tsx +511 -0
- package/app/my/knowledge/[id]/page.tsx +271 -0
- package/app/my/knowledge/new/page.tsx +234 -0
- package/app/my/knowledge/page.tsx +248 -0
- package/app/my/layout.tsx +32 -0
- package/app/my/memory/page.tsx +164 -0
- package/app/my/page.tsx +18 -0
- package/app/my/scheduled-tasks/[id]/edit/page.tsx +290 -0
- package/app/my/scheduled-tasks/[id]/executions/page.tsx +275 -0
- package/app/my/scheduled-tasks/[id]/page.tsx +284 -0
- package/app/my/scheduled-tasks/new/page.tsx +230 -0
- package/app/my/scheduled-tasks/page.tsx +27 -0
- package/app/my/skills/[name]/page.tsx +320 -0
- package/app/my/skills/new/page.tsx +394 -0
- package/app/my/skills/page.tsx +303 -0
- package/app/page.tsx +2288 -0
- package/app/share/[sessionId]/page.tsx +226 -0
- package/app/share/file/[id]/page.tsx +140 -0
- package/bin/README.md +63 -0
- package/bin/generate-api-system +300 -0
- package/bin/postinstall.js +95 -0
- package/bin/work-agent.js +173 -0
- package/components/ai-elements/agent.tsx +142 -0
- package/components/ai-elements/artifact.tsx +149 -0
- package/components/ai-elements/attachments.tsx +427 -0
- package/components/ai-elements/audio-player.tsx +232 -0
- package/components/ai-elements/canvas.tsx +26 -0
- package/components/ai-elements/chain-of-thought.tsx +223 -0
- package/components/ai-elements/checkpoint.tsx +72 -0
- package/components/ai-elements/code-block.tsx +555 -0
- package/components/ai-elements/commit.tsx +449 -0
- package/components/ai-elements/confirmation.tsx +173 -0
- package/components/ai-elements/connection.tsx +28 -0
- package/components/ai-elements/context.tsx +410 -0
- package/components/ai-elements/controls.tsx +19 -0
- package/components/ai-elements/conversation.tsx +167 -0
- package/components/ai-elements/edge.tsx +144 -0
- package/components/ai-elements/environment-variables.tsx +325 -0
- package/components/ai-elements/file-tree.tsx +298 -0
- package/components/ai-elements/image.tsx +25 -0
- package/components/ai-elements/inline-citation.tsx +294 -0
- package/components/ai-elements/jsx-preview.tsx +250 -0
- package/components/ai-elements/message.tsx +367 -0
- package/components/ai-elements/mic-selector.tsx +372 -0
- package/components/ai-elements/model-selector.tsx +214 -0
- package/components/ai-elements/node.tsx +72 -0
- package/components/ai-elements/open-in-chat.tsx +367 -0
- package/components/ai-elements/package-info.tsx +235 -0
- package/components/ai-elements/panel.tsx +16 -0
- package/components/ai-elements/persona.tsx +280 -0
- package/components/ai-elements/plan.tsx +144 -0
- package/components/ai-elements/prompt-input.tsx +1341 -0
- package/components/ai-elements/queue.tsx +275 -0
- package/components/ai-elements/reasoning.tsx +355 -0
- package/components/ai-elements/sandbox.tsx +133 -0
- package/components/ai-elements/schema-display.tsx +473 -0
- package/components/ai-elements/shimmer.tsx +78 -0
- package/components/ai-elements/snippet.tsx +141 -0
- package/components/ai-elements/sources.tsx +78 -0
- package/components/ai-elements/speech-input.tsx +324 -0
- package/components/ai-elements/stack-trace.tsx +531 -0
- package/components/ai-elements/suggestion.tsx +58 -0
- package/components/ai-elements/task.tsx +88 -0
- package/components/ai-elements/terminal.tsx +277 -0
- package/components/ai-elements/test-results.tsx +497 -0
- package/components/ai-elements/tool.tsx +174 -0
- package/components/ai-elements/toolbar.tsx +17 -0
- package/components/ai-elements/transcription.tsx +126 -0
- package/components/ai-elements/voice-selector.tsx +525 -0
- package/components/ai-elements/web-preview.tsx +282 -0
- package/components/audit-log-list.tsx +114 -0
- package/components/chat/EmptyPreviewState.tsx +12 -0
- package/components/chat/KnowledgePickerDialog.tsx +464 -0
- package/components/chat/KnowledgePreview.tsx +70 -0
- package/components/chat/KnowledgePreviewPanel.tsx +86 -0
- package/components/chat/MentionInput.tsx +309 -0
- package/components/chat/OrganizeDialog.tsx +258 -0
- package/components/chat/RecommendationBanner.tsx +94 -0
- package/components/chat/SaveToKnowledgeDialog.tsx +193 -0
- package/components/chat/SkillSelector.tsx +305 -0
- package/components/chat/SkillSwitcher.tsx +163 -0
- package/components/client-layout.tsx +15 -0
- package/components/knowledge/KnowledgeMetadataPanel.tsx +293 -0
- package/components/layout-wrapper.tsx +18 -0
- package/components/mobile-layout.tsx +62 -0
- package/components/scheduled-task-list.tsx +356 -0
- package/components/setup-guide.tsx +484 -0
- package/components/sub-nav.tsx +54 -0
- package/components/ticket-detail-content.tsx +383 -0
- package/components/ticket-list.tsx +366 -0
- package/components/top-nav.tsx +132 -0
- package/components/ui/accordion.tsx +58 -0
- package/components/ui/alert.tsx +59 -0
- package/components/ui/avatar.tsx +50 -0
- package/components/ui/badge.tsx +36 -0
- package/components/ui/button-group.tsx +83 -0
- package/components/ui/button.tsx +57 -0
- package/components/ui/card.tsx +91 -0
- package/components/ui/carousel.tsx +262 -0
- package/components/ui/collapsible.tsx +11 -0
- package/components/ui/command.tsx +153 -0
- package/components/ui/dialog.tsx +122 -0
- package/components/ui/dropdown-menu.tsx +200 -0
- package/components/ui/hover-card.tsx +29 -0
- package/components/ui/input-group.tsx +170 -0
- package/components/ui/input.tsx +22 -0
- package/components/ui/label.tsx +26 -0
- package/components/ui/popover.tsx +31 -0
- package/components/ui/progress.tsx +28 -0
- package/components/ui/scroll-area.tsx +48 -0
- package/components/ui/select.tsx +174 -0
- package/components/ui/separator.tsx +31 -0
- package/components/ui/spinner.tsx +16 -0
- package/components/ui/switch.tsx +29 -0
- package/components/ui/table.tsx +120 -0
- package/components/ui/tabs.tsx +55 -0
- package/components/ui/textarea.tsx +22 -0
- package/components/ui/tooltip.tsx +30 -0
- package/components/welcome-guide.tsx +182 -0
- package/components.json +24 -0
- package/lib/command-parser.ts +331 -0
- package/lib/dangerous-commands.ts +672 -0
- package/lib/db.ts +2250 -0
- package/lib/feishu-auth.ts +135 -0
- package/lib/file-storage.ts +306 -0
- package/lib/file-tool.ts +583 -0
- package/lib/knowledge-tool.ts +152 -0
- package/lib/knowledge-types.ts +66 -0
- package/lib/market-client.ts +313 -0
- package/lib/market-db.ts +736 -0
- package/lib/market-types.ts +51 -0
- package/lib/memory-tool.ts +211 -0
- package/lib/memory.ts +197 -0
- package/lib/pi-config.ts +436 -0
- package/lib/pi-session.ts +799 -0
- package/lib/pinyin.ts +13 -0
- package/lib/recommendation.ts +227 -0
- package/lib/risk-estimator.ts +350 -0
- package/lib/scheduled-task-tool.ts +184 -0
- package/lib/scheduler-init.ts +43 -0
- package/lib/scheduler.ts +416 -0
- package/lib/secure-bash-tool.ts +413 -0
- package/lib/skill-engine.ts +396 -0
- package/lib/skill-generator.ts +269 -0
- package/lib/skill-loader.ts +234 -0
- package/lib/skill-tool.ts +188 -0
- package/lib/skill-types.ts +82 -0
- package/lib/skills-init.ts +58 -0
- package/lib/ticket-tool.ts +246 -0
- package/lib/user-skill-types.ts +30 -0
- package/lib/user-skills.ts +362 -0
- package/lib/utils.ts +6 -0
- package/lib/workflow.ts +154 -0
- package/lib/zip-tool.ts +191 -0
- package/next.config.js +8 -0
- package/package.json +106 -0
- package/public/.gitkeep +1 -0
- package/public/icon.svg +1 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* API System Generator - CLI Tool
|
|
4
|
+
* ็ๆ Skill ๅฐ .pi/skills/ ็ฎๅฝ
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { writeFileSync, mkdirSync, chmodSync, existsSync, readFileSync } = require('fs');
|
|
8
|
+
const { join, dirname } = require('path');
|
|
9
|
+
|
|
10
|
+
const HELP = `
|
|
11
|
+
API Skill Generator - ไป Swagger ็ๆ AI ๅฏ่ฏปๅ็ Skill
|
|
12
|
+
|
|
13
|
+
็จๆณ:
|
|
14
|
+
generate-api-system -s <swagger-url> [้้กน]
|
|
15
|
+
|
|
16
|
+
้้กน:
|
|
17
|
+
-s, --swagger <url> Swagger/OpenAPI ๆๆกฃๅฐๅ (ๅฟ
ๅกซ)
|
|
18
|
+
-n, --name <name> Skill ๅ็งฐ (้ป่ฎค: ไป Swagger ๆๅ)
|
|
19
|
+
-d, --description <desc> Skill ๆ่ฟฐ
|
|
20
|
+
-b, --base-url <url> API ๅบ็กๅฐๅ
|
|
21
|
+
-t, --token <token> API Token
|
|
22
|
+
-h, --help ๆพ็คบๅธฎๅฉ
|
|
23
|
+
|
|
24
|
+
็คบไพ:
|
|
25
|
+
# ๅบๆฌ็จๆณ
|
|
26
|
+
generate-api-system -s "https://api.example.com/openapi.json"
|
|
27
|
+
|
|
28
|
+
# ๅฎๆดๅๆฐ
|
|
29
|
+
generate-api-system -s "https://api.example.com/openapi.json" \\
|
|
30
|
+
-n "my-api" \\
|
|
31
|
+
-d "ๆ็API็ณป็ป" \\
|
|
32
|
+
-b "https://api.example.com"
|
|
33
|
+
|
|
34
|
+
่พๅบ (็ๆๅฐ .pi/skills/):
|
|
35
|
+
.pi/skills/{name}/
|
|
36
|
+
โโโ SKILL.md โ AI Skill ๅฎไน
|
|
37
|
+
โโโ SKILL.json โ ็ปๆๅๅ
ๆฐๆฎ
|
|
38
|
+
โโโ config.env โ ็ฏๅขๅ้้
็ฝฎ๏ผไพ่ๆฌไฝฟ็จ๏ผ
|
|
39
|
+
โโโ config.yaml โ API ้
็ฝฎ่ฏดๆ
|
|
40
|
+
โโโ scripts/ โ ๅฏๆง่ก่ๆฌ
|
|
41
|
+
โโโ curl_examples/ โ curl ็คบไพ
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
function extractName(swaggerUrl, spec) {
|
|
45
|
+
if (spec.info?.title) {
|
|
46
|
+
return slugify(spec.info.title);
|
|
47
|
+
}
|
|
48
|
+
if (spec.info?.version) {
|
|
49
|
+
return slugify(spec.info.title || 'api') + '-' + slugify(spec.info.version);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const url = new URL(swaggerUrl);
|
|
53
|
+
return slugify(url.hostname);
|
|
54
|
+
} catch {
|
|
55
|
+
return 'api-system';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function slugify(str) {
|
|
60
|
+
return str.toLowerCase()
|
|
61
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
62
|
+
.replace(/^-|-$/g, '');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function extractBaseUrl(swaggerUrl, spec) {
|
|
66
|
+
if (spec.servers?.[0]?.url) {
|
|
67
|
+
return spec.servers[0].url;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const url = new URL(swaggerUrl);
|
|
71
|
+
return url.origin + url.pathname.replace(/\/[^/]*$/, '');
|
|
72
|
+
} catch {
|
|
73
|
+
return '';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function generate() {
|
|
78
|
+
const args = process.argv.slice(2);
|
|
79
|
+
|
|
80
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
81
|
+
console.log(HELP);
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const options = {
|
|
86
|
+
swaggerUrl: '',
|
|
87
|
+
name: '',
|
|
88
|
+
description: '',
|
|
89
|
+
baseUrl: ''
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
for (let i = 0; i < args.length; i++) {
|
|
93
|
+
const arg = args[i];
|
|
94
|
+
if (arg === '-s' || arg === '--swagger') options.swaggerUrl = args[++i];
|
|
95
|
+
if (arg === '-n' || arg === '--name') options.name = args[++i];
|
|
96
|
+
if (arg === '-d' || arg === '--description') options.description = args[++i];
|
|
97
|
+
if (arg === '-b' || arg === '--base-url') options.baseUrl = args[++i];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!options.swaggerUrl) {
|
|
101
|
+
console.error('้่ฏฏ: ่ฏทๆๅฎ Swagger URL (-s <url>)');
|
|
102
|
+
console.error('ๅธฎๅฉ: generate-api-system --help');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log('Fetching swagger...');
|
|
107
|
+
const response = await fetch(options.swaggerUrl);
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
console.error('Failed to fetch swagger:', response.statusText);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
const spec = await response.json();
|
|
113
|
+
|
|
114
|
+
const skillName = options.name || extractName(options.swaggerUrl, spec);
|
|
115
|
+
const skillDescription = options.description || spec.info?.description || spec.info?.title || 'API System';
|
|
116
|
+
const baseUrl = options.baseUrl || extractBaseUrl(options.swaggerUrl, spec);
|
|
117
|
+
|
|
118
|
+
// ่พๅบๅฐ .pi/skills/
|
|
119
|
+
const piSkillsDir = '.pi/skills';
|
|
120
|
+
const skillDir = join(piSkillsDir, skillName);
|
|
121
|
+
const scriptsDir = join(skillDir, 'scripts');
|
|
122
|
+
const curlDir = join(skillDir, 'curl_examples');
|
|
123
|
+
|
|
124
|
+
mkdirSync(piSkillsDir, { recursive: true });
|
|
125
|
+
mkdirSync(skillDir, { recursive: true });
|
|
126
|
+
mkdirSync(scriptsDir, { recursive: true });
|
|
127
|
+
mkdirSync(curlDir, { recursive: true });
|
|
128
|
+
|
|
129
|
+
console.log('Generating skill:', skillName);
|
|
130
|
+
console.log('Output:', skillDir);
|
|
131
|
+
|
|
132
|
+
// ็ๆ config.yaml
|
|
133
|
+
writeFileSync(join(skillDir, 'config.yaml'), `# ${skillName} - API้
็ฝฎ
|
|
134
|
+
|
|
135
|
+
api:
|
|
136
|
+
baseUrl: ${baseUrl}
|
|
137
|
+
auth:
|
|
138
|
+
type: bearer
|
|
139
|
+
credentials:
|
|
140
|
+
token: $TOKEN
|
|
141
|
+
`);
|
|
142
|
+
|
|
143
|
+
// ็ๆ config.env (ไพ่ๆฌไฝฟ็จ)
|
|
144
|
+
writeFileSync(join(skillDir, 'config.env'), `# ${skillName} - ็ฏๅขๅ้้
็ฝฎ
|
|
145
|
+
BASE_URL=${baseUrl}
|
|
146
|
+
TOKEN=your-token-here
|
|
147
|
+
`);
|
|
148
|
+
|
|
149
|
+
// ็ๆ SKILL.json
|
|
150
|
+
const paths = spec.paths || {};
|
|
151
|
+
const endpoints = [];
|
|
152
|
+
const readOnlyOps = [];
|
|
153
|
+
const modifyOps = [];
|
|
154
|
+
|
|
155
|
+
for (const [path, item] of Object.entries(paths)) {
|
|
156
|
+
const normalizedPath = path.replace(/\{/g, ':').replace(/\}/g, '');
|
|
157
|
+
for (const [method, op] of Object.entries(item)) {
|
|
158
|
+
if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) {
|
|
159
|
+
const operation = op;
|
|
160
|
+
const endpoint = {
|
|
161
|
+
method: method.toUpperCase(),
|
|
162
|
+
path,
|
|
163
|
+
summary: operation.summary || '',
|
|
164
|
+
isReadOnly: ['get', 'head', 'options'].includes(method)
|
|
165
|
+
};
|
|
166
|
+
endpoints.push(endpoint);
|
|
167
|
+
if (endpoint.isReadOnly) readOnlyOps.push(endpoint);
|
|
168
|
+
else modifyOps.push(endpoint);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const skillJson = {
|
|
174
|
+
name: skillName,
|
|
175
|
+
displayName: spec.info?.title || skillName,
|
|
176
|
+
description: skillDescription,
|
|
177
|
+
version: spec.info?.version || '1.0.0',
|
|
178
|
+
author: spec.info?.contact?.name || 'xuanwu',
|
|
179
|
+
keywords: ['api', 'generated', 'swagger'],
|
|
180
|
+
baseUrl,
|
|
181
|
+
endpoints: {
|
|
182
|
+
readOnly: readOnlyOps,
|
|
183
|
+
modify: modifyOps
|
|
184
|
+
},
|
|
185
|
+
scripts: {
|
|
186
|
+
readOnly: readOnlyOps.map(e => `${e.method.toLowerCase()}_${e.path.split('/').pop()?.replace(/[{}]/g, '')}`),
|
|
187
|
+
modify: modifyOps.map(e => `${e.method.toLowerCase()}_${e.path.split('/').pop()?.replace(/[{}]/g, '')}`)
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
writeFileSync(join(skillDir, 'SKILL.json'), JSON.stringify(skillJson, null, 2));
|
|
191
|
+
|
|
192
|
+
// ็ๆ SKILL.md
|
|
193
|
+
let skillMd = `# ${skillName}
|
|
194
|
+
|
|
195
|
+
${skillDescription}
|
|
196
|
+
|
|
197
|
+
## API ๅ่กจ
|
|
198
|
+
|
|
199
|
+
### ๅช่ฏปๆไฝ๏ผAI ่ชๅจๆง่ก๏ผ
|
|
200
|
+
|
|
201
|
+
| API | ๆ่ฟฐ | ่ๆฌ |
|
|
202
|
+
|-----|------|------|
|
|
203
|
+
${readOnlyOps.map(e => `| \`${e.method} ${e.path}\` | ${e.summary || '-'} | \`scripts/${e.method.toLowerCase()}_${e.path.split('/').pop()?.replace(/[{}]/g, '')}\` |`).join('\n')}
|
|
204
|
+
|
|
205
|
+
### ไฟฎๆนๆไฝ๏ผ้ๅฎกๆน๏ผ
|
|
206
|
+
|
|
207
|
+
| API | ๆ่ฟฐ | ่ๆฌ |
|
|
208
|
+
|-----|------|------|
|
|
209
|
+
${modifyOps.map(e => `| \`${e.method} ${e.path}\` | ${e.summary || '-'} | \`scripts/${e.method.toLowerCase()}_${e.path.split('/').pop()?.replace(/[{}]/g, '')}\` |`).join('\n')}
|
|
210
|
+
|
|
211
|
+
## ไฝฟ็จๆนๅผ
|
|
212
|
+
|
|
213
|
+
### ๅช่ฏปๆไฝ
|
|
214
|
+
|
|
215
|
+
\`\`\`bash
|
|
216
|
+
./scripts/get_users
|
|
217
|
+
\`\`\`
|
|
218
|
+
|
|
219
|
+
### ไฟฎๆนๆไฝ
|
|
220
|
+
|
|
221
|
+
\`\`\`bash
|
|
222
|
+
./scripts/create_user # ๅๅปบๅทฅๅ๏ผ็ญๅพ
ๅฎกๆน
|
|
223
|
+
\`\`\`
|
|
224
|
+
|
|
225
|
+
## ้
็ฝฎ
|
|
226
|
+
|
|
227
|
+
็ผ่พ \`config.env\` ้
็ฝฎ API ๅฐๅๅ่ฎค่ฏใ
|
|
228
|
+
|
|
229
|
+
## ็ธๅ
ณๆไปถ
|
|
230
|
+
|
|
231
|
+
- \`SKILL.json\` - ็ปๆๅๅ
ๆฐๆฎ
|
|
232
|
+
- \`config.env\` - ็ฏๅขๅ้้
็ฝฎ๏ผไพ่ๆฌไฝฟ็จ๏ผ
|
|
233
|
+
- \`config.yaml\` - API ้
็ฝฎ่ฏดๆ
|
|
234
|
+
- \`scripts/\` - ๅฏๆง่ก่ๆฌ
|
|
235
|
+
`;
|
|
236
|
+
writeFileSync(join(skillDir, 'SKILL.md'), skillMd);
|
|
237
|
+
|
|
238
|
+
// ็ๆ่ๆฌ
|
|
239
|
+
for (const [path, item] of Object.entries(paths)) {
|
|
240
|
+
const normalizedPath = path.replace(/\{/g, ':').replace(/\}/g, '');
|
|
241
|
+
const groupName = path.split('/').filter(Boolean)[1] || 'default';
|
|
242
|
+
|
|
243
|
+
for (const [method, op] of Object.entries(item)) {
|
|
244
|
+
if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) {
|
|
245
|
+
const operation = op;
|
|
246
|
+
const summary = operation.summary || '';
|
|
247
|
+
const isReadOnly = ['get', 'head', 'options'].includes(method);
|
|
248
|
+
const scriptName = method.toLowerCase() + '_' + path.split('/').pop()?.replace(/[{}]/g, '')?.replace(/-/g, '_') || method;
|
|
249
|
+
|
|
250
|
+
const scriptContent = `#!/bin/bash
|
|
251
|
+
# ${scriptName} - ${summary}
|
|
252
|
+
# ๅ็ฑป: ${isReadOnly ? 'ๅช่ฏปๆไฝ (read_only)' : 'ไฟฎๆนๆไฝ (modify)'}
|
|
253
|
+
# API: ${method.toUpperCase()} ${path}
|
|
254
|
+
|
|
255
|
+
SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
256
|
+
source "\${SCRIPT_DIR}/../config.env"
|
|
257
|
+
|
|
258
|
+
${isReadOnly ? `# ๅช่ฏปๆไฝ - ็ดๆฅๆง่ก
|
|
259
|
+
echo "ๆง่ก: ${method.toUpperCase()} ${path}"
|
|
260
|
+
curl -s -X ${method.toUpperCase()} "$BASE_URL${normalizedPath}" \\
|
|
261
|
+
-H "Authorization: Bearer $TOKEN" \\
|
|
262
|
+
-H "Content-Type: application/json" | jq .` : `# ไฟฎๆนๆไฝ - ้่ฆๅฎกๆน
|
|
263
|
+
echo "ๆง่ก: ${method.toUpperCase()} ${path}"
|
|
264
|
+
curl -s -X ${method.toUpperCase()} "$BASE_URL${normalizedPath}" \\
|
|
265
|
+
-H "Authorization: Bearer $TOKEN" \\
|
|
266
|
+
-H "Content-Type: application/json" \\
|
|
267
|
+
-d '{"data": "่ฏทไฟฎๆน"}' | jq .`}
|
|
268
|
+
`;
|
|
269
|
+
writeFileSync(join(scriptsDir, scriptName), scriptContent);
|
|
270
|
+
chmodSync(join(scriptsDir, scriptName), 0o755);
|
|
271
|
+
|
|
272
|
+
// curl ็คบไพ
|
|
273
|
+
const curlContent = `curl -X ${method.toUpperCase()} "${normalizedPath}" \\
|
|
274
|
+
-H "Authorization: Bearer $TOKEN" \\
|
|
275
|
+
-H "Content-Type: application/json"
|
|
276
|
+
`;
|
|
277
|
+
writeFileSync(join(curlDir, `${scriptName}.sh`), curlContent);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
console.log('');
|
|
283
|
+
console.log('โ
Skill ็ๆๅฎๆ๏ผ');
|
|
284
|
+
console.log('๐ ่ทฏๅพ:', skillDir);
|
|
285
|
+
console.log('');
|
|
286
|
+
console.log('ๆไปถๅ่กจ:');
|
|
287
|
+
console.log(' โโโ SKILL.md โ AI Skill ๅฎไน');
|
|
288
|
+
console.log(' โโโ SKILL.json โ ็ปๆๅๅ
ๆฐๆฎ');
|
|
289
|
+
console.log(' โโโ config.env โ ็ฏๅขๅ้้
็ฝฎ๏ผไฟฎๆนๆญคๆไปถ๏ผ');
|
|
290
|
+
console.log(' โโโ config.yaml โ API ้
็ฝฎ่ฏดๆ');
|
|
291
|
+
console.log(' โโโ scripts/ โ ๅฏๆง่ก่ๆฌ');
|
|
292
|
+
console.log(' โโโ curl_examples/ โ curl ็คบไพ');
|
|
293
|
+
console.log('');
|
|
294
|
+
console.log('AI ๅฏ็ดๆฅ่ฏปๅ .pi/skills/' + skillName + '/SKILL.md');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
generate().catch(err => {
|
|
298
|
+
console.error('Error:', err);
|
|
299
|
+
process.exit(1);
|
|
300
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* postinstall.js
|
|
7
|
+
*
|
|
8
|
+
* npm install / npm install -g ๅฎๆๅ่ชๅจ่งฆๅ๏ผ
|
|
9
|
+
* 1. ๆฃๆฅ Node.js ็ๆฌ
|
|
10
|
+
* 2. ๅฆๆ .next/standalone ไธๅญๅจ โ ๆง่ก next build๏ผ้ฆๆฌกๅฎ่ฃ
๏ผ
|
|
11
|
+
* 3. ๆ ่ฎบๅฆไฝ โ ๅฏน .next/standalone ้็ better-sqlite3 ๆง่ก rebuild
|
|
12
|
+
* ๏ผ็กฎไฟๅ็ๆจกๅไธๅฝๅ Node.js ABI ๅน้
๏ผ
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
|
|
19
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
20
|
+
const STANDALONE_DIR = path.join(PKG_ROOT, '.next', 'standalone');
|
|
21
|
+
const STANDALONE_SERVER = path.join(STANDALONE_DIR, 'server.js');
|
|
22
|
+
const BSQL3_NODE = path.join(
|
|
23
|
+
STANDALONE_DIR,
|
|
24
|
+
'node_modules', 'better-sqlite3', 'build', 'Release', 'better_sqlite3.node'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// โโ CI ็ฏๅข โ ๅ
จ้จ่ทณ่ฟ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
28
|
+
if (process.env.CI) {
|
|
29
|
+
console.log('[work-agent] CI environment detected, skipping postinstall.');
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// โโ Node.js ็ๆฌๆฃๆฅ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
34
|
+
const [major] = process.versions.node.split('.').map(Number);
|
|
35
|
+
if (major < 18) {
|
|
36
|
+
console.error(`[work-agent] Node.js >= 18 is required. Current: v${process.versions.node}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// โโ Step 1: ๅฆๆๆฒกๆ standalone โ ๅ
build โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
41
|
+
if (!fs.existsSync(STANDALONE_SERVER)) {
|
|
42
|
+
console.log('\n[work-agent] Building the app (first install, this may take a minute)...\n');
|
|
43
|
+
|
|
44
|
+
const buildResult = spawnSync('npm', ['run', 'build'], {
|
|
45
|
+
cwd: PKG_ROOT,
|
|
46
|
+
stdio: 'inherit',
|
|
47
|
+
shell: process.platform === 'win32',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (buildResult.status !== 0) {
|
|
51
|
+
console.error('\n[work-agent] Build failed. Retry manually:\n');
|
|
52
|
+
console.error(` cd ${PKG_ROOT} && npm run build\n`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('\n[work-agent] Build complete.\n');
|
|
57
|
+
} else {
|
|
58
|
+
console.log('[work-agent] Standalone build found, skipping next build.');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// โโ Step 2: ็กฎไฟ better-sqlite3 ไธๅฝๅ Node.js ABI ๅน้
โโโโโโโโโโโโโโโโโโโโโโ
|
|
62
|
+
// next build ไผๆ better-sqlite3 ็ .node ๆไปถๅคๅถ่ฟ standalone๏ผ
|
|
63
|
+
// ไฝ้ฃไธชๆไปถๆฏๅฎ่ฃ
ๆถ็ผ่ฏ็๏ผๆขไบ Node.js ็ๆฌๅฐฑไผๅดฉใ
|
|
64
|
+
// ๆฏๆฌก postinstall ้ฝๅผบๅถ rebuild ไธๆฌก๏ผไปฃไปทๅพไฝ๏ผ< 10 ็ง๏ผใ
|
|
65
|
+
if (fs.existsSync(BSQL3_NODE)) {
|
|
66
|
+
console.log('[work-agent] Rebuilding better-sqlite3 for current Node.js version...');
|
|
67
|
+
|
|
68
|
+
const rebuildResult = spawnSync(
|
|
69
|
+
'npm',
|
|
70
|
+
['rebuild', 'better-sqlite3'],
|
|
71
|
+
{
|
|
72
|
+
cwd: STANDALONE_DIR,
|
|
73
|
+
stdio: 'inherit',
|
|
74
|
+
shell: process.platform === 'win32',
|
|
75
|
+
env: {
|
|
76
|
+
...process.env,
|
|
77
|
+
// ้ฒๆญข npm rebuild ่งฆๅๅ
ถไปๅ
็ postinstall
|
|
78
|
+
npm_lifecycle_event: 'rebuild',
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (rebuildResult.status !== 0) {
|
|
84
|
+
console.warn('[work-agent] better-sqlite3 rebuild failed. You may need build tools:');
|
|
85
|
+
console.warn(' macOS: xcode-select --install');
|
|
86
|
+
console.warn(' Linux: apt install -y python3 make g++ (or yum equivalent)');
|
|
87
|
+
console.warn(' Windows: npm install -g windows-build-tools');
|
|
88
|
+
} else {
|
|
89
|
+
console.log('[work-agent] better-sqlite3 rebuild complete.');
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
console.log('[work-agent] better-sqlite3 not found in standalone, skipping rebuild.');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log('\n[work-agent] Ready. Run `work-agent` to start.\n');
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const { spawn, spawnSync } = require('child_process');
|
|
8
|
+
const http = require('http');
|
|
9
|
+
|
|
10
|
+
// โโ ่ทฏๅพ่งฃๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
11
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
12
|
+
const STANDALONE_DIR = path.join(PKG_ROOT, '.next', 'standalone');
|
|
13
|
+
const STANDALONE_SERVER = path.join(STANDALONE_DIR, 'server.js');
|
|
14
|
+
const STATIC_SRC = path.join(PKG_ROOT, '.next', 'static');
|
|
15
|
+
const PUBLIC_SRC = path.join(PKG_ROOT, 'public');
|
|
16
|
+
const BSQL3_DIR = path.join(STANDALONE_DIR, 'node_modules', 'better-sqlite3');
|
|
17
|
+
const BSQL3_NODE = path.join(BSQL3_DIR, 'build', 'Release', 'better_sqlite3.node');
|
|
18
|
+
|
|
19
|
+
// โโ ็ซฏๅฃ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
20
|
+
const PORT = parseInt(process.env.PORT || '11024', 10);
|
|
21
|
+
const HOST = process.env.HOST || '0.0.0.0';
|
|
22
|
+
|
|
23
|
+
// โโ ๆฃๆฅๆๅปบไบง็ฉๆฏๅฆๅญๅจ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
24
|
+
if (!fs.existsSync(STANDALONE_SERVER)) {
|
|
25
|
+
console.error('\n[work-agent] ๆชๆพๅฐๆๅปบไบง็ฉใ่ฏทๅ
่ฟ่ก๏ผ\n');
|
|
26
|
+
console.error(' cd ' + PKG_ROOT);
|
|
27
|
+
console.error(' npm run build\n');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// โโ ๆฃๆฅๅนถไฟฎๅค better-sqlite3 ABI ๅ
ผๅฎนๆง โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
32
|
+
// .node ๆไปถไธญๅตๅ
ฅไบ็ผ่ฏๆถ็ NODE_MODULE_VERSION๏ผ้่ฟ่ฏปๅๆไปถๅ
ๅฎนๆฅๆฃๆต๏ผ
|
|
33
|
+
// ้ฟๅ
try/require ๅจๆไบๅนณๅฐไธ่กไธบไธไธ่ดใ
|
|
34
|
+
function getNodeAbiFromBinary(nodePath) {
|
|
35
|
+
try {
|
|
36
|
+
// NODE_MODULE_VERSION ไปฅๅญ็ฌฆไธฒ "NODE_MODULE_VERSION_xx" ๆ็ดๆฅๆฐๅญๅตๅ
ฅๅจไบ่ฟๅถ้
|
|
37
|
+
// ๆดๅฏ้ ็ๆนๅผ๏ผ็ดๆฅ require ๅนถๆ่ท้่ฏฏๆถๆฏ
|
|
38
|
+
const mod = require('module');
|
|
39
|
+
// ้่ฟ process.versions.modules ่ทๅๅฝๅ่ฟ่กๆถ็ ABI
|
|
40
|
+
return parseInt(process.versions.modules, 10);
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function needsRebuild() {
|
|
47
|
+
if (!fs.existsSync(BSQL3_NODE)) return false;
|
|
48
|
+
|
|
49
|
+
// ่ฏปๅ .node ไบ่ฟๅถ๏ผๅจๅ
ถไธญๆ็ดข "NODE_MODULE_VERSION" ๆ ่ฎฐๅ็็ๆฌๅท
|
|
50
|
+
try {
|
|
51
|
+
const buf = fs.readFileSync(BSQL3_NODE);
|
|
52
|
+
const marker = Buffer.from('NODE_MODULE_VERSION');
|
|
53
|
+
let idx = buf.indexOf(marker);
|
|
54
|
+
if (idx === -1) {
|
|
55
|
+
// ๆพไธๅฐๆ ่ฎฐ๏ผ็จ try-require ๅ
ๅบ
|
|
56
|
+
try {
|
|
57
|
+
require(path.join(BSQL3_DIR, 'lib', 'database.js'));
|
|
58
|
+
return false;
|
|
59
|
+
} catch {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// marker ไนๅๆฏไธไธชๅญ่ 0x00๏ผๅ้๏ผ๏ผ็ถๅๆฏ็ๆฌๅทๅญ็ฌฆไธฒ๏ผๅฆ "115\0"๏ผ
|
|
64
|
+
// ๅฎ้
ๆ ผๅผๅ ็ผ่ฏๅทฅๅ
ท้พไธๅ๏ผ็ดๆฅ try-require ๆดๅฏ้
|
|
65
|
+
return false; // fallback ๅฐ try-require
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ๆๅฏ้ ๆนๆก๏ผ็ดๆฅ try-require๏ผๆ่ท ERR_DLOPEN_FAILED
|
|
72
|
+
function checkAndRebuild() {
|
|
73
|
+
if (!fs.existsSync(BSQL3_NODE)) return;
|
|
74
|
+
|
|
75
|
+
let failed = false;
|
|
76
|
+
try {
|
|
77
|
+
// ็จ child_process ๅจๅญ่ฟ็จ้ require๏ผ้ฟๅ
ๆฑกๆไธป่ฟ็จๆจกๅ็ผๅญ
|
|
78
|
+
const result = spawnSync(process.execPath, [
|
|
79
|
+
'-e',
|
|
80
|
+
`require(${JSON.stringify(path.join(BSQL3_DIR, 'lib', 'database.js'))})`,
|
|
81
|
+
], { timeout: 5000 });
|
|
82
|
+
failed = result.status !== 0 && result.stderr &&
|
|
83
|
+
result.stderr.toString().includes('NODE_MODULE_VERSION');
|
|
84
|
+
} catch {
|
|
85
|
+
failed = true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!failed) return;
|
|
89
|
+
|
|
90
|
+
console.log('[work-agent] Detected Node.js version mismatch for better-sqlite3.');
|
|
91
|
+
console.log('[work-agent] Rebuilding native module (this takes ~10 seconds)...\n');
|
|
92
|
+
|
|
93
|
+
const result = spawnSync(
|
|
94
|
+
'npm',
|
|
95
|
+
['rebuild', 'better-sqlite3'],
|
|
96
|
+
{
|
|
97
|
+
cwd: STANDALONE_DIR,
|
|
98
|
+
stdio: 'inherit',
|
|
99
|
+
shell: process.platform === 'win32',
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (result.status !== 0) {
|
|
104
|
+
console.error('\n[work-agent] Rebuild failed. Please install build tools:');
|
|
105
|
+
console.error(' macOS: xcode-select --install');
|
|
106
|
+
console.error(' Linux: apt install -y python3 make g++');
|
|
107
|
+
console.error(' Windows: npm install -g windows-build-tools\n');
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('\n[work-agent] Rebuild complete.\n');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
checkAndRebuild();
|
|
115
|
+
|
|
116
|
+
// โโ ็กฎไฟ static / public ่ฝฏ้พๅญๅจ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
117
|
+
function ensureLink(src, dst) {
|
|
118
|
+
if (!fs.existsSync(dst) && fs.existsSync(src)) {
|
|
119
|
+
try {
|
|
120
|
+
fs.symlinkSync(src, dst, 'junction');
|
|
121
|
+
} catch {
|
|
122
|
+
// ๅฟฝ็ฅ
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
ensureLink(STATIC_SRC, path.join(STANDALONE_DIR, '.next', 'static'));
|
|
128
|
+
ensureLink(PUBLIC_SRC, path.join(STANDALONE_DIR, 'public'));
|
|
129
|
+
|
|
130
|
+
// โโ ็ญๅพ
ๆๅกๅฐฑ็ปช โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
131
|
+
function waitForReady(port, retries, delay, cb) {
|
|
132
|
+
http.get(`http://127.0.0.1:${port}/`, () => cb(null))
|
|
133
|
+
.on('error', () => {
|
|
134
|
+
if (retries <= 0) return cb(new Error('timeout'));
|
|
135
|
+
setTimeout(() => waitForReady(port, retries - 1, delay, cb), delay);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// โโ ๅฏๅจๆๅก โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
140
|
+
console.log(`\n[work-agent] Starting on http://localhost:${PORT} ...\n`);
|
|
141
|
+
|
|
142
|
+
const server = spawn(process.execPath, [STANDALONE_SERVER], {
|
|
143
|
+
cwd: STANDALONE_DIR,
|
|
144
|
+
env: { ...process.env, PORT: String(PORT), HOST, NODE_ENV: 'production' },
|
|
145
|
+
stdio: 'inherit',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
server.on('error', (err) => {
|
|
149
|
+
console.error('[work-agent] Failed to start server:', err.message);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
server.on('exit', (code) => process.exit(code || 0));
|
|
154
|
+
|
|
155
|
+
// โโ ๅฐฑ็ปชๅๆๅผๆต่งๅจ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
156
|
+
const url = `http://localhost:${PORT}`;
|
|
157
|
+
|
|
158
|
+
waitForReady(PORT, 30, 500, (err) => {
|
|
159
|
+
if (err) {
|
|
160
|
+
console.log(`[work-agent] Open your browser at: ${url}`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
console.log(`[work-agent] Ready! Opening ${url}`);
|
|
164
|
+
try {
|
|
165
|
+
require('open')(url).catch(() => {});
|
|
166
|
+
} catch {
|
|
167
|
+
console.log(`[work-agent] Open your browser at: ${url}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
['SIGINT', 'SIGTERM'].forEach((sig) => {
|
|
172
|
+
process.on(sig, () => server.kill(sig));
|
|
173
|
+
});
|