pinokiod 7.2.18 → 7.3.1

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 (89) hide show
  1. package/Dockerfile +2 -0
  2. package/kernel/api/index.js +13 -179
  3. package/kernel/api/process/index.js +44 -99
  4. package/kernel/bin/conda-pins.js +53 -0
  5. package/kernel/bin/conda.js +35 -6
  6. package/kernel/bin/huggingface.js +1 -1
  7. package/kernel/bin/index.js +15 -2
  8. package/kernel/environment.js +11 -205
  9. package/kernel/git.js +13 -0
  10. package/kernel/index.js +1 -64
  11. package/kernel/plugin.js +58 -6
  12. package/kernel/prototype.js +0 -4
  13. package/kernel/shell.js +2 -23
  14. package/kernel/util.js +0 -60
  15. package/package.json +1 -1
  16. package/server/index.js +171 -229
  17. package/server/lib/content_validation.js +33 -47
  18. package/server/public/common.js +29 -103
  19. package/server/public/create-launcher.js +31 -4
  20. package/server/public/electron.css +6 -0
  21. package/server/public/style.css +0 -337
  22. package/server/public/task-launcher.css +3 -11
  23. package/server/public/task-launcher.js +32 -5
  24. package/server/public/universal-launcher.js +26 -3
  25. package/server/socket.js +11 -22
  26. package/server/views/app.ejs +30 -167
  27. package/server/views/d.ejs +35 -33
  28. package/server/views/editor.ejs +4 -25
  29. package/server/views/partials/main_sidebar.ejs +0 -1
  30. package/server/views/partials/menu.ejs +1 -1
  31. package/server/views/pre.ejs +1 -1
  32. package/server/views/shell.ejs +3 -11
  33. package/server/views/task_launch.ejs +10 -10
  34. package/server/views/terminal.ejs +5 -34
  35. package/spec/INSTRUCTION_SYNC.md +5 -5
  36. package/kernel/agent_instructions.js +0 -166
  37. package/kernel/api/shell_run_template.js +0 -273
  38. package/kernel/api/uri/index.js +0 -51
  39. package/kernel/plugin_sources.js +0 -289
  40. package/kernel/watch/context.js +0 -42
  41. package/kernel/watch/drivers/fs.js +0 -71
  42. package/kernel/watch/drivers/poll.js +0 -33
  43. package/kernel/watch/index.js +0 -185
  44. package/server/features/index.js +0 -13
  45. package/server/features/notes/index.js +0 -41
  46. package/server/features/notes/parser.js +0 -174
  47. package/server/features/notes/public/notes.css +0 -955
  48. package/server/features/notes/public/notes.js +0 -1149
  49. package/server/features/notes/registry_import.js +0 -412
  50. package/server/features/notes/routes.js +0 -156
  51. package/server/features/notes/service.js +0 -326
  52. package/server/features/notes/watcher.js +0 -74
  53. package/server/lib/workspace_catalog.js +0 -151
  54. package/server/lib/workspace_runtime.js +0 -390
  55. package/server/public/tasker.css +0 -336
  56. package/server/public/tasker.js +0 -407
  57. package/server/routes/workspaces.js +0 -44
  58. package/server/views/partials/workspace_row.ejs +0 -61
  59. package/server/views/tasker.ejs +0 -40
  60. package/server/views/workspaces.ejs +0 -813
  61. package/system/plugin/antigravity/antigravity.png +0 -0
  62. package/system/plugin/antigravity/pinokio.js +0 -35
  63. package/system/plugin/claude/claude.png +0 -0
  64. package/system/plugin/claude/pinokio.js +0 -61
  65. package/system/plugin/claude-auto/claude.png +0 -0
  66. package/system/plugin/claude-auto/pinokio.js +0 -72
  67. package/system/plugin/claude-desktop/icon.jpeg +0 -0
  68. package/system/plugin/claude-desktop/pinokio.js +0 -37
  69. package/system/plugin/codex/openai.webp +0 -0
  70. package/system/plugin/codex/pinokio.js +0 -56
  71. package/system/plugin/codex-auto/openai.webp +0 -0
  72. package/system/plugin/codex-auto/pinokio.js +0 -63
  73. package/system/plugin/codex-desktop/icon.png +0 -0
  74. package/system/plugin/codex-desktop/pinokio.js +0 -37
  75. package/system/plugin/crush/crush.png +0 -0
  76. package/system/plugin/crush/pinokio.js +0 -29
  77. package/system/plugin/cursor/cursor.jpeg +0 -0
  78. package/system/plugin/cursor/pinokio.js +0 -37
  79. package/system/plugin/gemini/gemini.jpeg +0 -0
  80. package/system/plugin/gemini/pinokio.js +0 -38
  81. package/system/plugin/gemini-auto/gemini.jpeg +0 -0
  82. package/system/plugin/gemini-auto/pinokio.js +0 -41
  83. package/system/plugin/qwen/pinokio.js +0 -48
  84. package/system/plugin/qwen/qwen.png +0 -0
  85. package/system/plugin/vscode/pinokio.js +0 -34
  86. package/system/plugin/vscode/vscode.png +0 -0
  87. package/system/plugin/windsurf/pinokio.js +0 -37
  88. package/system/plugin/windsurf/windsurf.png +0 -0
  89. package/test/plugin-sources.test.js +0 -45
