create-walle 0.9.19 → 0.9.21

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 (31) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/template/claude-task-manager/db.js +131 -0
  4. package/template/claude-task-manager/docs/microsoft-dev-tunnel-phone-access-design.md +58 -50
  5. package/template/claude-task-manager/docs/phone-access-design.md +23 -7
  6. package/template/claude-task-manager/docs/walle-session-model-preferences.md +119 -0
  7. package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +32 -48
  8. package/template/claude-task-manager/lib/remote-relay-protocol.js +5 -0
  9. package/template/claude-task-manager/lib/walle-external-actions.js +20 -3
  10. package/template/claude-task-manager/public/index.html +25 -0
  11. package/template/claude-task-manager/public/js/setup.js +16 -12
  12. package/template/claude-task-manager/public/js/walle-session.js +31 -3
  13. package/template/claude-task-manager/public/js/walle.js +93 -23
  14. package/template/claude-task-manager/public/m/app.css +417 -21
  15. package/template/claude-task-manager/public/m/app.js +831 -44
  16. package/template/claude-task-manager/public/m/claim.html +1 -1
  17. package/template/claude-task-manager/public/m/index.html +41 -7
  18. package/template/claude-task-manager/public/m/sw.js +1 -1
  19. package/template/claude-task-manager/server.js +377 -30
  20. package/template/claude-task-manager/workers/state-detectors/codex.js +18 -3
  21. package/template/package.json +1 -1
  22. package/template/wall-e/chat.js +32 -2
  23. package/template/wall-e/coding/stream-processor.js +36 -0
  24. package/template/wall-e/coding-orchestrator.js +45 -0
  25. package/template/wall-e/deploy.sh +1 -1
  26. package/template/wall-e/docs/external-action-controller.md +60 -2
  27. package/template/wall-e/external-action-controller.js +23 -1
  28. package/template/wall-e/external-action-gateway.js +163 -0
  29. package/template/wall-e/fly.toml +1 -0
  30. package/template/wall-e/tools/local-tools.js +122 -4
  31. package/template/website/index.html +2 -2
@@ -686,6 +686,39 @@ async function _fetchGmailMessage(accountRecord, id, includeContent = false) {
686
686
  ], { timeout: includeContent ? 45000 : 30000 });
687
687
  }
688
688
 
