gestalt-mobile 0.12.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.
Files changed (79) hide show
  1. package/README.md +42 -11
  2. package/dist/client/assets/index-C5qFcFUg.css +1 -0
  3. package/dist/client/assets/index-tMyOolAm.js +24 -0
  4. package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  5. package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  6. package/dist/client/assets/jetbrains-mono-cyrillic-ext-400-normal-Bh0R7Dhr.woff +0 -0
  7. package/dist/client/assets/jetbrains-mono-cyrillic-ext-400-normal-C_uLvvQ5.woff2 +0 -0
  8. package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  9. package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  10. package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  11. package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  12. package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  13. package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  14. package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-ByoDsISC.woff2 +0 -0
  15. package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  16. package/dist/client/assets/syne-greek-600-normal-BJs4kvyH.woff +0 -0
  17. package/dist/client/assets/syne-greek-600-normal-BpFII5Ja.woff2 +0 -0
  18. package/dist/client/assets/syne-latin-600-normal-BiwQbQXw.woff2 +0 -0
  19. package/dist/client/assets/syne-latin-600-normal-dRu9QuIh.woff +0 -0
  20. package/dist/client/assets/syne-latin-ext-600-normal-DEzBMW8B.woff +0 -0
  21. package/dist/client/assets/syne-latin-ext-600-normal-ZnizrDKU.woff2 +0 -0
  22. package/dist/client/index.html +3 -2
  23. package/dist/server/server/app.js +22 -227
  24. package/dist/server/server/cli.js +3 -1
  25. package/dist/server/server/composition.js +25 -26
  26. package/dist/server/server/features/auth/application/ceremony-attempts.js +22 -0
  27. package/dist/server/server/features/auth/devices/revoke/endpoint.js +3 -1
  28. package/dist/server/server/features/auth/domain/errors.js +7 -0
  29. package/dist/server/server/features/auth/enrollment-tickets/endpoint.js +7 -2
  30. package/dist/server/server/features/auth/enrollment-tickets/status/endpoint.js +3 -1
  31. package/dist/server/server/features/auth/http/cookies.js +20 -0
  32. package/dist/server/server/features/auth/login/options/endpoint.js +22 -20
  33. package/dist/server/server/features/auth/login/verify/endpoint.js +6 -14
  34. package/dist/server/server/features/auth/logout/endpoint.js +2 -6
  35. package/dist/server/server/features/auth/register/options/endpoint.js +43 -11
  36. package/dist/server/server/features/auth/register/verify/endpoint.js +74 -18
  37. package/dist/server/server/features/auth/register-routes.js +41 -0
  38. package/dist/server/server/features/git/checkout-branch/endpoint.js +1 -1
  39. package/dist/server/server/features/git/clone-repository/endpoint.js +1 -1
  40. package/dist/server/server/features/git/register-routes.js +34 -0
  41. package/dist/server/server/features/plans/application/measurement-snapshot.js +1 -1
  42. package/dist/server/server/features/plans/get-measurement/endpoint.js +1 -3
  43. package/dist/server/server/features/plans/register-routes.js +22 -0
  44. package/dist/server/server/features/sessions/interaction/kind.js +7 -1
  45. package/dist/server/server/features/sessions/list-recent-threads/endpoint.js +3 -1
  46. package/dist/server/server/features/sessions/model/relay-session.js +3 -1
  47. package/dist/server/server/features/sessions/promote-recent-thread/endpoint.js +1 -1
  48. package/dist/server/server/features/sessions/register-routes.js +138 -0
  49. package/dist/server/server/features/sessions/respond-interaction/endpoint.js +1 -1
  50. package/dist/server/server/features/sessions/select-model/endpoint.js +1 -1
  51. package/dist/server/server/features/sessions/start-session/endpoint.js +5 -2
  52. package/dist/server/server/features/sessions/start-session/use-case.js +1 -1
  53. package/dist/server/server/features/sessions/start-turn/endpoint.js +2 -1
  54. package/dist/server/server/features/skills/delete-profile/endpoint.js +12 -3
  55. package/dist/server/server/features/skills/list-available/endpoint.js +24 -6
  56. package/dist/server/server/features/skills/list-profiles/endpoint.js +29 -5
  57. package/dist/server/server/features/skills/model/skill-profile.js +23 -3
  58. package/dist/server/server/features/skills/register-routes.js +17 -0
  59. package/dist/server/server/features/skills/replace-profile/endpoint.js +20 -5
  60. package/dist/server/server/platform/auth/simple-webauthn-adapter.js +23 -3
  61. package/dist/server/server/platform/auth/sqlite-authorization-store.js +29 -6
  62. package/dist/server/server/platform/catalog/profile-command.js +8 -1
  63. package/dist/server/server/platform/codex/normalizer.js +50 -6
  64. package/dist/server/server/platform/codex/protocol-compatibility.js +19 -1
  65. package/dist/server/server/platform/codex/server-request.js +2 -0
  66. package/dist/server/server/platform/codex/session-runtime.js +235 -126
  67. package/dist/server/server/platform/codex/thread-plan-name.js +5 -2
  68. package/dist/server/server/platform/http/problem-handler.js +10 -0
  69. package/dist/server/server/platform/http/problem-reply.js +13 -0
  70. package/dist/server/server/platform/plans/filesystem-plan-status-source.js +11 -6
  71. package/dist/server/server/platform/plans/filesystem-workspace-plan-catalog.js +4 -1
  72. package/dist/server/server/platform/plans/plan-measurement-command.js +4 -1
  73. package/dist/server/server/platform/skills/codex-skill-catalog.js +29 -7
  74. package/dist/server/server/platform/skills/filesystem-skill-profile-store.js +5 -1
  75. package/dist/server/shared/contracts/quiz.js +30 -9
  76. package/package.json +4 -1
  77. package/dist/client/assets/index-B7KwEjTE.js +0 -19
  78. package/dist/client/assets/index-CMs5ZzxJ.css +0 -1
  79. package/dist/server/server/features/plans/application/native-plan-alignment.js +0 -39
