@dp-pcs/ogp 0.7.2 → 0.8.2

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 (63) hide show
  1. package/README.md +59 -12
  2. package/dist/cli/config.d.ts +4 -0
  3. package/dist/cli/config.d.ts.map +1 -1
  4. package/dist/cli/config.js +45 -2
  5. package/dist/cli/config.js.map +1 -1
  6. package/dist/cli/expose.d.ts +4 -1
  7. package/dist/cli/expose.d.ts.map +1 -1
  8. package/dist/cli/expose.js +7 -106
  9. package/dist/cli/expose.js.map +1 -1
  10. package/dist/cli/install.d.ts +1 -0
  11. package/dist/cli/install.d.ts.map +1 -1
  12. package/dist/cli/install.js +8 -2
  13. package/dist/cli/install.js.map +1 -1
  14. package/dist/cli/project.d.ts +24 -0
  15. package/dist/cli/project.d.ts.map +1 -1
  16. package/dist/cli/project.js +68 -15
  17. package/dist/cli/project.js.map +1 -1
  18. package/dist/cli/tunnel.d.ts +65 -0
  19. package/dist/cli/tunnel.d.ts.map +1 -0
  20. package/dist/cli/tunnel.js +413 -0
  21. package/dist/cli/tunnel.js.map +1 -0
  22. package/dist/cli.js +21 -8
  23. package/dist/cli.js.map +1 -1
  24. package/dist/daemon/contribution-signing.d.ts +49 -0
  25. package/dist/daemon/contribution-signing.d.ts.map +1 -0
  26. package/dist/daemon/contribution-signing.js +102 -0
  27. package/dist/daemon/contribution-signing.js.map +1 -0
  28. package/dist/daemon/message-handler.js +41 -18
  29. package/dist/daemon/message-handler.js.map +1 -1
  30. package/dist/daemon/openclaw-bridge.d.ts +6 -0
  31. package/dist/daemon/openclaw-bridge.d.ts.map +1 -1
  32. package/dist/daemon/openclaw-bridge.js +27 -12
  33. package/dist/daemon/openclaw-bridge.js.map +1 -1
  34. package/dist/daemon/peers.d.ts.map +1 -1
  35. package/dist/daemon/peers.js +19 -0
  36. package/dist/daemon/peers.js.map +1 -1
  37. package/dist/daemon/projects.d.ts +20 -0
  38. package/dist/daemon/projects.d.ts.map +1 -1
  39. package/dist/daemon/projects.js +70 -0
  40. package/dist/daemon/projects.js.map +1 -1
  41. package/dist/daemon/server.d.ts.map +1 -1
  42. package/dist/daemon/server.js +43 -2
  43. package/dist/daemon/server.js.map +1 -1
  44. package/dist/daemon/state-lock.d.ts +23 -0
  45. package/dist/daemon/state-lock.d.ts.map +1 -0
  46. package/dist/daemon/state-lock.js +115 -0
  47. package/dist/daemon/state-lock.js.map +1 -0
  48. package/package.json +13 -3
  49. package/scripts/completion.bash +25 -6
  50. package/scripts/completion.zsh +26 -8
  51. package/skills/ogp-expose/SKILL.md +40 -10
  52. package/docs/RC1-FEDERATION-TEST-CHECKLIST.md +0 -477
  53. package/docs/case-studies/CRASH_RESOLUTION_20260407.md +0 -190
  54. package/docs/case-studies/OpenClaw_Hermes_Status_Report_20260407.md +0 -142
  55. package/docs/case-studies/OpenClaw_Stability_Fix_Summary.md +0 -209
  56. package/docs/case-studies/README.md +0 -40
  57. package/docs/case-studies/crash_observations.md +0 -250
  58. package/docs/nat-hole-punch-spike.md +0 -399
  59. package/docs/project-intent-testing.md +0 -97
  60. package/scripts/render-ogp-overview-video.mjs +0 -454
  61. package/scripts/test-migration-execute.js +0 -74
  62. package/scripts/test-migration.js +0 -42
  63. package/scripts/test-project-intents.mjs +0 -614
