pinokiod 7.1.71 → 7.1.73

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.
@@ -4,7 +4,7 @@ const semver = require('semver')
4
4
 
5
5
  class Bluefairy {
6
6
  description = "Installs Bluefairy, a standalone package freshness guard."
7
- version = ">=0.0.27"
7
+ version = ">=0.0.28"
8
8
 
9
9
  packageName() {
10
10
  return "bluefairy"
@@ -51,11 +51,15 @@ class Bluefairy {
51
51
  path.resolve(binDir, "bluefairy-activate"),
52
52
  path.resolve(binDir, "bluefairy-activate.cmd"),
53
53
  path.resolve(binDir, "bluefairy-activate.ps1"),
54
+ path.resolve(binDir, "bluefairy-deactivate"),
55
+ path.resolve(binDir, "bluefairy-deactivate.cmd"),
56
+ path.resolve(binDir, "bluefairy-deactivate.ps1"),
54
57
  ]
55
58
  }
56
59
  return [
57
60
  path.resolve(binDir, "bluefairy"),
58
61
  path.resolve(binDir, "bluefairy-activate"),
62
+ path.resolve(binDir, "bluefairy-deactivate"),
59
63
  ]
60
64
  }
61
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "7.1.71",
3
+ "version": "7.1.73",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server/index.js CHANGED
@@ -8268,6 +8268,67 @@ class Server {
8268
8268
  Math.random().toString(16).slice(2)
8269
8269
  ].join("-")
8270
8270
  }