@@ -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(), description: z.string(), shortDescription: optionalString,
23
- interface: optionalObject(z.object({ displayName: optionalString, shortDescription: optionalString, iconSmall: optionalString, iconLarge: optionalString, brandColor: optionalString, defaultPrompt: optionalString })),
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(), scope: optionalString, enabled: z.boolean(),
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) => ({ message: typeof error === 'object' && error !== null && 'message' in error && typeof error.message === 'string' ? error.message : 'Codex skill discovery 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) => { timer = setTimeout(() => reject(new Error('timeout')), this.timeoutMs); }),
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), { encoding: 'utf8', mode: 0o600, flag: 'wx' });
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: { type: 'string', minLength: 1, maxLength: 64, pattern: '^[A-Za-z][A-Za-z0-9_-]*$' },
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 ? { questions: parsed } : null;
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.filter((answer) => answer.answer.trim()).map((answer) => [answer.id, answer.answer])),
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 || !isRecord(item) || item.type !== 'input_text' || typeof item.text !== 'string')
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) || !Array.isArray(value.choices) || value.choices.length < minimumChoices || value.choices.length > 5)
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) || !isBoundedText(value.header, 120) || !isBoundedText(value.question, 600))
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) || !isBoundedText(value.label, 160) || !isBoundedText(value.description, 600))
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 || entries.some(([id, answer]) => !isQuestionId(id) || !isBoundedText(answer, 2_000)))
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 || ids.some((id) => !quiz.questions.some((question) => question.id === id)))
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.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Mobile-first web relay for durable Codex development sessions",
5
5
  "keywords": [
6
6
  "codex",
@@ -45,6 +45,7 @@
45
45
  "format": "prettier --write .",
46
46
  "format:check": "prettier --check .",
47
47
  "test": "vitest run",
48
+ "audit:prod": "npm audit --omit=dev --audit-level=high",
48
49
  "test:open-profile-smoke": "tsx scripts/open-profile-smoke.ts",
49
50
  "test:watch": "vitest",
50
51
  "test:package": "node scripts/smoke-packed-cli.mjs",
@@ -57,6 +58,8 @@
57
58
  "dependencies": {
58
59
  "@fastify/cookie": "11.1.2",
59
60
  "@fastify/static": "^10.1.0",
61
+ "@fontsource/jetbrains-mono": "5.2.7",
62
+ "@fontsource/syne": "5.2.7",
60
63
  "@simplewebauthn/browser": "13.3.0",
61
64
  "@simplewebauthn/server": "13.3.2",
62
65
  "fastify": "^5.10.0",