gestalt-mobile 0.13.0 → 0.14.0
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 +42 -11
- package/dist/client/assets/index-C5qFcFUg.css +1 -0
- package/dist/client/assets/index-tMyOolAm.js +24 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-ext-400-normal-Bh0R7Dhr.woff +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-ext-400-normal-C_uLvvQ5.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-ByoDsISC.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/client/assets/syne-greek-600-normal-BJs4kvyH.woff +0 -0
- package/dist/client/assets/syne-greek-600-normal-BpFII5Ja.woff2 +0 -0
- package/dist/client/assets/syne-latin-600-normal-BiwQbQXw.woff2 +0 -0
- package/dist/client/assets/syne-latin-600-normal-dRu9QuIh.woff +0 -0
- package/dist/client/assets/syne-latin-ext-600-normal-DEzBMW8B.woff +0 -0
- package/dist/client/assets/syne-latin-ext-600-normal-ZnizrDKU.woff2 +0 -0
- package/dist/client/index.html +3 -2
- package/dist/server/server/cli.js +3 -1
- package/dist/server/server/composition.js +25 -21
- package/dist/server/server/features/auth/devices/revoke/endpoint.js +3 -1
- package/dist/server/server/features/auth/enrollment-tickets/endpoint.js +7 -2
- package/dist/server/server/features/auth/enrollment-tickets/status/endpoint.js +3 -1
- package/dist/server/server/features/auth/http/cookies.js +12 -2
- package/dist/server/server/features/auth/register/verify/endpoint.js +70 -15
- package/dist/server/server/features/plans/application/measurement-snapshot.js +1 -1
- package/dist/server/server/features/plans/get-measurement/endpoint.js +1 -3
- package/dist/server/server/features/sessions/interaction/kind.js +7 -1
- package/dist/server/server/features/sessions/list-recent-threads/endpoint.js +3 -1
- package/dist/server/server/features/sessions/model/relay-session.js +3 -1
- package/dist/server/server/features/sessions/start-session/use-case.js +1 -1
- package/dist/server/server/features/skills/delete-profile/endpoint.js +12 -3
- package/dist/server/server/features/skills/list-available/endpoint.js +24 -6
- package/dist/server/server/features/skills/list-profiles/endpoint.js +29 -5
- package/dist/server/server/features/skills/model/skill-profile.js +23 -3
- package/dist/server/server/platform/auth/simple-webauthn-adapter.js +23 -3
- package/dist/server/server/platform/catalog/profile-command.js +8 -1
- package/dist/server/server/platform/codex/normalizer.js +22 -4
- package/dist/server/server/platform/codex/session-runtime.js +52 -11
- package/dist/server/server/platform/codex/thread-plan-name.js +5 -2
- package/dist/server/server/platform/http/problem-reply.js +4 -1
- package/dist/server/server/platform/plans/filesystem-plan-status-source.js +11 -6
- package/dist/server/server/platform/plans/filesystem-workspace-plan-catalog.js +4 -1
- package/dist/server/server/platform/plans/plan-measurement-command.js +4 -1
- package/dist/server/server/platform/skills/codex-skill-catalog.js +29 -7
- package/dist/server/server/platform/skills/filesystem-skill-profile-store.js +5 -1
- package/dist/server/shared/contracts/quiz.js +30 -9
- package/package.json +3 -1
- package/dist/client/assets/index-CMs5ZzxJ.css +0 -1
- package/dist/client/assets/index-D2sT9ZHY.js +0 -19
|
@@ -36,18 +36,34 @@ export function decodeNotification(input) {
|
|
|
36
36
|
if (input.method === 'item/agentMessage/delta') {
|
|
37
37
|
const params = record(input.params);
|
|
38
38
|
return typeof params?.delta === 'string' && params.delta.length <= 64_000
|
|
39
|
-
? { method: input.method, params: { delta: params.delta } }
|
|
39
|
+
? { method: input.method, params: { delta: params.delta } }
|
|
40
|
+
: null;
|
|
40
41
|
}
|
|
41
42
|
if (input.method === 'turn/completed') {
|
|
42
43
|
const params = record(input.params);
|
|
43
44
|
const turn = record(params?.turn);
|
|
44
45
|
if (!turn || typeof turn.id !== 'string' || turn.id.length > 256)
|
|
45
46
|
return null;
|
|
46
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
method: input.method,
|
|
49
|
+
params: {
|
|
50
|
+
...(typeof params?.threadId === 'string' && params.threadId.length <= 256
|
|
51
|
+
? { threadId: params.threadId }
|
|
52
|
+
: {}),
|
|
53
|
+
turn: {
|
|
54
|
+
id: turn.id,
|
|
55
|
+
...(typeof turn.status === 'string' && turn.status.length <= 64
|
|
56
|
+
? { status: turn.status }
|
|
57
|
+
: {}),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
47
61
|
}
|
|
48
62
|
if (input.method === 'item/started' || input.method === 'item/completed') {
|
|
49
63
|
const params = record(input.params);
|
|
50
|
-
return params && 'item' in params
|
|
64
|
+
return params && 'item' in params
|
|
65
|
+
? { method: input.method, params: { item: params.item } }
|
|
66
|
+
: null;
|
|
51
67
|
}
|
|
52
68
|
return null;
|
|
53
69
|
}
|
|
@@ -103,5 +119,7 @@ function reasoningSummary(parts) {
|
|
|
103
119
|
});
|
|
104
120
|
}
|
|
105
121
|
function record(value) {
|
|
106
|
-
return value && typeof value === 'object' && !Array.isArray(value)
|
|
122
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
123
|
+
? value
|
|
124
|
+
: null;
|
|
107
125
|
}
|
|
@@ -47,8 +47,12 @@ class SessionResource {
|
|
|
47
47
|
this.onDisposed();
|
|
48
48
|
return true;
|
|
49
49
|
}
|
|
50
|
-
get active() {
|
|
51
|
-
|
|
50
|
+
get active() {
|
|
51
|
+
return !this.disposed;
|
|
52
|
+
}
|
|
53
|
+
attach(unregister) {
|
|
54
|
+
this.unregister = unregister;
|
|
55
|
+
}
|
|
52
56
|
}
|
|
53
57
|
export class CodexSessionRuntime {
|
|
54
58
|
launch;
|
|
@@ -149,7 +153,10 @@ export class CodexSessionRuntime {
|
|
|
149
153
|
throw new Error('CODEX_SESSION_NOT_RUNNING');
|
|
150
154
|
const [rateLimits, thread] = await Promise.all([
|
|
151
155
|
resource.process.rpc.request('account/rateLimits/read', {}),
|
|
152
|
-
resource.process.rpc.request('thread/read', {
|
|
156
|
+
resource.process.rpc.request('thread/read', {
|
|
157
|
+
threadId: session.threadId,
|
|
158
|
+
includeTurns: true,
|
|
159
|
+
}),
|
|
153
160
|
]);
|
|
154
161
|
return createPlanMeasurementSnapshot({
|
|
155
162
|
capturedAt: new Date().toISOString(),
|
|
@@ -208,7 +215,9 @@ export class CodexSessionRuntime {
|
|
|
208
215
|
catch (error) {
|
|
209
216
|
if (!canRebindMissingRollout(session, error))
|
|
210
217
|
throw error;
|
|
211
|
-
const replacementThreadId = await this.startThread(resource.process, session, {
|
|
218
|
+
const replacementThreadId = await this.startThread(resource.process, session, {
|
|
219
|
+
model: session.model,
|
|
220
|
+
});
|
|
212
221
|
result = rebindMissingRollout(session, error, replacementThreadId, now);
|
|
213
222
|
}
|
|
214
223
|
resource.threadId = result.session.threadId;
|
|
@@ -234,7 +243,11 @@ export class CodexSessionRuntime {
|
|
|
234
243
|
const resource = this.sessions.get(sessionId);
|
|
235
244
|
const threadId = resource?.threadId;
|
|
236
245
|
const name = resource?.pendingThreadName;
|
|
237
|
-
if (!resource ||
|
|
246
|
+
if (!resource ||
|
|
247
|
+
!threadId ||
|
|
248
|
+
!name ||
|
|
249
|
+
resource.writtenThreadName === name ||
|
|
250
|
+
resource.capabilities.get('thread/name/set') === false)
|
|
238
251
|
return;
|
|
239
252
|
try {
|
|
240
253
|
await resource.process.rpc.request('thread/name/set', { threadId, name });
|
|
@@ -286,7 +299,7 @@ export class CodexSessionRuntime {
|
|
|
286
299
|
profile: session.profile,
|
|
287
300
|
cwd: session.workspacePath,
|
|
288
301
|
skillsConfig: await this.resolveSkills?.(session),
|
|
289
|
-
...(
|
|
302
|
+
...(lease || this.planMeasurementBaseUrl
|
|
290
303
|
? {
|
|
291
304
|
environment: {
|
|
292
305
|
...(lease
|
|
@@ -347,7 +360,12 @@ function decodeRateLimits(value) {
|
|
|
347
360
|
return undefined;
|
|
348
361
|
const decoded = limits.flatMap((limit) => {
|
|
349
362
|
const record = asRecord(limit);
|
|
350
|
-
return typeof record?.windowDurationMins === 'number' &&
|
|
363
|
+
return typeof record?.windowDurationMins === 'number' &&
|
|
364
|
+
Number.isFinite(record.windowDurationMins) &&
|
|
365
|
+
typeof record.usedPercent === 'number' &&
|
|
366
|
+
Number.isFinite(record.usedPercent)
|
|
367
|
+
? [{ windowDurationMins: record.windowDurationMins, usedPercent: record.usedPercent }]
|
|
368
|
+
: [];
|
|
351
369
|
});
|
|
352
370
|
return decoded.length === limits.length ? { rateLimits: decoded } : undefined;
|
|
353
371
|
}
|
|
@@ -396,10 +414,18 @@ function decodeThreadRead(value) {
|
|
|
396
414
|
const record = asRecord(turn);
|
|
397
415
|
if (!record)
|
|
398
416
|
throw new Error('CODEX_THREAD_READ_MALFORMED');
|
|
399
|
-
return {
|
|
417
|
+
return {
|
|
418
|
+
id: boundedString(record.id),
|
|
419
|
+
status: boundedString(record.status),
|
|
420
|
+
startedAt: typeof record.startedAt === 'number' ? record.startedAt : undefined,
|
|
421
|
+
completedAt: typeof record.completedAt === 'number' ? record.completedAt : undefined,
|
|
422
|
+
items: Array.isArray(record.items) ? record.items.flatMap(decodeHistoryItem) : undefined,
|
|
423
|
+
};
|
|
400
424
|
});
|
|
401
425
|
}
|
|
402
|
-
function boundedString(value, max = 64_000) {
|
|
426
|
+
function boundedString(value, max = 64_000) {
|
|
427
|
+
return typeof value === 'string' && value.length <= max ? value : undefined;
|
|
428
|
+
}
|
|
403
429
|
function decodeHistoryItem(value) {
|
|
404
430
|
const item = asRecord(value);
|
|
405
431
|
const id = boundedString(item?.id, 256);
|
|
@@ -407,10 +433,25 @@ function decodeHistoryItem(value) {
|
|
|
407
433
|
if (!item || !id || !type)
|
|
408
434
|
return [];
|
|
409
435
|
if (type === 'agentMessage')
|
|
410
|
-
return [
|
|
436
|
+
return [
|
|
437
|
+
{
|
|
438
|
+
id,
|
|
439
|
+
type,
|
|
440
|
+
...(boundedString(item.text) ? { text: boundedString(item.text) } : {}),
|
|
441
|
+
...(boundedString(item.phase, 64) ? { phase: boundedString(item.phase, 64) } : {}),
|
|
442
|
+
},
|
|
443
|
+
];
|
|
411
444
|
if (type === 'plan' && boundedString(item.text))
|
|
412
445
|
return [{ id, type, text: boundedString(item.text) }];
|
|
413
446
|
if (type === 'commandExecution' && boundedString(item.command) && boundedString(item.status, 64))
|
|
414
|
-
return [
|
|
447
|
+
return [
|
|
448
|
+
{
|
|
449
|
+
id,
|
|
450
|
+
type,
|
|
451
|
+
command: boundedString(item.command),
|
|
452
|
+
status: boundedString(item.status, 64),
|
|
453
|
+
...(typeof item.exitCode === 'number' ? { exitCode: item.exitCode } : {}),
|
|
454
|
+
},
|
|
455
|
+
];
|
|
415
456
|
return [];
|
|
416
457
|
}
|
|
@@ -12,12 +12,15 @@ export function threadPlanName(plan, limit = 120) {
|
|
|
12
12
|
? `L1 ${l1.indexOf(active) + 1}/${l1.length}`
|
|
13
13
|
: awaiting
|
|
14
14
|
? `Review ${l1.indexOf(awaiting) + 1}/${l1.length}`
|
|
15
|
-
: l1.length > 0 &&
|
|
15
|
+
: l1.length > 0 &&
|
|
16
|
+
l1.every((step) => step.state === 'DONE' && step.reviewStatus === 'REVIEWED')
|
|
16
17
|
? 'Complete'
|
|
17
18
|
: 'Authoring';
|
|
18
19
|
return `${truncateTitle(plan.title, Math.max(1, limit - suffix.length - 3))} — ${suffix}`;
|
|
19
20
|
}
|
|
20
21
|
function truncateTitle(value, limit) {
|
|
21
22
|
const characters = Array.from(value);
|
|
22
|
-
return characters.length <= limit
|
|
23
|
+
return characters.length <= limit
|
|
24
|
+
? value
|
|
25
|
+
: `${characters.slice(0, Math.max(0, limit - 1)).join('')}…`;
|
|
23
26
|
}
|
|
@@ -6,5 +6,8 @@
|
|
|
6
6
|
import { problem } from './problem.js';
|
|
7
7
|
/** Send the established RFC 7807-compatible response without deciding its semantics. */
|
|
8
8
|
export function sendProblem(reply, code, status, detail) {
|
|
9
|
-
return reply
|
|
9
|
+
return reply
|
|
10
|
+
.code(status)
|
|
11
|
+
.type('application/problem+json')
|
|
12
|
+
.send(problem(code, status, detail));
|
|
10
13
|
}
|
|
@@ -29,10 +29,7 @@ export class FilesystemPlanStatusSource {
|
|
|
29
29
|
await mkdir(this.dismissalDirectory, { recursive: true, mode: 0o700 });
|
|
30
30
|
await mkdir(statusDirectory, { recursive: true, mode: 0o700 });
|
|
31
31
|
if (process.platform !== 'win32') {
|
|
32
|
-
await Promise.all([
|
|
33
|
-
chmod(this.dismissalDirectory, 0o700),
|
|
34
|
-
chmod(statusDirectory, 0o700),
|
|
35
|
-
]);
|
|
32
|
+
await Promise.all([chmod(this.dismissalDirectory, 0o700), chmod(statusDirectory, 0o700)]);
|
|
36
33
|
}
|
|
37
34
|
const lease = new ActiveLease(statusDirectory, session.id, session.workspacePath, listener, this.planReadFilesystem, (identity) => this.isDismissed(session.id, identity), (statusPath) => this.activeStatusPaths.set(session.id, statusPath), () => {
|
|
38
35
|
this.leases.delete(session.id);
|
|
@@ -97,7 +94,9 @@ export class FilesystemPlanStatusSource {
|
|
|
97
94
|
const next = new Set(dismissed).add(identity);
|
|
98
95
|
const candidate = join(this.dismissalDirectory, `.${randomUUID()}.dismissals.tmp`);
|
|
99
96
|
try {
|
|
100
|
-
await this.dismissalFilesystem.writeFile(candidate, JSON.stringify([...next]), {
|
|
97
|
+
await this.dismissalFilesystem.writeFile(candidate, JSON.stringify([...next]), {
|
|
98
|
+
mode: 0o600,
|
|
99
|
+
});
|
|
101
100
|
await this.dismissalFilesystem.rename(candidate, path);
|
|
102
101
|
}
|
|
103
102
|
catch (error) {
|
|
@@ -272,7 +271,13 @@ class ActiveLease {
|
|
|
272
271
|
const previousStatusPath = this.activeStatusPath;
|
|
273
272
|
this.activeStatusPath = statusPath;
|
|
274
273
|
this.onActiveStatusPath(statusPath);
|
|
275
|
-
const update = {
|
|
274
|
+
const update = {
|
|
275
|
+
kind: 'updated',
|
|
276
|
+
plan: result.plan,
|
|
277
|
+
identity,
|
|
278
|
+
planPath,
|
|
279
|
+
reason: signal.reason,
|
|
280
|
+
};
|
|
276
281
|
const serializedUpdate = JSON.stringify(update);
|
|
277
282
|
if (serializedUpdate !== this.lastEmittedUpdate) {
|
|
278
283
|
this.lastEmittedUpdate = serializedUpdate;
|
|
@@ -78,7 +78,10 @@ export class FilesystemWorkspacePlanCatalog {
|
|
|
78
78
|
return { kind: 'unavailable' };
|
|
79
79
|
const source = await this.filesystem.readFile(canonical, 'utf8');
|
|
80
80
|
const after = await this.filesystem.stat(canonical);
|
|
81
|
-
if (!after.isFile() ||
|
|
81
|
+
if (!after.isFile() ||
|
|
82
|
+
after.size !== before.size ||
|
|
83
|
+
after.ino !== before.ino ||
|
|
84
|
+
after.dev !== before.dev)
|
|
82
85
|
return { kind: 'unavailable' };
|
|
83
86
|
const parsed = parseSupervisedPlan({ source, planPath: canonical, workspacePath });
|
|
84
87
|
return parsed.kind === 'available' ? parsed : { kind: 'unavailable' };
|
|
@@ -9,5 +9,8 @@ const execute = promisify(execFile);
|
|
|
9
9
|
export const PLAN_MEASUREMENT_COMMAND_TIMEOUT_MS = 15_000;
|
|
10
10
|
/** Invokes the explicitly configured Org Plan helper without a shell. */
|
|
11
11
|
export async function checkpointPlanMeasurement(helperPath, planPath, stepId, snapshot) {
|
|
12
|
-
await execute(helperPath, ['measure', 'checkpoint', planPath, stepId, JSON.stringify(snapshot)], {
|
|
12
|
+
await execute(helperPath, ['measure', 'checkpoint', planPath, stepId, JSON.stringify(snapshot)], {
|
|
13
|
+
shell: false,
|
|
14
|
+
timeout: PLAN_MEASUREMENT_COMMAND_TIMEOUT_MS,
|
|
15
|
+
});
|
|
13
16
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { resolve } from 'node:path';
|
|
8
|
-
import { availableSkillSchema } from '../../features/skills/model/skill-profile.js';
|
|
8
|
+
import { availableSkillSchema, } from '../../features/skills/model/skill-profile.js';
|
|
9
9
|
import { SkillProfileError } from '../../features/skills/model/errors.js';
|
|
10
10
|
import { launchCodexAppServer } from '../codex/codex-process-launcher.js';
|
|
11
11
|
const optionalString = z.preprocess((value) => (value === null ? undefined : value), z.string().optional());
|
|
@@ -19,12 +19,25 @@ const toolSchema = z.object({
|
|
|
19
19
|
url: optionalString,
|
|
20
20
|
});
|
|
21
21
|
const wireSkillSchema = z.object({
|
|
22
|
-
name: z.string(),
|
|
23
|
-
|
|
22
|
+
name: z.string(),
|
|
23
|
+
description: z.string(),
|
|
24
|
+
shortDescription: optionalString,
|
|
25
|
+
interface: optionalObject(z.object({
|
|
26
|
+
displayName: optionalString,
|
|
27
|
+
shortDescription: optionalString,
|
|
28
|
+
iconSmall: optionalString,
|
|
29
|
+
iconLarge: optionalString,
|
|
30
|
+
brandColor: optionalString,
|
|
31
|
+
defaultPrompt: optionalString,
|
|
32
|
+
})),
|
|
24
33
|
dependencies: optionalObject(z.object({ tools: optionalObject(z.array(toolSchema)) })),
|
|
25
|
-
path: z.string(),
|
|
34
|
+
path: z.string(),
|
|
35
|
+
scope: optionalString,
|
|
36
|
+
enabled: z.boolean(),
|
|
37
|
+
});
|
|
38
|
+
const resultSchema = z.object({
|
|
39
|
+
data: z.array(z.object({ cwd: z.string(), skills: z.array(wireSkillSchema), errors: z.array(z.unknown()) })),
|
|
26
40
|
});
|
|
27
|
-
const resultSchema = z.object({ data: z.array(z.object({ cwd: z.string(), skills: z.array(wireSkillSchema), errors: z.array(z.unknown()) })) });
|
|
28
41
|
/** Short-lived Codex app-server adapter: initialize, discover, and always terminate. */
|
|
29
42
|
export class CodexSkillCatalog {
|
|
30
43
|
profile;
|
|
@@ -58,7 +71,14 @@ export class CodexSkillCatalog {
|
|
|
58
71
|
});
|
|
59
72
|
return {
|
|
60
73
|
skills,
|
|
61
|
-
errors: entry.errors.map((error) => ({
|
|
74
|
+
errors: entry.errors.map((error) => ({
|
|
75
|
+
message: typeof error === 'object' &&
|
|
76
|
+
error !== null &&
|
|
77
|
+
'message' in error &&
|
|
78
|
+
typeof error.message === 'string'
|
|
79
|
+
? error.message
|
|
80
|
+
: 'Codex skill discovery error.',
|
|
81
|
+
})),
|
|
62
82
|
};
|
|
63
83
|
}
|
|
64
84
|
catch (error) {
|
|
@@ -75,7 +95,9 @@ export class CodexSkillCatalog {
|
|
|
75
95
|
try {
|
|
76
96
|
return await Promise.race([
|
|
77
97
|
promise,
|
|
78
|
-
new Promise((_, reject) => {
|
|
98
|
+
new Promise((_, reject) => {
|
|
99
|
+
timer = setTimeout(() => reject(new Error('timeout')), this.timeoutMs);
|
|
100
|
+
}),
|
|
79
101
|
]);
|
|
80
102
|
}
|
|
81
103
|
finally {
|
|
@@ -55,7 +55,11 @@ export class FilesystemSkillProfileStore {
|
|
|
55
55
|
const destination = join(root, `${name}.yml`);
|
|
56
56
|
const temporary = join(root, `.${name}.${randomUUID()}.tmp`);
|
|
57
57
|
try {
|
|
58
|
-
await writeFile(temporary, serializeSkillProfileYaml(profile), {
|
|
58
|
+
await writeFile(temporary, serializeSkillProfileYaml(profile), {
|
|
59
|
+
encoding: 'utf8',
|
|
60
|
+
mode: 0o600,
|
|
61
|
+
flag: 'wx',
|
|
62
|
+
});
|
|
59
63
|
await rename(temporary, destination);
|
|
60
64
|
}
|
|
61
65
|
finally {
|
|
@@ -26,7 +26,12 @@ export const gestaltQuizDynamicTool = {
|
|
|
26
26
|
additionalProperties: false,
|
|
27
27
|
required: ['id', 'header', 'question', 'choices', 'allowCustom'],
|
|
28
28
|
properties: {
|
|
29
|
-
id: {
|
|
29
|
+
id: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
minLength: 1,
|
|
32
|
+
maxLength: 64,
|
|
33
|
+
pattern: '^[A-Za-z][A-Za-z0-9_-]*$',
|
|
34
|
+
},
|
|
30
35
|
header: { type: 'string', minLength: 1, maxLength: 120 },
|
|
31
36
|
question: { type: 'string', minLength: 1, maxLength: 600 },
|
|
32
37
|
choices: {
|
|
@@ -61,7 +66,9 @@ export function parseQuiz(value, minimumChoices = 2) {
|
|
|
61
66
|
if (questions.some((question) => question === null))
|
|
62
67
|
return null;
|
|
63
68
|
const parsed = questions;
|
|
64
|
-
return new Set(parsed.map((question) => question.id)).size === parsed.length
|
|
69
|
+
return new Set(parsed.map((question) => question.id)).size === parsed.length
|
|
70
|
+
? { questions: parsed }
|
|
71
|
+
: null;
|
|
65
72
|
}
|
|
66
73
|
/** Maps Codex's experimental native request shape into the common quiz value. */
|
|
67
74
|
export function mapNativeUserInputToQuiz(value) {
|
|
@@ -87,7 +94,9 @@ export function toQuizToolResponse(answers) {
|
|
|
87
94
|
{
|
|
88
95
|
type: 'input_text',
|
|
89
96
|
text: JSON.stringify({
|
|
90
|
-
answers: Object.fromEntries(answers
|
|
97
|
+
answers: Object.fromEntries(answers
|
|
98
|
+
.filter((answer) => answer.answer.trim())
|
|
99
|
+
.map((answer) => [answer.id, answer.answer])),
|
|
91
100
|
}),
|
|
92
101
|
},
|
|
93
102
|
],
|
|
@@ -98,7 +107,10 @@ export function isQuizToolResponseForQuiz(quiz, value) {
|
|
|
98
107
|
if (!isRecord(value) || value.success !== true || !Array.isArray(value.contentItems))
|
|
99
108
|
return false;
|
|
100
109
|
const item = value.contentItems[0];
|
|
101
|
-
if (value.contentItems.length !== 1 ||
|
|
110
|
+
if (value.contentItems.length !== 1 ||
|
|
111
|
+
!isRecord(item) ||
|
|
112
|
+
item.type !== 'input_text' ||
|
|
113
|
+
typeof item.text !== 'string')
|
|
102
114
|
return false;
|
|
103
115
|
try {
|
|
104
116
|
const response = parseQuizResponse(JSON.parse(item.text));
|
|
@@ -109,9 +121,14 @@ export function isQuizToolResponseForQuiz(quiz, value) {
|
|
|
109
121
|
}
|
|
110
122
|
}
|
|
111
123
|
function parseQuestion(value, minimumChoices) {
|
|
112
|
-
if (!isRecord(value) ||
|
|
124
|
+
if (!isRecord(value) ||
|
|
125
|
+
!Array.isArray(value.choices) ||
|
|
126
|
+
value.choices.length < minimumChoices ||
|
|
127
|
+
value.choices.length > 5)
|
|
113
128
|
return null;
|
|
114
|
-
if (!isQuestionId(value.id) ||
|
|
129
|
+
if (!isQuestionId(value.id) ||
|
|
130
|
+
!isBoundedText(value.header, 120) ||
|
|
131
|
+
!isBoundedText(value.question, 600))
|
|
115
132
|
return null;
|
|
116
133
|
if (typeof value.allowCustom !== 'boolean')
|
|
117
134
|
return null;
|
|
@@ -128,7 +145,9 @@ function parseQuestion(value, minimumChoices) {
|
|
|
128
145
|
};
|
|
129
146
|
}
|
|
130
147
|
function parseChoice(value) {
|
|
131
|
-
if (!isRecord(value) ||
|
|
148
|
+
if (!isRecord(value) ||
|
|
149
|
+
!isBoundedText(value.label, 160) ||
|
|
150
|
+
!isBoundedText(value.description, 600))
|
|
132
151
|
return null;
|
|
133
152
|
return { label: value.label, description: value.description };
|
|
134
153
|
}
|
|
@@ -136,13 +155,15 @@ function parseQuizResponse(value) {
|
|
|
136
155
|
if (!isRecord(value) || !isRecord(value.answers))
|
|
137
156
|
return null;
|
|
138
157
|
const entries = Object.entries(value.answers);
|
|
139
|
-
if (entries.length === 0 ||
|
|
158
|
+
if (entries.length === 0 ||
|
|
159
|
+
entries.some(([id, answer]) => !isQuestionId(id) || !isBoundedText(answer, 2_000)))
|
|
140
160
|
return null;
|
|
141
161
|
return { answers: Object.fromEntries(entries) };
|
|
142
162
|
}
|
|
143
163
|
function isCompleteQuizResponse(quiz, response) {
|
|
144
164
|
const ids = Object.keys(response.answers);
|
|
145
|
-
if (ids.length !== quiz.questions.length ||
|
|
165
|
+
if (ids.length !== quiz.questions.length ||
|
|
166
|
+
ids.some((id) => !quiz.questions.some((question) => question.id === id)))
|
|
146
167
|
return false;
|
|
147
168
|
return quiz.questions.every((question) => {
|
|
148
169
|
const answer = response.answers[question.id];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gestalt-mobile",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Mobile-first web relay for durable Codex development sessions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -58,6 +58,8 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@fastify/cookie": "11.1.2",
|
|
60
60
|
"@fastify/static": "^10.1.0",
|
|
61
|
+
"@fontsource/jetbrains-mono": "5.2.7",
|
|
62
|
+
"@fontsource/syne": "5.2.7",
|
|
61
63
|
"@simplewebauthn/browser": "13.3.0",
|
|
62
64
|
"@simplewebauthn/server": "13.3.2",
|
|
63
65
|
"fastify": "^5.10.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.session-path.svelte-t9laac{text-align:center;text-overflow:ellipsis;white-space:nowrap;min-inline-size:0;margin:0;overflow:hidden}.session-model.svelte-t9laac{margin-inline-start:clamp(.75rem,3vw,2rem)}@media (width<=34rem){.session-model.svelte-t9laac{display:none}}#chat-activity.svelte-thyolt{--activity-gap:.4rem;--activity-type-color:var(--muted-text,currentColor)}#chat-activity.svelte-thyolt>summary:where(.svelte-thyolt){color:var(--activity-type-color);cursor:pointer;font-size:.875em}.activity-list.svelte-thyolt{gap:var(--activity-gap);margin-block:.25rem 0;margin-inline:0;padding:0;list-style:none;display:grid}.activity-row.svelte-thyolt{flex-wrap:wrap;align-items:baseline;gap:.25rem .5rem;display:flex}.activity-type.svelte-thyolt{color:var(--activity-type-color);font-size:.75em;line-height:1.2}.activity-content.svelte-thyolt{overflow-wrap:anywhere;white-space:pre-wrap;min-inline-size:0}.quiz-form.svelte-77f3gb{gap:1rem;display:grid}fieldset.svelte-77f3gb{border:0;min-inline-size:0;margin:0;padding:0}legend.svelte-77f3gb{gap:.25rem;max-inline-size:100%;display:grid}.choices.svelte-77f3gb{gap:.5rem;margin-block-start:.5rem;display:grid}.choice.svelte-77f3gb{position:relative}.choice.svelte-77f3gb>input:where(.svelte-77f3gb){opacity:0;cursor:pointer;block-size:100%;inline-size:100%;margin:0;position:absolute;inset:0}.choice.svelte-77f3gb>label:where(.svelte-77f3gb){border:2px solid color-mix(in srgb, CanvasText 28%, Canvas);border-radius:.5rem;gap:.125rem;min-block-size:44px;padding:.75rem;display:grid}.choice.svelte-77f3gb>input:where(.svelte-77f3gb):checked+label:where(.svelte-77f3gb){border-width:3px;border-color:highlight}.choice.svelte-77f3gb>input:where(.svelte-77f3gb):focus-visible+label:where(.svelte-77f3gb){outline-offset:2px;outline:3px solid highlight}label.svelte-77f3gb span:where(.svelte-77f3gb),legend.svelte-77f3gb span:where(.svelte-77f3gb){color:color-mix(in srgb, CanvasText 72%, Canvas)}.custom.svelte-77f3gb{margin-block-start:.25rem}.custom.svelte-77f3gb input:where(.svelte-77f3gb){box-sizing:border-box;min-block-size:44px;inline-size:100%;font:inherit;margin-block-start:.375rem}.command-approval-command.svelte-ajsqcq{white-space:pre-wrap;background:color-mix(in srgb, CanvasText 8%, Canvas);border-radius:.375rem;max-inline-size:100%;margin-block:.5rem .75rem;padding:.625rem;overflow-x:auto}.command-approval-missing.svelte-ajsqcq{margin-block:.5rem .75rem}.file-change-approval-targets.svelte-ajsqcq{overflow-wrap:anywhere;margin-block:.5rem .75rem;padding-inline-start:1.5rem}.file-change-approval-missing.svelte-ajsqcq{margin-block:.5rem .75rem}.approval-actions.svelte-ajsqcq{flex-wrap:wrap;gap:clamp(.5rem,2vw,1rem);display:flex}form.svelte-1264sfg>[role=status]:where(.svelte-1264sfg){text-align:start;margin-block:1rem .35rem}.command-menu.svelte-1264sfg{border:1px solid color-mix(in srgb, CanvasText 20%, Canvas);background:canvas;border-radius:.375rem;gap:.125rem;max-inline-size:min(100%,32rem);margin:0 0 .35rem;padding:.25rem;list-style:none;display:grid}.command-menu.svelte-1264sfg button:where(.svelte-1264sfg){inline-size:100%;color:inherit;text-align:start;background:0 0;border:0;border-radius:.25rem;align-items:baseline;gap:.5rem;padding:.25rem .375rem;display:flex}.command-menu.svelte-1264sfg .command-selected:where(.svelte-1264sfg) button:where(.svelte-1264sfg),.command-menu.svelte-1264sfg button:where(.svelte-1264sfg):hover{background:color-mix(in srgb, CanvasText 10%, Canvas)}.command-menu.svelte-1264sfg small:where(.svelte-1264sfg){color:#666;font-size:.8em}.command-menu.svelte-1264sfg button:where(.svelte-1264sfg):focus-visible{outline-offset:1px;outline:2px solid}.prompt-row.svelte-1264sfg{align-items:end;gap:.5rem;display:flex}textarea.svelte-1264sfg{resize:vertical;flex:auto;min-block-size:2.75rem}.prompt-row.svelte-1264sfg button:where(.svelte-1264sfg){flex:none;place-items:center;min-block-size:3rem;inline-size:3rem;padding:0;display:grid}.prompt-row.svelte-1264sfg svg:where(.svelte-1264sfg){fill:none;stroke:currentColor;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;block-size:1.35rem;inline-size:1.35rem}.block-cursor.svelte-1264sfg{vertical-align:-.1em;background:currentColor;block-size:1em;inline-size:.55ch;animation:1s steps(2,start) infinite svelte-1264sfg-blink;display:inline-block}@media (prefers-reduced-motion:reduce){.block-cursor.svelte-1264sfg{animation:none}}@keyframes svelte-1264sfg-blink{50%{opacity:0}}ol.svelte-1im954t{inline-size:100%;margin:0;padding:0;list-style:none}li.svelte-1im954t{box-sizing:border-box;white-space:pre-wrap;overflow-wrap:anywhere;inline-size:100%;margin-block-end:0}li.svelte-1im954t+li:where(.svelte-1im954t){margin-block-start:1rem}.prompt-turn.svelte-1im954t{background:color-mix(in srgb, Canvas 94%, CanvasText);border-radius:.375rem;padding:.5rem .625rem}.entry-heading.svelte-1im954t{align-items:baseline;gap:.75rem;display:flex}time.svelte-1im954t{color:#666;white-space:nowrap;margin-inline-start:auto;font-size:.875em}.commentary-toggle.svelte-1im954t{color:#666;background:0 0;border:0;min-block-size:1.5rem;padding:0 .125rem;font-size:.875em}.commentary-content.svelte-1im954t{margin-block:.25rem .5rem}.entry-content.svelte-1im954t{margin-block:.125rem 0;margin-inline:0}pre.svelte-1im954t,code.svelte-1im954t{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}pre.svelte-1im954t{white-space:pre;overflow-x:auto}.table-scroll.svelte-1im954t{margin-block:.75rem;overflow-x:auto}table.svelte-1im954t{border-collapse:collapse;white-space:normal;width:max-content;min-width:100%}th.svelte-1im954t,td.svelte-1im954t{text-align:left;vertical-align:top;padding:.25rem .5rem}th.svelte-1im954t{font-weight:600}.toast-viewport.svelte-1a0rutm{z-index:10;pointer-events:none;gap:.5rem;max-block-size:calc(100dvh - 7rem);inline-size:min(24rem,100vw - 1.5rem);display:grid;position:fixed;inset-block-start:calc(1rem + env(safe-area-inset-top));inset-inline-end:max(.75rem, env(safe-area-inset-right));overflow-y:auto}.toast.svelte-1a0rutm{box-sizing:border-box;color:canvastext;border:1px solid canvastext;min-inline-size:0;box-shadow:0 .4rem 1.2rem color-mix(in srgb, CanvasText 24%, transparent);pointer-events:auto;background:canvas;border-inline-start-width:.35rem;border-radius:.55rem;grid-template-columns:auto minmax(0,1fr) 44px;align-items:start;gap:.6rem;padding:.65rem;display:grid}.toast.error.svelte-1a0rutm{border-inline-start-style:double}.toast-symbol.svelte-1a0rutm{box-sizing:border-box;border:2px solid;border-radius:50%;place-items:center;block-size:1.6rem;inline-size:1.6rem;font-weight:800;line-height:1;display:grid}.toast-copy.svelte-1a0rutm{overflow-wrap:anywhere;gap:.15rem;min-inline-size:0;padding-block:.1rem;display:grid}.toast-copy.svelte-1a0rutm strong:where(.svelte-1a0rutm){text-transform:capitalize}.toast-copy.svelte-1a0rutm small:where(.svelte-1a0rutm){opacity:.72}button.svelte-1a0rutm{min-block-size:44px;inline-size:44px;color:inherit;font:inherit;background:0 0;border:0;border-radius:.35rem;place-items:center;padding:0;font-size:1.5rem;display:grid}button.svelte-1a0rutm:hover{background:color-mix(in srgb, CanvasText 10%, transparent)}@media (width<=24rem){.toast.svelte-1a0rutm{grid-template-columns:minmax(0,1fr) 44px;gap:.25rem;max-block-size:5rem;padding:.35rem;overflow-y:auto}.toast-symbol.svelte-1a0rutm{display:none}.toast-copy.svelte-1a0rutm strong:where(.svelte-1a0rutm){clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;block-size:1px;inline-size:1px;padding:0;position:absolute;overflow:hidden}}@media (forced-colors:active){.toast.svelte-1a0rutm,.toast-symbol.svelte-1a0rutm{border-color:canvastext}}.evidence-page.svelte-1j55xyh{box-sizing:border-box;min-block-size:100dvh;inline-size:100%;padding:1rem 1rem 7rem}h1.svelte-1j55xyh{margin-block:0 .5rem}.evidence-composer.svelte-1j55xyh{position:fixed;inset-block-end:2.75rem;inset-inline:1rem}.evidence-prompt.svelte-1j55xyh{box-sizing:border-box;inline-size:100%;margin-block-start:.35rem;display:block}.evidence-nav.svelte-1j55xyh{padding:.5rem 1rem calc(.5rem + env(safe-area-inset-bottom));background:canvas;border-block-start:1px solid canvastext;grid-template-columns:repeat(3,minmax(0,1fr));gap:.5rem;display:grid;position:fixed;inset-block-end:0;inset-inline:0}.evidence-nav.svelte-1j55xyh button:where(.svelte-1j55xyh){text-overflow:ellipsis;min-block-size:44px;min-inline-size:0;overflow:hidden}@media (width<=24rem){.evidence-page.svelte-1j55xyh{padding:.5rem .5rem 7rem}.evidence-composer.svelte-1j55xyh{inset-inline:.5rem}}.filesystem-tree.svelte-6z3q4v{inline-size:100%;max-inline-size:100%;display:grid;overflow-x:clip}.tree-row.svelte-6z3q4v{min-inline-size:0;align-items:stretch;padding-inline-start:min(calc(var(--tree-level) * .75rem), 4.5rem);display:flex}.disclosure.svelte-6z3q4v,.disclosure-spacer.svelte-6z3q4v{flex:0 0 44px;min-block-size:44px;inline-size:44px}.disclosure.svelte-6z3q4v{color:inherit;font:inherit;background:0 0;border:0;border-radius:.35rem;place-items:center;padding:0;font-size:1.25rem;font-weight:700;display:grid}.disclosure.svelte-6z3q4v:hover{background:color-mix(in srgb, CanvasText 10%, transparent)}.tree-item.svelte-6z3q4v{min-block-size:44px;min-inline-size:0;color:inherit;font:inherit;text-align:start;background:0 0;border:1px solid #0000;border-radius:.35rem;flex:auto;align-items:center;gap:.5rem;padding:.3rem .5rem;display:flex;overflow:hidden}.tree-item.svelte-6z3q4v:hover{background:color-mix(in srgb, CanvasText 8%, transparent)}.tree-item.selected.svelte-6z3q4v{background:color-mix(in srgb, Highlight 16%, Canvas);border-color:currentColor;font-weight:650}.tree-item[aria-disabled=true].svelte-6z3q4v{opacity:.58}.tree-item.repository.svelte-6z3q4v{border-inline-start-width:3px}.selection-mark.svelte-6z3q4v{text-align:center;flex:0 0 1rem;inline-size:1rem}.node-copy.svelte-6z3q4v{flex:auto;min-inline-size:0;display:grid}.node-name.svelte-6z3q4v,.node-path.svelte-6z3q4v{text-overflow:ellipsis;white-space:nowrap;min-inline-size:0;overflow:hidden}.node-path.svelte-6z3q4v{opacity:.72;font-size:.75em;font-weight:400}.repository-badge.svelte-6z3q4v{border:1px solid;border-radius:999px;flex:none;padding:.1rem .35rem;font-size:.72em;font-weight:700;line-height:1.2}@media (width<=24rem){.tree-row.svelte-6z3q4v{padding-inline-start:min(calc(var(--tree-level) * .25rem), 1.5rem)}.tree-item.svelte-6z3q4v{gap:.35rem;padding-inline:.35rem}.repository-badge.svelte-6z3q4v{display:none}}@media (forced-colors:active){.tree-item.selected.svelte-6z3q4v,.tree-item.repository.svelte-6z3q4v,.repository-badge.svelte-6z3q4v{border-color:canvastext}}.evidence-shell.svelte-1d6w4ti{box-sizing:border-box;inline-size:min(100%,48rem);min-inline-size:0;margin-inline:auto;padding:1rem}.eyebrow.svelte-1d6w4ti{letter-spacing:.08em;text-transform:uppercase;margin:0;font-size:.8rem;font-weight:750}h1.svelte-1d6w4ti{margin-block:.25rem .5rem;font-size:clamp(1.35rem,6vw,2rem);line-height:1.15}.instructions.svelte-1d6w4ti{max-inline-size:42rem;margin-block:0 1rem}.tree-panel.svelte-1d6w4ti{border:1px solid color-mix(in srgb, CanvasText 35%, transparent);border-radius:.6rem;min-inline-size:0;padding:.5rem}@media (width<=24rem){.evidence-shell.svelte-1d6w4ti{padding:.5rem}.tree-panel.svelte-1d6w4ti{padding:.25rem}}.git-view.svelte-pudr3t{gap:1.5rem;inline-size:100%;min-inline-size:0;display:grid}.git-tree.svelte-pudr3t,.repository-details.svelte-pudr3t{min-inline-size:0}.section-heading.svelte-pudr3t h3:where(.svelte-pudr3t),.repository-details.svelte-pudr3t h3:where(.svelte-pudr3t){margin-block:0 .35rem}.section-heading.svelte-pudr3t p:where(.svelte-pudr3t){color:color-mix(in srgb, CanvasText 70%, Canvas);margin-block:0 .75rem}.clone-form.svelte-pudr3t{gap:.35rem;min-inline-size:0;display:grid}.clone-controls.svelte-pudr3t{grid-template-columns:minmax(10rem,.45fr) minmax(0,1fr) auto;align-items:end;gap:.5rem;display:grid}.clone-field.svelte-pudr3t{gap:.35rem;min-inline-size:0;display:grid}.field-label.svelte-pudr3t{font-weight:600}.clone-destination.svelte-pudr3t output:where(.svelte-pudr3t){overflow-wrap:anywhere;border:1px solid color-mix(in srgb, CanvasText 35%, Canvas);border-radius:.35rem;min-block-size:2.75rem;padding:.65rem .75rem}.clone-controls.svelte-pudr3t button:where(.svelte-pudr3t){min-inline-size:5.75rem}.clone-form.svelte-pudr3t p:where(.svelte-pudr3t){color:color-mix(in srgb, CanvasText 70%, Canvas);margin:0;font-size:.875rem}.clone-status.svelte-pudr3t{font-weight:600;color:canvastext!important}.git-overview.svelte-pudr3t{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:1rem;display:grid}.git-status.svelte-pudr3t p:where(.svelte-pudr3t){margin-block:.5rem}.git-actions.svelte-pudr3t{gap:.5rem;display:grid}.git-actions.svelte-pudr3t button:where(.svelte-pudr3t){min-inline-size:6rem}.commit-history.svelte-pudr3t{margin-block-start:2rem}.commit-history.svelte-pudr3t h3:where(.svelte-pudr3t){margin-block-end:.75rem}.commit-list.svelte-pudr3t{gap:.5rem;margin:0;padding:0;list-style:none;display:grid}.commit-entry.svelte-pudr3t{border-block-end:1px solid color-mix(in srgb, CanvasText 20%, Canvas);gap:.35rem;min-inline-size:0;padding:.8rem 0;display:grid}.commit-subject.svelte-pudr3t,.commit-meta.svelte-pudr3t{gap:.65rem;min-inline-size:0;display:flex}.commit-subject.svelte-pudr3t{overflow-wrap:anywhere;align-items:baseline;font-weight:600}.commit-subject.svelte-pudr3t code:where(.svelte-pudr3t){color:color-mix(in srgb, CanvasText 75%, Canvas);flex:none;font-size:.875em}.commit-meta.svelte-pudr3t{color:color-mix(in srgb, CanvasText 70%, Canvas);flex-wrap:wrap;justify-content:space-between;font-size:.875rem}.commit-meta.svelte-pudr3t time:where(.svelte-pudr3t){overflow-wrap:anywhere;min-inline-size:0;max-inline-size:100%}@media (width<=28rem){.clone-controls.svelte-pudr3t{grid-template-columns:1fr}.clone-controls.svelte-pudr3t button:where(.svelte-pudr3t){inline-size:100%}}.plan.svelte-3rmyvg{overflow-wrap:anywhere;min-inline-size:0}header.svelte-3rmyvg{justify-content:space-between;align-items:start;gap:1rem;display:flex}h2.svelte-3rmyvg,p.svelte-3rmyvg{margin-block:.4rem}progress.svelte-3rmyvg{inline-size:100%}ol.svelte-3rmyvg{padding-inline-start:1.25rem}details.svelte-3rmyvg{margin-block:.5rem}summary.svelte-3rmyvg{cursor:pointer;gap:.2rem;display:grid}.measurement.svelte-3rmyvg{color:var(--muted,currentColor);font-variant-numeric:tabular-nums}.metadata.svelte-3rmyvg{gap:.25rem;display:grid}.metadata.svelte-3rmyvg div:where(.svelte-3rmyvg){gap:.5rem;display:flex}.metadata.svelte-3rmyvg dd:where(.svelte-3rmyvg){margin:0}.close.svelte-3rmyvg{flex:none;block-size:2.75rem;inline-size:2.75rem;font-size:1.5rem}button.svelte-3rmyvg:focus-visible,summary.svelte-3rmyvg:focus-visible{outline-offset:2px;outline:3px solid}@media (prefers-reduced-motion:reduce){.svelte-3rmyvg{scroll-behavior:auto}}.plans.svelte-x2ko9l{overflow-wrap:anywhere;min-inline-size:0}h2.svelte-x2ko9l{margin-block:.4rem}ul.svelte-x2ko9l{gap:.5rem;margin:0;padding:0;list-style:none;display:grid}button.svelte-x2ko9l{text-align:start;gap:.2rem;min-block-size:2.75rem;inline-size:100%;padding:.75rem;display:grid}button.svelte-x2ko9l:focus-visible{outline-offset:2px;outline:3px solid}.session-list.svelte-hxb22h{gap:1rem;inline-size:100%;margin-block:0 1.5rem;padding-inline:0;list-style:none;display:grid}.current-session.svelte-hxb22h{outline:2px solid var(--accent,#4f46e5);outline-offset:2px}.session-select.svelte-hxb22h{inline-size:100%;color:inherit;font:inherit;text-align:inherit;cursor:pointer;background:0 0;border:0;padding:0;display:block}.managed-session.svelte-hxb22h{box-sizing:border-box;border:1px solid canvastext;border-radius:.5rem;grid-template-columns:max-content minmax(0,1fr);align-items:start;gap:.75rem;inline-size:100%;padding:.75rem;display:grid}.open-session.svelte-hxb22h{background:color-mix(in srgb, Highlight 12%, Canvas);border-inline-start:.3rem solid highlight}.session-details.svelte-hxb22h{min-inline-size:0}.workspace-path.svelte-hxb22h{overflow-wrap:anywhere}.profile-badge.svelte-hxb22h{background:color-mix(in srgb, Highlight 14%, Canvas);color:canvastext;overflow-wrap:anywhere;border-radius:999px;margin-block-start:.35rem;padding:.15rem .4rem;font-size:.875rem;display:inline-block}.org-plan-metadata.svelte-hxb22h{gap:.125rem;margin-block-start:.35rem;display:grid}.org-plan-title.svelte-hxb22h{font-weight:600}.org-plan-filename.svelte-hxb22h{overflow-wrap:anywhere;color:color-mix(in srgb, CanvasText 72%, Canvas)}.session-actions.svelte-hxb22h{flex-wrap:wrap;gap:.5rem;display:flex}@media (width<=30rem){.managed-session.svelte-hxb22h{grid-template-columns:minmax(0,1fr)}}.recent-session.svelte-hxb22h{grid-template-columns:minmax(0,1fr) max-content;align-items:start;gap:.75rem;display:grid}.session-base.svelte-hxb22h{gap:.65rem;min-inline-size:0;margin-block:1rem;display:grid}.session-base-heading.svelte-hxb22h h3:where(.svelte-hxb22h),.session-base-heading.svelte-hxb22h p:where(.svelte-hxb22h){margin:0}.session-base-heading.svelte-hxb22h p:where(.svelte-hxb22h){margin-block-start:.25rem}.tree-panel.svelte-hxb22h{box-sizing:border-box;overscroll-behavior:contain;scrollbar-gutter:stable;border:1px solid color-mix(in srgb, CanvasText 35%, transparent);border-radius:.6rem;max-block-size:min(22rem,48vh);min-inline-size:0;padding:.35rem;overflow-y:auto}.session-settings.svelte-hxb22h{gap:.5rem;min-inline-size:0;margin-block-end:.75rem;display:grid}.session-setting-labels.svelte-hxb22h,.session-setting-controls.svelte-hxb22h{grid-template-columns:repeat(3,minmax(0,1fr));gap:.5rem;min-inline-size:0;display:grid}.session-setting-labels.svelte-hxb22h label:where(.svelte-hxb22h){overflow-wrap:anywhere;min-inline-size:0}.session-setting-controls.svelte-hxb22h select:where(.svelte-hxb22h){text-overflow:ellipsis;inline-size:100%;min-inline-size:0;max-inline-size:100%;overflow:hidden}.session-secondary-actions.svelte-hxb22h,.model-control.svelte-hxb22h{align-items:center;gap:.5rem;min-inline-size:0;display:flex}.session-secondary-actions.svelte-hxb22h{flex-wrap:wrap}.model-control.svelte-hxb22h{margin-inline-start:auto}.skills-profile-error.svelte-hxb22h{color:#8a1c14;margin:0;font-size:.875rem}.new-session-button.svelte-hxb22h{color:canvas;inline-size:auto;box-shadow:inset 0 .15rem 0 color-mix(in srgb, Canvas 45%, transparent);background:canvastext;border-color:canvastext;font-weight:700}@media (width<=28rem){.tree-panel.svelte-hxb22h{padding:.2rem}.model-control.svelte-hxb22h{margin-inline-start:0}}.skills-view.svelte-dg6sjj{min-inline-size:0;padding:1rem max(1rem, env(safe-area-inset-right)) calc(5rem + env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left))}.intro.svelte-dg6sjj,.save-intent.svelte-dg6sjj,.summary.svelte-dg6sjj{max-inline-size:70ch}form.svelte-dg6sjj,.field-grid.svelte-dg6sjj{gap:.65rem;display:grid}.field-grid.svelte-dg6sjj{grid-template-columns:minmax(0,1fr)}label.svelte-dg6sjj{font-weight:650}select.svelte-dg6sjj,input.svelte-dg6sjj,button.svelte-dg6sjj{box-sizing:border-box;min-block-size:3rem;inline-size:100%;font:inherit}dialog.svelte-dg6sjj{max-inline-size:min(100% - 2rem,32rem)}.dialog-actions.svelte-dg6sjj{gap:.65rem;display:grid}input.svelte-dg6sjj,select.svelte-dg6sjj{padding-inline:.7rem;font-size:1rem}button.svelte-dg6sjj{padding-inline:1rem}.profile-actions.svelte-dg6sjj{grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem;display:grid}.skills-toolbar.svelte-dg6sjj{flex-wrap:wrap;align-items:center;gap:.65rem;margin-block:1rem;display:flex}.refresh-skills.svelte-dg6sjj{flex:none;min-block-size:2.25rem;inline-size:auto;padding-inline:.65rem}.refresh-skills.svelte-dg6sjj span:where(.svelte-dg6sjj):first-child{font-size:1.2em;line-height:1}.summary.svelte-dg6sjj{overflow-wrap:anywhere;min-inline-size:0;margin:0}.notice.svelte-dg6sjj{border-inline-start:.3rem solid #976600;padding-inline-start:.7rem}.error.svelte-dg6sjj{color:#8a1c14;border-inline-start:.3rem solid #b42318;padding-inline-start:.7rem}.skill-list.svelte-dg6sjj{gap:.75rem;padding:0;list-style:none;display:grid}.skill-card.svelte-dg6sjj{border:1px solid color-mix(in srgb, var(--brand-color,currentColor) 35%, transparent);border-radius:.5rem;min-inline-size:0;padding:.75rem;scroll-margin-block:1rem}.skill-toggle.svelte-dg6sjj{flex-wrap:wrap;align-items:center;gap:.65rem;min-block-size:3rem;display:flex}.skill-toggle.svelte-dg6sjj>span:where(.svelte-dg6sjj){overflow-wrap:anywhere;min-inline-size:0}.skill-toggle.svelte-dg6sjj input:where(.svelte-dg6sjj){flex:none;min-block-size:1.25rem;inline-size:1.25rem}.state.svelte-dg6sjj{margin-inline-start:auto;font-weight:500}.skill-details.svelte-dg6sjj{overflow-wrap:anywhere;padding-inline-start:1.9rem}.skill-details.svelte-dg6sjj>:where(.svelte-dg6sjj):first-child{margin-block-start:.25rem}.skill-details.svelte-dg6sjj>:where(.svelte-dg6sjj):last-child{margin-block-end:0}dl.svelte-dg6sjj{grid-template-columns:minmax(7rem,auto) minmax(0,1fr);gap:.45rem .75rem;display:grid}dt.svelte-dg6sjj{font-weight:650}dd.svelte-dg6sjj{min-inline-size:0;margin:0}dd.svelte-dg6sjj ul:where(.svelte-dg6sjj){margin:0;padding-inline-start:1.25rem}.path.svelte-dg6sjj{overflow-wrap:anywhere}.svelte-dg6sjj:where(button:where(.svelte-dg6sjj),input:where(.svelte-dg6sjj),select:where(.svelte-dg6sjj)):focus-visible{outline-offset:2px;outline:3px solid #1261a0}@media (prefers-color-scheme:dark){.error.svelte-dg6sjj{color:#ffb4ab}.notice.svelte-dg6sjj{color:#ffd8a8}}@media (width>=42rem){.field-grid.svelte-dg6sjj{grid-template-columns:minmax(10rem,1fr) minmax(0,2fr);align-items:center}}@media (width<=30rem){dl.svelte-dg6sjj{grid-template-columns:1fr;gap:.2rem}}.devices.svelte-1nygetn{max-inline-size:48rem;margin:auto;padding:1rem}.devices.svelte-1nygetn header:where(.svelte-1nygetn){align-items:center;gap:1rem;display:flex}.devices.svelte-1nygetn ul:where(.svelte-1nygetn){padding:0;list-style:none}.devices.svelte-1nygetn li:where(.svelte-1nygetn),section.svelte-1nygetn{border:1px solid canvastext;border-radius:.5rem;margin-block:1rem;padding:1rem}.devices.svelte-1nygetn form:where(.svelte-1nygetn){gap:.65rem;display:grid}.devices.svelte-1nygetn p:where(.svelte-1nygetn){overflow-wrap:anywhere;margin:0}.devices.svelte-1nygetn input:where(.svelte-1nygetn),.devices.svelte-1nygetn textarea:where(.svelte-1nygetn),.devices.svelte-1nygetn button:where(.svelte-1nygetn){min-block-size:44px;font:inherit}.devices.svelte-1nygetn input:where(.svelte-1nygetn),.devices.svelte-1nygetn textarea:where(.svelte-1nygetn){min-inline-size:0;padding:.45rem}.devices.svelte-1nygetn textarea:where(.svelte-1nygetn){box-sizing:border-box;overflow-wrap:anywhere;resize:vertical;inline-size:100%}.devices.svelte-1nygetn .actions:where(.svelte-1nygetn){flex-wrap:wrap;gap:.5rem;display:flex}.devices.svelte-1nygetn .actions:where(.svelte-1nygetn) button:where(.svelte-1nygetn){flex:11rem}.devices.svelte-1nygetn img:where(.svelte-1nygetn){background:#fff;inline-size:12rem;max-inline-size:100%;margin-block:.75rem;padding:.5rem;display:block}.feedback.svelte-1nygetn{color:canvastext;font-weight:700}dialog.svelte-1nygetn{color:canvastext;background:canvas;border:1px solid canvastext;border-radius:.5rem;max-inline-size:min(32rem,100% - 2rem)}dialog.svelte-1nygetn form:where(.svelte-1nygetn){flex-wrap:wrap;gap:.5rem;display:flex}@media (forced-colors:active){.devices.svelte-1nygetn li:where(.svelte-1nygetn),section.svelte-1nygetn,dialog.svelte-1nygetn{border-color:canvastext}}@media (prefers-reduced-motion:reduce){.svelte-1nygetn{transition-duration:.01ms!important;animation-duration:.01ms!important}}.chat-view.svelte-1d2e8zz{margin-inline:calc(.25rem - var(--page-inline-padding))}.swipe-surface.svelte-1d2e8zz{touch-action:pan-y}.evidence-mode.svelte-1d2e8zz{box-sizing:border-box;inline-size:100%;min-inline-size:0;padding:0}.session-profile-manager-header.svelte-1d2e8zz{box-sizing:border-box;inline-size:100%;min-inline-size:0;padding-inline:max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));justify-content:space-between;align-items:safe center;gap:1rem;display:flex}.session-profile-manager-header.svelte-1d2e8zz h2:where(.svelte-1d2e8zz){overflow-wrap:anywhere;min-inline-size:0;margin:0}.close-profile-manager.svelte-1d2e8zz{min-block-size:2.5rem;inline-size:2.5rem;color:inherit;background:0 0;border:0;flex:none;padding:0;font-size:2rem;line-height:1}.enrollment.svelte-1c5qcm6{box-sizing:border-box;inline-size:100%;max-inline-size:none;color:#f5f6ed;background:#10231e;place-items:center;min-height:100dvh;margin:0;padding:1rem;display:grid}.card.svelte-1c5qcm6{box-sizing:border-box;background:#17352c;border:1px solid #88bda7;border-radius:1rem;width:min(100%,42rem);padding:clamp(1.25rem,5vw,3rem)}.brand.svelte-1c5qcm6{color:#b6e6ce;letter-spacing:.08em;text-transform:uppercase;font-weight:700}h1.svelte-1c5qcm6{margin-block:.25rem 1rem;font-size:clamp(1.8rem,7vw,3rem)}.warning.svelte-1c5qcm6{background:#294237;border-left:.3rem solid #f0c96a;padding:1rem}label.svelte-1c5qcm6,input.svelte-1c5qcm6{box-sizing:border-box;width:100%;display:block}label.svelte-1c5qcm6{margin-top:1.5rem;font-weight:700}input.svelte-1c5qcm6,button.svelte-1c5qcm6{min-height:44px;font:inherit}input.svelte-1c5qcm6{margin-top:.4rem;padding:.6rem}button.svelte-1c5qcm6{cursor:pointer;border-radius:.4rem;margin-top:1rem;padding:.55rem 1rem}.authorize.svelte-1c5qcm6{color:#10231e;background:#b6e6ce;width:100%;font-weight:700}.feedback.svelte-1c5qcm6,.error.svelte-1c5qcm6{color:#ffd2c5}.handoff.svelte-1c5qcm6{border-top:1px solid #88bda7;grid-template-columns:minmax(0,1fr);gap:1rem;margin-top:2rem;padding-top:1.5rem;display:grid}.handoff.svelte-1c5qcm6 img:where(.svelte-1c5qcm6){background:#fff;width:12rem;max-width:100%;padding:.5rem}a.svelte-1c5qcm6{color:#b6e6ce;overflow-wrap:anywhere}.copy.svelte-1c5qcm6{display:block}@media (width>=48rem){.handoff.svelte-1c5qcm6{grid-template-columns:12rem minmax(0,1fr);align-items:start}}@media (prefers-reduced-motion:reduce){.svelte-1c5qcm6,.svelte-1c5qcm6:before,.svelte-1c5qcm6:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important}}.login.svelte-1byekj9{box-sizing:border-box;inline-size:100%;max-inline-size:none;color:#f5f6ed;background:#10231e;place-items:center;min-height:100dvh;margin:0;padding:1rem;display:grid}.card.svelte-1byekj9{box-sizing:border-box;background:#17352c;border:1px solid #88bda7;border-radius:1rem;width:min(100%,32rem);padding:clamp(1.25rem,5vw,3rem)}.brand.svelte-1byekj9{color:#b6e6ce;letter-spacing:.08em;text-transform:uppercase;font-weight:700}h1.svelte-1byekj9{margin-block:.25rem 1rem;font-size:clamp(1.8rem,7vw,3rem)}.sign-in.svelte-1byekj9{color:#10231e;width:100%;min-height:44px;font:inherit;background:#b6e6ce;border-radius:.4rem;margin-top:1rem;padding:.55rem 1rem;font-weight:700}.error.svelte-1byekj9{color:#ffd2c5}@media (prefers-reduced-motion:reduce){.svelte-1byekj9,.svelte-1byekj9:before,.svelte-1byekj9:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important}}.auth-gate.svelte-y74n0s{max-width:32rem;margin:12vh auto;padding:2rem}button.svelte-y74n0s{margin-right:.75rem}:root{--bottom-navigation-clearance:calc(4rem + env(safe-area-inset-bottom));--sticky-header-clearance:calc(5rem + env(safe-area-inset-top));--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;font-family:system-ui,sans-serif}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}:root[data-theme=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:root[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}body{min-block-size:100dvh;margin:0}.visually-hidden{clip-path:inset(50%)!important;white-space:nowrap!important;border:0!important;block-size:1px!important;inline-size:1px!important;margin:-1px!important;padding:0!important;position:absolute!important;overflow:hidden!important}main{--page-inline-padding:1rem;box-sizing:border-box;min-block-size:100dvh;max-inline-size:42rem;padding:calc(1rem + env(safe-area-inset-top)) var(--page-inline-padding) calc(var(--bottom-navigation-clearance) + 1rem);margin-inline:auto}@media (width<=24rem){main{--page-inline-padding:.5rem}}.app-header{z-index:1;margin:calc(-1rem - env(safe-area-inset-top)) calc(.25rem - var(--page-inline-padding)) 1.5rem;padding:calc(1rem + env(safe-area-inset-top)) calc(var(--page-inline-padding) - .25rem) .75rem;background:color-mix(in srgb, Canvas 78%, transparent);-webkit-backdrop-filter:blur(.75rem);backdrop-filter:blur(.75rem);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:1rem;display:flex;position:sticky;inset-block-start:0}.app-header [role=status]{overflow-wrap:anywhere;text-align:end;min-inline-size:0;margin:0}.brand{align-items:center;gap:.4rem;display:flex}.header-actions{flex:none;align-items:center;gap:.25rem;margin-inline-start:auto;display:flex}.weekly-quota{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:.875rem}.menu-trigger{min-block-size:44px;inline-size:44px;color:inherit;background:0 0;border:0;flex:none;place-items:center;padding:0;display:grid}.menu-lines{gap:.25rem;inline-size:1.25rem;display:grid}.menu-lines span{box-sizing:border-box;background:currentColor;block-size:1px;display:block}.menu-lines span:first-child,.menu-lines span:nth-child(2),.menu-lines span:last-child{block-size:2px}@media (width<=28rem){.app-header [role=status]{flex-basis:100%;margin-inline-start:0}}.brand-icon{block-size:2rem;inline-size:2rem}.brand-logotype{block-size:auto;inline-size:6.25rem}.dark-asset,:root[data-theme=dark] .light-asset{display:none}:root[data-theme=dark] .dark-asset{display:initial}@media (prefers-color-scheme:dark){:root:not([data-theme]) .light-asset{display:none}:root:not([data-theme]) .dark-asset{display:initial}}.configuration-panel{color:canvastext;min-inline-size:min(13rem,100vw - 2rem);box-shadow:0 .5rem 1.5rem color-mix(in srgb, CanvasText 25%, transparent);background:canvas;border:1px solid canvastext;border-radius:.5rem;padding:.75rem;position:fixed;inset:4.5rem 1rem auto auto}.configuration-logo{block-size:auto;inline-size:4.5rem;margin-block-end:.5rem;margin-inline-start:auto;display:block}.appearance-control{align-items:center;gap:.5rem;display:flex}.appearance-control span{letter-spacing:-.08em;font-weight:700}.appearance-control select{field-sizing:content;flex:none;min-block-size:2.25rem;inline-size:auto;padding-inline:.5rem}.bottom-navigation{padding:.5rem calc(.25rem + env(safe-area-inset-right)) calc(.5rem + env(safe-area-inset-bottom)) calc(.25rem + env(safe-area-inset-left));background:canvas;border-block-start:1px solid canvastext;grid-template-columns:repeat(4,minmax(0,1fr));gap:.25rem;display:grid;position:fixed;inset-block-end:0;inset-inline:0}.bottom-navigation button{overflow-wrap:anywhere;word-break:break-word;min-inline-size:0;max-inline-size:100%;padding-inline:0;transition:color .12s,background-color .12s,box-shadow .12s}.bottom-navigation button[aria-pressed=true]{color:canvas;box-shadow:inset 0 .2rem 0 color-mix(in srgb, Canvas 70%, transparent);background:canvastext;font-weight:700}.bottom-navigation button:disabled{color:color-mix(in srgb, CanvasText 40%, transparent);cursor:not-allowed;opacity:.65}@media (width<=30rem){:root{--bottom-navigation-clearance:calc(10rem + env(safe-area-inset-bottom));--sticky-header-clearance:calc(14rem + env(safe-area-inset-top))}.bottom-navigation{grid-template-columns:repeat(2,minmax(0,1fr))}.bottom-navigation button{text-align:center;padding-inline:.25rem}}button{min-block-size:44px;font:inherit}.git-view button{scroll-margin-block:var(--sticky-header-clearance) var(--bottom-navigation-clearance)}input,select,textarea{box-sizing:border-box;min-block-size:44px;inline-size:100%;font:inherit;font-size:max(1rem,16px)}:focus-visible{outline-offset:3px;outline:3px solid canvastext}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important}}@media (forced-colors:active){button,input,select,textarea{border:1px solid canvastext}}
|