wtt-connect 0.2.44 → 0.2.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wtt-connect",
3
- "version": "0.2.44",
3
+ "version": "0.2.45",
4
4
  "private": false,
5
5
  "description": "WTT-native connector daemon for Codex, Claude Code, Cursor, Gemini, ACP, and other coding agent surfaces.",
6
6
  "type": "module",
package/src/main.js CHANGED
@@ -97,6 +97,9 @@ function parseArgs(args) {
97
97
  else if (a === '--preview-name') out.previewName = args[++i];
98
98
  else if (a === '--preview-token') out.previewToken = args[++i];
99
99
  else if (a === '--keep-last') out.keepLast = Number(args[++i]);
100
+ else if (a === '--snapshot-dir') out.snapshotDir = args[++i];
101
+ else if (a === '--snapshot-entry') out.snapshotEntry = args[++i];
102
+ else if (a === '--no-snapshot') out.noSnapshot = true;
100
103
  else if (a === '--timeout') out.timeout = Number(args[++i]) * 1000;
101
104
  else if (a === '--sender-agent-id') out.senderAgentId = args[++i];
102
105
  else if (a === '--sender-token') out.senderToken = args[++i];
@@ -134,8 +137,8 @@ Commands:
134
137
  upload-artifact --dir <path> Upload an OpenDesign/artifact directory to WTT
135
138
  opendesign-upload --dir <path>
136
139
  Alias for upload-artifact
137
- preview-port --port <port> [--topic-id <id>]
138
- Create a Cloud Sandbox port preview URL through sandbox outbox
140
+ preview-port --port <port> [--topic-id <id>] [--snapshot-dir <dir>]
141
+ Create a Cloud Sandbox preview URL and optional persistent snapshot
139
142
  cleanup-previews Stop preview servers previously registered by this agent
140
143
  help Show this help
141
144
  `);
@@ -159,7 +162,17 @@ async function previewPort(config, argv) {
159
162
  const url = preview.preview_url || preview.url;
160
163
  if (!url) throw new Error('Cloud Sandbox preview API returned no URL');
161
164
  const title = String(argv.title || argv.previewName || preview.name || 'Cloud Sandbox Preview').trim();
162
- const markdown = preview.markdown || `[preview_url:${title}](${url})`;
165
+ const snapshot = argv.noSnapshot ? null : await createPreviewSnapshot(config, argv, { title });
166
+ const snapshotUrl = snapshot?.snapshot_url || '';
167
+ const markdown = JSON.stringify({
168
+ type: 'cloud_sandbox_preview',
169
+ title,
170
+ preview_url: url,
171
+ url,
172
+ ...(snapshotUrl ? { snapshot_url: snapshotUrl } : {}),
173
+ ...(snapshot?.artifact_url ? { artifact_url: snapshot.artifact_url } : {}),
174
+ ...(snapshot?.artifact_id ? { artifact_id: snapshot.artifact_id } : {}),
175
+ });
163
176
  const topicId = String(argv.topicId || argv.sourceId || '').trim();
164
177
  let published = null;
165
178
  if (topicId) {
@@ -170,6 +183,8 @@ async function previewPort(config, argv) {
170
183
  type: 'cloud_sandbox_preview',
171
184
  port,
172
185
  preview_url: url,
186
+ ...(snapshotUrl ? { snapshot_url: snapshotUrl } : {}),
187
+ ...(snapshot?.artifact_id ? { artifact_id: snapshot.artifact_id } : {}),
173
188
  preview_cleanup: cleanup,
174
189
  });
175
190
  } finally {
@@ -177,7 +192,60 @@ async function previewPort(config, argv) {
177
192
  }
178
193
  }
179
194
  recordPreview(config, { port, url, name: preview.name || title });
180
- console.log(JSON.stringify({ ok: true, port, url, preview_url: url, markdown, cleanup, published }, null, 2));
195
+ console.log(JSON.stringify({ ok: true, port, url, preview_url: url, snapshot, markdown, cleanup, published }, null, 2));
196
+ }
197
+
198
+ async function createPreviewSnapshot(config, argv, { title = 'Cloud Sandbox Preview' } = {}) {
199
+ const dir = String(argv.snapshotDir || '').trim();
200
+ if (!dir) return null;
201
+ const resolved = resolveSnapshotDir(dir, config);
202
+ if (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory()) {
203
+ throw new Error(`snapshot directory not found: ${resolved}`);
204
+ }
205
+ const store = new DurableStore(config.storeFile).load();
206
+ const artifacts = new ArtifactManager(config, store);
207
+ const entry = String(argv.snapshotEntry || 'index.html').trim();
208
+ const artifact = await artifacts.uploadDirectory(resolved, {
209
+ source: 'cloud_sandbox_preview',
210
+ sourceId: String(argv.topicId || argv.sourceId || ''),
211
+ title,
212
+ entry,
213
+ type: 'cloud_sandbox_preview_snapshot',
214
+ metadata: {
215
+ uploaded_by: 'wtt-connect',
216
+ command: 'preview-port',
217
+ live_preview_port: Number(argv.port || argv._?.[0] || 0),
218
+ },
219
+ });
220
+ const previewUrl = absoluteWttUrl(config.wttBaseUrl, artifact.preview_url || artifact.url || '');
221
+ return {
222
+ artifact_id: artifact.artifact_id || artifact.id || '',
223
+ artifact_url: absoluteWttUrl(config.wttBaseUrl, artifact.url || ''),
224
+ snapshot_url: previewUrl,
225
+ entry,
226
+ dir: resolved,
227
+ };
228
+ }
229
+
230
+ function resolveSnapshotDir(dir, config) {
231
+ const expanded = dir.startsWith('~/') ? path.join(process.env.HOME || '', dir.slice(2)) : dir;
232
+ const base = path.resolve(config.workDir || process.cwd());
233
+ const resolved = path.resolve(path.isAbsolute(expanded) ? expanded : path.join(base, expanded));
234
+ const roots = [
235
+ config.workDir,
236
+ config.artifactDir,
237
+ config.persistentOutputDir,
238
+ ].filter(Boolean).map((root) => path.resolve(root));
239
+ if (!roots.some((root) => isPathInside(resolved, root))) {
240
+ throw new Error(`snapshot-dir refused path outside WTT workspace/state/persistent roots: ${resolved}`);
241
+ }
242
+ return resolved;
243
+ }
244
+
245
+ function absoluteWttUrl(base, maybeRelative) {
246
+ if (!maybeRelative) return '';
247
+ if (/^https?:\/\//i.test(maybeRelative)) return maybeRelative;
248
+ return `${String(base || '').replace(/\/$/, '')}${String(maybeRelative).startsWith('/') ? '' : '/'}${maybeRelative}`;
181
249
  }
182
250
 
183
251
  async function cleanupPreviewsCommand(config, argv) {
package/src/runner.js CHANGED
@@ -943,11 +943,11 @@ function renderCloudSandboxStorageInstruction(config, topicId = '') {
943
943
  '- Before publishing a preview URL, verify the server is actually listening and serving content with `curl -fsS http://127.0.0.1:<port>/ >/dev/null`.',
944
944
  '- If local curl fails, fix or restart the web server first. Never publish a preview URL for a dead port.',
945
945
  '- `wtt-connect preview-port` automatically keeps the most recent preview servers for this agent and stops older registered previews beyond the retention limit. Default retention is 3 live previews; use `--keep-last <n>` only when the user asks.',
946
- '- For historical results that should remain available after preview cleanup, also save static HTML, screenshots, reports, or build artifacts under the persistent R2 output directory and publish them as files/artifacts. Live preview URLs are for recent interactive previews, not permanent archival storage.',
946
+ '- For static pages, animations, charts, dashboards, and HTML demos, pass the generated static directory to `wtt-connect preview-port --snapshot-dir <dir> --snapshot-entry index.html` so WTT stores a persistent snapshot fallback. Live preview URLs are for recent interactive previews; snapshots/artifacts preserve history after cleanup.',
947
947
  '- If you start a web server in the sandbox and the user should preview it, call the Cloudflare Sandbox outbound Worker directly with curl and include the returned `preview_url` in your reply as `[preview_url:Short Title](<preview_url>)`.',
948
948
  '- Preview ports must be 1024-65535 and cannot be 3000. For Vite/Next-style dev servers prefer 5173, 4173, or 8080.',
949
949
  `- Preview curl rule: curl -sS -X POST "\${WTT_SANDBOX_OUTBOX_URL:-http://wtt.preview}/preview-port" -H 'content-type: application/json' -d '{"agent_id":"'\${WTT_AGENT_ID:-cloud-agent}'","port":<port>}'`,
950
- `- Prefer automatic WTT publishing when topic id is available: wtt-connect preview-port --port <port>${topicId ? ` --topic-id ${topicId}` : ' --topic-id <topic_id>'} --title "Short Title". This publishes a cloud_sandbox_preview card and is a convenience wrapper around the same sandbox outbound Worker.`,
950
+ `- Prefer automatic WTT publishing when topic id is available: wtt-connect preview-port --port <port>${topicId ? ` --topic-id ${topicId}` : ' --topic-id <topic_id>'} --title "Short Title" --snapshot-dir <static_dir> --snapshot-entry index.html. This publishes a cloud_sandbox_preview card with live and snapshot URLs.`,
951
951
  );
952
952
  return lines.join('\n');
953
953
  }