wtt-connect 0.2.43 → 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 +1 -1
- package/src/main.js +74 -5
- package/src/runner.js +2 -2
package/package.json
CHANGED
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
|
|
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
|
`);
|
|
@@ -146,9 +149,10 @@ async function previewPort(config, argv) {
|
|
|
146
149
|
if (!Number.isInteger(port) || port < 1024 || port > 65535 || port === 3000) {
|
|
147
150
|
throw new Error('preview-port requires --port <1024-65535>, excluding 3000');
|
|
148
151
|
}
|
|
152
|
+
const keepLast = previewKeepLast(config, argv);
|
|
149
153
|
const cleanup = cleanupOldPreviews(config, {
|
|
150
154
|
currentPort: port,
|
|
151
|
-
keepLast:
|
|
155
|
+
keepLast: Math.max(0, keepLast - 1),
|
|
152
156
|
});
|
|
153
157
|
const preview = await createSandboxPreviewFromOutbox(config, port, {
|
|
154
158
|
name: String(argv.previewName || argv.title || '').trim(),
|
|
@@ -158,7 +162,17 @@ async function previewPort(config, argv) {
|
|
|
158
162
|
const url = preview.preview_url || preview.url;
|
|
159
163
|
if (!url) throw new Error('Cloud Sandbox preview API returned no URL');
|
|
160
164
|
const title = String(argv.title || argv.previewName || preview.name || 'Cloud Sandbox Preview').trim();
|
|
161
|
-
const
|
|
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
|
+
});
|
|
162
176
|
const topicId = String(argv.topicId || argv.sourceId || '').trim();
|
|
163
177
|
let published = null;
|
|
164
178
|
if (topicId) {
|
|
@@ -169,6 +183,8 @@ async function previewPort(config, argv) {
|
|
|
169
183
|
type: 'cloud_sandbox_preview',
|
|
170
184
|
port,
|
|
171
185
|
preview_url: url,
|
|
186
|
+
...(snapshotUrl ? { snapshot_url: snapshotUrl } : {}),
|
|
187
|
+
...(snapshot?.artifact_id ? { artifact_id: snapshot.artifact_id } : {}),
|
|
172
188
|
preview_cleanup: cleanup,
|
|
173
189
|
});
|
|
174
190
|
} finally {
|
|
@@ -176,7 +192,60 @@ async function previewPort(config, argv) {
|
|
|
176
192
|
}
|
|
177
193
|
}
|
|
178
194
|
recordPreview(config, { port, url, name: preview.name || title });
|
|
179
|
-
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}`;
|
|
180
249
|
}
|
|
181
250
|
|
|
182
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
|
|
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
|
|
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
|
}
|