tide-commander 0.78.1 → 0.80.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.
@@ -1 +1 @@
1
- import{W as s}from"./main-B3ggaJoY.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react-uS-d4TUT.js";import"./vendor-three-DJ4p3FLF.js";class f extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{f as LocalNotificationsWeb};
1
+ import{W as s}from"./main-DLhL06nK.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react-uS-d4TUT.js";import"./vendor-three-DJ4p3FLF.js";class f extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{f as LocalNotificationsWeb};
package/dist/index.html CHANGED
@@ -22,11 +22,11 @@
22
22
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
23
23
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
24
24
  <title>Tide Commander</title>
25
- <script type="module" crossorigin src="/assets/main-B3ggaJoY.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-DLhL06nK.js"></script>
26
26
  <link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-uS-d4TUT.js">
28
28
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-DJ4p3FLF.js">
29
- <link rel="stylesheet" crossorigin href="/assets/main-D893RHwB.css">
29
+ <link rel="stylesheet" crossorigin href="/assets/main-DsPovOaA.css">
30
30
  </head>
31
31
  <body>
32
32
  <div id="app"></div>
@@ -129,13 +129,20 @@ export class RunnerStdoutPipeline {
129
129
  break;
130
130
  }
131
131
  case 'step_complete': {
132
- if (event.resultText && !this.textEmittedInTurn.has(agentId)) {
132
+ const hasErrorResultText = this.isLikelyErrorResultText(event.resultText);
133
+ if (event.resultText && (!this.textEmittedInTurn.has(agentId) || hasErrorResultText)) {
133
134
  log.log(`[step_complete] Emitting resultText as fallback (no prior text events) for agent ${agentId.slice(0, 4)}`);
134
135
  this.callbacks.onOutput(agentId, event.resultText, false, undefined, event.uuid);
135
136
  }
136
137
  else if (event.resultText) {
137
138
  log.log(`[step_complete] Skipping resultText (already emitted via text events) for agent ${agentId.slice(0, 4)}`);
138
139
  }
140
+ if (event.permissionDenials && event.permissionDenials.length > 0) {
141
+ for (const denial of event.permissionDenials) {
142
+ const denialSummary = this.formatPermissionDenialSummary(denial.toolName, denial.toolInput);
143
+ this.callbacks.onOutput(agentId, `[System] Permission denied: ${denialSummary}`, false, undefined, event.uuid);
144
+ }
145
+ }
139
146
  this.textEmittedInTurn.delete(agentId);
140
147
  if (event.tokens) {
141
148
  this.callbacks.onOutput(agentId, `Tokens: ${event.tokens.input} in, ${event.tokens.output} out`, false, undefined, event.uuid);
@@ -160,4 +167,28 @@ export class RunnerStdoutPipeline {
160
167
  break;
161
168
  }
162
169
  }
170
+ isLikelyErrorResultText(resultText) {
171
+ if (!resultText)
172
+ return false;
173
+ const lower = resultText.toLowerCase();
174
+ return (lower.includes('api error') ||
175
+ lower.includes('internal server error') ||
176
+ lower.includes('permission denied') ||
177
+ lower.includes('tool denied') ||
178
+ lower.includes('error'));
179
+ }
180
+ formatPermissionDenialSummary(toolName, input) {
181
+ const details = input && typeof input === 'object' ? this.summarizeToolInput(input) : '';
182
+ return details ? `${toolName} (${details})` : toolName;
183
+ }
184
+ summarizeToolInput(input) {
185
+ const summaryKeys = ['command', 'file_path', 'path', 'pattern', 'url', 'query', 'description'];
186
+ for (const key of summaryKeys) {
187
+ const value = input[key];
188
+ if (typeof value === 'string' && value.trim().length > 0) {
189
+ return value.length > 120 ? `${value.slice(0, 117)}...` : value;
190
+ }
191
+ }
192
+ return '';
193
+ }
163
194
  }
@@ -1,7 +1,7 @@
1
1
  export const releasePipeline = {
2
2
  slug: 'release-pipeline',
3
3
  name: 'TC Release Pipeline',
4
- description: 'Full release workflow: lint, type-check, test, build, APK, version bump, changelog, git tag, GitHub release. Use when asked to release, publish, ship, or do a full build pipeline.',
4
+ description: 'Full release workflow: lint, type-check, test, build, APK artifacts, version bump, changelog, git tag, GitHub release, npm public publish. Use when asked to release, publish, ship, or do a full build pipeline.',
5
5
  allowedTools: [
6
6
  'Bash(git:*)',
7
7
  'Bash(npm:*)',
@@ -16,7 +16,7 @@ export const releasePipeline = {
16
16
  ],
17
17
  content: `# Release Pipeline
18
18
 
19
- Full release workflow for Tide Commander. Runs quality checks, builds web app + debug APK, bumps the version, updates the changelog, tags, pushes, creates a GitHub release with the APK attached.
19
+ Full release workflow for Tide Commander. Runs quality checks, builds web app + APK artifacts, bumps the version, updates the changelog, tags, pushes, creates a GitHub release with APKs attached, and publishes publicly to npm.
20
20
 
21
21
  ## Core Principles
22
22
 
@@ -122,6 +122,20 @@ Output APK location: \`android/app/build/outputs/apk/debug/app-debug.apk\`
122
122
 
123
123
  If the APK build fails, STOP and report the error.
124
124
 
125
+ #### Build Android Non-Dev Debug APK (signing-safe artifact)
126
+
127
+ Build a non-dev debug APK using bundled assets:
128
+
129
+ \`\`\`bash
130
+ curl -s -X POST http://localhost:5174/api/exec \\
131
+ -H "Content-Type: application/json" \\
132
+ -d '{"agentId":"YOUR_AGENT_ID","command":"make apk-release-nondev"}'
133
+ \`\`\`
134
+
135
+ Output APK location: \`android/app/build/outputs/apk/debug/app-debug.apk\`
136
+
137
+ If the non-dev debug APK build fails, STOP and report the error.
138
+
125
139
  ---
126
140
 
127
141
  ### Phase 4: Version Bump
@@ -217,7 +231,7 @@ git push origin v<VERSION>
217
231
 
218
232
  ---
219
233
 
220
- ### Phase 7: GitHub Release
234
+ ### Phase 7: Public Release (GitHub + npm)
221
235
 
222
236
  Create the GitHub release using the \`gh\` CLI:
223
237
 
@@ -243,14 +257,33 @@ gh release create v<VERSION> --title "v<VERSION>" --notes "<RELEASE_NOTES>"
243
257
  - Architecture changes
244
258
  \`\`\`
245
259
 
246
- #### Attach Debug APK to Release
260
+ #### Attach APK Artifacts to Release
247
261
 
248
- Attach the debug APK to the GitHub release:
262
+ Attach APK artifacts to the GitHub release:
249
263
 
250
264
  \`\`\`bash
251
265
  gh release upload v<VERSION> android/app/build/outputs/apk/debug/app-debug.apk --clobber
252
266
  \`\`\`
253
267
 
268
+ #### Publish to npm (public)
269
+
270
+ Preferred path: pushing tag \`v<VERSION>\` triggers the trusted publish workflow in \`.github/workflows/publish.yml\`.
271
+
272
+ Verify publish workflow completion:
273
+
274
+ \`\`\`bash
275
+ gh run list --workflow publish.yml --limit 5
276
+ \`\`\`
277
+
278
+ If workflow is unavailable or user asks for manual publish, run:
279
+
280
+ \`\`\`bash
281
+ npm whoami
282
+ npm publish --provenance --access public
283
+ \`\`\`
284
+
285
+ If publish fails, STOP and report exact error (auth, 2FA, version exists, provenance, etc).
286
+
254
287
  ---
255
288
 
256
289
  ## Partial Workflows
@@ -284,6 +317,8 @@ Skip Phases 2-4, run Phases 5-7 only.
284
317
  - **Test failures**: STOP, report failing tests, do NOT auto-fix
285
318
  - **Build failure**: STOP, report the build error
286
319
  - **APK build failure**: STOP, report the error (often SDK/Gradle issues)
320
+ - **GitHub release failure**: STOP, report the \`gh\` error and current release/tag state
321
+ - **npm publish failure**: STOP, report exact publish error (auth, 2FA, version exists, provenance)
287
322
  - **Git conflicts**: STOP, list conflicting files, ask user to resolve manually
288
323
  - **Push rejected**: STOP, report the rejection reason (likely needs pull first)
289
324
 
@@ -300,11 +335,13 @@ Skip Phases 2-4, run Phases 5-7 only.
300
335
  | Tests | \`npm test\` | All passing |
301
336
  | Build | \`npm run build\` | Exit code 0 |
302
337
  | APK Debug | \`make apk\` | Exit code 0 |
338
+ | APK Non-Dev Debug | \`make apk-release-nondev\` | Exit code 0 |
303
339
  | Version | \`npm version <type> --no-git-tag-version\` | - |
304
340
  | Tag | \`git tag -a v<VER> -m "..."\` | - |
305
341
  | Push | \`git push origin <branch> && git push origin v<VER>\` | - |
306
342
  | GH Release | \`gh release create v<VER> --notes "..."\` | - |
307
- | Attach APK | \`gh release upload v<VER> <apk-path> --clobber\` | - |
343
+ | Attach APKs | \`gh release upload v<VER> <apk-path> --clobber\` | - |
344
+ | npm Publish | \`npm publish --provenance --access public\` | Exit code 0 |
308
345
 
309
346
  ---
310
347
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "0.78.1",
3
+ "version": "0.80.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",