8271
+ const prepareUniversalLauncherTarget = async ({ type, name, prompt, tool, uploadToken }) => {
8272
+ const normalizedType = typeof type === "string" ? type.trim().toLowerCase() : ""
8273
+ if (normalizedType !== "ask" && normalizedType !== "create_plugin") {
8274
+ const error = new Error("Unsupported launcher type.")
8275
+ error.status = 400
8276
+ throw error
8277
+ }
8278
+
8279
+ const pluginHref = resolveUniversalLauncherPluginHref(tool)
8280
+ let folderName = typeof name === "string" ? name.trim() : ""
8281
+ if (normalizedType === "ask" && !folderName) {
8282
+ folderName = await generateTerminalWorkspaceFolderName()
8283
+ }
8284
+ if (!folderName) {
8285
+ const error = new Error("Folder name is required.")
8286
+ error.status = 400
8287
+ throw error
8288
+ }
8289
+
8290
+ const rootDir = normalizedType === "ask"
8291
+ ? path.resolve(getTerminalWorkspacesRoot())
8292
+ : path.resolve(this.kernel.path("plugin"))
8293
+ const targetPath = await createLauncherTargetFolder(rootDir, folderName)
8294
+ try {
8295
+ await copyLauncherUploadsToDir(uploadToken, targetPath)
8296
+ } catch (error) {
8297
+ await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
8298
+ throw error
8299
+ }
8300
+ try {
8301
+ await bootstrapLauncherInstructionFiles(targetPath)
8302
+ } catch (error) {
8303
+ await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
8304
+ throw error
8305
+ }
8306
+ try {
8307
+ await persistLauncherPromptContext(targetPath, {
8308
+ prompt,
8309
+ includeSpec: true,
8310
+ includeRequest: normalizedType === "ask"
8311
+ })
8312
+ } catch (error) {
8313
+ await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
8314
+ throw error
8315
+ }
8316
+
8317
+ const params = new URLSearchParams()
8318
+ params.set("cwd", targetPath)
8319
+ params.set("chrome", "full")
8320
+ if (prompt) {
8321
+ params.set("prompt", prompt)
8322
+ }
8323
+
8324
+ return {
8325
+ ok: true,
8326
+ type: normalizedType,
8327
+ name: folderName,
8328
+ cwd: targetPath,
8329
+ url: `${pluginHref}?${params.toString()}`
8330
+ }
8331
+ }
8271
8332
  const prepareUniversalCreateApp = async ({ name, prompt, tool, uploadToken }) => {
8272
8333
  const folderName = typeof name === "string" ? name.trim() : ""
8273
8334
  if (!folderName) {
@@ -8345,6 +8406,44 @@ class Server {
8345
8406
  }
8346
8407
  return `${baseName}-${Date.now()}`
8347
8408
  }
8409
+ const suggestTaskWorkspaceName = async (task) => {
8410
+ const baseName = taskPackages.slugify(
8411
+ task && task.config ? task.config.title : (task && task.id ? task.id : "task"),
8412
+ "task"
8413
+ )
8414
+ let links = { workspaces: [] }
8415
+ try {
8416
+ links = await taskWorkspaceLinks.listTaskWorkspaces(task && task.id ? task.id : "", {
8417
+ root: "workspaces",
8418
+ pruneMissing: true
8419
+ })
8420
+ } catch (_) {
8421
+ }
8422
+ const existingNames = new Set(
8423
+ (Array.isArray(links.workspaces) ? links.workspaces : [])
8424
+ .map((workspace) => {
8425
+ const ref = workspace && typeof workspace.ref === "string" ? workspace.ref.trim() : ""
8426
+ if (!ref) {
8427
+ return ""
8428
+ }
8429
+ const relative = ref.split("/").slice(1).join("/")
8430
+ return relative ? path.posix.basename(relative).toLowerCase() : ""
8431
+ })
8432
+ .filter(Boolean)
8433
+ )
8434
+ let attempt = 0
8435
+ while (attempt < 1000) {
8436
+ const suffix = attempt === 0 ? "" : `-${attempt + 1}`
8437
+ const maxBaseLength = Math.max(1, 80 - suffix.length)
8438
+ const candidateBase = baseName.slice(0, maxBaseLength) || "task"
8439
+ const candidate = `${candidateBase}${suffix}`
8440
+ if (!existingNames.has(candidate.toLowerCase())) {
8441
+ return candidate
8442
+ }
8443
+ attempt += 1
8444
+ }
8445
+ return `${baseName}-${Date.now()}`
8446
+ }
8348
8447
  const getTaskLaunchTarget = (taskConfig) => {
8349
8448
  const validatedTaskConfig = taskPackages.validateTaskConfig(taskConfig)
8350
8449
  return validatedTaskConfig.target
@@ -8656,7 +8755,7 @@ class Server {
8656
8755
  const taskUi = buildTaskPresentationState(task, shareState)
8657
8756
  const sidebarContext = await buildTaskSidebarContext()
8658
8757
  const suggestedFolderName = task && task.config && usesWorkspaceTaskTarget(task.config)
8659
- ? ""
8758
+ ? await suggestTaskWorkspaceName(task)
8660
8759
  : taskPackages.slugify(task && task.config ? task.config.title : task.id, task && task.id ? task.id : "task")
8661
8760
  const renderedPrompt = taskPackages.applyTemplateValues(task.template, promptValues)
8662
8761
  const protocol = (req.$source && req.$source.protocol) || req.protocol || "http"
@@ -9943,37 +10042,84 @@ class Server {
9943
10042
  }
9944
10043
 
9945
10044
  const pluginHref = resolveUniversalLauncherPluginHref(selectedTool)
10045
+ const launchTarget = getTaskLaunchTarget(task.config)
9946
10046
  const launchRoot = getTaskLaunchRoot(task.config)
9947
10047
  let folderName = folderNameInput
9948
10048
  if (!folderName) {
9949
- if (usesWorkspaceTaskTarget(task.config)) {
9950
- folderName = await generateTerminalWorkspaceFolderName()
10049
+ if (launchTarget === "workspaces") {
10050
+ folderName = await suggestTaskWorkspaceName(task)
9951
10051
  } else {
9952
- folderName = await suggestTaskFolderName(launchRoot, task.config.title)
10052
+ await renderTaskLaunchPage(req, res, task, {
10053
+ selectedTool,
10054
+ inputValues,
10055
+ folderName: "",
10056
+ error: "Folder name is required."
10057
+ })
10058
+ return
9953
10059
  }
9954
10060
  }
9955
10061
 
9956
- let targetPath
9957
- try {
9958
- targetPath = await createLauncherTargetFolder(launchRoot, folderName)
9959
- } catch (error) {
10062
+ const prompt = taskPackages.applyTemplateValues(task.template, filterFilledTaskInputValues(inputValues)).trim()
10063
+ if (!prompt) {
9960
10064
  await renderTaskLaunchPage(req, res, task, {
9961
10065
  selectedTool,
9962
10066
  inputValues,
9963
10067
  folderName: folderNameInput || folderName,
9964
- error: error && error.message ? error.message : "Failed to create task folder."
10068
+ error: "The rendered task prompt is empty."
9965
10069
  })
9966
10070
  return
9967
10071
  }
9968
10072
 
9969
- const prompt = taskPackages.applyTemplateValues(task.template, filterFilledTaskInputValues(inputValues)).trim()
9970
- if (!prompt) {
9971
- await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
10073
+ if (launchTarget === "api") {
10074
+ try {
10075
+ const payload = await prepareUniversalCreateApp({
10076
+ name: folderName,
10077
+ prompt,
10078
+ tool: selectedTool,
10079
+ uploadToken: ""
10080
+ })
10081
+ res.redirect(payload.url)
10082
+ } catch (error) {
10083
+ await renderTaskLaunchPage(req, res, task, {
10084
+ selectedTool,
10085
+ inputValues,
10086
+ folderName: folderNameInput || folderName,
10087
+ error: error && error.message ? error.message : "Failed to create app."
10088
+ })
10089
+ }
10090
+ return
10091
+ }
10092
+
10093
+ if (launchTarget === "plugin") {
10094
+ try {
10095
+ const payload = await prepareUniversalLauncherTarget({
10096
+ type: "create_plugin",
10097
+ name: folderName,
10098
+ prompt,
10099
+ tool: selectedTool,
10100
+ uploadToken: ""
10101
+ })
10102
+ res.redirect(payload.url)
10103
+ } catch (error) {
10104
+ await renderTaskLaunchPage(req, res, task, {
10105
+ selectedTool,
10106
+ inputValues,
10107
+ folderName: folderNameInput || folderName,
10108
+ error: error && error.message ? error.message : "Failed to initialize task folder."
10109
+ })
10110
+ }
10111
+ return
10112
+ }
10113
+
10114
+ let targetPath
10115
+ try {
10116
+ targetPath = await createLauncherTargetFolder(launchRoot, folderName)
10117
+ } catch (error) {
9972
10118
  await renderTaskLaunchPage(req, res, task, {
9973
10119
  selectedTool,
9974
10120
  inputValues,
9975
10121
  folderName: folderNameInput || folderName,
9976
- error: "The rendered task prompt is empty."
10122
+ error: error && error.message ? error.message : "Failed to create task folder."
9977
10123
  })
9978
10124
  return
9979
10125
  }
@@ -10006,6 +10152,29 @@ class Server {
10006
10152
  })
10007
10153
  return
10008
10154
  }
10155
+ if (launchTarget === "workspaces") {
10156
+ const workspaceRef = taskWorkspaceLinks.createWorkspaceRef("workspaces", targetPath)
10157
+ if (!workspaceRef) {
10158
+ await renderTaskLaunchPage(req, res, task, {
10159
+ selectedTool,
10160
+ inputValues,
10161
+ folderName: folderNameInput || folderName,
10162
+ error: "Failed to remember the created workspace."
10163
+ })
10164
+ return
10165
+ }
10166
+ try {
10167
+ await taskWorkspaceLinks.touchTaskWorkspace(task.id, workspaceRef)
10168
+ } catch (error) {
10169
+ await renderTaskLaunchPage(req, res, task, {
10170
+ selectedTool,
10171
+ inputValues,
10172
+ folderName: folderNameInput || folderName,
10173
+ error: error && error.message ? error.message : "Failed to remember the created workspace."
10174
+ })
10175
+ return
10176
+ }
10177
+ }
10009
10178
 
10010
10179
  const params = new URLSearchParams()
10011
10180
  params.set("cwd", targetPath)
@@ -10438,9 +10607,7 @@ class Server {
10438
10607
  try {
10439
10608
  const body = req.body && typeof req.body === "object" ? req.body : {}
10440
10609
  const type = typeof body.type === "string" ? body.type.trim().toLowerCase() : ""
10441
- const requestedFolderName = typeof body.name === "string" ? body.name.trim() : ""
10442
10610
  const prompt = typeof body.prompt === "string" ? body.prompt.trim() : ""
10443
- const pluginHref = resolveUniversalLauncherPluginHref(body.tool)
10444
10611
 
10445
10612
  if (type !== "ask" && type !== "create_plugin") {
10446
10613
  res.status(400).json({
@@ -10449,59 +10616,14 @@ class Server {
10449
10616
  })
10450
10617
  return
10451
10618
  }
10452
- let folderName = requestedFolderName
10453
- if (type === "ask" && !folderName) {
10454
- folderName = await generateTerminalWorkspaceFolderName()
10455
- }
10456
- if (!folderName) {
10457
- res.status(400).json({
10458
- ok: false,
10459
- error: "Folder name is required."
10460
- })
10461
- return
10462
- }
10463
-
10464
- const rootDir = type === "ask"
10465
- ? path.resolve(getTerminalWorkspacesRoot())
10466
- : path.resolve(this.kernel.path("plugin"))
10467
- const targetPath = await createLauncherTargetFolder(rootDir, folderName)
10468
- try {
10469
- await copyLauncherUploadsToDir(body.uploadToken, targetPath)
10470
- } catch (error) {
10471
- await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
10472
- throw error
10473
- }
10474
- try {
10475
- await bootstrapLauncherInstructionFiles(targetPath)
10476
- } catch (error) {
10477
- await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
10478
- throw error
10479
- }
10480
- try {
10481
- await persistLauncherPromptContext(targetPath, {
10482
- prompt,
10483
- includeSpec: true,
10484
- includeRequest: type === "ask"
10485
- })
10486
- } catch (error) {
10487
- await fs.promises.rm(targetPath, { recursive: true, force: true }).catch(() => {})
10488
- throw error
10489
- }
10490
-
10491
- const params = new URLSearchParams()
10492
- params.set("cwd", targetPath)
10493
- params.set("chrome", "full")
10494
- if (prompt) {
10495
- params.set("prompt", prompt)
10496
- }
10497
-
10498
- res.json({
10499
- ok: true,
10619
+ const payload = await prepareUniversalLauncherTarget({
10500
10620
  type,
10501
- name: folderName,
10502
- cwd: targetPath,
10503
- url: `${pluginHref}?${params.toString()}`
10621
+ name: typeof body.name === "string" ? body.name : "",
10622
+ prompt,
10623
+ tool: typeof body.tool === "string" ? body.tool : "",
10624
+ uploadToken: typeof body.uploadToken === "string" ? body.uploadToken : ""
10504
10625
  })
10626
+ res.json(payload)
10505
10627
  } catch (error) {
10506
10628
  const status = Number.isInteger(error && error.status) ? error.status : 500
10507
10629
  res.status(status).json({
@@ -12682,7 +12804,7 @@ class Server {
12682
12804
 
12683
12805
  await this.kernel.peer.check_peers()
12684
12806
 
12685
- let list = this.getPeers()
12807
+ let list = this.kernel.peer.info ? this.getPeers() : []
12686
12808
 
12687
12809
  // let list = this.getPeerInfo()
12688
12810
  let processes = []
@@ -12695,8 +12817,22 @@ class Server {
12695
12817
  peer = item
12696
12818
  }
12697
12819
  }
12820
+ let peer_info = host && this.kernel.peer.info ? this.kernel.peer.info[host] : null
12821
+ if (!peer_info && req.params.name === this.kernel.peer.name) {
12822
+ try {
12823
+ await this.kernel.peer.refresh_host(this.kernel.peer.host)
12824
+ } catch (e) {
12825
+ }
12826
+ host = this.kernel.peer.host
12827
+ peer_info = this.kernel.peer.info && this.kernel.peer.info[host] ? this.kernel.peer.info[host] : null
12828
+ if (peer_info) {
12829
+ peer = peer_info
12830
+ }
12831
+ }
12698
12832
  try {
12699
- processes = this.kernel.peer.info[host].router_info
12833
+ if (peer_info) {
12834
+ processes = peer_info.router_info
12835
+ }
12700
12836
  for(let i=0; i<processes.length; i++) {
12701
12837
  if (!processes[i].icon) {
12702
12838
  if (protocol === "https") {
@@ -12709,8 +12845,8 @@ class Server {
12709
12845
  }
12710
12846
  } catch (e) {
12711
12847
  }
12712
- let installed = this.kernel.peer.info[host].installed
12713
- let serverless_mapping = this.kernel.peer.info[host].rewrite_mapping
12848
+ let installed = peer_info ? peer_info.installed : []
12849
+ let serverless_mapping = peer_info ? peer_info.rewrite_mapping : {}
12714
12850
  let serverless = Object.keys(serverless_mapping).map((name) => {
12715
12851
  return serverless_mapping[name]
12716
12852
  })
@@ -12719,7 +12855,7 @@ class Server {
12719
12855
  return this.kernel.router.rewrite_mapping[key]
12720
12856
  })
12721
12857
  const peerAccess = await this.composePeerAccessPayload()
12722
- const allow_dns_creation = req.params.name === this.kernel.peer.name
12858
+ const allow_dns_creation = !!peer_info && req.params.name === this.kernel.peer.name
12723
12859
  res.render("net", {
12724
12860
  static_routes,
12725
12861
  selected_name: req.params.name,
@@ -12732,7 +12868,7 @@ class Server {
12732
12868
  processes,
12733
12869
  installed,
12734
12870
  serverless,
12735
- error: null,
12871
+ error: peer_info ? null : `Peer "${req.params.name}" is not ready yet. Try again in a moment.`,
12736
12872
  list,
12737
12873
  host,
12738
12874
  peer,
@@ -280,15 +280,25 @@ body.task-page .task-shell {
280
280
  }
281
281
 
282
282
  .task-detail-sidebar {
283
+ position: relative;
283
284
  min-width: 0;
284
285
  align-self: start;
285
286
  margin-top: 0;
286
- padding: 2px 0 0 28px;
287
- border-left: 1px solid var(--task-border);
287
+ padding: 2px 0 0 40px;
288
288
  border-radius: 0;
289
289
  background: transparent;
290
290
  }
291
291
 
292
+ .task-detail-sidebar::before {
293
+ content: "";
294
+ position: absolute;
295
+ top: 0;
296
+ bottom: 0;
297
+ left: 12px;
298
+ width: 1px;
299
+ background: var(--task-border);
300
+ }
301
+
292
302
  .task-shell {
293
303
  width: min(880px, calc(100vw - 32px));
294
304
  margin: 24px auto 40px;
@@ -2758,10 +2768,13 @@ body.dark .plugin-option .option-icon {
2758
2768
  .task-detail-sidebar {
2759
2769
  margin-top: 0;
2760
2770
  padding: 18px 0 0;
2761
- border-left: 0;
2762
2771
  border-top: 1px solid var(--task-border);
2763
2772
  }
2764
2773
 
2774
+ .task-detail-sidebar::before {
2775
+ display: none;
2776
+ }
2777
+
2765
2778
  .task-shell {
2766
2779
  width: min(100vw - 20px, 100%);
2767
2780
  margin: 12px auto 20px;
@@ -24,6 +24,10 @@
24
24
  ? 'Creates a new plugin.'
25
25
  : 'Runs in a new workspace.'
26
26
  const folderMeta = effectiveTaskTarget === 'workspaces' ? 'Optional' : ''
27
+ const folderRequired = effectiveTaskTarget !== 'workspaces'
28
+ const folderPlaceholder = effectiveTaskTarget === 'workspaces'
29
+ ? (suggestedFolderName || 'auto-generated')
30
+ : 'Enter folder name, e.g. my-project'
27
31
  const headerDescription = task.config.description && !/{{/.test(task.config.description)
28
32
  ? task.config.description
29
33
  : ''
@@ -157,8 +161,8 @@
157
161
  </label>
158
162
 
159
163
  <label class="task-field">
160
- <span class="task-label">Folder<% if (folderMeta) { %><span class="task-label-meta"><%= folderMeta %></span><% } %></span>
161
- <input class="task-input" type="text" name="folderName" value="<%= folderName || '' %>" placeholder="<%= suggestedFolderName || 'auto-generated' %>">
164
+ <span class="task-label">Folder<% if (folderRequired) { %><span class="task-label-required">*</span><% } %><% if (folderMeta) { %><span class="task-label-meta"><%= folderMeta %></span><% } %></span>
165
+ <input class="task-input" type="text" name="folderName" value="<%= folderName || '' %>" placeholder="<%= folderPlaceholder %>" <%= folderRequired ? 'required' : '' %>>
162
166
  </label>
163
167
  </div>
164
168
  </section>