mouaif 0.3.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 (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/bin/mouaif.js +281 -0
  4. package/frontend/dist/assets/AgentFilePicker-CcKLJorU.js +1 -0
  5. package/frontend/dist/assets/CliModal-Hs5phmNZ.js +7 -0
  6. package/frontend/dist/assets/DictationPage-BI23lp42.js +2 -0
  7. package/frontend/dist/assets/FileEditor-DDl31c6d.js +2 -0
  8. package/frontend/dist/assets/GitModal-3EC_gpJ5.js +2 -0
  9. package/frontend/dist/assets/Inspector-Ba3R1w04.js +73 -0
  10. package/frontend/dist/assets/SettingsAbout-bvZGDEDw.js +1 -0
  11. package/frontend/dist/assets/SettingsActions-Dk6WX9jv.js +1 -0
  12. package/frontend/dist/assets/SettingsAgents-BNV0MgDB.js +1 -0
  13. package/frontend/dist/assets/SettingsDefaults-DbMmQbzc.js +1 -0
  14. package/frontend/dist/assets/SettingsHiddenContent-BZ2sloH1.js +1 -0
  15. package/frontend/dist/assets/SettingsMcp-DOrfbQd1.js +1 -0
  16. package/frontend/dist/assets/SettingsMcpEdit-BGMQ2CWC.js +3 -0
  17. package/frontend/dist/assets/SettingsMcpRegistry-BywXee_A.js +1 -0
  18. package/frontend/dist/assets/SettingsNotifications-B0LEs11a.js +1 -0
  19. package/frontend/dist/assets/SettingsPricing-BAg33iVF.js +1 -0
  20. package/frontend/dist/assets/SettingsProject-DNrKhCcZ.js +14 -0
  21. package/frontend/dist/assets/SettingsProjects-IqkBfDcm.js +1 -0
  22. package/frontend/dist/assets/SettingsPrompts-BgeiASuk.js +1 -0
  23. package/frontend/dist/assets/SettingsProviders-k0xJN0IK.js +1 -0
  24. package/frontend/dist/assets/SettingsTags-B5kjFdQi.js +1 -0
  25. package/frontend/dist/assets/agentNavigation-BiiCpFz5.js +1 -0
  26. package/frontend/dist/assets/codemirror-Bp6CUUFk.js +30 -0
  27. package/frontend/dist/assets/index-BGvI4n0T.js +61 -0
  28. package/frontend/dist/assets/index-Bgg1gnDf.css +1 -0
  29. package/frontend/dist/assets/index-C1sQFIC-.css +1 -0
  30. package/frontend/dist/assets/index-CANPYzQg.css +1 -0
  31. package/frontend/dist/assets/index-Crn1LdzK.css +1 -0
  32. package/frontend/dist/assets/index-FbCWDPiB.css +1 -0
  33. package/frontend/dist/assets/projectQS-D1cSZ7Gr.js +1 -0
  34. package/frontend/dist/assets/virtual-list-6H9b4K51.js +1 -0
  35. package/frontend/dist/icons/favicon-32.png +0 -0
  36. package/frontend/dist/icons/icon-180-apple.png +0 -0
  37. package/frontend/dist/icons/icon-192.png +0 -0
  38. package/frontend/dist/icons/icon-512.png +0 -0
  39. package/frontend/dist/icons/icon-maskable-512.png +0 -0
  40. package/frontend/dist/index.html +83 -0
  41. package/frontend/dist/manifest.webmanifest +33 -0
  42. package/frontend/dist/sw.js +482 -0
  43. package/package.json +98 -0
  44. package/scripts/patch-zimmerframe.js +58 -0
  45. package/src/access-auth.js +515 -0
  46. package/src/agentFeatures.js +294 -0
  47. package/src/agentFiles.js +164 -0
  48. package/src/agentSkills.js +147 -0
  49. package/src/agents.js +230 -0
  50. package/src/ai-chat.js +21 -0
  51. package/src/ai-endpoints.js +1880 -0
  52. package/src/ai-stream.js +2048 -0
  53. package/src/ai.js +68 -0
  54. package/src/auth.js +391 -0
  55. package/src/chatdb.js +816 -0
  56. package/src/chats.js +275 -0
  57. package/src/custom-actions.js +65 -0
  58. package/src/files.js +431 -0
  59. package/src/hideFileContent.js +327 -0
  60. package/src/http-server.js +535 -0
  61. package/src/index.js +15 -0
  62. package/src/inspector.js +731 -0
  63. package/src/inspectorProfiles.js +503 -0
  64. package/src/live-chat.js +107 -0
  65. package/src/mcp.js +1517 -0
  66. package/src/messages.js +238 -0
  67. package/src/modelList.js +137 -0
  68. package/src/notifications.js +52 -0
  69. package/src/oauth-anthropic.js +280 -0
  70. package/src/oauth-github-copilot.js +417 -0
  71. package/src/oauth-mcp.js +216 -0
  72. package/src/oauth-openrouter.js +285 -0
  73. package/src/package-version.js +20 -0
  74. package/src/projects.js +285 -0
  75. package/src/promptProfiles.js +256 -0
  76. package/src/prompts.js +384 -0
  77. package/src/providerShapes.js +44 -0
  78. package/src/providers/base.js +41 -0
  79. package/src/providers/index.js +25 -0
  80. package/src/push.js +315 -0
  81. package/src/qr.js +192 -0
  82. package/src/restart.js +47 -0
  83. package/src/server-handlers-access.js +306 -0
  84. package/src/server-handlers-actions.js +100 -0
  85. package/src/server-handlers-ai.js +248 -0
  86. package/src/server-handlers-auth.js +273 -0
  87. package/src/server-handlers-chats.js +1436 -0
  88. package/src/server-handlers-git.js +467 -0
  89. package/src/server-handlers-mcp-oauth.js +56 -0
  90. package/src/server-handlers-misc.js +783 -0
  91. package/src/server-handlers-projects.js +289 -0
  92. package/src/server-handlers-prompts.js +259 -0
  93. package/src/server-handlers-push.js +102 -0
  94. package/src/server-handlers-settings.js +406 -0
  95. package/src/server-handlers-tools.js +654 -0
  96. package/src/server-handlers-transcribe.js +399 -0
  97. package/src/server-shared.js +780 -0
  98. package/src/server-web-static.js +191 -0
  99. package/src/settings.js +898 -0
  100. package/src/statusBar.js +541 -0
  101. package/src/tags.js +414 -0
  102. package/src/toolFeedback.js +225 -0
  103. package/src/tools/ask.js +154 -0
  104. package/src/tools/authorization.js +932 -0
  105. package/src/tools/files.js +1150 -0
  106. package/src/tools/progress.js +71 -0
  107. package/src/tools/restart.js +32 -0
  108. package/src/tools/searchEngine.js +957 -0
  109. package/src/tools/shell.js +341 -0
  110. package/src/tools/subagent.js +47 -0
  111. package/src/tools/task.js +234 -0
  112. package/src/tools/webpreview.js +448 -0
  113. package/src/trace.js +103 -0
  114. package/src/transcribe.js +683 -0
  115. package/src/usage.js +389 -0
  116. package/src/util.js +151 -0
@@ -0,0 +1,154 @@
1
+ 'use strict';
2
+
3
+ // Native `ask_user` tool — lets the model pause and ask the user a
4
+ // structured question during a chat. The model provides a question
5
+ // text and a list of options (2 or more, no upper bound — the UI
6
+ // scrolls long lists); the user picks one and may always add a
7
+ // free-form "extra answer" alongside their pick. The selection +
8
+ // extra text is returned to the model as a single tool result.
9
+ //
10
+ // Implements docs/features/ask-user-tool.md.
11
+ //
12
+ // Design notes:
13
+ // - This tool *always* prompts. The authorization module's
14
+ // `ask_user` mode is treated specially: it is binary
15
+ // `off` / `ask`. There is no allowlist (the model can't predict
16
+ // user answers) and no `allow` mode (the user must always be
17
+ // the source of truth). `off` returns ETOOL_DISABLED.
18
+ // - The runner is the simplest possible: it returns the structured
19
+ // payload to the caller. The actual user interaction rides the
20
+ // existing `authorization_required` SSE event, augmented with
21
+ // `question` / `options` / `multiSelect` fields the chat UI
22
+ // renders as an answer card. The authorization module's wait()
23
+ // resolves with the user's { choice, extra } so the dispatcher
24
+ // can fold both into the `tool` message.
25
+ // - No new runtime dependencies. The runner is a plain function
26
+ // that returns the result; the chat UI handles the input side.
27
+
28
+ const MAX_QUESTION_CHARS = 500;
29
+ const MAX_OPTION_CHARS = 120;
30
+ const MAX_EXTRA_CHARS = 1000;
31
+ const MAX_PRESETS = 6;
32
+
33
+ const SPEC = {
34
+ type: 'function',
35
+ function: {
36
+ name: 'ask_user',
37
+ description: 'Ask the user a structured question with options. The user picks one option and may always add a free-form "extra" note to clarify or elaborate.',
38
+ parameters: {
39
+ type: 'object',
40
+ properties: {
41
+ question: { type: 'string', description: 'The question to ask the user.' },
42
+ options: {
43
+ type: 'array',
44
+ description: 'Answer options (2 or more). Label is shown to the user; value is returned as the choice.',
45
+ minItems: 2,
46
+ items: {
47
+ type: 'object',
48
+ properties: {
49
+ label: { type: 'string' },
50
+ value: { type: 'string' },
51
+ description: { type: 'string', description: 'Optional hint shown under the label.' }
52
+ },
53
+ required: ['label', 'value'],
54
+ additionalProperties: false
55
+ }
56
+ },
57
+ multiSelect: { type: 'boolean', description: 'When true, the user may pick multiple options.' },
58
+ presets: {
59
+ type: 'array',
60
+ items: { type: 'string' },
61
+ description: 'Quick-answer presets shown as chips above the option list. Tapping a preset immediately submits it without showing the option list.',
62
+ maxItems: 6
63
+ }
64
+ },
65
+ required: ['question', 'options'],
66
+ additionalProperties: false
67
+ }
68
+ }
69
+ };
70
+
71
+ function trimString(value, max) {
72
+ if (typeof value !== 'string') return '';
73
+ const s = value.trim();
74
+ if (s.length <= max) return s;
75
+ return s.slice(0, max);
76
+ }
77
+
78
+ // Build the validated payload the chat UI renders. Throws a typed
79
+ // EBADINPUT on the first violation so the tool_result forwarded to
80
+ // the model explains what was wrong.
81
+ function validateArgs(args) {
82
+ if (!args || typeof args !== 'object') {
83
+ const e = new Error('args is required'); e.code = 'EBADINPUT'; throw e;
84
+ }
85
+ const question = trimString(args.question, MAX_QUESTION_CHARS);
86
+ if (!question) {
87
+ const e = new Error('question is required'); e.code = 'EBADINPUT'; throw e;
88
+ }
89
+ const rawOptions = Array.isArray(args.options) ? args.options : null;
90
+ if (!rawOptions || rawOptions.length < 2) {
91
+ const e = new Error('at least 2 options are required'); e.code = 'EBADINPUT'; throw e;
92
+ }
93
+ const seenValues = new Set();
94
+ const options = [];
95
+ for (let i = 0; i < rawOptions.length; i++) {
96
+ const raw = rawOptions[i];
97
+ if (!raw || typeof raw !== 'object') {
98
+ const e = new Error('option ' + i + ' must be an object'); e.code = 'EBADINPUT'; throw e;
99
+ }
100
+ const label = trimString(raw.label, MAX_OPTION_CHARS);
101
+ const value = trimString(raw.value, MAX_OPTION_CHARS);
102
+ if (!label) { const e = new Error('option ' + i + '.label is required'); e.code = 'EBADINPUT'; throw e; }
103
+ if (!value) { const e = new Error('option ' + i + '.value is required'); e.code = 'EBADINPUT'; throw e; }
104
+ if (seenValues.has(value)) {
105
+ const e = new Error('option ' + i + '.value duplicates an earlier option'); e.code = 'EBADINPUT'; throw e;
106
+ }
107
+ seenValues.add(value);
108
+ options.push({
109
+ label,
110
+ value,
111
+ description: trimString(raw.description, MAX_OPTION_CHARS) || ''
112
+ });
113
+ }
114
+ const multiSelect = args.multiSelect === true;
115
+ const presets = Array.isArray(args.presets)
116
+ ? args.presets.slice(0, MAX_PRESETS).map((value) => trimString(value, MAX_OPTION_CHARS)).filter(Boolean)
117
+ : [];
118
+ return { question, options, multiSelect, presets };
119
+ }
120
+
121
+ // Shape the runner result. `cancelled: true` means the user picked
122
+ // "Dismiss" or otherwise refused to answer; the model still receives
123
+ // a tool result, so the loop can continue with a sensible default.
124
+ function buildResult({ choice, extra, options, multiSelect, cancelled }) {
125
+ const result = {
126
+ answered: !cancelled,
127
+ choice: Array.isArray(choice) ? choice.slice() : (choice || ''),
128
+ extra: typeof extra === 'string' ? extra : '',
129
+ options: (options || []).map((o) => ({ label: o.label, value: o.value })),
130
+ multiSelect: !!multiSelect,
131
+ cancelled: !!cancelled
132
+ };
133
+ return { ok: !cancelled, content: JSON.stringify(result), result };
134
+ }
135
+
136
+ // Truncate the user's free-form answer. Returns the empty string
137
+ // when missing. Pure; safe to call on the model side too.
138
+ function clampExtra(value) {
139
+ if (typeof value !== 'string') return '';
140
+ const s = value.trim();
141
+ if (s.length <= MAX_EXTRA_CHARS) return s;
142
+ return s.slice(0, MAX_EXTRA_CHARS);
143
+ }
144
+
145
+ module.exports = {
146
+ SPEC,
147
+ validateArgs,
148
+ buildResult,
149
+ clampExtra,
150
+ MAX_QUESTION_CHARS,
151
+ MAX_OPTION_CHARS,
152
+ MAX_EXTRA_CHARS,
153
+ MAX_PRESETS
154
+ };