@monoes/monodesign 1.2.20 → 1.2.23
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 +2 -2
- package/cli/engine/cli/main.mjs +21 -1
- package/cli/engine/design-system-checks.mjs +381 -0
- package/cli/engine/design-system-parse.mjs +433 -0
- package/cli/engine/design-system.mjs +20 -736
- package/cli/engine/detect-antipatterns-browser.js +28 -5
- package/cli/engine/detect-antipatterns.mjs +1 -0
- package/cli/engine/engines/regex/detect-text-matchers.mjs +371 -0
- package/cli/engine/engines/regex/detect-text-run.mjs +186 -0
- package/cli/engine/engines/regex/detect-text.mjs +11 -523
- package/cli/engine/engines/static-html/css-cascade-color.mjs +219 -0
- package/cli/engine/engines/static-html/css-cascade-static-data.mjs +138 -0
- package/cli/engine/engines/static-html/css-cascade-static-dom.mjs +132 -0
- package/cli/engine/engines/static-html/css-cascade-static-parse.mjs +393 -0
- package/cli/engine/engines/static-html/css-cascade.mjs +24 -837
- package/cli/engine/engines/static-html/detect-html.mjs +6 -1
- package/cli/engine/findings-group.mjs +94 -0
- package/cli/engine/fix/index.mjs +1 -26
- package/cli/engine/fix/unified-diff.mjs +107 -0
- package/cli/engine/rules/checks-background.mjs +17 -3
- package/cli/engine/rules/checks-element.mjs +2 -0
- package/cli/engine/rules/checks-pure.mjs +9 -2
- package/cli/lib/monodesign-config-consent.mjs +93 -0
- package/cli/lib/monodesign-config-core.mjs +37 -0
- package/cli/lib/monodesign-config-detection.mjs +133 -0
- package/cli/lib/monodesign-config-filter.mjs +198 -0
- package/cli/lib/monodesign-config-ignore-value.mjs +212 -0
- package/cli/lib/monodesign-config.mjs +21 -623
- package/package.json +2 -2
- package/skill/scripts/context-fields.mjs +65 -0
- package/skill/scripts/context-resolve.mjs +425 -0
- package/skill/scripts/context-update.mjs +151 -0
- package/skill/scripts/context-utils.mjs +68 -0
- package/skill/scripts/context-workspace.mjs +245 -0
- package/skill/scripts/context.mjs +17 -891
- package/skill/scripts/hook-admin-config.mjs +152 -0
- package/skill/scripts/hook-admin-ignore.mjs +131 -0
- package/skill/scripts/hook-admin-manifest.mjs +292 -0
- package/skill/scripts/hook-admin.mjs +8 -541
- package/skill/scripts/hook-lib-cache.mjs +145 -0
- package/skill/scripts/hook-lib-config.mjs +292 -0
- package/skill/scripts/hook-lib-detector.mjs +72 -0
- package/skill/scripts/hook-lib-events.mjs +182 -0
- package/skill/scripts/hook-lib-findings.mjs +201 -0
- package/skill/scripts/hook-lib-ignore.mjs +205 -0
- package/skill/scripts/hook-lib-render.mjs +273 -0
- package/skill/scripts/hook-lib-run.mjs +281 -0
- package/skill/scripts/hook-lib-scan-targets.mjs +128 -0
- package/skill/scripts/hook-lib.mjs +71 -1747
- package/skill/scripts/lib/design-parser-colors.mjs +182 -0
- package/skill/scripts/lib/design-parser-extract.mjs +333 -0
- package/skill/scripts/lib/design-parser-sections.mjs +214 -0
- package/skill/scripts/lib/design-parser-yaml.mjs +135 -0
- package/skill/scripts/lib/design-parser.mjs +10 -783
- package/skill/scripts/live/manual-apply-chunk.mjs +151 -0
- package/skill/scripts/live/manual-apply-compact.mjs +122 -0
- package/skill/scripts/live/manual-apply-evidence.mjs +115 -0
- package/skill/scripts/live/manual-apply-log.mjs +179 -0
- package/skill/scripts/live/manual-apply-transaction.mjs +122 -0
- package/skill/scripts/live/manual-apply.mjs +65 -640
- package/skill/scripts/live/svelte-component-accept.mjs +248 -0
- package/skill/scripts/live/svelte-component-css.mjs +230 -0
- package/skill/scripts/live/svelte-component-markup.mjs +104 -0
- package/skill/scripts/live/svelte-component-scaffold.mjs +118 -0
- package/skill/scripts/live/svelte-component-session.mjs +158 -0
- package/skill/scripts/live/svelte-component.mjs +32 -792
- package/skill/scripts/live-accept-mutate.mjs +152 -0
- package/skill/scripts/live-accept-parse.mjs +370 -0
- package/skill/scripts/live-accept-scrub.mjs +59 -0
- package/skill/scripts/live-accept-search.mjs +58 -0
- package/skill/scripts/live-accept.mjs +15 -631
- package/skill/scripts/live-commit-manual-edits-paths.mjs +27 -0
- package/skill/scripts/live-commit-manual-edits-repair.mjs +166 -0
- package/skill/scripts/live-commit-manual-edits-rollback.mjs +231 -0
- package/skill/scripts/live-commit-manual-edits-utils.mjs +167 -0
- package/skill/scripts/live-commit-manual-edits-verify.mjs +356 -0
- package/skill/scripts/live-commit-manual-edits.mjs +24 -881
- package/skill/scripts/live-copy-edit-agent.mjs +16 -551
- package/skill/scripts/live-copy-edit-compact.mjs +137 -0
- package/skill/scripts/live-copy-edit-post-apply.mjs +175 -0
- package/skill/scripts/live-copy-edit-runners.mjs +297 -0
- package/skill/scripts/live-inject-csp.mjs +132 -0
- package/skill/scripts/live-inject-files.mjs +229 -0
- package/skill/scripts/live-inject-tag.mjs +114 -0
- package/skill/scripts/live-inject.mjs +13 -440
- package/skill/scripts/live-server-poll.mjs +232 -0
- package/skill/scripts/live-server-routes.mjs +449 -0
- package/skill/scripts/live-server-state.mjs +361 -0
- package/skill/scripts/live-server.mjs +10 -946
- package/skill/scripts/live-wrap-css.mjs +132 -0
- package/skill/scripts/live-wrap-manual-edit.mjs +153 -0
- package/skill/scripts/live-wrap-search.mjs +247 -0
- package/skill/scripts/live-wrap.mjs +21 -484
- package/skill/scripts/palette-seeds.mjs +401 -0
- package/skill/scripts/palette.mjs +1 -395
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
// Live server session state: config, the shared `state` object, the pending
|
|
2
|
+
// event/poll queue, manual-edit coordination, and small request-auth helpers.
|
|
3
|
+
// Split out of live-server.mjs (file-size sweep — pure move, no behaviour
|
|
4
|
+
// change). Imported by live-server-routes.mjs, live-server-poll.mjs and
|
|
5
|
+
// live-server.mjs itself.
|
|
6
|
+
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import net from 'node:net';
|
|
10
|
+
import { loadContext } from './context.mjs';
|
|
11
|
+
import { getLiveDir } from './lib/monodesign-paths.mjs';
|
|
12
|
+
import { countByPage as countPendingByPage } from './live/manual-edits-buffer.mjs';
|
|
13
|
+
import { createManualApplyController } from './live/manual-apply.mjs';
|
|
14
|
+
import { createManualEditRoutes } from './live/manual-edit-routes.mjs';
|
|
15
|
+
|
|
16
|
+
// PRODUCT.md / DESIGN.md live wherever context.mjs resolves. The generated
|
|
17
|
+
// DESIGN sidecar is project-local at .monodesign/design.json, with legacy
|
|
18
|
+
// DESIGN.json fallback for existing projects.
|
|
19
|
+
const PROJECT_CONTEXT = loadContext(process.cwd());
|
|
20
|
+
const CONTEXT_DIR = PROJECT_CONTEXT.contextDir;
|
|
21
|
+
const DESIGN_MD_PATH = PROJECT_CONTEXT.designPath
|
|
22
|
+
? path.resolve(process.cwd(), PROJECT_CONTEXT.designPath)
|
|
23
|
+
: null;
|
|
24
|
+
const DEFAULT_POLL_TIMEOUT = 600_000; // 10 min — agent re-polls on timeout anyway
|
|
25
|
+
const SSE_HEARTBEAT_INTERVAL = 30_000; // keepalive ping every 30s
|
|
26
|
+
// Query param name every protected route checks against the per-process credential.
|
|
27
|
+
const AUTH_QUERY_KEY = 'token';
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Port detection
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
async function findOpenPort(start = 8400) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const srv = net.createServer();
|
|
36
|
+
srv.listen(start, '127.0.0.1', () => {
|
|
37
|
+
const port = srv.address().port;
|
|
38
|
+
srv.close(() => resolve(port));
|
|
39
|
+
});
|
|
40
|
+
srv.on('error', () => resolve(findOpenPort(start + 1)));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Session state
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
const state = {
|
|
49
|
+
token: null,
|
|
50
|
+
port: null,
|
|
51
|
+
sseClients: new Set(), // SSE response objects (server→browser push)
|
|
52
|
+
pendingEvents: [], // browser events waiting for agent ack ({ event, leaseUntil })
|
|
53
|
+
pendingPolls: [], // agent poll callbacks waiting for browser events
|
|
54
|
+
nextEventSeq: 1,
|
|
55
|
+
lastAgentPollingBroadcast: null,
|
|
56
|
+
exitTimer: null,
|
|
57
|
+
sessionDir: null, // per-session tmp dir for annotation screenshots
|
|
58
|
+
sessionStore: null,
|
|
59
|
+
leaseTimer: null,
|
|
60
|
+
manualEditActivity: null,
|
|
61
|
+
nextManualEditSeq: 1,
|
|
62
|
+
// Deferreds for in-flight chat-routed Apply events. Keyed by event id; each
|
|
63
|
+
// entry is resolved when the chat agent POSTs an ack carrying the batch
|
|
64
|
+
// result, or rejected when the hard timeout fires.
|
|
65
|
+
pendingApplyDeferreds: new Map(),
|
|
66
|
+
// Updated whenever a /poll long-poll request arrives or is resolved with an
|
|
67
|
+
// event. Used to detect "a chat agent is likely attached" without requiring
|
|
68
|
+
// a poll to be parked at the exact moment we dispatch.
|
|
69
|
+
lastPollAt: 0,
|
|
70
|
+
timedOutApplyIds: new Map(),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const CHAT_POLL_FRESHNESS_MS = 60_000;
|
|
74
|
+
const POLL_LEASE_EXPIRY_TIMER_GRACE_MS = 2;
|
|
75
|
+
const DEBUG_MANUAL_EDIT_EVENTS = /^(1|true|yes)$/i.test(process.env.MONODESIGN_LIVE_DEBUG_EVENTS || '');
|
|
76
|
+
|
|
77
|
+
const manualApply = createManualApplyController({
|
|
78
|
+
pendingEvents: state.pendingEvents,
|
|
79
|
+
pendingApplyDeferreds: state.pendingApplyDeferreds,
|
|
80
|
+
timedOutApplyIds: state.timedOutApplyIds,
|
|
81
|
+
enqueueEvent,
|
|
82
|
+
acknowledgePendingEvent,
|
|
83
|
+
flushPendingPolls,
|
|
84
|
+
recordManualEditActivity,
|
|
85
|
+
cwd: () => process.cwd(),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const manualEditRoutes = createManualEditRoutes({
|
|
89
|
+
getToken: () => state.token,
|
|
90
|
+
manualApply,
|
|
91
|
+
recordManualEditActivity,
|
|
92
|
+
getManualEditStatus,
|
|
93
|
+
chatAgentLikelyActive,
|
|
94
|
+
cwd: () => process.cwd(),
|
|
95
|
+
env: () => process.env,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
function chatAgentLikelyActive() {
|
|
99
|
+
if (state.pendingPolls.length > 0) return true;
|
|
100
|
+
if (!state.lastPollAt) return false;
|
|
101
|
+
return Date.now() - state.lastPollAt < CHAT_POLL_FRESHNESS_MS;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Cap per-annotation upload size. A full 1920×1080 PNG is typically <1 MB;
|
|
105
|
+
// cap at 10 MB to guard against runaway writes from a misbehaving client.
|
|
106
|
+
const MAX_ANNOTATION_BYTES = 10 * 1024 * 1024;
|
|
107
|
+
|
|
108
|
+
function enqueueEvent(event) {
|
|
109
|
+
if (!event || (event.id && state.pendingEvents.some((entry) => entry.event?.id === event.id && entry.event?.type === event.type))) return;
|
|
110
|
+
state.pendingEvents.push({ event, leaseUntil: 0, seq: state.nextEventSeq++ });
|
|
111
|
+
flushPendingPolls();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function restorePendingEventsFromStore() {
|
|
115
|
+
if (!state.sessionStore) return;
|
|
116
|
+
for (const snapshot of state.sessionStore.listActiveSessions()) {
|
|
117
|
+
if (snapshot.pendingEvent) enqueueEvent(snapshot.pendingEvent);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function findAvailablePendingEvent(now = Date.now()) {
|
|
122
|
+
for (const entry of state.pendingEvents) {
|
|
123
|
+
if (entry.leaseUntil && entry.leaseUntil > now) continue;
|
|
124
|
+
return entry;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function leaseEvent(entry, leaseMs) {
|
|
130
|
+
if (!entry.event?.id) {
|
|
131
|
+
const idx = state.pendingEvents.indexOf(entry);
|
|
132
|
+
if (idx !== -1) state.pendingEvents.splice(idx, 1);
|
|
133
|
+
return entry.event;
|
|
134
|
+
}
|
|
135
|
+
entry.leaseUntil = Date.now() + leaseMs;
|
|
136
|
+
scheduleLeaseFlush();
|
|
137
|
+
broadcastAgentPollingIfChanged();
|
|
138
|
+
return entry.event;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function acknowledgePendingEvent(id) {
|
|
142
|
+
if (!id) return false;
|
|
143
|
+
const idx = state.pendingEvents.findIndex((entry) => entry.event?.id === id);
|
|
144
|
+
if (idx === -1) return false;
|
|
145
|
+
const acknowledged = state.pendingEvents[idx].event;
|
|
146
|
+
state.pendingEvents.splice(idx, 1);
|
|
147
|
+
scheduleLeaseFlush();
|
|
148
|
+
broadcastAgentPollingIfChanged();
|
|
149
|
+
return acknowledged;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function findPendingEventById(id) {
|
|
153
|
+
if (!id) return null;
|
|
154
|
+
const entry = state.pendingEvents.find((item) => item.event?.id === id);
|
|
155
|
+
return entry?.event || null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function summarizePendingEventForStatus(entry) {
|
|
159
|
+
const event = entry.event || {};
|
|
160
|
+
const summary = {
|
|
161
|
+
id: event.id,
|
|
162
|
+
type: event.type,
|
|
163
|
+
leased: !!(entry.leaseUntil && entry.leaseUntil > Date.now()),
|
|
164
|
+
leaseUntil: entry.leaseUntil || null,
|
|
165
|
+
};
|
|
166
|
+
if (event.type === 'manual_edit_apply') {
|
|
167
|
+
summary.pageUrl = event.pageUrl || null;
|
|
168
|
+
summary.chunk = event.chunk || null;
|
|
169
|
+
summary.repair = event.repair || null;
|
|
170
|
+
summary.evidencePath = event.evidencePath || null;
|
|
171
|
+
summary.agentAction = event.agentAction || manualApply.buildAgentAction(event);
|
|
172
|
+
summary.manualApplySummary = manualApply.summarizeEvent(event, manualApply.getDeferred(event.id)?.batch || event.batch);
|
|
173
|
+
}
|
|
174
|
+
return summary;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function summarizeActiveSessionForClient(snapshot = {}) {
|
|
178
|
+
return {
|
|
179
|
+
id: snapshot.id,
|
|
180
|
+
phase: snapshot.phase,
|
|
181
|
+
pageUrl: snapshot.pageUrl ?? null,
|
|
182
|
+
sourceFile: snapshot.sourceFile ?? null,
|
|
183
|
+
previewFile: snapshot.previewFile ?? null,
|
|
184
|
+
previewMode: snapshot.previewMode ?? null,
|
|
185
|
+
expectedVariants: snapshot.expectedVariants ?? 0,
|
|
186
|
+
arrivedVariants: snapshot.arrivedVariants ?? 0,
|
|
187
|
+
visibleVariant: snapshot.visibleVariant ?? null,
|
|
188
|
+
checkpointRevision: snapshot.checkpointRevision ?? 0,
|
|
189
|
+
paramValues: snapshot.paramValues || {},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function activeSessionSummaries() {
|
|
194
|
+
if (!state.sessionStore) return [];
|
|
195
|
+
return state.sessionStore.listActiveSessions().map((snapshot) => summarizeActiveSessionForClient(snapshot));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function cancelQueuedAnonymousExitEvents() {
|
|
199
|
+
let removed = 0;
|
|
200
|
+
for (let i = state.pendingEvents.length - 1; i >= 0; i -= 1) {
|
|
201
|
+
const event = state.pendingEvents[i]?.event;
|
|
202
|
+
if (event?.type !== 'exit' || event.id) continue;
|
|
203
|
+
state.pendingEvents.splice(i, 1);
|
|
204
|
+
removed += 1;
|
|
205
|
+
}
|
|
206
|
+
if (removed > 0) {
|
|
207
|
+
scheduleLeaseFlush();
|
|
208
|
+
broadcastAgentPollingIfChanged();
|
|
209
|
+
}
|
|
210
|
+
return removed;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function scheduleLeaseFlush() {
|
|
214
|
+
if (state.leaseTimer) {
|
|
215
|
+
clearTimeout(state.leaseTimer);
|
|
216
|
+
state.leaseTimer = null;
|
|
217
|
+
}
|
|
218
|
+
const now = Date.now();
|
|
219
|
+
const nextLeaseUntil = state.pendingEvents
|
|
220
|
+
.map((entry) => entry.leaseUntil || 0)
|
|
221
|
+
.filter((leaseUntil) => leaseUntil > now)
|
|
222
|
+
.sort((a, b) => a - b)[0];
|
|
223
|
+
if (!nextLeaseUntil) return;
|
|
224
|
+
state.leaseTimer = setTimeout(() => {
|
|
225
|
+
state.leaseTimer = null;
|
|
226
|
+
flushPendingPolls();
|
|
227
|
+
broadcastAgentPollingIfChanged();
|
|
228
|
+
}, Math.max(0, nextLeaseUntil - now + POLL_LEASE_EXPIRY_TIMER_GRACE_MS));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function flushPendingPolls() {
|
|
232
|
+
let changed = false;
|
|
233
|
+
while (state.pendingPolls.length > 0) {
|
|
234
|
+
const entry = findAvailablePendingEvent();
|
|
235
|
+
if (!entry) {
|
|
236
|
+
scheduleLeaseFlush();
|
|
237
|
+
broadcastAgentPollingIfChanged();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const poll = state.pendingPolls.shift();
|
|
241
|
+
poll.resolve(leaseEvent(entry, poll.leaseMs));
|
|
242
|
+
changed = true;
|
|
243
|
+
}
|
|
244
|
+
scheduleLeaseFlush();
|
|
245
|
+
if (changed) broadcastAgentPollingIfChanged();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function agentPollingConnected() {
|
|
249
|
+
const now = Date.now();
|
|
250
|
+
return state.pendingPolls.length > 0
|
|
251
|
+
|| state.pendingEvents.some((entry) => entry.leaseUntil && entry.leaseUntil > now);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function broadcastAgentPollingIfChanged() {
|
|
255
|
+
const connected = agentPollingConnected();
|
|
256
|
+
if (state.lastAgentPollingBroadcast === connected) return;
|
|
257
|
+
state.lastAgentPollingBroadcast = connected;
|
|
258
|
+
broadcast({ type: 'agent_polling', connected });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Push a message to all connected SSE clients. */
|
|
262
|
+
function broadcast(msg) {
|
|
263
|
+
const data = `data: ${JSON.stringify(msg)}\n\n`;
|
|
264
|
+
for (const res of state.sseClients) {
|
|
265
|
+
try { res.write(data); } catch { /* client gone */ }
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function recordManualEditActivity(type, details = {}) {
|
|
270
|
+
const entry = {
|
|
271
|
+
seq: state.nextManualEditSeq++,
|
|
272
|
+
type,
|
|
273
|
+
ts: new Date().toISOString(),
|
|
274
|
+
...details,
|
|
275
|
+
};
|
|
276
|
+
state.manualEditActivity = entry;
|
|
277
|
+
if (DEBUG_MANUAL_EDIT_EVENTS) {
|
|
278
|
+
try {
|
|
279
|
+
const filePath = path.join(getLiveDir(process.cwd()), 'manual-edit-events.jsonl');
|
|
280
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
281
|
+
fs.appendFileSync(filePath, `${JSON.stringify(entry)}\n`);
|
|
282
|
+
} catch {
|
|
283
|
+
/* diagnostics are best-effort; never block live mode on observability */
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
broadcast(entry);
|
|
287
|
+
return entry;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function getManualEditStatus() {
|
|
291
|
+
try {
|
|
292
|
+
const { totalCount, perPage } = countPendingByPage(process.cwd());
|
|
293
|
+
return { totalCount, perPage, lastActivity: state.manualEditActivity };
|
|
294
|
+
} catch (err) {
|
|
295
|
+
return {
|
|
296
|
+
totalCount: null,
|
|
297
|
+
perPage: {},
|
|
298
|
+
lastActivity: state.manualEditActivity,
|
|
299
|
+
error: err.message,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function hasProjectContext() {
|
|
304
|
+
// PRODUCT.md carries brand voice / anti-references — that's what determines
|
|
305
|
+
// whether variants are brand-aware. DESIGN.md (visual tokens) is a separate
|
|
306
|
+
// concern, surfaced by the design panel's own empty state.
|
|
307
|
+
return !!PROJECT_CONTEXT.hasProduct;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function statOrNull(filePath) {
|
|
311
|
+
try { return fs.statSync(filePath); } catch { return null; }
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Shared gate for every protected route, including /live.js (see its call
|
|
315
|
+
// site for why that one needs it too). Writes the 401 itself and returns
|
|
316
|
+
// false so callers can `if (!requireAuthQueryCred(url, res)) return;`.
|
|
317
|
+
function requireAuthQueryCred(url, res) {
|
|
318
|
+
const provided = url.searchParams.get(AUTH_QUERY_KEY);
|
|
319
|
+
const expected = state[AUTH_QUERY_KEY];
|
|
320
|
+
if (provided !== expected) {
|
|
321
|
+
res.writeHead(401);
|
|
322
|
+
res.end('Unauthorized');
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export {
|
|
329
|
+
PROJECT_CONTEXT,
|
|
330
|
+
CONTEXT_DIR,
|
|
331
|
+
DESIGN_MD_PATH,
|
|
332
|
+
DEFAULT_POLL_TIMEOUT,
|
|
333
|
+
SSE_HEARTBEAT_INTERVAL,
|
|
334
|
+
AUTH_QUERY_KEY,
|
|
335
|
+
findOpenPort,
|
|
336
|
+
state,
|
|
337
|
+
MAX_ANNOTATION_BYTES,
|
|
338
|
+
manualApply,
|
|
339
|
+
manualEditRoutes,
|
|
340
|
+
chatAgentLikelyActive,
|
|
341
|
+
enqueueEvent,
|
|
342
|
+
restorePendingEventsFromStore,
|
|
343
|
+
findAvailablePendingEvent,
|
|
344
|
+
leaseEvent,
|
|
345
|
+
acknowledgePendingEvent,
|
|
346
|
+
findPendingEventById,
|
|
347
|
+
summarizePendingEventForStatus,
|
|
348
|
+
summarizeActiveSessionForClient,
|
|
349
|
+
activeSessionSummaries,
|
|
350
|
+
cancelQueuedAnonymousExitEvents,
|
|
351
|
+
scheduleLeaseFlush,
|
|
352
|
+
flushPendingPolls,
|
|
353
|
+
agentPollingConnected,
|
|
354
|
+
broadcastAgentPollingIfChanged,
|
|
355
|
+
broadcast,
|
|
356
|
+
recordManualEditActivity,
|
|
357
|
+
getManualEditStatus,
|
|
358
|
+
hasProjectContext,
|
|
359
|
+
statOrNull,
|
|
360
|
+
requireAuthQueryCred,
|
|
361
|
+
};
|