@winmatrix/daemon 0.2.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.
Files changed (51) hide show
  1. package/README.md +59 -0
  2. package/bin/winmatrix-daemon.js +6 -0
  3. package/dist/core/AgentProcessManager.d.ts +99 -0
  4. package/dist/core/AgentProcessManager.d.ts.map +1 -0
  5. package/dist/core/AgentProcessManager.js +292 -0
  6. package/dist/core/AgentProcessManager.js.map +1 -0
  7. package/dist/core/ConfigLoader.d.ts +92 -0
  8. package/dist/core/ConfigLoader.d.ts.map +1 -0
  9. package/dist/core/ConfigLoader.js +240 -0
  10. package/dist/core/ConfigLoader.js.map +1 -0
  11. package/dist/core/DaemonFileLogger.d.ts +34 -0
  12. package/dist/core/DaemonFileLogger.d.ts.map +1 -0
  13. package/dist/core/DaemonFileLogger.js +157 -0
  14. package/dist/core/DaemonFileLogger.js.map +1 -0
  15. package/dist/core/DaemonLifecycle.d.ts +22 -0
  16. package/dist/core/DaemonLifecycle.d.ts.map +1 -0
  17. package/dist/core/DaemonLifecycle.js +155 -0
  18. package/dist/core/DaemonLifecycle.js.map +1 -0
  19. package/dist/core/DiagnosticsServer.d.ts +28 -0
  20. package/dist/core/DiagnosticsServer.d.ts.map +1 -0
  21. package/dist/core/DiagnosticsServer.js +155 -0
  22. package/dist/core/DiagnosticsServer.js.map +1 -0
  23. package/dist/core/InstallationId.d.ts +14 -0
  24. package/dist/core/InstallationId.d.ts.map +1 -0
  25. package/dist/core/InstallationId.js +50 -0
  26. package/dist/core/InstallationId.js.map +1 -0
  27. package/dist/core/RuntimeAvailabilityReporter.d.ts +27 -0
  28. package/dist/core/RuntimeAvailabilityReporter.d.ts.map +1 -0
  29. package/dist/core/RuntimeAvailabilityReporter.js +79 -0
  30. package/dist/core/RuntimeAvailabilityReporter.js.map +1 -0
  31. package/dist/core/WorkspaceScanner.d.ts +45 -0
  32. package/dist/core/WorkspaceScanner.d.ts.map +1 -0
  33. package/dist/core/WorkspaceScanner.js +166 -0
  34. package/dist/core/WorkspaceScanner.js.map +1 -0
  35. package/dist/index.d.ts +16 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +238 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/wrapper/AgentWrapper.d.ts +23 -0
  40. package/dist/wrapper/AgentWrapper.d.ts.map +1 -0
  41. package/dist/wrapper/AgentWrapper.js +873 -0
  42. package/dist/wrapper/AgentWrapper.js.map +1 -0
  43. package/dist/wrapper/ClaudeStreamParser.d.ts +63 -0
  44. package/dist/wrapper/ClaudeStreamParser.d.ts.map +1 -0
  45. package/dist/wrapper/ClaudeStreamParser.js +104 -0
  46. package/dist/wrapper/ClaudeStreamParser.js.map +1 -0
  47. package/dist/wrapper/supportedAgentTypes.d.ts +7 -0
  48. package/dist/wrapper/supportedAgentTypes.d.ts.map +1 -0
  49. package/dist/wrapper/supportedAgentTypes.js +6 -0
  50. package/dist/wrapper/supportedAgentTypes.js.map +1 -0
  51. package/package.json +39 -0
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 本机只读诊断 HTTP 服务(默认 127.0.0.1:18767):状态、子 Agent、最近日志。
3
+ * 不鉴权 — 仅回环,切勿 bind 到 0.0.0.0。
4
+ */
5
+ import http from 'node:http';
6
+ import type { DaemonFileLogger } from './DaemonFileLogger.js';
7
+ import type { AgentProcessManager } from './AgentProcessManager.js';
8
+ export interface DaemonDiagnosticsContext {
9
+ version: string;
10
+ installationId: string;
11
+ /** 已脱敏 */
12
+ serverUrl: string;
13
+ computerState: string | null;
14
+ computerId: string | null;
15
+ uptimeSec: number;
16
+ }
17
+ export declare function startDiagnosticsServer(options: {
18
+ fileLogger: DaemonFileLogger;
19
+ agentManager: AgentProcessManager;
20
+ getContext: () => DaemonDiagnosticsContext;
21
+ onRescanProfiles?: () => Promise<{
22
+ ok: boolean;
23
+ error?: string;
24
+ }>;
25
+ host?: string;
26
+ port?: number;
27
+ }): http.Server;
28
+ //# sourceMappingURL=DiagnosticsServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DiagnosticsServer.d.ts","sourceRoot":"","sources":["../../src/core/DiagnosticsServer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAKpE,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU;IACV,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAoFD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,mBAAmB,CAAC;IAClC,UAAU,EAAE,MAAM,wBAAwB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAAC,MAAM,CAqEd"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * 本机只读诊断 HTTP 服务(默认 127.0.0.1:18767):状态、子 Agent、最近日志。
3
+ * 不鉴权 — 仅回环,切勿 bind 到 0.0.0.0。
4
+ */
5
+ import http from 'node:http';
6
+ const DEFAULT_HOST = '127.0.0.1';
7
+ const DEFAULT_PORT = 18767;
8
+ function json(res, code, body) {
9
+ const payload = JSON.stringify(body);
10
+ res.writeHead(code, {
11
+ 'Content-Type': 'application/json; charset=utf-8',
12
+ 'Cache-Control': 'no-store',
13
+ });
14
+ res.end(payload);
15
+ }
16
+ function htmlDashboard() {
17
+ return `<!DOCTYPE html>
18
+ <html lang="zh-CN">
19
+ <head>
20
+ <meta charset="utf-8" />
21
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
22
+ <title>WinMatrix Daemon</title>
23
+ <style>
24
+ body { font-family: system-ui, sans-serif; margin: 16px; background: #0f1419; color: #e6edf3; }
25
+ h1 { font-size: 1.1rem; }
26
+ pre { background: #161b22; padding: 12px; overflow: auto; max-height: 420px; border-radius: 6px; font-size: 12px; line-height: 1.4; }
27
+ section { margin-bottom: 20px; }
28
+ .muted { color: #8b949e; font-size: 13px; }
29
+ a { color: #58a6ff; }
30
+ code { background: #21262d; padding: 2px 6px; border-radius: 4px; }
31
+ </style>
32
+ </head>
33
+ <body>
34
+ <h1>WinMatrix Daemon 本机诊断</h1>
35
+ <p class="muted">仅监听 127.0.0.1;API:<code>/api/status</code> <code>/api/agents</code> <code>/api/tasks</code> <code>/api/logs</code> <code>POST /api/rescan-profiles</code></p>
36
+ <p><button id="rescanBtn" style="padding:6px 14px;cursor:pointer;">刷新技能</button> <span id="rescanMsg" style="margin-left:8px;font-size:13px;"></span></p>
37
+ <section>
38
+ <h2>状态</h2>
39
+ <pre id="status">加载中…</pre>
40
+ </section>
41
+ <section>
42
+ <h2>子 Agent</h2>
43
+ <pre id="agents">加载中…</pre>
44
+ </section>
45
+ <section>
46
+ <h2>近期任务</h2>
47
+ <p class="muted">仅在<strong>本子 Agent WebSocket</strong>收到服务端 <code>task.assign</code> 并由适配器执行时写入(进程内存)。OpenClaw 工作站 HTTP / <code>openclaw_chat</code> 工具、或未绑定到此 Daemon 上「子 Agent」注册 ID 的对话不会出现在此处;重启 Daemon 后会清空。</p>
48
+ <pre id="tasks">加载中…</pre>
49
+ </section>
50
+ <section>
51
+ <h2>最近日志</h2>
52
+ <pre id="logs">加载中…</pre>
53
+ </section>
54
+ <script>
55
+ async function load() {
56
+ const [st, ag, tk, lg] = await Promise.all([
57
+ fetch('/api/status').then(r => r.json()),
58
+ fetch('/api/agents').then(r => r.json()),
59
+ fetch('/api/tasks').then(r => r.json()),
60
+ fetch('/api/logs?lines=200').then(r => r.json()),
61
+ ]);
62
+ document.getElementById('status').textContent = JSON.stringify(st.data ?? st, null, 2);
63
+ document.getElementById('agents').textContent = JSON.stringify(ag.data ?? ag, null, 2);
64
+ document.getElementById('tasks').textContent = JSON.stringify(tk.data ?? tk, null, 2);
65
+ document.getElementById('logs').textContent = ((lg.data && lg.data.lines) || []).join(String.fromCharCode(10));
66
+ }
67
+ document.getElementById('rescanBtn').onclick = async function() {
68
+ const btn = document.getElementById('rescanBtn');
69
+ const msg = document.getElementById('rescanMsg');
70
+ btn.disabled = true;
71
+ msg.textContent = '扫描中...';
72
+ try {
73
+ const r = await fetch('/api/rescan-profiles', { method: 'POST' });
74
+ const j = await r.json();
75
+ msg.textContent = j.success ? '已刷新并上报' : ('失败: ' + (j.error || '未知错误'));
76
+ } catch(e) {
77
+ msg.textContent = '请求失败: ' + e.message;
78
+ } finally {
79
+ btn.disabled = false;
80
+ }
81
+ };
82
+ load();
83
+ setInterval(load, 8000);
84
+ </script>
85
+ </body>
86
+ </html>`;
87
+ }
88
+ export function startDiagnosticsServer(options) {
89
+ const host = options.host ?? process.env.WINMATRIX_DAEMON_DIAG_HOST ?? DEFAULT_HOST;
90
+ const port = Number(process.env.WINMATRIX_DAEMON_DIAG_PORT ?? options.port ?? DEFAULT_PORT);
91
+ const server = http.createServer((req, res) => {
92
+ const url = new URL(req.url ?? '/', `http://${host}`);
93
+ try {
94
+ if (req.method === 'GET' && url.pathname === '/') {
95
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
96
+ res.end(htmlDashboard());
97
+ return;
98
+ }
99
+ if (req.method === 'GET' && url.pathname === '/api/status') {
100
+ json(res, 200, { success: true, data: options.getContext() });
101
+ return;
102
+ }
103
+ if (req.method === 'GET' && url.pathname === '/api/agents') {
104
+ json(res, 200, {
105
+ success: true,
106
+ data: options.agentManager.listAgents(),
107
+ });
108
+ return;
109
+ }
110
+ if (req.method === 'GET' && url.pathname === '/api/tasks') {
111
+ json(res, 200, {
112
+ success: true,
113
+ data: options.agentManager.getRecentTaskEvents(),
114
+ });
115
+ return;
116
+ }
117
+ if (req.method === 'GET' && url.pathname === '/api/logs') {
118
+ const lines = Math.min(2000, Math.max(1, Number(url.searchParams.get('lines')) || 200));
119
+ json(res, 200, {
120
+ success: true,
121
+ data: {
122
+ logDir: options.fileLogger.getLogDirectory(),
123
+ lines: options.fileLogger.getRecentLines(lines),
124
+ },
125
+ });
126
+ return;
127
+ }
128
+ if (req.method === 'POST' && url.pathname === '/api/rescan-profiles') {
129
+ if (options.onRescanProfiles) {
130
+ options.onRescanProfiles().then((result) => {
131
+ json(res, result.ok ? 200 : 500, { success: result.ok, data: result.ok ? null : undefined, error: result.error });
132
+ }).catch((e) => {
133
+ json(res, 500, { success: false, error: e instanceof Error ? e.message : String(e) });
134
+ });
135
+ }
136
+ else {
137
+ json(res, 501, { success: false, error: 'Profile rescan not configured' });
138
+ }
139
+ return;
140
+ }
141
+ json(res, 404, { success: false, error: 'Not found' });
142
+ }
143
+ catch (e) {
144
+ json(res, 500, { success: false, error: e instanceof Error ? e.message : String(e) });
145
+ }
146
+ });
147
+ server.listen(port, host, () => {
148
+ console.log(`[daemon] Diagnostics UI http://${host}:${port}/`);
149
+ });
150
+ server.on('error', (err) => {
151
+ console.error(`[daemon] Diagnostics server error: ${err instanceof Error ? err.message : String(err)}`);
152
+ });
153
+ return server;
154
+ }
155
+ //# sourceMappingURL=DiagnosticsServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DiagnosticsServer.js","sourceRoot":"","sources":["../../src/core/DiagnosticsServer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,YAAY,GAAG,KAAK,CAAC;AAY3B,SAAS,IAAI,CAAC,GAAwB,EAAE,IAAY,EAAE,IAAa;IACjE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE;QAClB,cAAc,EAAE,iCAAiC;QACjD,eAAe,EAAE,UAAU;KAC5B,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,aAAa;IACpB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqED,CAAC;AACT,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAOtC;IACC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,YAAY,CAAC;IACpF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,OAAO,CAAC,IAAI,IAAI,YAAY,CAAC,CAAC;IAE5F,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;QAEtD,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;gBACjD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACnE,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;gBACzB,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;gBAC3D,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;gBAC9D,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;gBAC3D,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;oBACb,OAAO,EAAE,IAAI;oBACb,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,UAAU,EAAE;iBACxC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;gBAC1D,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;oBACb,OAAO,EAAE,IAAI;oBACb,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,mBAAmB,EAAE;iBACjD,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;gBACxF,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;oBACb,OAAO,EAAE,IAAI;oBACb,IAAI,EAAE;wBACJ,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE;wBAC5C,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,CAAC;qBAChD;iBACF,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,sBAAsB,EAAE,CAAC;gBACrE,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;oBAC7B,OAAO,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;wBACzC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;oBACpH,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;wBACb,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACxF,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC;gBAC7E,CAAC;gBACD,OAAO;YACT,CAAC;YACD,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QACzD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;QAC7B,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACzB,OAAO,CAAC,KAAK,CAAC,sCAAsC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1G,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * WinMatrix Daemon - Installation ID
3
+ *
4
+ * Generates a unique installation UUID on first run and persists it to
5
+ * ~/.winmatrix/installation (0600). The ~/.winmatrix directory is created
6
+ * with 0700 permissions. On subsequent runs, the existing ID is read back.
7
+ */
8
+ /**
9
+ * Get the persisted installation ID, or generate and persist a new one.
10
+ * The ~/.winmatrix directory is created with 0700 if it doesn't exist.
11
+ * The installation file is written with 0600 permissions.
12
+ */
13
+ export declare function getOrCreateInstallationId(): string;
14
+ //# sourceMappingURL=InstallationId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstallationId.d.ts","sourceRoot":"","sources":["../../src/core/InstallationId.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiCH;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAelD"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * WinMatrix Daemon - Installation ID
3
+ *
4
+ * Generates a unique installation UUID on first run and persists it to
5
+ * ~/.winmatrix/installation (0600). The ~/.winmatrix directory is created
6
+ * with 0700 permissions. On subsequent runs, the existing ID is read back.
7
+ */
8
+ import { randomUUID } from 'node:crypto';
9
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'node:fs';
10
+ import { homedir } from 'node:os';
11
+ import path from 'node:path';
12
+ /* ── Constants ── */
13
+ const DAEMON_HOME_DIR = '.winmatrix';
14
+ const INSTALLATION_FILE = 'installation';
15
+ /* ── Helpers ── */
16
+ function getDaemonHome() {
17
+ return path.join(homedir(), DAEMON_HOME_DIR);
18
+ }
19
+ function getInstallationPath() {
20
+ return path.join(getDaemonHome(), INSTALLATION_FILE);
21
+ }
22
+ function ensureDaemonHome() {
23
+ const dir = getDaemonHome();
24
+ if (!existsSync(dir)) {
25
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
26
+ // Explicit chmod to guarantee 0700 regardless of umask
27
+ chmodSync(dir, 0o700);
28
+ }
29
+ }
30
+ /* ── Public API ── */
31
+ /**
32
+ * Get the persisted installation ID, or generate and persist a new one.
33
+ * The ~/.winmatrix directory is created with 0700 if it doesn't exist.
34
+ * The installation file is written with 0600 permissions.
35
+ */
36
+ export function getOrCreateInstallationId() {
37
+ ensureDaemonHome();
38
+ const filePath = getInstallationPath();
39
+ if (existsSync(filePath)) {
40
+ const id = readFileSync(filePath, 'utf-8').trim();
41
+ if (id.length > 0) {
42
+ return id;
43
+ }
44
+ // File exists but is empty — regenerate
45
+ }
46
+ const id = randomUUID();
47
+ writeFileSync(filePath, id, { mode: 0o600 });
48
+ return id;
49
+ }
50
+ //# sourceMappingURL=InstallationId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstallationId.js","sourceRoot":"","sources":["../../src/core/InstallationId.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,qBAAqB;AAErB,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEzC,mBAAmB;AAEnB,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,iBAAiB,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,uDAAuD;QACvD,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,sBAAsB;AAEtB;;;;GAIG;AACH,MAAM,UAAU,yBAAyB;IACvC,gBAAgB,EAAE,CAAC;IACnB,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IAEvC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,wCAAwC;IAC1C,CAAC;IAED,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;IACxB,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7C,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * WinMatrix Daemon - Runtime Availability Reporter
3
+ *
4
+ * Periodically re-detects runtime availability every 5 minutes and reports
5
+ * status changes to the WinMatrix server via the `runtime.availability` WebSocket event.
6
+ * Only sends events when reachability actually changes (edge-triggered).
7
+ */
8
+ import type { DaemonClient } from '@winmatrix/agent-sdk';
9
+ export interface RuntimeAvailabilityEvent {
10
+ name: string;
11
+ available: boolean;
12
+ checkedAt: string;
13
+ error?: string;
14
+ }
15
+ /**
16
+ * Start periodic runtime availability monitoring.
17
+ *
18
+ * Every `intervalMs` the daemon re-detects all runtimes and sends
19
+ * `runtime.availability` events only for those whose availability
20
+ * has changed since the last check.
21
+ *
22
+ * @returns A stop function that clears the interval timer.
23
+ */
24
+ export declare function startRuntimeAvailabilityReporter(client: DaemonClient, options?: {
25
+ intervalMs?: number;
26
+ }): () => void;
27
+ //# sourceMappingURL=RuntimeAvailabilityReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeAvailabilityReporter.d.ts","sourceRoot":"","sources":["../../src/core/RuntimeAvailabilityReporter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuBD;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,MAAM,IAAI,CAkDZ"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * WinMatrix Daemon - Runtime Availability Reporter
3
+ *
4
+ * Periodically re-detects runtime availability every 5 minutes and reports
5
+ * status changes to the WinMatrix server via the `runtime.availability` WebSocket event.
6
+ * Only sends events when reachability actually changes (edge-triggered).
7
+ */
8
+ import { detectRuntimes } from '@winmatrix/agent-sdk';
9
+ /* ── Constants ── */
10
+ const DEFAULT_INTERVAL_MS = 5 * 60 * 1000;
11
+ /* ── Helpers ── */
12
+ function runtimeToKey(r) {
13
+ return r.name;
14
+ }
15
+ function buildAvailabilityEvent(r) {
16
+ return {
17
+ name: r.name,
18
+ available: r.available,
19
+ checkedAt: new Date().toISOString(),
20
+ ...(r.available ? {} : { error: `Runtime '${r.name}' is not available` }),
21
+ };
22
+ }
23
+ /* ── Public API ── */
24
+ /**
25
+ * Start periodic runtime availability monitoring.
26
+ *
27
+ * Every `intervalMs` the daemon re-detects all runtimes and sends
28
+ * `runtime.availability` events only for those whose availability
29
+ * has changed since the last check.
30
+ *
31
+ * @returns A stop function that clears the interval timer.
32
+ */
33
+ export function startRuntimeAvailabilityReporter(client, options) {
34
+ const intervalMs = options?.intervalMs ?? DEFAULT_INTERVAL_MS;
35
+ const lastState = new Map();
36
+ let stopped = false;
37
+ const sendEvent = (event) => {
38
+ if (stopped)
39
+ return;
40
+ if (client.getState() !== 'registered')
41
+ return;
42
+ try {
43
+ client.sendFrame({
44
+ type: 'event',
45
+ event: 'runtime.availability',
46
+ payload: event,
47
+ });
48
+ }
49
+ catch {
50
+ // Ignore send errors — will retry next interval
51
+ }
52
+ };
53
+ const tick = () => {
54
+ if (stopped)
55
+ return;
56
+ if (client.getState() !== 'registered')
57
+ return;
58
+ const runtimes = detectRuntimes();
59
+ for (const runtime of runtimes) {
60
+ const key = runtimeToKey(runtime);
61
+ const previous = lastState.get(key);
62
+ if (previous !== runtime.available) {
63
+ lastState.set(key, runtime.available);
64
+ sendEvent(buildAvailabilityEvent(runtime));
65
+ }
66
+ }
67
+ };
68
+ // Run immediately on start to establish baseline
69
+ const runtimes = detectRuntimes();
70
+ for (const runtime of runtimes) {
71
+ lastState.set(runtimeToKey(runtime), runtime.available);
72
+ }
73
+ const timer = setInterval(tick, intervalMs);
74
+ return () => {
75
+ stopped = true;
76
+ clearInterval(timer);
77
+ };
78
+ }
79
+ //# sourceMappingURL=RuntimeAvailabilityReporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeAvailabilityReporter.js","sourceRoot":"","sources":["../../src/core/RuntimeAvailabilityReporter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAAgB,MAAM,sBAAsB,CAAC;AAYpE,qBAAqB;AAErB,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAE1C,mBAAmB;AAEnB,SAAS,YAAY,CAAC,CAAU;IAC9B,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,sBAAsB,CAAC,CAAU;IACxC,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,IAAI,oBAAoB,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,sBAAsB;AAEtB;;;;;;;;GAQG;AACH,MAAM,UAAU,gCAAgC,CAC9C,MAAoB,EACpB,OAAiC;IAEjC,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,mBAAmB,CAAC;IAE9D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,SAAS,GAAG,CAAC,KAA+B,EAAQ,EAAE;QAC1D,IAAI,OAAO;YAAE,OAAO;QACpB,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,YAAY;YAAE,OAAO;QAE/C,IAAI,CAAC;YACH,MAAM,CAAC,SAAS,CAAC;gBACf,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,sBAAsB;gBAC7B,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,IAAI,OAAO;YAAE,OAAO;QACpB,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,YAAY;YAAE,OAAO;QAE/C,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;QAElC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEpC,IAAI,QAAQ,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;gBACnC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;gBACtC,SAAS,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,iDAAiD;IACjD,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAE5C,OAAO,GAAG,EAAE;QACV,OAAO,GAAG,IAAI,CAAC;QACf,aAAa,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * WorkspaceScanner - 扫描 workDir 获取项目元数据
3
+ *
4
+ * 在 Agent 注册成功后调用,将扫描结果通过 Daemon WS 上报至 Server。
5
+ * 安全约束:不上报绝对路径、文件内容、环境变量、含凭据的 Git remote。
6
+ */
7
+ interface TechStack {
8
+ [key: string]: string;
9
+ }
10
+ interface WorkspaceInfo {
11
+ pathSummary: string;
12
+ gitRemote?: string;
13
+ gitBranch?: string;
14
+ techStack?: TechStack;
15
+ scripts?: Record<string, string>;
16
+ installedCli?: string[];
17
+ }
18
+ interface RuntimeInfo {
19
+ version?: string;
20
+ available: boolean;
21
+ }
22
+ export interface WorkspaceReportPayload {
23
+ agentId: string;
24
+ workdir?: WorkspaceInfo;
25
+ runtimes?: Record<string, RuntimeInfo>;
26
+ }
27
+ /**
28
+ * 扫描指定工作目录,提取项目元数据。
29
+ * 所有 git/which 调用均带 5s 超时,失败不影响整体结果。
30
+ */
31
+ export declare function scanWorkDir(workDir: string): Promise<WorkspaceInfo>;
32
+ /**
33
+ * 脱敏 Git remote URL:
34
+ * - HTTPS: 移除 userinfo(用户名:密码@)
35
+ * - SSH: 保持原样(git@host:org/repo)
36
+ * - 仅保留 host/org/repo
37
+ */
38
+ export declare function sanitizeGitRemote(remote: string): string;
39
+ /**
40
+ * 检测运行时可用的运行时版本信息。
41
+ * 基于 agentType 选择性检测,避免不必要的磁盘扫描。
42
+ */
43
+ export declare function detectRuntimeInfo(runtimeBinary: string): Promise<RuntimeInfo>;
44
+ export {};
45
+ //# sourceMappingURL=WorkspaceScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspaceScanner.d.ts","sourceRoot":"","sources":["../../src/core/WorkspaceScanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,UAAU,SAAS;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACxC;AAQD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA2HzE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQnF"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * WorkspaceScanner - 扫描 workDir 获取项目元数据
3
+ *
4
+ * 在 Agent 注册成功后调用,将扫描结果通过 Daemon WS 上报至 Server。
5
+ * 安全约束:不上报绝对路径、文件内容、环境变量、含凭据的 Git remote。
6
+ */
7
+ import { readdir, readFile } from 'node:fs/promises';
8
+ import { basename } from 'node:path';
9
+ import { execFile } from 'node:child_process';
10
+ import { promisify } from 'node:util';
11
+ const execFileAsync = promisify(execFile);
12
+ /** 常用 CLI 工具列表 */
13
+ const COMMON_CLI_TOOLS = ['git', 'docker', 'pnpm', 'yarn', 'npm', 'python', 'go', 'cargo', 'node'];
14
+ /** 对 execFile 调用的超时(毫秒) */
15
+ const EXEC_TIMEOUT_MS = 5000;
16
+ /**
17
+ * 扫描指定工作目录,提取项目元数据。
18
+ * 所有 git/which 调用均带 5s 超时,失败不影响整体结果。
19
+ */
20
+ export async function scanWorkDir(workDir) {
21
+ const result = {
22
+ pathSummary: basename(workDir),
23
+ };
24
+ try {
25
+ const files = await readdir(workDir);
26
+ // 仅判断是否存在 package.json,不读取内容(后续统一读取)
27
+ const hasPackageJson = files.includes('package.json');
28
+ // 读取 package.json 提取关键字段
29
+ if (hasPackageJson) {
30
+ try {
31
+ const pkgRaw = await readFile(`${workDir}/package.json`, 'utf-8');
32
+ const pkg = JSON.parse(pkgRaw);
33
+ const techStack = {};
34
+ if (pkg.name) {
35
+ // name 仅用于内部识别
36
+ }
37
+ // 提取 scripts(最多 20 个 key,防止 package.json 异常膨胀)
38
+ const scriptKeys = Object.keys(pkg.scripts ?? {}).slice(0, 20);
39
+ if (scriptKeys.length > 0) {
40
+ result.scripts = {};
41
+ for (const key of scriptKeys) {
42
+ result.scripts[key] = String(pkg.scripts[key]);
43
+ }
44
+ }
45
+ // 提取技术栈信息(从 dependencies/devDependencies 推断)
46
+ const allDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
47
+ const depNames = Object.keys(allDeps);
48
+ if (depNames.includes('vue')) {
49
+ techStack.framework = 'vue';
50
+ techStack.frameworkVersion = allDeps.vue;
51
+ }
52
+ else if (depNames.includes('react')) {
53
+ techStack.framework = 'react';
54
+ techStack.frameworkVersion = allDeps.react;
55
+ }
56
+ if (depNames.includes('vite')) {
57
+ techStack.bundler = 'vite';
58
+ techStack.bundlerVersion = allDeps.vite;
59
+ }
60
+ else if (depNames.includes('webpack')) {
61
+ techStack.bundler = 'webpack';
62
+ techStack.bundlerVersion = allDeps.webpack;
63
+ }
64
+ if (depNames.includes('typescript')) {
65
+ techStack.language = 'typescript';
66
+ techStack.languageVersion = allDeps.typescript;
67
+ }
68
+ else if (allDeps['@types/node'] || depNames.some((d) => d.startsWith('@types/'))) {
69
+ techStack.language = 'typescript';
70
+ }
71
+ const runtimeEntry = depNames.find((d) => d === 'next' || d === 'nuxt' || d === 'express' || d === 'fastify');
72
+ if (runtimeEntry) {
73
+ techStack.runtime = runtimeEntry;
74
+ techStack.runtimeVersion = allDeps[runtimeEntry];
75
+ }
76
+ else if (depNames.includes('node')) {
77
+ techStack.runtime = 'node';
78
+ }
79
+ // 包管理器检测
80
+ const lockFiles = files.filter((f) => ['pnpm-lock.yaml', 'yarn.lock', 'package-lock.json', 'bun.lockb'].includes(f));
81
+ if (lockFiles.includes('pnpm-lock.yaml'))
82
+ techStack.packageManager = 'pnpm';
83
+ else if (lockFiles.includes('yarn.lock'))
84
+ techStack.packageManager = 'yarn';
85
+ else if (lockFiles.includes('package-lock.json'))
86
+ techStack.packageManager = 'npm';
87
+ else if (lockFiles.includes('bun.lockb'))
88
+ techStack.packageManager = 'bun';
89
+ if (Object.keys(techStack).length > 0) {
90
+ result.techStack = techStack;
91
+ }
92
+ }
93
+ catch {
94
+ // package.json 读取或解析失败,静默跳过
95
+ }
96
+ }
97
+ // Git 信息
98
+ try {
99
+ const { stdout: remoteOut } = await execFileAsync('git', ['-C', workDir, 'remote', 'get-url', 'origin'], { timeout: EXEC_TIMEOUT_MS });
100
+ result.gitRemote = sanitizeGitRemote(remoteOut.trim());
101
+ }
102
+ catch {
103
+ // git remote 获取失败
104
+ }
105
+ try {
106
+ const { stdout: branchOut } = await execFileAsync('git', ['-C', workDir, 'rev-parse', '--abbrev-ref', 'HEAD'], { timeout: EXEC_TIMEOUT_MS });
107
+ result.gitBranch = branchOut.trim();
108
+ }
109
+ catch {
110
+ // git branch 获取失败
111
+ }
112
+ // 扫描已安装 CLI 工具
113
+ const installedCli = [];
114
+ for (const cli of COMMON_CLI_TOOLS) {
115
+ try {
116
+ await execFileAsync('which', [cli], { timeout: EXEC_TIMEOUT_MS });
117
+ installedCli.push(cli);
118
+ }
119
+ catch {
120
+ // CLI 未安装
121
+ }
122
+ }
123
+ if (installedCli.length > 0) {
124
+ result.installedCli = installedCli;
125
+ }
126
+ }
127
+ catch {
128
+ // readdir 失败(权限不足或路径不存在),返回基本信息
129
+ }
130
+ return result;
131
+ }
132
+ /**
133
+ * 脱敏 Git remote URL:
134
+ * - HTTPS: 移除 userinfo(用户名:密码@)
135
+ * - SSH: 保持原样(git@host:org/repo)
136
+ * - 仅保留 host/org/repo
137
+ */
138
+ export function sanitizeGitRemote(remote) {
139
+ // HTTPS with credentials: https://user:token@github.com/org/repo.git
140
+ const httpsMatch = remote.match(/^https?:\/\/(?:[^@]+@)?(.+)$/i);
141
+ if (httpsMatch) {
142
+ return httpsMatch[1].replace(/\.git$/, '');
143
+ }
144
+ // SSH: git@github.com:org/repo.git - already safe
145
+ const sshMatch = remote.match(/^git@(.+)$/);
146
+ if (sshMatch) {
147
+ return sshMatch[0].replace(/\.git$/, '');
148
+ }
149
+ // Unknown format: return as-is but strip potential userinfo
150
+ return remote.replace(/\/\/[^@]+@/, '//').replace(/\.git$/, '');
151
+ }
152
+ /**
153
+ * 检测运行时可用的运行时版本信息。
154
+ * 基于 agentType 选择性检测,避免不必要的磁盘扫描。
155
+ */
156
+ export async function detectRuntimeInfo(runtimeBinary) {
157
+ try {
158
+ const { stdout } = await execFileAsync(runtimeBinary, ['--version'], { timeout: EXEC_TIMEOUT_MS });
159
+ const version = stdout.trim().split('\n')[0]; // 取第一行
160
+ return { version, available: true };
161
+ }
162
+ catch {
163
+ return { available: false };
164
+ }
165
+ }
166
+ //# sourceMappingURL=WorkspaceScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspaceScanner.js","sourceRoot":"","sources":["../../src/core/WorkspaceScanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * WinMatrix Daemon v2 — CLI Entry Point
4
+ *
5
+ * 使用 @winmatrix/agent-sdk 的 DaemonClient + AgentAdapter 架构。
6
+ * 方案 B:adapter 在 daemon 进程内直接运行,不再 spawn 子进程。
7
+ *
8
+ * 1. 解析 CLI 参数
9
+ * 2. 加载或生成持久化 installation UUID
10
+ * 3. 检测本地 AI runtimes
11
+ * 4. 注册 adapters 到全局 registry
12
+ * 5. 连接 WinMatrix Server (DaemonClient)
13
+ * 6. 监听 agent.create / agent.stop 信令
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG"}