689
+ async function _verifyGmailMessageSent(accountRecord, gmailMessageId, expected = {}) {
690
+ if (!gmailMessageId) {
691
+ return {
692
+ ok: false,
693
+ source: 'gmail.messages.get',
694
+ reason: 'gmail_send_returned_no_message_id',
695
+ account: accountRecord?.email || null,
696
+ };
697
+ }
698
+ try {
699
+ const msg = await _fetchGmailMessage(accountRecord, gmailMessageId, false);
700
+ const threadOk = expected.threadId ? msg.threadId === expected.threadId : true;
701
+ return {
702
+ ok: threadOk,
703
+ source: 'gmail.messages.get',
704
+ account: accountRecord.email,
705
+ gmailMessageId,
706
+ messageId: _gmailMessageRef(accountRecord.email, gmailMessageId),
707
+ threadId: msg.threadId || null,
708
+ labels: msg.labelIds || [],
709
+ reason: threadOk ? undefined : `sent message threadId ${msg.threadId || '(none)'} did not match expected ${expected.threadId}`,
710
+ };
711
+ } catch (err) {
712
+ return {
713
+ ok: false,
714
+ source: 'gmail.messages.get',
715
+ account: accountRecord?.email || null,
716
+ gmailMessageId,
717
+ error: err.message || String(err),
718
+ };
719
+ }
720
+ }
721
+
689
722
  async function _fetchGmailAttachment(accountRecord, messageId, attachmentId) {
690
723
  if (!attachmentId) throw new Error('attachment_id is required');
691
724
  const url = new URL(`https://gmail.googleapis.com/gmail/v1/users/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`);
@@ -1062,7 +1095,19 @@ async function _tryGwsMailSend(input = {}) {
1062
1095
  args.push('--body', input.body || '');
1063
1096
  args.push('--format', 'json');
1064
1097
  const result = await _runGwsGmail(acct, args, { timeout: 45000 });
1065
- return _attachGwsMeta({ sent: !result?.error, output: result, account: acct.email }, [acct], _gwsScopeExtra(scope));
1098
+ const sentId = result?.id || result?.message?.id || result?.messageId || null;
1099
+ const verification = !result?.error
1100
+ ? await _verifyGmailMessageSent(acct, sentId)
1101
+ : { ok: false, source: 'gmail.messages.get', reason: 'gmail_send_failed' };
1102
+ return _attachGwsMeta({
1103
+ sent: !result?.error,
1104
+ verified: verification.ok === true,
1105
+ verification,
1106
+ output: result,
1107
+ account: acct.email,
1108
+ gmailMessageId: sentId,
1109
+ messageId: sentId ? _gmailMessageRef(acct.email, sentId) : null,
1110
+ }, [acct], _gwsScopeExtra(scope));
1066
1111
  }
1067
1112
 
1068
1113
  async function _tryGwsMailReply(input = {}) {
@@ -1137,13 +1182,21 @@ async function _tryGwsMailReply(input = {}) {
1137
1182
  '--format', 'json',
1138
1183
  ];
1139
1184
  const result = await _runGwsGmail(acct, args, { timeout: 45000 });
1185
+ const sentId = result?.id || result?.message?.id || result?.messageId || null;
1186
+ const verification = !result?.error
1187
+ ? await _verifyGmailMessageSent(acct, sentId, { threadId: reply.threadId })
1188
+ : { ok: false, source: 'gmail.messages.get', reason: 'gmail_reply_failed' };
1140
1189
  return _attachGwsMeta({
1141
1190
  sent: !result?.error,
1191
+ verified: verification.ok === true,
1192
+ verification,
1142
1193
  reply: true,
1143
1194
  output: result,
1144
1195
  account: acct.email,
1145
1196
  messageId: _gmailMessageRef(acct.email, id),
1146
1197
  gmailMessageId: id,
1198
+ sentMessageId: sentId ? _gmailMessageRef(acct.email, sentId) : null,
1199
+ gmailSentMessageId: sentId,
1147
1200
  threadId: result?.threadId || reply.threadId,
1148
1201
  to: reply.to,
1149
1202
  cc: reply.cc,
@@ -2025,6 +2078,45 @@ function _normalizeGwsCalendar(cal = {}, accountRecord = {}) {
2025
2078
  };
2026
2079
  }
2027
2080
 
2081
+ async function _verifyGwsCalendarEvent(accountRecord, calendarId, eventId, expected = {}) {
2082
+ if (!calendarId || !eventId) {
2083
+ return {
2084
+ ok: false,
2085
+ source: 'calendar.events.get',
2086
+ account: accountRecord?.email || null,
2087
+ calendarId: calendarId || null,
2088
+ eventId: eventId || null,
2089
+ reason: 'calendar_create_returned_no_event_id',
2090
+ };
2091
+ }
2092
+ try {
2093
+ const url = new URL(`https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`);
2094
+ const event = await _googleWorkspaceApiRequest(accountRecord, url, { timeout: 45000 });
2095
+ const titleOk = expected.title ? String(event.summary || '') === String(expected.title) : true;
2096
+ return {
2097
+ ok: titleOk,
2098
+ source: 'calendar.events.get',
2099
+ account: accountRecord.email,
2100
+ calendarId,
2101
+ eventId,
2102
+ htmlLink: event.htmlLink || null,
2103
+ summary: event.summary || '',
2104
+ start: event.start || null,
2105
+ end: event.end || null,
2106
+ reason: titleOk ? undefined : `verified event title "${event.summary || ''}" did not match expected "${expected.title}"`,
2107
+ };
2108
+ } catch (err) {
2109
+ return {
2110
+ ok: false,
2111
+ source: 'calendar.events.get',
2112
+ account: accountRecord?.email || null,
2113
+ calendarId,
2114
+ eventId,
2115
+ error: err.message || String(err),
2116
+ };
2117
+ }
2118
+ }
2119
+
2028
2120
  async function _tryGwsCalendarList(input = {}) {
2029
2121
  const source = String(input.source || input.provider || 'auto').toLowerCase();
2030
2122
  if (source === 'macos' || source === 'calendar_app' || source === 'apple_calendar') return null;
@@ -2198,12 +2290,25 @@ async function _tryGwsCalendarCreate(input = {}) {
2198
2290
  ];
2199
2291
  if (input.dry_run) args.push('--dry-run');
2200
2292
  const result = await _runGws(account, args, { timeout: 45000 });
2293
+ const eventId = result?.id || null;
2294
+ const verification = (!input.dry_run && !result?.error)
2295
+ ? await _verifyGwsCalendarEvent(account, match.id, eventId, { title: input.title || '' })
2296
+ : {
2297
+ ok: input.dry_run ? false : false,
2298
+ source: 'calendar.events.get',
2299
+ reason: input.dry_run ? 'dry_run_not_created' : 'calendar_create_failed',
2300
+ account: account.email,
2301
+ calendarId: match.id,
2302
+ eventId,
2303
+ };
2201
2304
  return _attachGwsCalendarMeta({
2202
2305
  created: input.dry_run ? false : !result?.error,
2306
+ verified: verification.ok === true,
2307
+ verification,
2203
2308
  validated: input.dry_run ? !result?.error : undefined,
2204
2309
  dry_run: Boolean(input.dry_run),
2205
- id: result?.id || null,
2206
- uid: result?.iCalUID || result?.id || null,
2310
+ id: eventId,
2311
+ uid: result?.iCalUID || eventId,
2207
2312
  htmlLink: result?.htmlLink || null,
2208
2313
  output: result,
2209
2314
  calendar: { id: match.id, name: match.name, account: match.account, provider: match.provider },
@@ -2318,7 +2423,20 @@ async function createCalendarEvent(input = {}) {
2318
2423
  end tell
2319
2424
  `;
2320
2425
  const result = await runAppleScript(script);
2321
- return { created: true, uid: result.output, calendar: exact.name, source: 'macos' };
2426
+ return {
2427
+ created: true,
2428
+ verified: false,
2429
+ verification: {
2430
+ ok: false,
2431
+ source: 'macos_calendar',
2432
+ reason: 'macos_calendar_create_has_no_read_after_write_verifier',
2433
+ calendar: exact.name,
2434
+ uid: result.output,
2435
+ },
2436
+ uid: result.output,
2437
+ calendar: exact.name,
2438
+ source: 'macos',
2439
+ };
2322
2440
  }
2323
2441
 
2324
2442
  async function createReminder({ title, due_date, notes, list }) {
@@ -241,7 +241,7 @@
241
241
  <h1>Your AI Coding <span class="accent">Command Center</span> +<br>Personal <span class="accent">Agent</span></h1>
242
242
  <p class="sub">
243
243
  Run Claude Code, Codex, Gemini, Aider, OpenCode, and Cursor Agent sessions side by side. Manage prompts,
244
- queue tasks, review code and docs, open a phone-friendly remote UI, and let an AI agent build a second brain from your work life.
244
+ queue tasks, review code and docs, open a phone-friendly remote UI with live prompts and model controls, and let an AI agent build a second brain from your work life.
245
245
  </p>
246
246
  <div class="install-box" onclick="navigator.clipboard.writeText('npx create-walle install ./walle');this.querySelector('.copy-hint').textContent='Copied!'">
247
247
  <code>npx create-walle install ./walle</code>
@@ -307,7 +307,7 @@
307
307
  <div class="feature-card">
308
308
  <span class="icon">&#128241;</span>
309
309
  <h3>Remote Phone Access</h3>
310
- <p>Pair your phone with a QR code and use a mobile CTM UI through Microsoft Dev Tunnels, Tailscale, Cloudflare Tunnel, or Walle Remote.</p>
310
+ <p>Pair your phone with a QR code and use a mobile CTM UI through Microsoft Dev Tunnels, Tailscale, Cloudflare Tunnel, or Walle Remote, including live prompts and model controls.</p>
311
311
  </div>
312
312
  <div class="feature-card">
313
313
  <span class="icon">&#916;</span>