@@ -0,0 +1,413 @@
1
+ import { spawn, execFile, execFileSync } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { Command } from 'commander';
4
+ import fs from 'node:fs';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { loadConfig, requireConfig, getConfigDir } from '../shared/config.js';
8
+ const execFileAsync = promisify(execFile);
9
+ /**
10
+ * Parse the JSON array emitted by `cloudflared tunnel list --output json`.
11
+ * Filters out deleted tunnels and classifies live = has active connections.
12
+ * Returns [] on any parse failure (caller surfaces the raw error separately).
13
+ */
14
+ export function parseCloudflaredTunnels(jsonText) {
15
+ let arr;
16
+ try {
17
+ arr = JSON.parse(jsonText);
18
+ }
19
+ catch {
20
+ return [];
21
+ }
22
+ if (!Array.isArray(arr))
23
+ return [];
24
+ return arr
25
+ .filter((t) => !t?.deleted_at || String(t.deleted_at).startsWith('0001-01-01'))
26
+ .map((t) => {
27
+ const conns = Array.isArray(t.connections) ? t.connections : [];
28
+ const colos = Array.from(new Set(conns.map((c) => c?.colo_name).filter(Boolean)));
29
+ return {
30
+ tool: 'cloudflared',
31
+ name: typeof t.name === 'string' ? t.name : undefined,
32
+ id: typeof t.id === 'string' ? t.id : undefined,
33
+ live: conns.length > 0,
34
+ detail: colos.length ? `via ${colos.join(', ')}` : undefined,
35
+ source: 'cloudflared tunnel list'
36
+ };
37
+ });
38
+ }
39
+ /**
40
+ * Parse the JSON from the ngrok local agent API (http://127.0.0.1:4040/api/tunnels).
41
+ * ngrok historically returns one entry per proto (http + https) for the same
42
+ * forward; we dedupe by public-URL host, preferring https. Returns [] on failure.
43
+ */
44
+ export function parseNgrokAgentTunnels(jsonText) {
45
+ let obj;
46
+ try {
47
+ obj = JSON.parse(jsonText);
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ const tunnels = Array.isArray(obj?.tunnels) ? obj.tunnels : [];
53
+ const byHost = new Map();
54
+ for (const t of tunnels) {
55
+ const publicUrl = typeof t?.public_url === 'string' ? t.public_url : undefined;
56
+ if (!publicUrl)
57
+ continue;
58
+ let host;
59
+ try {
60
+ host = new URL(publicUrl).host;
61
+ }
62
+ catch {
63
+ continue;
64
+ }
65
+ const isHttps = publicUrl.startsWith('https://');
66
+ const existing = byHost.get(host);
67
+ if (existing && !isHttps)
68
+ continue; // keep https over http for same host
69
+ byHost.set(host, {
70
+ tool: 'ngrok',
71
+ name: typeof t.name === 'string' ? t.name : undefined,
72
+ publicUrl,
73
+ target: typeof t?.config?.addr === 'string' ? t.config.addr : undefined,
74
+ live: true,
75
+ detail: typeof t?.proto === 'string' ? t.proto : undefined,
76
+ source: 'ngrok agent (:4040)'
77
+ });
78
+ }
79
+ return Array.from(byHost.values());
80
+ }
81
+ /**
82
+ * Best-effort extraction of ingress hostnames from a cloudflared config.yml.
83
+ * Used to resolve a public hostname for named tunnels during reconcile.
84
+ */
85
+ export function parseCloudflaredIngressHosts(yamlText) {
86
+ const hosts = [];
87
+ for (const line of yamlText.split('\n')) {
88
+ const m = line.match(/^\s*-?\s*hostname:\s*["']?([^"'#\s/]+)/);
89
+ if (m)
90
+ hosts.push(m[1]);
91
+ }
92
+ return hosts;
93
+ }
94
+ /**
95
+ * Compare resolvable live public hosts against config gatewayUrl.
96
+ * `liveHosts` is the precomputed set of hosts (ngrok public_url hosts + cloudflared
97
+ * ingress hosts when a cloudflared tunnel is live). Pure; returns null when there is
98
+ * nothing meaningful to report.
99
+ */
100
+ export function reconcileGatewayUrl(liveHosts, gatewayUrl) {
101
+ if (!gatewayUrl)
102
+ return null;
103
+ let gwHost;
104
+ try {
105
+ gwHost = new URL(gatewayUrl).host;
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ if (liveHosts.length === 0) {
111
+ return {
112
+ verdict: 'none',
113
+ message: `⚠ gatewayUrl ${gwHost} is set but no live tunnel with a resolvable public URL serves it`
114
+ };
115
+ }
116
+ if (liveHosts.includes(gwHost)) {
117
+ return { verdict: 'match', message: `✓ gatewayUrl ${gwHost} is served by a live tunnel` };
118
+ }
119
+ return {
120
+ verdict: 'mismatch',
121
+ message: `✗ gatewayUrl ${gwHost} does not match any live tunnel (live: ${liveHosts.join(', ')})`
122
+ };
123
+ }
124
+ const PANE_LABEL = {
125
+ cloudflared: 'cloudflared — named tunnels registered to your Cloudflare account',
126
+ ngrok: 'ngrok — tunnels running on this machine'
127
+ };
128
+ /**
129
+ * Format tunnel panes for the terminal. Pure: takes resolved data, returns a string.
130
+ */
131
+ export function renderTunnels(panes, reconcile) {
132
+ const lines = [];
133
+ for (const pane of panes) {
134
+ lines.push('');
135
+ lines.push(`▸ ${PANE_LABEL[pane.tool]}`);
136
+ if (pane.error) {
137
+ lines.push(` ⚠ ${pane.error}`);
138
+ if (pane.note)
139
+ lines.push(` ${pane.note}`);
140
+ continue;
141
+ }
142
+ if (pane.infos.length === 0) {
143
+ lines.push(` (no ${pane.tool} tunnels found)`);
144
+ if (pane.note)
145
+ lines.push(` ${pane.note}`);
146
+ continue;
147
+ }
148
+ for (const t of pane.infos) {
149
+ const status = t.live ? 'LIVE' : 'idle';
150
+ const label = t.name ?? t.publicUrl ?? t.id ?? '(unnamed)';
151
+ const bits = [
152
+ ` [${status}] ${label}`,
153
+ t.publicUrl && t.publicUrl !== label ? `→ ${t.publicUrl}` : '',
154
+ t.target ? `(${t.target})` : '',
155
+ t.id && t.id !== label ? `id=${t.id.slice(0, 8)}` : '',
156
+ t.detail ? t.detail : ''
157
+ ].filter(Boolean);
158
+ lines.push(bits.join(' '));
159
+ }
160
+ if (pane.note)
161
+ lines.push(` ${pane.note}`);
162
+ }
163
+ if (reconcile) {
164
+ lines.push('');
165
+ lines.push(reconcile.message);
166
+ }
167
+ return lines.join('\n');
168
+ }
169
+ /** Check if a command exists in PATH (mirrors framework-detection.ts). */
170
+ function commandExists(command) {
171
+ try {
172
+ const which = process.platform === 'win32' ? 'where' : 'which';
173
+ execFileSync(which, [command], { stdio: 'ignore' });
174
+ return true;
175
+ }
176
+ catch {
177
+ return false;
178
+ }
179
+ }
180
+ export async function listCloudflaredTunnels() {
181
+ if (!commandExists('cloudflared')) {
182
+ return { tool: 'cloudflared', infos: [], error: 'cloudflared not installed — `brew install cloudflared`' };
183
+ }
184
+ try {
185
+ const { stdout } = await execFileAsync('cloudflared', ['tunnel', 'list', '--output', 'json'], {
186
+ timeout: 15000
187
+ });
188
+ return { tool: 'cloudflared', infos: parseCloudflaredTunnels(stdout) };
189
+ }
190
+ catch (err) {
191
+ const stderr = (err?.stderr || err?.message || '').toString().trim();
192
+ const note = /login|cert|origincert|not.*authenticat/i.test(stderr)
193
+ ? 'Run `cloudflared tunnel login` to authenticate.'
194
+ : undefined;
195
+ return {
196
+ tool: 'cloudflared',
197
+ infos: [],
198
+ error: `cloudflared tunnel list failed: ${stderr.split('\n')[0] || 'unknown error'}`,
199
+ note
200
+ };
201
+ }
202
+ }
203
+ async function fetchNgrokAgent() {
204
+ // Probe the default agent port and the next two (multiple agents bump the port).
205
+ for (const port of [4040, 4041, 4042]) {
206
+ try {
207
+ const res = await fetch(`http://127.0.0.1:${port}/api/tunnels`, {
208
+ signal: AbortSignal.timeout(2000)
209
+ });
210
+ if (!res.ok)
211
+ continue;
212
+ const infos = parseNgrokAgentTunnels(await res.text());
213
+ if (infos.length > 0)
214
+ return infos;
215
+ }
216
+ catch {
217
+ // try next port
218
+ }
219
+ }
220
+ return null;
221
+ }
222
+ export async function listNgrokTunnels() {
223
+ if (!commandExists('ngrok')) {
224
+ return { tool: 'ngrok', infos: [], error: 'ngrok not installed — `brew install ngrok`' };
225
+ }
226
+ const agent = await fetchNgrokAgent();
227
+ if (agent && agent.length > 0) {
228
+ return { tool: 'ngrok', infos: agent };
229
+ }
230
+ return { tool: 'ngrok', infos: [], note: 'No local ngrok agent running on :4040.' };
231
+ }
232
+ export async function tunnelList(tool) {
233
+ const panes = [];
234
+ if (!tool || tool === 'cloudflared')
235
+ panes.push(await listCloudflaredTunnels());
236
+ if (!tool || tool === 'ngrok')
237
+ panes.push(await listNgrokTunnels());
238
+ // Build the set of resolvable live public hosts for reconcile.
239
+ const liveHosts = [];
240
+ for (const pane of panes) {
241
+ for (const info of pane.infos) {
242
+ if (info.live && info.publicUrl) {
243
+ try {
244
+ liveHosts.push(new URL(info.publicUrl).host);
245
+ }
246
+ catch {
247
+ /* skip */
248
+ }
249
+ }
250
+ }
251
+ }
252
+ // cloudflared named tunnels: if any is live, treat config.yml ingress hosts as live.
253
+ const cfPane = panes.find((p) => p.tool === 'cloudflared');
254
+ if (cfPane && cfPane.infos.some((i) => i.live)) {
255
+ const cfgPath = path.join(os.homedir(), '.cloudflared', 'config.yml');
256
+ if (fs.existsSync(cfgPath)) {
257
+ liveHosts.push(...parseCloudflaredIngressHosts(fs.readFileSync(cfgPath, 'utf-8')));
258
+ }
259
+ }
260
+ const config = loadConfig();
261
+ const reconcile = config ? reconcileGatewayUrl(liveHosts, config.gatewayUrl) : null;
262
+ console.log(renderTunnels(panes, reconcile));
263
+ }
264
+ function getTunnelPidFile() {
265
+ return path.join(getConfigDir(), 'tunnel.pid');
266
+ }
267
+ function getTunnelLogFile() {
268
+ return path.join(getConfigDir(), 'tunnel.log');
269
+ }
270
+ /** True if the ogp-managed tunnel PID file points at a live process. */
271
+ function isManagedTunnelAlive() {
272
+ const pidFile = getTunnelPidFile();
273
+ if (!fs.existsSync(pidFile))
274
+ return false;
275
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
276
+ if (Number.isNaN(pid))
277
+ return false;
278
+ try {
279
+ process.kill(pid, 0);
280
+ return true;
281
+ }
282
+ catch {
283
+ return false;
284
+ }
285
+ }
286
+ function spawnTunnel(tool, port, background) {
287
+ const args = tool === 'cloudflared'
288
+ ? ['tunnel', '--url', `http://localhost:${port}`]
289
+ : ['http', port.toString()];
290
+ if (background) {
291
+ const logStream = fs.openSync(getTunnelLogFile(), 'a');
292
+ const proc = spawn(tool, args, { detached: true, stdio: ['ignore', logStream, logStream] });
293
+ proc.unref();
294
+ fs.closeSync(logStream);
295
+ fs.writeFileSync(getTunnelPidFile(), proc.pid.toString(), 'utf-8');
296
+ console.log(`${tool} tunnel started (PID: ${proc.pid})`);
297
+ console.log(`Logs: ${getTunnelLogFile()}`);
298
+ console.log('Run "ogp tunnel stop" to stop the tunnel');
299
+ }
300
+ else {
301
+ const proc = spawn(tool, args, { stdio: 'inherit' });
302
+ proc.on('error', (error) => {
303
+ console.error(`Failed to start ${tool}:`, error);
304
+ console.log(`Make sure ${tool} is installed and in your PATH`);
305
+ });
306
+ proc.on('close', (code) => console.log(`${tool} exited with code ${code}`));
307
+ }
308
+ }
309
+ /**
310
+ * Start a quick tunnel for the given tool. Idempotent: if an ogp-managed tunnel is
311
+ * already alive (or, for ngrok, a local agent is already serving), prints current
312
+ * status instead of starting a duplicate. Note: the duplicate-guard relies on the
313
+ * background PID file (and the ngrok :4040 agent), so a foreground cloudflared quick
314
+ * tunnel started twice cannot be detected — cloudflared exposes no local agent to query.
315
+ */
316
+ export async function tunnelStart(tool, background = false) {
317
+ const config = requireConfig();
318
+ if (!commandExists(tool)) {
319
+ console.error(`${tool} not installed — \`brew install ${tool}\``);
320
+ process.exitCode = 1;
321
+ return;
322
+ }
323
+ if (isManagedTunnelAlive()) {
324
+ console.log('An ogp-managed tunnel is already running. Current tunnels:');
325
+ await tunnelList(tool);
326
+ return;
327
+ }
328
+ if (tool === 'ngrok') {
329
+ const agent = await fetchNgrokAgent();
330
+ if (agent && agent.length > 0) {
331
+ console.log('A local ngrok agent is already running. Current tunnels:');
332
+ await tunnelList('ngrok');
333
+ return;
334
+ }
335
+ }
336
+ console.log(`Exposing OGP daemon on port ${config.daemonPort} via ${tool}...`);
337
+ spawnTunnel(tool, config.daemonPort, background);
338
+ }
339
+ /** Stop the ogp-managed tunnel (PID file). Does not affect externally-started tunnels. */
340
+ export function tunnelStop() {
341
+ const pidFile = getTunnelPidFile();
342
+ if (!fs.existsSync(pidFile)) {
343
+ console.log('No ogp-managed tunnel is running.');
344
+ console.log('(Tunnels started outside ogp are not tracked here — stop them with their own CLI.)');
345
+ return;
346
+ }
347
+ try {
348
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
349
+ if (Number.isNaN(pid)) {
350
+ console.error('Invalid PID in tunnel.pid file');
351
+ fs.unlinkSync(pidFile);
352
+ return;
353
+ }
354
+ try {
355
+ process.kill(pid, 0);
356
+ }
357
+ catch {
358
+ console.log('Tunnel is not running (stale PID file)');
359
+ fs.unlinkSync(pidFile);
360
+ return;
361
+ }
362
+ process.kill(pid, 'SIGTERM');
363
+ fs.unlinkSync(pidFile);
364
+ console.log('Tunnel stopped');
365
+ }
366
+ catch (error) {
367
+ if (error?.code === 'ESRCH') {
368
+ console.log('Tunnel already stopped (process exited between checks)');
369
+ try {
370
+ fs.unlinkSync(pidFile);
371
+ }
372
+ catch { /* already gone */ }
373
+ }
374
+ else {
375
+ console.error('Failed to stop tunnel:', error);
376
+ }
377
+ }
378
+ }
379
+ export const tunnelCommand = new Command('tunnel')
380
+ .description('Inspect and manage cloudflared / ngrok tunnels');
381
+ tunnelCommand
382
+ .command('list')
383
+ .alias('show')
384
+ .description('List running tunnels (cloudflared, ngrok, or both)')
385
+ .argument('[tool]', 'Limit to one tool: cloudflared | ngrok')
386
+ .action(async (tool) => {
387
+ if (tool && tool !== 'cloudflared' && tool !== 'ngrok') {
388
+ console.error(`Unknown tool '${tool}'. Use 'cloudflared' or 'ngrok'.`);
389
+ process.exitCode = 1;
390
+ return;
391
+ }
392
+ await tunnelList(tool);
393
+ });
394
+ tunnelCommand
395
+ .command('start')
396
+ .description('Start a quick tunnel (idempotent — no-op if one is already running)')
397
+ .argument('<tool>', 'cloudflared | ngrok')
398
+ .option('-b, --background', 'Run in background')
399
+ .action(async (tool, options) => {
400
+ if (tool !== 'cloudflared' && tool !== 'ngrok') {
401
+ console.error(`Unknown tool '${tool}'. Use 'cloudflared' or 'ngrok'.`);
402
+ process.exitCode = 1;
403
+ return;
404
+ }
405
+ await tunnelStart(tool, options.background ?? false);
406
+ });
407
+ tunnelCommand
408
+ .command('stop')
409
+ .description('Stop the ogp-managed tunnel')
410
+ .action(() => {
411
+ tunnelStop();
412
+ });
413
+ //# sourceMappingURL=tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../src/cli/tunnel.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -10,6 +10,7 @@ import { requireConfig, loadConfig } from './shared/config.js';
10
10
  import { loadMetaConfig } from './shared/meta-config.js';
11
11
  import { federationList, federationStatus, federationRequest, federationApprove, federationReject, federationRemove, federationSend, federationShowScopes, federationUpdateGrants, federationSendAgentComms, federationConnect, federationInvite, federationAccept, federationSetAlias, federationTagPeer, federationUntagPeer, federationUpdateIdentity } from './cli/federation.js';
12
12
  import { expose, stopExpose } from './cli/expose.js';
13
+ import { tunnelCommand } from './cli/tunnel.js';
13
14
  import { installLaunchAgent, uninstallLaunchAgent } from './cli/install.js';
14
15
  import { installCompletion } from './cli/completion.js';
15
16
  import { showPolicies, configurePolicies, addTopic, removeTopic, resetPolicy, showActivity, clearActivity, setDefault, setLogging, setTopic, setPeerDefault } from './cli/agent-comms.js';
@@ -411,7 +412,14 @@ program
411
412
  console.log(` Check interval: ${heartbeatConfig.intervalMs / 1000}s`);
412
413
  console.log(` Check timeout: ${heartbeatConfig.timeoutMs / 1000}s`);
413
414
  console.log(` Max consecutive failures: ${heartbeatConfig.maxConsecutiveFailures}`);
414
- console.log(` Heartbeat status: ${heartbeatConfig.isRunning ? 'Running' : 'Stopped'}`);
415
+ // The heartbeat loop runs inside the long-lived daemon process and is started
416
+ // unconditionally at daemon boot (see startHeartbeat()). This `ogp status` command
417
+ // runs in a *separate*, short-lived CLI process where the heartbeat timer is always
418
+ // null, so heartbeatConfig.isRunning here reflects the CLI process, not the daemon —
419
+ // it would always read 'Stopped' even while the daemon's heartbeat is actively
420
+ // checking peers (bd-d1l). The authoritative cross-process signal is whether the
421
+ // daemon itself is running.
422
+ console.log(` Heartbeat status: ${status.running ? 'Running' : 'Stopped'}`);
415
423
  });
416
424
  /**
417
425
  * Pad string to the right with spaces
@@ -655,17 +663,18 @@ federation
655
663
  toAgent: options.toAgent
656
664
  });
657
665
  });
666
+ program.addCommand(tunnelCommand);
658
667
  program
659
- .command('expose')
660
- .description('Expose daemon via tunnel (cloudflared or ngrok)')
668
+ .command('expose', { hidden: true })
669
+ .description('[deprecated] Use "ogp tunnel start"')
661
670
  .option('-m, --method <method>', 'Tunnel method (cloudflared|ngrok)', 'cloudflared')
662
671
  .option('-b, --background', 'Run in background')
663
672
  .action(async (options) => {
664
673
  await expose(options.method, options.background);
665
674
  });
666
675
  program
667
- .command('expose-stop')
668
- .description('Stop background tunnel')
676
+ .command('expose-stop', { hidden: true })
677
+ .description('[deprecated] Use "ogp tunnel stop"')
669
678
  .action(() => {
670
679
  stopExpose();
671
680
  });
@@ -896,11 +905,13 @@ project
896
905
  .option('--author <id>', 'Filter by author')
897
906
  .option('--search <text>', 'Search by text content')
898
907
  .option('--limit <n>', 'Maximum results to return', '20')
908
+ .option('--json', 'Output machine-readable JSON (includes contribution ids + ISO timestamps)')
899
909
  .action(async (projectId, options) => {
900
910
  const queryOptions = {
901
911
  ...options,
902
912
  entryType: options.type || options.topic, // --type takes precedence; --topic remains a legacy alias
903
- limit: parseInt(options.limit, 10)
913
+ limit: parseInt(options.limit, 10),
914
+ json: options.json ?? false
904
915
  };
905
916
  await projectQuery(projectId, queryOptions);
906
917
  });
@@ -943,13 +954,15 @@ project
943
954
  .option('--topic <name>', 'Filter by entry type (alias for --type)')
944
955
  .option('--author <id>', 'Filter by author')
945
956
  .option('--limit <n>', 'Maximum results to return', '20')
946
- .option('--timeout <ms>', 'Response timeout in milliseconds', '10000')
957
+ .option('--timeout <ms>', 'Response timeout in milliseconds', '30000')
958
+ .option('--json', 'Output machine-readable JSON (includes contribution ids + ISO timestamps)')
947
959
  .action(async (peerId, projectId, options) => {
948
960
  const queryOptions = {
949
961
  ...options,
950
962
  entryType: options.type || options.topic, // --type takes precedence; --topic remains a legacy alias
951
963
  limit: parseInt(options.limit, 10),
952
- timeout: parseInt(options.timeout, 10)
964
+ timeout: parseInt(options.timeout, 10),
965
+ json: options.json ?? false
953
966
  };
954
967
  await projectQueryPeer(peerId, projectId, queryOptions);
955
968
  });