@@ -5288,7 +5288,6 @@ header.navheader .mode-selector .community-mode-toggle {
5288
5288
  </a>
5289
5289
  <%})%>
5290
5290
  </div>
5291
- <div class='active-nested-path hidden' id='active-nested-path'></div>
5292
5291
  </div>
5293
5292
  <div class='menu-actions'>
5294
5293
  <% if (type === 'run') { %>
@@ -6315,7 +6314,7 @@ header.navheader .mode-selector .community-mode-toggle {
6315
6314
  const href = typeof launch.href === "string" ? launch.href : ""
6316
6315
  try {
6317
6316
  const parsed = new URL(href, window.location.origin)
6318
- if (parsed.pathname.startsWith("/run/plugin/") || parsed.pathname.startsWith("/pinokio/run/plugin/") || (parsed.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(parsed.pathname))) {
6317
+ if (parsed.pathname.startsWith("/run/plugin/") || (parsed.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(parsed.pathname))) {
6319
6318
  const parts = parsed.pathname.split("/").filter(Boolean)
6320
6319
  const pluginSlug = parts.length >= 2 ? parts[parts.length - 2] : ""
6321
6320
  const pluginLabel = titleCaseSlug(pluginSlug)
@@ -7185,7 +7184,6 @@ const rerenderMenuSection = (container, html) => {
7185
7184
  }
7186
7185
 
7187
7186
  if (!target) {
7188
- activeNestedFocusMenu = null
7189
7187
  syncActiveNestedPath()
7190
7188
  browserPopoutSurface.hide()
7191
7189
  document.querySelector(".container").classList.remove("active")
@@ -7219,7 +7217,6 @@ const rerenderMenuSection = (container, html) => {
7219
7217
  el.classList.remove("selected")
7220
7218
  })
7221
7219
  target.classList.add("selected")
7222
- activeNestedFocusMenu = null
7223
7220
  syncActiveNestedPath({ selectedLink: target })
7224
7221
  if (skipPersistedSelection && target.hasAttribute('data-default')) {
7225
7222
  ignorePersistedSelection = false
@@ -8055,162 +8052,7 @@ const rerenderMenuSection = (container, html) => {
8055
8052
 
8056
8053
  const getSubmenu = (menu) => getDirectChild(menu, ".submenu")
8057
8054
  const getToggle = (menu) => getDirectChild(menu, ".reveal")
8058
- const activeNestedPathRoot = document.getElementById("active-nested-path")
8059
- const activeNestedProxyMap = new WeakMap()
8060
- let activeNestedFocusMenu = null
8061
-
8062
- const getNestedMenuChain = (node) => {
8063
- if (!node) {
8064
- return []
8065
- }
8066
- let current = node
8067
- if (!current.classList || !current.classList.contains("nested-menu")) {
8068
- current = current.closest(".nested-menu")
8069
- }
8070
- const chain = []
8071
- while (current) {
8072
- chain.unshift(current)
8073
- current = current.parentElement ? current.parentElement.closest(".nested-menu") : null
8074
- }
8075
- return chain
8076
- }
8077
-
8078
- const sanitizeActiveNestedProxy = (proxy) => {
8079
- if (!proxy) {
8080
- return null
8081
- }
8082
- proxy.removeAttribute("id")
8083
- proxy.classList.remove("frame-link", "selected", "tab-link-popover-host")
8084
- proxy.classList.add("active-nested-proxy")
8085
- proxy.setAttribute("data-active-nested-proxy", "true")
8086
- proxy.querySelectorAll(".tab-link-popover-trigger").forEach((node) => {
8087
- node.remove()
8088
- })
8089
- return proxy
8090
- }
8091
-
8092
- const buildActiveNestedProxy = (child, isCurrent) => {
8093
- if (!child) {
8094
- return null
8095
- }
8096
- let proxy
8097
- if (child.classList && child.classList.contains("nested-menu")) {
8098
- const toggle = getToggle(child)
8099
- if (!toggle) {
8100
- return null
8101
- }
8102
- proxy = toggle.cloneNode(true)
8103
- } else {
8104
- proxy = child.cloneNode(true)
8105
- }
8106
- sanitizeActiveNestedProxy(proxy)
8107
- if (child.classList && child.classList.contains("nested-menu")) {
8108
- const loader = proxy.querySelector(".loader")
8109
- if (loader) {
8110
- loader.innerHTML = `<i class="fa-solid ${isCurrent ? "fa-angle-down" : "fa-angle-right"}"></i>`
8111
- }
8112
- }
8113
- proxy.classList.toggle("is-current", Boolean(isCurrent))
8114
- activeNestedProxyMap.set(proxy, child)
8115
- return proxy
8116
- }
8117
-
8118
- const syncActiveNestedPath = ({ selectedLink = null } = {}) => {
8119
- if (!activeNestedPathRoot) {
8120
- return
8121
- }
8122
- if (activeNestedFocusMenu && !activeNestedFocusMenu.isConnected) {
8123
- activeNestedFocusMenu = null
8124
- }
8125
- const currentSelectedLink = (selectedLink && selectedLink.isConnected)
8126
- ? selectedLink
8127
- : document.querySelector("aside .frame-link.selected")
8128
- const chain = activeNestedFocusMenu
8129
- ? getNestedMenuChain(activeNestedFocusMenu)
8130
- : getNestedMenuChain(currentSelectedLink)
8131
-
8132
- activeNestedPathRoot.replaceChildren()
8133
-
8134
- if (!chain.length) {
8135
- activeNestedPathRoot.classList.add("hidden")
8136
- if (window.PinokioMenuScrollHints && typeof window.PinokioMenuScrollHints.update === "function") {
8137
- window.PinokioMenuScrollHints.update()
8138
- }
8139
- return
8140
- }
8141
-
8142
- chain.forEach((menu, index) => {
8143
- const submenu = getSubmenu(menu)
8144
- if (!submenu) {
8145
- return
8146
- }
8147
- const row = document.createElement("div")
8148
- row.className = "m active-nested-row"
8149
- row.dataset.activeNestedLevel = String(index)
8150
- const nextMenu = chain[index + 1] || null
8151
-
8152
- Array.from(submenu.children).forEach((child) => {
8153
- let isCurrent = false
8154
- if (child.classList && child.classList.contains("nested-menu")) {
8155
- isCurrent = child === nextMenu || (!nextMenu && currentSelectedLink ? child.contains(currentSelectedLink) : false)
8156
- } else {
8157
- isCurrent = child === currentSelectedLink
8158
- }
8159
- const proxy = buildActiveNestedProxy(child, isCurrent)
8160
- if (proxy) {
8161
- row.appendChild(proxy)
8162
- }
8163
- })
8164
-
8165
- if (row.childElementCount > 0) {
8166
- activeNestedPathRoot.appendChild(row)
8167
- }
8168
- })
8169
-
8170
- if (!activeNestedPathRoot.childElementCount) {
8171
- activeNestedPathRoot.classList.add("hidden")
8172
- if (window.PinokioMenuScrollHints && typeof window.PinokioMenuScrollHints.update === "function") {
8173
- window.PinokioMenuScrollHints.update()
8174
- }
8175
- return
8176
- }
8177
-
8178
- activeNestedPathRoot.classList.remove("hidden")
8179
- const currentProxy = activeNestedPathRoot.querySelector(".active-nested-proxy.is-current")
8180
- if (currentProxy && typeof currentProxy.scrollIntoView === "function") {
8181
- currentProxy.scrollIntoView({
8182
- block: "nearest",
8183
- inline: "nearest"
8184
- })
8185
- }
8186
- if (window.PinokioMenuScrollHints && typeof window.PinokioMenuScrollHints.update === "function") {
8187
- window.PinokioMenuScrollHints.update()
8188
- }
8189
- }
8190
-
8191
- if (activeNestedPathRoot) {
8192
- activeNestedPathRoot.addEventListener("click", (event) => {
8193
- const proxy = event.target.closest("[data-active-nested-proxy='true']")
8194
- if (!proxy || !activeNestedPathRoot.contains(proxy)) {
8195
- return
8196
- }
8197
- const source = activeNestedProxyMap.get(proxy)
8198
- if (!source || !source.isConnected) {
8199
- return
8200
- }
8201
- event.preventDefault()
8202
- event.stopPropagation()
8203
- if (source.classList && source.classList.contains("nested-menu")) {
8204
- activeNestedFocusMenu = source
8205
- syncActiveNestedPath()
8206
- return
8207
- }
8208
- activeNestedFocusMenu = null
8209
- if (typeof source.click === "function") {
8210
- source.click()
8211
- }
8212
- })
8213
- }
8055
+ const syncActiveNestedPath = () => {}
8214
8056
 
8215
8057
  renderSelection()
8216
8058
 
@@ -13091,6 +12933,32 @@ document.addEventListener("DOMContentLoaded", () => {
13091
12933
  const defaultWorkspaceCwd = drawer.dataset.workspaceCwd || ""
13092
12934
  const widthKey = "pinokio.ask_ai.width"
13093
12935
  const ASK_AI_MIN_WIDTH = 240
12936
+ const ASK_AI_FALLBACK_TOOLS = [
12937
+ {
12938
+ value: "claude",
12939
+ label: "Claude Code",
12940
+ iconSrc: "/asset/plugin/code/claude/claude.png",
12941
+ href: "/run/plugin/code/claude/pinokio.js",
12942
+ category: "CLI",
12943
+ isDefault: true
12944
+ },
12945
+ {
12946
+ value: "codex",
12947
+ label: "OpenAI Codex",
12948
+ iconSrc: "/asset/plugin/code/codex/openai.webp",
12949
+ href: "/run/plugin/code/codex/pinokio.js",
12950
+ category: "IDE",
12951
+ isDefault: false
12952
+ },
12953
+ {
12954
+ value: "gemini",
12955
+ label: "Google Gemini CLI",
12956
+ iconSrc: "/asset/plugin/code/gemini/gemini.jpeg",
12957
+ href: "/run/plugin/code/gemini/pinokio.js",
12958
+ category: "CLI",
12959
+ isDefault: false
12960
+ }
12961
+ ]
13094
12962
 
13095
12963
  let open = false
13096
12964
  let currentUrl = ""
@@ -13218,7 +13086,6 @@ document.addEventListener("DOMContentLoaded", () => {
13218
13086
  }
13219
13087
  if (
13220
13088
  parsed.pathname.startsWith("/run/plugin/")
13221
- || parsed.pathname.startsWith("/pinokio/run/plugin/")
13222
13089
  || (parsed.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(parsed.pathname))
13223
13090
  ) {
13224
13091
  if (workspaceCwd && !parsed.searchParams.has("cwd")) {
@@ -13283,7 +13150,6 @@ document.addEventListener("DOMContentLoaded", () => {
13283
13150
  return null
13284
13151
  }
13285
13152
  const isPluginLauncher = parsed.pathname.startsWith("/run/plugin/")
13286
- || parsed.pathname.startsWith("/pinokio/run/plugin/")
13287
13153
  || (parsed.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(parsed.pathname))
13288
13154
  if (parsed.origin !== window.location.origin || !isPluginLauncher) {
13289
13155
  return null
@@ -13334,12 +13200,9 @@ document.addEventListener("DOMContentLoaded", () => {
13334
13200
  })
13335
13201
  .then((payload) => {
13336
13202
  const mapped = mapPluginMenuToAskAiTools(payload && Array.isArray(payload.menu) ? payload.menu : [])
13337
- return mapped
13338
- })
13339
- .catch((error) => {
13340
- console.warn("Failed to load Ask AI plugins", error)
13341
- return []
13203
+ return mapped.length > 0 ? mapped : ASK_AI_FALLBACK_TOOLS.slice()
13342
13204
  })
13205
+ .catch(() => ASK_AI_FALLBACK_TOOLS.slice())
13343
13206
  .finally(() => {
13344
13207
  askAiToolsPromise = null
13345
13208
  })
@@ -11,26 +11,13 @@
11
11
  <link href="/markdown.css" rel="stylesheet"/>
12
12
  <link href="/noty.css" rel="stylesheet"/>
13
13
  <link href="/style.css" rel="stylesheet"/>
14
- <link href="/notes.css?v=d-launcher-notes" rel="stylesheet"/>
15
14
  <% if (agent === "electron") { %>
16
15
  <link href="/electron.css" rel="stylesheet"/>
17
16
  <% } %>
18
17
  <style>
19
- html,
20
- body {
21
- height: 100%;
22
- }
23
- body {
24
- display: flex;
25
- flex-direction: column;
26
- }
27
18
  main {
28
19
  box-sizing: border-box;
29
20
  padding: 0;
30
- flex: 1 1 auto;
31
- min-height: 0;
32
- display: flex;
33
- flex-direction: column;
34
21
  /*
35
22
  flex-wrap: wrap;
36
23
  */
@@ -271,10 +258,8 @@ body.dark .column-subtitle-link:focus-visible {
271
258
  }
272
259
  .menu-grid {
273
260
  display: grid;
274
- flex: 1 1 auto;
275
261
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
276
- align-items: stretch;
277
- min-height: 0;
262
+ align-items: start;
278
263
  }
279
264
  .menu-grid.menu-grid--triptych {
280
265
  grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -523,8 +508,6 @@ body.dark form.search {
523
508
  background: rgba(255,255,255,0.07);
524
509
  }
525
510
  form.search {
526
- flex: 0 0 auto;
527
- align-items: center;
528
511
  padding: 10px;
529
512
  background: #F1F1F1;
530
513
  }
@@ -557,11 +540,23 @@ body.dark #update-spec {
557
540
  <script src="/nav.js"></script>
558
541
  </head>
559
542
  <body class='<%=theme%>' data-agent="<%=agent%>">
560
- <main data-pinokio-notes-scope="true">
561
- <div id="pinokio-notes-slot" class="pinokio-notes-slot" aria-live="polite"></div>
543
+ <main>
562
544
  <form class='search'>
563
545
  <input type='search' class="flexible" placeholder='Filter tools'>
564
546
  </form>
547
+ <!--
548
+ <header>
549
+ <h1>Build</h1>
550
+ <div class='flexible'></div>
551
+ <a class='btn' href="https://github.com/pinokiocomputer/code/issues" target="_blank"><i class="fa-solid fa-up-right-from-square"></i> Request a tool</a>
552
+ <a class='btn' id='git-pull'><i class="fa-solid fa-rotate"></i> Check for new tools</a>
553
+ <div class='pulling hidden'>
554
+ <div class='loading'>
555
+ <i class="fa-solid fa-circle-notch fa-spin"></i> refreshing...
556
+ </div>
557
+ </div>
558
+ </header>
559
+ -->
565
560
  <div class='spec'>
566
561
  <div class='explain'>
567
562
  <h3><i class="fa-regular fa-circle-check"></i> TODO</h3>
@@ -757,24 +752,32 @@ body.dark #update-spec {
757
752
  <% } %>
758
753
  </main>
759
754
  <script>
760
- const pinokioNotePublish = { target: "registry", type: "post" }
761
- const pinokioNoteParentUrl = <%- JSON.stringify(typeof registry_parent_url !== 'undefined' ? registry_parent_url || '' : '').replace(/</g, '\\u003c') %>
762
- if (pinokioNoteParentUrl) {
763
- pinokioNotePublish.parent = { type: "app", url: pinokioNoteParentUrl }
764
- }
765
- window.PinokioNoteContext = {
766
- cwd: <%- JSON.stringify(filepath || '').replace(/</g, '\\u003c') %>,
767
- publish: pinokioNotePublish
768
- }
769
- </script>
770
- <script src="/notes.js?v=d-launcher-notes"></script>
771
- <script>
772
755
  <% if (retry) { %>
773
756
  setTimeout(() => {
774
757
  location.href = location.href
775
758
  }, 2000)
776
759
  <% } %>
777
760
  /*
761
+ document.querySelector("#git-pull").addEventListener("click", (e) => {
762
+ e.preventDefault()
763
+ e.stopPropagation()
764
+ document.querySelector(".pulling").classList.remove("hidden")
765
+ document.querySelector("#git-pull").classList.add("hidden")
766
+ fetch("/plugin/update", {
767
+ method: "POST"
768
+ }).then((res) => {
769
+ return res.json()
770
+ }).then((res) => {
771
+ if (res.success) {
772
+ location.href = location.href
773
+ } else if(res.error) {
774
+ document.querySelector("#git-pull").classList.remove("hidden")
775
+ alert(res.error)
776
+ }
777
+ })
778
+ })
779
+ */
780
+ /*
778
781
  const resize = (textarea) => {
779
782
  textarea.style.height = "";
780
783
  textarea.style.height = textarea.scrollHeight + "px";
@@ -920,7 +923,6 @@ const appendWorkspaceCwd = (value, cwd = workspaceCwd) => {
920
923
  try {
921
924
  const parsed = new URL(raw, window.location.origin)
922
925
  const isPluginLauncher = parsed.pathname.startsWith("/run/plugin/")
923
- || parsed.pathname.startsWith("/pinokio/run/plugin/")
924
926
  || (parsed.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(parsed.pathname))
925
927
  if (parsed.origin !== window.location.origin || !isPluginLauncher) {
926
928
  return value
@@ -143,7 +143,6 @@ body.frozen {
143
143
  <script>
144
144
  let shell_id
145
145
  document.addEventListener("DOMContentLoaded", async () => {
146
- const readOnly = <%= readonly ? "true" : "false" %>;
147
146
  <% if (error) { %>
148
147
  document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
149
148
  <% } %>
@@ -196,7 +195,6 @@ document.addEventListener("DOMContentLoaded", async () => {
196
195
  // maxLines: Infinity, // set to a large number
197
196
  minLines: 1 // set to a small number
198
197
  });
199
- editor.setReadOnly(readOnly);
200
198
  console.log("location.pathname", location.pathname)
201
199
  <% if (mod) { %>
202
200
  <% if (js) { %>
@@ -233,9 +231,6 @@ document.addEventListener("DOMContentLoaded", async () => {
233
231
  let str;
234
232
  let original = editor.getValue()
235
233
  editor.getSession().on("change", () => {
236
- if (readOnly) {
237
- return
238
- }
239
234
  let v = editor.getValue()
240
235
  if (original === v) {
241
236
  dirty = false
@@ -248,10 +243,6 @@ document.addEventListener("DOMContentLoaded", async () => {
248
243
  });
249
244
  <% } %>
250
245
  const n = new N()
251
- const activeProcessWait = <% if (typeof active_process_wait !== 'undefined' && active_process_wait) { %><%- JSON.stringify(active_process_wait) %><% } else { %>null<% } %>
252
- if (activeProcessWait && (activeProcessWait.title || activeProcessWait.description) && window.PinokioWaitFooterStatus) {
253
- window.PinokioWaitFooterStatus.show(activeProcessWait)
254
- }
255
246
  class RPC {
256
247
  constructor() {
257
248
  this.socket = new Socket()
@@ -284,10 +275,6 @@ document.addEventListener("DOMContentLoaded", async () => {
284
275
  }
285
276
  save() {
286
277
  return new Promise((resolve, reject) => {
287
- if (readOnly) {
288
- resolve()
289
- return
290
- }
291
278
  let cwd = "<%-JSON.stringify(execUrl).slice(1, -1)%>"
292
279
  //let cwd = "<%=execUrl%>"
293
280
  //let cwd = "~" + location.pathname
@@ -333,12 +320,12 @@ document.addEventListener("DOMContentLoaded", async () => {
333
320
  if (packet.type === 'start') {
334
321
  // refreshParent(packet)
335
322
  reloadMemory()
336
- if (packet.data && (packet.data.title || packet.data.description)) {
323
+ if (packet.data && packet.data.description) {
337
324
  if ('current' in packet.data) {
338
325
  document.querySelector("footer").innerHTML = `<b>
339
326
  <i class="fa-solid fa-circle-notch fa-spin"></i>(${packet.data.current+1}/${packet.data.total}) ${packet.data.title ? packet.data.title : ''}
340
327
  </b>
341
- <div class='flexible content'>${packet.data.description ? packet.data.description : ''}</div>`
328
+ <div class='flexible content'>${packet.data.description}</div>`
342
329
  // <div class='toggle-expand'>
343
330
  // <i class="fa-solid fa-circle-chevron-up"></i>
344
331
  // </div>`
@@ -346,7 +333,7 @@ document.addEventListener("DOMContentLoaded", async () => {
346
333
  document.querySelector("footer").innerHTML = `<b>
347
334
  <i class="fa-solid fa-circle-notch fa-spin"></i> ${packet.data.title ? packet.data.title : ''}
348
335
  </b>
349
- <div class='flexible content'>${packet.data.description ? packet.data.description : ''}</div>`
336
+ <div class='flexible content'></div>`
350
337
  // <div class='toggle-expand'>
351
338
  // <i class="fa-solid fa-circle-chevron-up"></i>
352
339
  // </div>`
@@ -445,14 +432,6 @@ document.addEventListener("DOMContentLoaded", async () => {
445
432
  response: {},
446
433
  uri: packet.id
447
434
  })
448
- } else if (packet.type === "process.wait.start") {
449
- if (window.PinokioWaitFooterStatus) {
450
- window.PinokioWaitFooterStatus.show(packet.data)
451
- }
452
- } else if (packet.type === "process.wait.end") {
453
- if (window.PinokioWaitFooterStatus) {
454
- window.PinokioWaitFooterStatus.hide()
455
- }
456
435
  } else if (packet.type === 'wait') {
457
436
  await WaitModal(packet.data)
458
437
  } else if (packet.type === "htmlmodal") {
@@ -980,7 +959,7 @@ const reloadMemory = async () => {
980
959
  <!--
981
960
  <button class='btn' id='source' data-editor-url="<%=editorUrl%>">Navigate</button>
982
961
  -->
983
- <div id='save' class='btn disabled <%= readonly ? "hidden" : "" %>'>
962
+ <div id='save' class='btn disabled'>
984
963
  <span class='save'><i class="fa-solid fa-check"></i> Save</span>
985
964
  </div>
986
965
  </div>
@@ -27,7 +27,6 @@
27
27
  </button>
28
28
  </div>
29
29
  <a href="/home" class="tab <%= sidebarSelected === 'home' ? 'selected' : '' %>" data-tippy-content="This machine"><i class='fas fa-laptop-code'></i><div class='caption'>This machine</div></a>
30
- <a href="/workspaces" class="tab <%= sidebarSelected === 'workspaces' ? 'selected' : '' %>" data-tippy-content="Workspaces"><i class="fa-solid fa-folder-tree"></i><div class='caption'>Workspaces</div></a>
31
30
  <a href="/network" class="tab <%= sidebarSelected === 'network' ? 'selected' : '' %>" data-tippy-content="Local network"><i class="fa-solid fa-wifi"></i><div class='caption'>Local network</div></a>
32
31
  <% if (sidebarList.length > 0) { %>
33
32
  <% sidebarList.forEach(({ host, name, platform }) => { %>
@@ -18,7 +18,7 @@
18
18
  <i class="fa-solid fa-angle-right"></i>
19
19
  <% } %>
20
20
  </div>
21
- <% } else if (item.run && typeof item.run === 'string') { %>
21
+ <% } else if (item.run) { %>
22
22
  <div data-run="<%=item.run%>" data-cwd="<%=item.cwd%>" class='btn header-item frame-link <%=item.display || ""%>'>
23
23
  <div class='tab'><%-item.btn%></div>
24
24
  <% if (item.arrow) { %>
@@ -117,7 +117,7 @@ footer a.btn {
117
117
  </div>
118
118
  <div class='items'>
119
119
  <% items.forEach((item) => { %>
120
- <% if (typeof item.href === "string" && item.href) { %>
120
+ <% if (item.href) { %>
121
121
  <div class='item'>
122
122
  <% if (item.icon) { %>
123
123
  <img src="<%=item.icon%>">
@@ -621,12 +621,12 @@ document.addEventListener("DOMContentLoaded", async () => {
621
621
  document.querySelector(".play-btn").classList.add("hidden")
622
622
  document.querySelector(".starting-btn").classList.add("hidden")
623
623
  document.querySelector(".stop-btn").classList.remove("hidden")
624
- if (packet.data && (packet.data.title || packet.data.description)) {
624
+ if (packet.data && packet.data.description) {
625
625
  if ('current' in packet.data) {
626
626
  document.querySelector("footer").innerHTML = `<b>
627
627
  <i class="fa-solid fa-circle-notch fa-spin"></i>(${packet.data.current+1}/${packet.data.total}) ${packet.data.title ? packet.data.title : ''}
628
628
  </b>
629
- <div class='flexible content'>${packet.data.description ? packet.data.description : ''}</div>`
629
+ <div class='flexible content'>${packet.data.description}</div>`
630
630
  // <div class='toggle-expand'>
631
631
  // <i class="fa-solid fa-circle-chevron-up"></i>
632
632
  // </div>`
@@ -634,7 +634,7 @@ document.addEventListener("DOMContentLoaded", async () => {
634
634
  document.querySelector("footer").innerHTML = `<b>
635
635
  <i class="fa-solid fa-circle-notch fa-spin"></i> ${packet.data.title ? packet.data.title : ''}
636
636
  </b>
637
- <div class='flexible content'>${packet.data.description ? packet.data.description : ''}</div>`
637
+ <div class='flexible content'></div>`
638
638
  // <div class='toggle-expand'>
639
639
  // <i class="fa-solid fa-circle-chevron-up"></i>
640
640
  // </div>`
@@ -734,14 +734,6 @@ document.addEventListener("DOMContentLoaded", async () => {
734
734
  // uri: "~" + location.pathname,
735
735
  uri: packet.id
736
736
  })
737
- } else if (packet.type === "process.wait.start") {
738
- if (window.PinokioWaitFooterStatus) {
739
- window.PinokioWaitFooterStatus.show(packet.data)
740
- }
741
- } else if (packet.type === "process.wait.end") {
742
- if (window.PinokioWaitFooterStatus) {
743
- window.PinokioWaitFooterStatus.hide()
744
- }
745
737
  } else if (packet.type === 'wait') {
746
738
  await WaitModal(packet.data)
747
739
  } else if (packet.type === "htmlmodal") {
@@ -125,6 +125,16 @@
125
125
  <div class="task-detail-main">
126
126
  <section class="task-section task-prompt-section">
127
127
  <pre class="task-code task-prompt-code" data-task-rendered-prompt><%= renderedPrompt %></pre>
128
+ <div class="task-prompt-actions">
129
+ <button class="task-button primary task-run-button" type="submit">
130
+ <i class="fa-solid fa-bolt" aria-hidden="true"></i>
131
+ <span>Run</span>
132
+ </button>
133
+ <p class="task-inline-help">Tool and folder stay local. The permalink tracks only the task inputs.</p>
134
+ <p class="task-submit-feedback" data-task-submit-feedback aria-live="polite" aria-hidden="true">
135
+ <span data-task-submit-feedback-text></span>
136
+ </p>
137
+ </div>
128
138
  </section>
129
139
  </div>
130
140
 
@@ -154,16 +164,6 @@
154
164
  <span class="task-label">Folder<% if (folderRequired) { %><span class="task-label-required">*</span><% } %><% if (folderMeta) { %><span class="task-label-meta"><%= folderMeta %></span><% } %></span>
155
165
  <input class="task-input" type="text" name="folderName" value="<%= folderName || '' %>" placeholder="<%= folderPlaceholder %>" <%= folderRequired ? 'required' : '' %>>
156
166
  </label>
157
- <div class="task-run-footer">
158
- <button class="task-button primary task-run-button task-run-actions" type="submit">
159
- <i class="fa-solid fa-bolt" aria-hidden="true"></i>
160
- <span>Run</span>
161
- </button>
162
- <p class="task-inline-help">Tool and folder stay local. The permalink tracks only the task inputs.</p>
163
- <p class="task-submit-feedback" data-task-submit-feedback aria-live="polite" aria-hidden="true">
164
- <span data-task-submit-feedback-text></span>
165
- </p>
166
- </div>
167
167
  </div>
168
168
  </section>
169
169
  </aside>