@lnar/cli 0.0.1-dev.5da411d → 0.0.1-dev.632e82b
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 +16 -54
- package/dist/api-client.d.ts +19 -0
- package/dist/api-client.js +40 -0
- package/dist/api-client.js.map +1 -1
- package/dist/auth.d.ts +20 -0
- package/dist/auth.js +74 -0
- package/dist/auth.js.map +1 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +68 -0
- package/dist/browser.js.map +1 -0
- package/dist/capture-client.d.ts +13 -0
- package/dist/capture-client.js +37 -0
- package/dist/capture-client.js.map +1 -0
- package/dist/capture-worker.d.ts +14 -0
- package/dist/capture-worker.js +105 -0
- package/dist/capture-worker.js.map +1 -0
- package/dist/cli.js +21 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +114 -1
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +19 -9
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/record.d.ts +7 -0
- package/dist/commands/record.js +117 -0
- package/dist/commands/record.js.map +1 -0
- package/dist/commands/scan.js +12 -0
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/sync.js +3 -0
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/up.js +19 -0
- package/dist/commands/up.js.map +1 -1
- package/dist/machine-id.d.ts +2 -0
- package/dist/machine-id.js +48 -0
- package/dist/machine-id.js.map +1 -0
- package/dist/pending-client.d.ts +1 -1
- package/dist/recording/bundle.d.ts +25 -0
- package/dist/recording/bundle.js +55 -0
- package/dist/recording/bundle.js.map +1 -0
- package/dist/recording/capture.d.ts +53 -0
- package/dist/recording/capture.js +163 -0
- package/dist/recording/capture.js.map +1 -0
- package/dist/recording/session.d.ts +30 -0
- package/dist/recording/session.js +47 -0
- package/dist/recording/session.js.map +1 -0
- package/dist/recording/types.d.ts +59 -0
- package/dist/recording/types.js +8 -0
- package/dist/recording/types.js.map +1 -0
- package/dist/run-client.d.ts +19 -0
- package/dist/run-client.js +44 -0
- package/dist/run-client.js.map +1 -0
- package/dist/run-worker.d.ts +25 -0
- package/dist/run-worker.js +85 -0
- package/dist/run-worker.js.map +1 -0
- package/dist/runtime/actions.d.ts +13 -0
- package/dist/runtime/actions.js +107 -0
- package/dist/runtime/actions.js.map +1 -0
- package/dist/runtime/client.d.ts +3 -0
- package/dist/runtime/client.js +85 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/login.d.ts +20 -0
- package/dist/runtime/login.js +34 -0
- package/dist/runtime/login.js.map +1 -0
- package/dist/runtime/loop.d.ts +28 -0
- package/dist/runtime/loop.js +68 -0
- package/dist/runtime/loop.js.map +1 -0
- package/dist/runtime/playbook.d.ts +49 -0
- package/dist/runtime/playbook.js +73 -0
- package/dist/runtime/playbook.js.map +1 -0
- package/dist/runtime/runner.d.ts +20 -0
- package/dist/runtime/runner.js +54 -0
- package/dist/runtime/runner.js.map +1 -0
- package/dist/runtime/types.d.ts +69 -0
- package/dist/runtime/types.js +10 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/scanners/claude-code-skills.d.ts +6 -0
- package/dist/scanners/claude-code-skills.js +201 -0
- package/dist/scanners/claude-code-skills.js.map +1 -0
- package/dist/scanners/claude-code.js +10 -3
- package/dist/scanners/claude-code.js.map +1 -1
- package/dist/scanners/index.js +3 -2
- package/dist/scanners/index.js.map +1 -1
- package/dist/service/files.d.ts +14 -2
- package/dist/service/files.js +16 -4
- package/dist/service/files.js.map +1 -1
- package/dist/service/install.js +83 -16
- package/dist/service/install.js.map +1 -1
- package/dist/sse-client.d.ts +72 -0
- package/dist/sse-client.js +174 -0
- package/dist/sse-client.js.map +1 -0
- package/dist/types.d.ts +43 -3
- package/dist/types.js +34 -2
- package/dist/types.js.map +1 -1
- package/dist/writers/claude-code.js +31 -10
- package/dist/writers/claude-code.js.map +1 -1
- package/dist/writers/registry.js +0 -4
- package/dist/writers/registry.js.map +1 -1
- package/package.json +11 -1
- package/dist/scanners/chatgpt.d.ts +0 -20
- package/dist/scanners/chatgpt.js +0 -49
- package/dist/scanners/chatgpt.js.map +0 -1
- package/dist/writers/chatgpt.d.ts +0 -8
- package/dist/writers/chatgpt.js +0 -12
- package/dist/writers/chatgpt.js.map +0 -1
package/dist/commands/daemon.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { hostname } from 'node:os';
|
|
2
2
|
import { ApiError, postSnapshot } from '../api-client.js';
|
|
3
|
+
import { executePendingCaptures } from '../capture-worker.js';
|
|
3
4
|
import { DEFAULT_CLIENT_ID, loadConfig, saveConfig } from '../config.js';
|
|
5
|
+
import { loadOrCreateMachineId } from '../machine-id.js';
|
|
4
6
|
import { OAuthError, refreshAccessToken } from '../oauth-client.js';
|
|
5
7
|
import { listPendingForHost, reportApplied, reportFailed, } from '../pending-client.js';
|
|
8
|
+
import { executePendingRuns } from '../run-worker.js';
|
|
6
9
|
import { runAllScanners } from '../scanners/index.js';
|
|
10
|
+
import { runSseClient, SseFatalError } from '../sse-client.js';
|
|
7
11
|
import { getWriter } from '../writers/registry.js';
|
|
8
12
|
const DEFAULT_INTERVAL_SECONDS = 30;
|
|
9
13
|
const ACCESS_TOKEN_REFRESH_SKEW_SECONDS = 60;
|
|
@@ -60,8 +64,10 @@ const bearerFor = (config) => {
|
|
|
60
64
|
};
|
|
61
65
|
const runScanAndSync = async (config) => {
|
|
62
66
|
const agents = await runAllScanners();
|
|
67
|
+
const machineId = await loadOrCreateMachineId();
|
|
63
68
|
const scan = {
|
|
64
69
|
hostname: hostname(),
|
|
70
|
+
machineId,
|
|
65
71
|
scannedAt: new Date().toISOString(),
|
|
66
72
|
agents,
|
|
67
73
|
};
|
|
@@ -97,6 +103,31 @@ const applyPending = async (config, change) => {
|
|
|
97
103
|
const runOnce = async (config) => {
|
|
98
104
|
// 1. 最新スナップショットを送信 → サーバ側 agent ID が最新化される
|
|
99
105
|
await runScanAndSync(config);
|
|
106
|
+
// 1.5. 録画 run-job をローカル実行する (Demo-to-MCP)。失敗しても以降の
|
|
107
|
+
// スキャン / pending 適用は継続させる (機能を分離する)。
|
|
108
|
+
try {
|
|
109
|
+
const ran = await executePendingRuns(config.apiBaseUrl, bearerFor(config), hostname());
|
|
110
|
+
if (ran > 0) {
|
|
111
|
+
process.stdout.write(`lnar daemon: executed ${ran} recording run(s)\n`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
116
|
+
process.stderr.write(`lnar daemon: recording runs error: ${message}\n`);
|
|
117
|
+
}
|
|
118
|
+
// 1.6. 録画キャプチャジョブ (start_recording 由来) をローカル録画する。
|
|
119
|
+
// ブラウザを開いて人間の実演を待つため時間がかかるが、失敗・例外しても
|
|
120
|
+
// 以降の処理は継続させる。
|
|
121
|
+
try {
|
|
122
|
+
const captured = await executePendingCaptures(config.apiBaseUrl, bearerFor(config), hostname());
|
|
123
|
+
if (captured > 0) {
|
|
124
|
+
process.stdout.write(`lnar daemon: ran ${captured} recording capture(s)\n`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
129
|
+
process.stderr.write(`lnar daemon: recording captures error: ${message}\n`);
|
|
130
|
+
}
|
|
100
131
|
// 2. 自 host 向けの pending を取得
|
|
101
132
|
const host = hostname();
|
|
102
133
|
const pending = await listPendingForHost(config.apiBaseUrl, bearerFor(config), host);
|
|
@@ -112,6 +143,61 @@ const runOnce = async (config) => {
|
|
|
112
143
|
// 3. 反映後に再スキャン送信して dashboard の表示も最新化
|
|
113
144
|
await runScanAndSync(config);
|
|
114
145
|
};
|
|
146
|
+
/**
|
|
147
|
+
* runOnce が重複実行されないよう mutex を取る。SSE 通知と polling が同時に発火
|
|
148
|
+
* したとき、両方が runOnce を呼んで pending を二重処理するのを防ぐ。pending が
|
|
149
|
+
* あれば即時実行、すでに走っていれば 1 回だけ追い焚き予約 (coalesce)。
|
|
150
|
+
*/
|
|
151
|
+
const createRunOnceMutex = () => {
|
|
152
|
+
let inFlight = null;
|
|
153
|
+
let queued = false;
|
|
154
|
+
const trigger = (config) => {
|
|
155
|
+
if (inFlight) {
|
|
156
|
+
// すでに走っているなら次回追い焚き予約 (複数回呼ばれても 1 回に集約)。
|
|
157
|
+
queued = true;
|
|
158
|
+
return inFlight;
|
|
159
|
+
}
|
|
160
|
+
const run = async () => {
|
|
161
|
+
try {
|
|
162
|
+
await runOnce(config);
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
if (queued) {
|
|
166
|
+
queued = false;
|
|
167
|
+
// 1 回だけ追い焚き。caller の最新 trigger に応答する。
|
|
168
|
+
inFlight = run();
|
|
169
|
+
await inFlight;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
inFlight = run().finally(() => {
|
|
174
|
+
inFlight = null;
|
|
175
|
+
});
|
|
176
|
+
return inFlight;
|
|
177
|
+
};
|
|
178
|
+
return { trigger };
|
|
179
|
+
};
|
|
180
|
+
const startSseListener = (config, host, trigger, signal) => {
|
|
181
|
+
const url = new URL('/v1/monitoring/daemon/events', config.apiBaseUrl);
|
|
182
|
+
url.searchParams.set('hostname', host);
|
|
183
|
+
process.stdout.write(`lnar daemon: SSE connecting to ${url.toString()}\n`);
|
|
184
|
+
return runSseClient({
|
|
185
|
+
url: url.toString(),
|
|
186
|
+
token: bearerFor(config),
|
|
187
|
+
signal,
|
|
188
|
+
onOpen: async () => {
|
|
189
|
+
// 接続 / 再接続のたびに 1 回 fetch (取りこぼし防止)
|
|
190
|
+
process.stdout.write('lnar daemon: SSE connected\n');
|
|
191
|
+
await trigger(config);
|
|
192
|
+
},
|
|
193
|
+
onEvent: async (event) => {
|
|
194
|
+
if (event.type === 'pending_created') {
|
|
195
|
+
process.stdout.write('lnar daemon: SSE event → fetching pending\n');
|
|
196
|
+
await trigger(config);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
};
|
|
115
201
|
export const runDaemon = async (options = {}) => {
|
|
116
202
|
const initial = await loadConfig();
|
|
117
203
|
if (initial == null) {
|
|
@@ -119,13 +205,36 @@ export const runDaemon = async (options = {}) => {
|
|
|
119
205
|
process.exit(1);
|
|
120
206
|
}
|
|
121
207
|
const interval = (options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS) * 1000;
|
|
208
|
+
const enableSse = options.enableSse ?? !options.once;
|
|
209
|
+
const host = hostname();
|
|
210
|
+
const { trigger } = createRunOnceMutex();
|
|
122
211
|
let running = true;
|
|
212
|
+
const sseAbort = new AbortController();
|
|
123
213
|
const stop = () => {
|
|
124
214
|
running = false;
|
|
215
|
+
sseAbort.abort();
|
|
125
216
|
process.stdout.write('\nlnar daemon: shutting down…\n');
|
|
126
217
|
};
|
|
127
218
|
process.on('SIGINT', stop);
|
|
128
219
|
process.on('SIGTERM', stop);
|
|
220
|
+
// SSE listener は background で常時走らせる。fatal error (401 等) は
|
|
221
|
+
// catch して polling loop 側の token refresh に任せる。
|
|
222
|
+
// Box にしないと TS が closure 内の代入をフローに反映できず never 扱いになる。
|
|
223
|
+
const sseTaskRef = { current: null };
|
|
224
|
+
const startSse = (config) => {
|
|
225
|
+
if (!enableSse)
|
|
226
|
+
return;
|
|
227
|
+
sseTaskRef.current = startSseListener(config, host, trigger, sseAbort.signal).catch((err) => {
|
|
228
|
+
if (err instanceof SseFatalError) {
|
|
229
|
+
process.stderr.write(`lnar daemon: SSE fatal (${err.status}); falling back to polling only\n`);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
233
|
+
process.stderr.write(`lnar daemon: SSE listener stopped: ${message}\n`);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
startSse(initial);
|
|
129
238
|
while (running) {
|
|
130
239
|
let config;
|
|
131
240
|
try {
|
|
@@ -140,7 +249,7 @@ export const runDaemon = async (options = {}) => {
|
|
|
140
249
|
continue;
|
|
141
250
|
}
|
|
142
251
|
try {
|
|
143
|
-
await
|
|
252
|
+
await trigger(config);
|
|
144
253
|
}
|
|
145
254
|
catch (err) {
|
|
146
255
|
if (err instanceof ApiError && err.status === 401) {
|
|
@@ -154,5 +263,9 @@ export const runDaemon = async (options = {}) => {
|
|
|
154
263
|
break;
|
|
155
264
|
await sleep(interval);
|
|
156
265
|
}
|
|
266
|
+
if (sseTaskRef.current) {
|
|
267
|
+
sseAbort.abort();
|
|
268
|
+
await sseTaskRef.current.catch(() => undefined);
|
|
269
|
+
}
|
|
157
270
|
};
|
|
158
271
|
//# sourceMappingURL=daemon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAqB,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,kBAAkB,EAElB,aAAa,EACb,YAAY,GACb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AASnD,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAE7C,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACtB,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEL,MAAM,oBAAoB,GAAG,CAAC,MAAoB,EAAW,EAAE;IAC7D,IAAI,CAAC,MAAM,CAAC,oBAAoB;QAAE,OAAO,KAAK,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,iCAAiC,GAAG,IAAI,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,KAAK,EAAE,MAAoB,EAAyB,EAAE;IAC5E,IAAI,CAAC,MAAM,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACtD,IAAI,KAAqD,CAAC;IAC1D,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IACrF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,UAAU,IAAI,GAAG,CAAC,SAAS,KAAK,eAAe,EAAE,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,oBAAoB,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1F,MAAM,IAAI,GAAkC;QAC1C,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,WAAW,EAAE,KAAK,CAAC,YAAY;QAC/B,YAAY,EAAE,KAAK,CAAC,aAAa,IAAI,MAAM,CAAC,YAAY;QACxD,oBAAoB;QACpB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM;QAC5D,QAAQ;KACT,CAAC;IACF,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,MAAoB,EAAU,EAAE;IACjD,IAAI,MAAM,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC,WAAW,CAAC;IAClD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IACxC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC9C,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,KAAK,EAAE,MAAoB,EAAiB,EAAE;IACnE,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;IACtC,MAAM,SAAS,GAAG,MAAM,qBAAqB,EAAE,CAAC;IAChD,MAAM,IAAI,GAAe;QACvB,QAAQ,EAAE,QAAQ,EAAE;QACpB,SAAS;QACT,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM;KACP,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAChC,MAAM,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,KAAK,EAAE,MAAoB,EAAE,MAAqB,EAAiB,EAAE;IACxF,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,MAAM,YAAY,CAChB,MAAM,CAAC,UAAU,EACjB,KAAK,EACL,MAAM,CAAC,EAAE,EACT,uCAAuC,MAAM,CAAC,UAAU,EAAE,CAC3D,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;YAC7B,MAAM,YAAY,CAChB,MAAM,CAAC,UAAU,EACjB,KAAK,EACL,MAAM,CAAC,EAAE,EACT,cAAc,MAAM,CAAC,UAAU,oCAAoC,CACpE,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,aAAa,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,KAAK,EAAE,MAAoB,EAAiB,EAAE;IAC5D,2CAA2C;IAC3C,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAE7B,mDAAmD;IACnD,0CAA0C;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvF,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,qBAAqB,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,OAAO,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED,kDAAkD;IAClD,0CAA0C;IAC1C,oBAAoB;IACpB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChG,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,QAAQ,yBAAyB,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,OAAO,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,4BAA4B;IAC5B,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,IAAI,IAAI,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yBAAyB,OAAO,CAAC,MAAM,kBAAkB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CACxG,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,QAAQ,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,WAAW,MAAM,CAAC,UAAU,KAAK,CAC9E,CAAC;QACF,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,qCAAqC;IACrC,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,GAAG,EAAE;IAC9B,IAAI,QAAQ,GAAyB,IAAI,CAAC;IAC1C,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,OAAO,GAAG,CAAC,MAAoB,EAAiB,EAAE;QACtD,IAAI,QAAQ,EAAE,CAAC;YACb,wCAAwC;YACxC,MAAM,GAAG,IAAI,CAAC;YACd,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;YACpC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC;oBAAS,CAAC;gBACT,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,GAAG,KAAK,CAAC;oBACf,sCAAsC;oBACtC,QAAQ,GAAG,GAAG,EAAE,CAAC;oBACjB,MAAM,QAAQ,CAAC;gBACjB,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,QAAQ,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YAC5B,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CACvB,MAAoB,EACpB,IAAY,EACZ,OAA6C,EAC7C,MAAmB,EACJ,EAAE;IACjB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,8BAA8B,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IACvE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAE3E,OAAO,YAAY,CAAC;QAClB,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;QACnB,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC;QACxB,MAAM;QACN,MAAM,EAAE,KAAK,IAAI,EAAE;YACjB,mCAAmC;YACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACrD,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACvB,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBACpE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,UAAyB,EAAE,EAAiB,EAAE;IAC5E,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,wBAAwB,CAAC,GAAG,IAAI,CAAC;IAC9E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IACrD,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,MAAM,EAAE,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAEzC,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,OAAO,GAAG,KAAK,CAAC;QAChB,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC1D,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAE5B,0DAA0D;IAC1D,+CAA+C;IAC/C,qDAAqD;IACrD,MAAM,UAAU,GAAsC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACxE,MAAM,QAAQ,GAAG,CAAC,MAAoB,EAAQ,EAAE;QAC9C,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,UAAU,CAAC,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CACjF,CAAC,GAAY,EAAE,EAAE;YACf,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;gBACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2BAA2B,GAAG,CAAC,MAAM,mCAAmC,CACzE,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,OAAO,IAAI,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC,CAAC;IAEF,QAAQ,CAAC,OAAO,CAAC,CAAC;IAElB,OAAO,OAAO,EAAE,CAAC;QACf,IAAI,MAAoB,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,OAAO,IAAI,CAAC,CAAC;YACxE,IAAI,OAAO,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,OAAO,IAAI,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,OAAO,CAAC,IAAI;YAAE,MAAM;QACxB,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC"}
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -2,5 +2,7 @@ export type LoginOptions = {
|
|
|
2
2
|
apiBaseUrl?: string;
|
|
3
3
|
clientId?: string;
|
|
4
4
|
scopes?: ReadonlyArray<string>;
|
|
5
|
+
/** true なら認可 URL を自動でブラウザに開かない (env `LNAR_NO_BROWSER=1` 相当)。 */
|
|
6
|
+
noBrowser?: boolean;
|
|
5
7
|
};
|
|
6
8
|
export declare const runLogin: (options?: LoginOptions) => Promise<void>;
|
package/dist/commands/login.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { openBrowser } from '../browser.js';
|
|
1
2
|
import { DEFAULT_API_BASE_URL, DEFAULT_CLIENT_ID, saveConfig } from '../config.js';
|
|
2
|
-
import { OAuthError, pollForToken, requestDeviceAuthorization, sleep
|
|
3
|
+
import { OAuthError, pollForToken, requestDeviceAuthorization, sleep } from '../oauth-client.js';
|
|
3
4
|
const DEFAULT_SCOPES = ['monitoring:read', 'monitoring:write'];
|
|
4
5
|
const resolveBaseUrl = (override) => {
|
|
5
6
|
const value = override ?? process.env.LNAR_API_BASE_URL ?? DEFAULT_API_BASE_URL;
|
|
@@ -11,15 +12,22 @@ const resolveBaseUrl = (override) => {
|
|
|
11
12
|
}
|
|
12
13
|
return value;
|
|
13
14
|
};
|
|
14
|
-
const printAuthorizationInstructions = (verificationUri, verificationUriComplete, userCode, expiresInSeconds) => {
|
|
15
|
+
const printAuthorizationInstructions = (verificationUri, verificationUriComplete, userCode, expiresInSeconds, browserOpened) => {
|
|
15
16
|
const minutes = Math.max(1, Math.round(expiresInSeconds / 60));
|
|
16
17
|
process.stdout.write('\n');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
if (browserOpened) {
|
|
19
|
+
process.stdout.write('Opening your browser to authorize this device…\n');
|
|
20
|
+
process.stdout.write('If it does not open automatically, visit:\n');
|
|
21
|
+
process.stdout.write(` ${verificationUriComplete}\n\n`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
process.stdout.write('To authorize this device, visit:\n');
|
|
25
|
+
process.stdout.write(` ${verificationUri}\n`);
|
|
26
|
+
process.stdout.write('and enter the code:\n\n');
|
|
27
|
+
process.stdout.write(` ${userCode}\n\n`);
|
|
28
|
+
process.stdout.write('Or open the URL with the code pre-filled:\n');
|
|
29
|
+
process.stdout.write(` ${verificationUriComplete}\n\n`);
|
|
30
|
+
}
|
|
23
31
|
process.stdout.write(`Waiting for authorization (this code expires in ${minutes} minute${minutes === 1 ? '' : 's'})…\n`);
|
|
24
32
|
};
|
|
25
33
|
export const runLogin = async (options = {}) => {
|
|
@@ -37,7 +45,9 @@ export const runLogin = async (options = {}) => {
|
|
|
37
45
|
}
|
|
38
46
|
throw err;
|
|
39
47
|
}
|
|
40
|
-
|
|
48
|
+
const shouldOpenBrowser = !(options.noBrowser ?? process.env.LNAR_NO_BROWSER === '1');
|
|
49
|
+
const browserOpened = shouldOpenBrowser && openBrowser(auth.verification_uri_complete);
|
|
50
|
+
printAuthorizationInstructions(auth.verification_uri, auth.verification_uri_complete, auth.user_code, auth.expires_in, browserOpened);
|
|
41
51
|
// RFC 8628 §3.5: ポーリング間隔はサーバ指定の `interval` 以上、
|
|
42
52
|
// `slow_down` を受け取ったら +5 秒 (サーバ側で自動加算済みだが、念のためここでも対応)。
|
|
43
53
|
let intervalSeconds = Math.max(1, auth.interval || 5);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lnar record` — ローカルブラウザでデモ操作を記録し、バンドルを lnar にアップロードする。
|
|
3
|
+
*
|
|
4
|
+
* Demo-to-MCP (Phase 1)。記録したバンドルは後段で gemini-3.5-flash が解析し、
|
|
5
|
+
* タスク手順書 (playbook) → ブラウザ操作 MCP の生成に使う。
|
|
6
|
+
*
|
|
7
|
+
* 録画内容 (キーフレーム画像) はメモリ上の Buffer としてのみ保持し、tar.gz も
|
|
8
|
+
* メモリ上で組み立ててアップロードする。ローカルディスクには一切書き出さない。
|
|
9
|
+
*/
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { stdin, stdout } from 'node:process';
|
|
13
|
+
import { createInterface } from 'node:readline/promises';
|
|
14
|
+
import { ApiError, createRecording, uploadRecordingBundle } from '../api-client.js';
|
|
15
|
+
import { NotLoggedInError, resolveAuth } from '../auth.js';
|
|
16
|
+
import { packBundleToBuffer } from '../recording/bundle.js';
|
|
17
|
+
import { recordSession } from '../recording/session.js';
|
|
18
|
+
const MAX_PURPOSE = 2000;
|
|
19
|
+
/**
|
|
20
|
+
* 録画後に「この作業の目的」を尋ねる。--purpose 指定時はそれを使い、対話端末
|
|
21
|
+
* (TTY) でなければスキップする。目的は解析プロンプトに渡され playbook 精度を高める。
|
|
22
|
+
*/
|
|
23
|
+
const resolvePurpose = async (option) => {
|
|
24
|
+
if (option != null && option.trim() !== '')
|
|
25
|
+
return option.trim().slice(0, MAX_PURPOSE);
|
|
26
|
+
if (!stdin.isTTY)
|
|
27
|
+
return null;
|
|
28
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
29
|
+
try {
|
|
30
|
+
stdout.write('\nこの作業の目的を入力してください (任意、Enter でスキップ):\n');
|
|
31
|
+
const answer = await rl.question('> ');
|
|
32
|
+
const trimmed = answer.trim();
|
|
33
|
+
return trimmed === '' ? null : trimmed.slice(0, MAX_PURPOSE);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
rl.close();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const fsSafeTimestamp = () => new Date().toISOString().replace(/[:.]/g, '-');
|
|
40
|
+
/** Enter キー or ブラウザ終了で停止するシグナルを作る。 */
|
|
41
|
+
const makeWaitForStop = () => (page, context) => new Promise((resolve) => {
|
|
42
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
43
|
+
let done = false;
|
|
44
|
+
const finish = () => {
|
|
45
|
+
if (done)
|
|
46
|
+
return;
|
|
47
|
+
done = true;
|
|
48
|
+
rl.close();
|
|
49
|
+
resolve();
|
|
50
|
+
};
|
|
51
|
+
stdout.write('\n● 録画中。ブラウザで操作してください。\n');
|
|
52
|
+
stdout.write(' 終了するには、このターミナルで Enter を押すかブラウザを閉じてください。\n\n');
|
|
53
|
+
// ブラウザ close 起因で先に rl.close() されると question が reject するため、
|
|
54
|
+
// 成功/reject どちらでも finish() を呼び unhandled rejection を防ぐ。
|
|
55
|
+
void rl.question('').then(finish, finish);
|
|
56
|
+
context.on('close', finish);
|
|
57
|
+
page.on('close', finish);
|
|
58
|
+
});
|
|
59
|
+
export const runRecord = async (options = {}) => {
|
|
60
|
+
// アップロードは必須。録画後に失敗して取り直しを避けるため先に認証を解決する。
|
|
61
|
+
let auth;
|
|
62
|
+
try {
|
|
63
|
+
auth = await resolveAuth();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (err instanceof NotLoggedInError) {
|
|
67
|
+
process.stderr.write(`lnar: ${err.message}\n`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
const createdAt = new Date().toISOString();
|
|
73
|
+
const name = options.name ?? `recording-${fsSafeTimestamp()}`;
|
|
74
|
+
const profileDir = join(homedir(), '.config', 'lnar', 'record-profile');
|
|
75
|
+
const result = await recordSession({
|
|
76
|
+
name,
|
|
77
|
+
startUrl: options.url ?? null,
|
|
78
|
+
profileDir,
|
|
79
|
+
headless: options.headless,
|
|
80
|
+
createdAt,
|
|
81
|
+
waitForStop: makeWaitForStop(),
|
|
82
|
+
});
|
|
83
|
+
process.stdout.write(`\n録画完了: ${result.manifest.actionCount} アクション, ` +
|
|
84
|
+
`${result.manifest.screenshots.length} キーフレーム\n`);
|
|
85
|
+
// 録画後に作業の目的を尋ねる (解析プロンプトに渡し playbook 精度を高める)。
|
|
86
|
+
const purpose = await resolvePurpose(options.purpose);
|
|
87
|
+
try {
|
|
88
|
+
const created = await createRecording(auth.baseUrl, auth.token, {
|
|
89
|
+
name,
|
|
90
|
+
startUrl: result.manifest.startUrl,
|
|
91
|
+
purpose,
|
|
92
|
+
manifest: result.manifest,
|
|
93
|
+
actions: result.actions,
|
|
94
|
+
});
|
|
95
|
+
// tar.gz をメモリ上で組み立ててそのままアップロードする (ディスク不使用)。
|
|
96
|
+
const bundle = await packBundleToBuffer({
|
|
97
|
+
manifest: result.manifest,
|
|
98
|
+
actions: result.actions,
|
|
99
|
+
frames: result.frames,
|
|
100
|
+
});
|
|
101
|
+
// アップロード時にサーバー側で即解析される (画像は保存されない)。
|
|
102
|
+
const analyzed = await uploadRecordingBundle(auth.baseUrl, auth.token, created.id, bundle);
|
|
103
|
+
process.stdout.write(`アップロード・解析完了: recording ${analyzed.id} (status=${analyzed.status})\n`);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
if (err instanceof ApiError) {
|
|
107
|
+
if (err.status === 401) {
|
|
108
|
+
process.stderr.write('lnar: not authorized (token may be expired). Run `lnar login`.\n');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
process.stderr.write(`lnar: ${err.message}\n`);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/commands/record.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/scan.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { hostname } from 'node:os';
|
|
2
|
+
import { loadOrCreateMachineId } from '../machine-id.js';
|
|
2
3
|
import { runAllScanners } from '../scanners/index.js';
|
|
4
|
+
const truncate = (s, max) => s.length <= max ? s : `${s.slice(0, max - 1)}…`;
|
|
3
5
|
const formatHuman = (result) => {
|
|
4
6
|
if (result.agents.length === 0) {
|
|
5
7
|
return 'No AI agents with MCP servers detected on this machine.';
|
|
@@ -16,14 +18,24 @@ const formatHuman = (result) => {
|
|
|
16
18
|
const scope = `[${s.sourceScope}]`.padEnd(10);
|
|
17
19
|
lines.push(` - ${s.name.padEnd(24)} ${transport} ${scope} ${target}`);
|
|
18
20
|
}
|
|
21
|
+
if (agent.skills && agent.skills.length > 0) {
|
|
22
|
+
lines.push('');
|
|
23
|
+
lines.push(` skills (${agent.skills.length})`);
|
|
24
|
+
for (const sk of agent.skills) {
|
|
25
|
+
const scope = `[${sk.scope}]`.padEnd(10);
|
|
26
|
+
lines.push(` - ${sk.name.padEnd(28)} ${scope} ${truncate(sk.description, 64)}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
19
29
|
lines.push('');
|
|
20
30
|
}
|
|
21
31
|
return lines.join('\n');
|
|
22
32
|
};
|
|
23
33
|
export const runScan = async (options = {}) => {
|
|
24
34
|
const agents = await runAllScanners();
|
|
35
|
+
const machineId = await loadOrCreateMachineId();
|
|
25
36
|
const result = {
|
|
26
37
|
hostname: hostname(),
|
|
38
|
+
machineId,
|
|
27
39
|
scannedAt: new Date().toISOString(),
|
|
28
40
|
agents,
|
|
29
41
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAOtD,MAAM,WAAW,GAAG,CAAC,MAAkB,EAAU,EAAE;IACjD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,yDAAyD,CAAC;IACnE,CAAC;IACD,MAAM,KAAK,GAAa,CAAC,SAAS,MAAM,CAAC,QAAQ,gBAAgB,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IACzF,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,KAAK,KAAK,CAAC,SAAS,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,UAAU,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CACjG,CAAC;QACF,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;YAC7E,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,SAAS,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,EAAE,UAA8B,EAAE,EAAiB,EAAE;IAC/E,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;IACtC,MAAM,MAAM,GAAe;QACzB,QAAQ,EAAE,QAAQ,EAAE;QACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM;KACP,CAAC;IACF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO;IACT,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/sync.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { hostname } from 'node:os';
|
|
2
2
|
import { ApiError, postSnapshot } from '../api-client.js';
|
|
3
3
|
import { DEFAULT_CLIENT_ID, loadConfig, saveConfig } from '../config.js';
|
|
4
|
+
import { loadOrCreateMachineId } from '../machine-id.js';
|
|
4
5
|
import { OAuthError, refreshAccessToken } from '../oauth-client.js';
|
|
5
6
|
import { runAllScanners } from '../scanners/index.js';
|
|
6
7
|
const ACCESS_TOKEN_REFRESH_SKEW_SECONDS = 60;
|
|
@@ -60,8 +61,10 @@ export const runSync = async (options = {}) => {
|
|
|
60
61
|
}
|
|
61
62
|
const config = await refreshIfNeeded(initial);
|
|
62
63
|
const agents = await runAllScanners();
|
|
64
|
+
const machineId = await loadOrCreateMachineId();
|
|
63
65
|
const scan = {
|
|
64
66
|
hostname: hostname(),
|
|
67
|
+
machineId,
|
|
65
68
|
scannedAt: new Date().toISOString(),
|
|
66
69
|
agents,
|
|
67
70
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/up.js
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 1. `~/.config/lnar/auth.json` を読んで、認証済みでなければ device flow を起動する
|
|
5
5
|
* 2. OS の常駐サービスとして登録 (macOS=launchd / Linux=systemd / Windows=Task Scheduler)
|
|
6
|
+
* 3. インストール直後に初回 sync を 1 回だけ同期実行し、daemon の最初の cycle を
|
|
7
|
+
* 待たずダッシュボードへの反映を即時化する。Tailscale が `tailscale up` で
|
|
8
|
+
* 同期的に "phone home" するのと同じ思想。失敗しても daemon 側 polling が
|
|
9
|
+
* 後続 cycle で再試行するので、ここはベストエフォート扱いにする。
|
|
6
10
|
*
|
|
7
11
|
* 認証済みかどうかは「資格情報ファイルが存在し、accessToken or apiKey が入っているか」で
|
|
8
12
|
* 判断する。トークンの有効期限は daemon 側の API クライアントが refresh するので、
|
|
@@ -12,6 +16,20 @@
|
|
|
12
16
|
import { loadConfig } from '../config.js';
|
|
13
17
|
import { runDaemonInstall } from '../service/install.js';
|
|
14
18
|
import { runLogin } from './login.js';
|
|
19
|
+
import { runSync } from './sync.js';
|
|
20
|
+
const runInitialSync = async () => {
|
|
21
|
+
process.stdout.write('\nRunning initial sync…\n');
|
|
22
|
+
try {
|
|
23
|
+
await runSync();
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
// runSync は ApiError / 401 では process.exit(1) を直接呼ぶので、ここに到達する
|
|
27
|
+
// のは予期しない例外のみ。daemon サービスのインストール自体は成功しているので、
|
|
28
|
+
// 続く polling cycle が同じ scan を再試行できる。lnar up 自体は warn で済ませる。
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
process.stderr.write(`lnar up: initial sync failed (${message}). The daemon will retry on its next cycle.\n`);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
15
33
|
export const runUp = async (options = {}) => {
|
|
16
34
|
const config = await loadConfig();
|
|
17
35
|
if (config == null) {
|
|
@@ -23,5 +41,6 @@ export const runUp = async (options = {}) => {
|
|
|
23
41
|
process.stdout.write(`Using existing credentials (${config.apiBaseUrl}).\n\n`);
|
|
24
42
|
}
|
|
25
43
|
await runDaemonInstall();
|
|
44
|
+
await runInitialSync();
|
|
26
45
|
};
|
|
27
46
|
//# sourceMappingURL=up.js.map
|
package/dist/commands/up.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"up.js","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"up.js","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAqB,QAAQ,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,cAAc,GAAG,KAAK,IAAmB,EAAE;IAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,8DAA8D;QAC9D,6CAA6C;QAC7C,4DAA4D;QAC5D,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iCAAiC,OAAO,+CAA+C,CACxF,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EAAE,UAAqB,EAAE,EAAiB,EAAE;IACpE,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACxF,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,UAAU,QAAQ,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,gBAAgB,EAAE,CAAC;IACzB,MAAM,cAAc,EAAE,CAAC;AACzB,CAAC,CAAC"}
|