pinokiod 7.2.17 → 7.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 (78) hide show
  1. package/Dockerfile +2 -0
  2. package/kernel/api/index.js +1 -42
  3. package/kernel/api/process/index.js +44 -99
  4. package/kernel/bin/conda-python.js +30 -0
  5. package/kernel/bin/conda.js +22 -3
  6. package/kernel/bin/index.js +11 -1
  7. package/kernel/environment.js +2 -182
  8. package/kernel/git.js +13 -0
  9. package/kernel/index.js +1 -64
  10. package/kernel/plugin.js +58 -6
  11. package/kernel/shell.js +2 -21
  12. package/kernel/util.js +0 -60
  13. package/package.json +1 -1
  14. package/server/index.js +149 -176
  15. package/server/lib/content_validation.js +25 -28
  16. package/server/public/common.js +29 -103
  17. package/server/public/create-launcher.js +31 -4
  18. package/server/public/electron.css +6 -0
  19. package/server/public/style.css +0 -337
  20. package/server/public/task-launcher.js +32 -5
  21. package/server/public/universal-launcher.js +26 -3
  22. package/server/socket.js +11 -22
  23. package/server/views/app.ejs +30 -167
  24. package/server/views/d.ejs +33 -0
  25. package/server/views/editor.ejs +4 -25
  26. package/server/views/partials/main_sidebar.ejs +0 -1
  27. package/server/views/shell.ejs +3 -11
  28. package/server/views/terminal.ejs +3 -23
  29. package/server/views/terminals.ejs +0 -1
  30. package/spec/INSTRUCTION_SYNC.md +5 -5
  31. package/kernel/api/shell_run_template.js +0 -273
  32. package/kernel/api/uri/index.js +0 -51
  33. package/kernel/plugin_sources.js +0 -236
  34. package/kernel/watch/context.js +0 -42
  35. package/kernel/watch/drivers/fs.js +0 -71
  36. package/kernel/watch/drivers/poll.js +0 -33
  37. package/kernel/watch/index.js +0 -158
  38. package/server/features/drafts/index.js +0 -41
  39. package/server/features/drafts/parser.js +0 -169
  40. package/server/features/drafts/public/drafts.js +0 -1504
  41. package/server/features/drafts/registry_import.js +0 -412
  42. package/server/features/drafts/routes.js +0 -68
  43. package/server/features/drafts/service.js +0 -261
  44. package/server/features/drafts/watcher.js +0 -76
  45. package/server/features/index.js +0 -13
  46. package/server/lib/workspace_catalog.js +0 -151
  47. package/server/lib/workspace_runtime.js +0 -390
  48. package/server/routes/workspaces.js +0 -44
  49. package/server/views/partials/workspace_row.ejs +0 -61
  50. package/server/views/workspaces.ejs +0 -812
  51. package/system/plugin/antigravity/antigravity.png +0 -0
  52. package/system/plugin/antigravity/pinokio.js +0 -37
  53. package/system/plugin/claude/claude.png +0 -0
  54. package/system/plugin/claude/pinokio.js +0 -63
  55. package/system/plugin/claude-auto/claude.png +0 -0
  56. package/system/plugin/claude-auto/pinokio.js +0 -74
  57. package/system/plugin/claude-desktop/icon.jpeg +0 -0
  58. package/system/plugin/claude-desktop/pinokio.js +0 -39
  59. package/system/plugin/codex/openai.webp +0 -0
  60. package/system/plugin/codex/pinokio.js +0 -58
  61. package/system/plugin/codex-auto/openai.webp +0 -0
  62. package/system/plugin/codex-auto/pinokio.js +0 -65
  63. package/system/plugin/codex-desktop/icon.png +0 -0
  64. package/system/plugin/codex-desktop/pinokio.js +0 -39
  65. package/system/plugin/crush/crush.png +0 -0
  66. package/system/plugin/crush/pinokio.js +0 -31
  67. package/system/plugin/cursor/cursor.jpeg +0 -0
  68. package/system/plugin/cursor/pinokio.js +0 -39
  69. package/system/plugin/gemini/gemini.jpeg +0 -0
  70. package/system/plugin/gemini/pinokio.js +0 -40
  71. package/system/plugin/gemini-auto/gemini.jpeg +0 -0
  72. package/system/plugin/gemini-auto/pinokio.js +0 -43
  73. package/system/plugin/qwen/pinokio.js +0 -50
  74. package/system/plugin/qwen/qwen.png +0 -0
  75. package/system/plugin/vscode/pinokio.js +0 -36
  76. package/system/plugin/vscode/vscode.png +0 -0
  77. package/system/plugin/windsurf/pinokio.js +0 -39
  78. package/system/plugin/windsurf/windsurf.png +0 -0
package/server/index.js CHANGED
@@ -28,8 +28,6 @@ const system = require('systeminformation')
28
28
  const serveIndex = require('./serveIndex')
29
29
  const registerFileRoutes = require('./routes/files')
30
30
  const registerAppRoutes = require('./routes/apps')
31
- const registerWorkspacesRoutes = require('./routes/workspaces')
32
- const { mountFeatures } = require('./features')
33
31
  const Git = require("../kernel/git")
34
32
  const TerminalApi = require('../kernel/api/terminal')
35
33
 
@@ -78,11 +76,8 @@ const { createLauncherInstructionBootstrap } = require("./lib/launcher_instructi
78
76
  const { createTerminalGitResetHandler } = require("./lib/terminal_git_reset")
79
77
  const { createDesktopEventRouter } = require("./lib/desktop_event_router")
80
78
  const { createInjectRouter, resolveInjectList } = require("./lib/inject_router")
81
- const PluginSources = require("../kernel/plugin_sources")
82
79
  const { createTaskPackageService } = require("./lib/task_packages")
83
80
  const { createTaskWorkspaceLinkService } = require("./lib/task_workspace_links")
84
- const { createWorkspaceRuntimeService } = require("./lib/workspace_runtime")
85
- const { createWorkspaceCatalogService } = require("./lib/workspace_catalog")
86
81
  const { createContentValidationService } = require("./lib/content_validation")
87
82
  const { buildSecureRouterDebugSnapshot, createSecureRouterDebugStore } = require("./lib/secure_router_debug")
88
83
  const AppRegistryService = require("./lib/app_registry")
@@ -496,12 +491,14 @@ class Server {
496
491
  assignProjectSlug(obj)
497
492
  running_dynamic.push(obj)
498
493
  }
499
- } else if (PluginSources.isRunPath(href)) {
500
- let filepath = PluginSources.resolveRunPath(this.kernel, href)
494
+ } else if (href.startsWith("/run")) {
495
+ let uri_path = new URL("http://localhost" + href).pathname
496
+ let _filepath = uri_path.split("/").filter(x=>x).slice(1)
497
+ let filepath = this.kernel.path(..._filepath)
501
498
  let id = `${filepath}?cwd=${cwd}`
502
499
  obj.script_id = id
503
500
  //if (this.kernel.api.running[filepath]) {
504
- if (PluginSources.pluginSelectionMatches(obj.src, selected_query && selected_query.plugin)) {
501
+ if (obj.src.startsWith("/run" + selected_query.plugin)) {
505
502
  obj.running = true
506
503
  obj.display = "indent"
507
504
  obj.default = true
@@ -2396,10 +2393,8 @@ class Server {
2396
2393
  filepath = full_filepath
2397
2394
  }
2398
2395
 
2399
- if ((req.action || PluginSources.isRunPath(req.originalUrl)) && this.contentValidation) {
2400
- const validation = await this.contentValidation.validateRunPath(pathComponents, {
2401
- system: req.pinokioSystem === true,
2402
- })
2396
+ if ((req.action || req.originalUrl.startsWith("/run/")) && this.contentValidation) {
2397
+ const validation = await this.contentValidation.validateRunPath(pathComponents)
2403
2398
  if (validation && !validation.valid) {
2404
2399
  await this.renderInvalidContentPage(req, res, validation, {
2405
2400
  sidebarSelected: validation.type === "plugin" ? "plugins" : validation.type === "task" ? "tasks" : "home",
@@ -2870,27 +2865,11 @@ class Server {
2870
2865
  const protectionPreference = protectionAppId && this.appPreferences && typeof this.appPreferences.getPreference === "function"
2871
2866
  ? await this.appPreferences.getPreference(protectionAppId)
2872
2867
  : null
2873
- const draftWatchEnabled = this.kernel.watch && typeof this.kernel.watch.hasHandler === "function"
2874
- ? this.kernel.watch.hasHandler(resolved, "draft")
2875
- : false
2876
- const draftWatchCwd = draftWatchEnabled
2877
- ? (req.query.cwd || path.dirname(filepath))
2878
- : ""
2879
- const activeProcessWait = this.kernel.activeProcessWaits && this.kernel.activeProcessWaits[filepath]
2880
- ? this.kernel.activeProcessWaits[filepath]
2881
- : null
2882
2868
  const result = {
2883
2869
  portal: this.portal,
2884
2870
  projectName: (pathComponents.length > 0 ? pathComponents[0] : ''),
2885
2871
  protection_app_id: protectionAppId,
2886
2872
  protection_enabled: protectionPreference ? protectionPreference.protection_enabled !== false : false,
2887
- draft_watch_enabled: draftWatchEnabled,
2888
- draft_watch_cwd: draftWatchCwd,
2889
- active_process_wait: activeProcessWait ? {
2890
- title: activeProcessWait.title,
2891
- description: activeProcessWait.description,
2892
- message: activeProcessWait.message
2893
- } : null,
2894
2873
  kill_message,
2895
2874
  callback,
2896
2875
  callback_target,
@@ -2905,7 +2884,6 @@ class Server {
2905
2884
  //run: true, // run mode by default
2906
2885
  run: (req.query && req.query.mode === "source" ? false : true),
2907
2886
  stop: (req.query && req.query.stop ? true : false),
2908
- readonly: req.pinokioSystem === true,
2909
2887
  pinokioPath,
2910
2888
  action: actionKey,
2911
2889
  runnable,
@@ -3122,7 +3100,6 @@ class Server {
3122
3100
  if (pathComponents.length === 0) {
3123
3101
  const normalizedApiRoot = path.normalize(this.kernel.path("api"))
3124
3102
  const normalizedPluginRoot = path.normalize(this.kernel.path("plugin"))
3125
- const normalizedSystemPluginRoot = path.normalize(PluginSources.systemPluginRoot(this.kernel))
3126
3103
  const isPathWithinRoot = (candidatePath, rootPath) => {
3127
3104
  if (typeof candidatePath !== "string" || typeof rootPath !== "string") {
3128
3105
  return false
@@ -3148,9 +3125,6 @@ class Server {
3148
3125
  if (isPathWithinRoot(normalizedCandidate, normalizedPluginRoot)) {
3149
3126
  return true
3150
3127
  }
3151
- if (isPathWithinRoot(normalizedCandidate, normalizedSystemPluginRoot)) {
3152
- return true
3153
- }
3154
3128
  const relativeToApiRoot = path.relative(normalizedApiRoot, normalizedCandidate)
3155
3129
  if (!relativeToApiRoot || relativeToApiRoot.startsWith("..") || path.isAbsolute(relativeToApiRoot)) {
3156
3130
  return false
@@ -3964,7 +3938,8 @@ class Server {
3964
3938
  if (menuitem.href.startsWith("http")) {
3965
3939
  menuitem.src = menuitem.href
3966
3940
  } else if (menuitem.href.startsWith("/")) {
3967
- if (PluginSources.isRunPath(menuitem.href)) {
3941
+ let run_path = "/run"
3942
+ if (menuitem.href.startsWith(run_path)) {
3968
3943
  menuitem.src = menuitem.href
3969
3944
  // u = new URL("http://localhost" + menuitem.href.slice(run_path.length))
3970
3945
  // cwd = u.searchParams.get("cwd")
@@ -3984,14 +3959,7 @@ class Server {
3984
3959
  }
3985
3960
 
3986
3961
  // check running
3987
- let srcPathname = menuitem.src
3988
- try {
3989
- srcPathname = new URL("http://localhost" + menuitem.src).pathname
3990
- } catch (_) {
3991
- }
3992
- let fullpath = PluginSources.isRunPath(srcPathname)
3993
- ? PluginSources.resolveRunPath(this.kernel, srcPathname)
3994
- : this.kernel.path(srcPathname.slice(1))
3962
+ let fullpath = this.kernel.path(menuitem.src.slice(1))
3995
3963
  let relpath = path.relative(this.kernel.homedir, fullpath)
3996
3964
  if (relpath.startsWith("api")) {
3997
3965
  // api script
@@ -5705,6 +5673,7 @@ class Server {
5705
5673
  "prototype/PTERM.md",
5706
5674
  ]
5707
5675
  const managedRefreshTargets = [
5676
+ "plugin/code",
5708
5677
  "prototype/system",
5709
5678
  "network/system",
5710
5679
  "prototype/PINOKIO.md",
@@ -5726,16 +5695,6 @@ class Server {
5726
5695
 
5727
5696
  needsManagedRefresh = true
5728
5697
  console.log("[TRY] Updating to the new version")
5729
- let envPath = path.resolve(home, "ENVIRONMENT")
5730
- let envExists = await this.kernel.exists(envPath)
5731
- if (!envExists) {
5732
- let str = await Environment.ENV("system", home, this.kernel)
5733
- await fs.promises.writeFile(envPath, str)
5734
- }
5735
- await Environment.ensurePinokioCacheDirs(this.kernel, {
5736
- throwOnFailure: true,
5737
- elevatedRepair: this.kernel.elevatedCacheRepair.bind(this.kernel)
5738
- })
5739
5698
  this.kernel.store.set("version", this.version.pinokiod)
5740
5699
  console.log("[DONE] Updating to the new version")
5741
5700
  console.log("not up to date. update py.")
@@ -5748,6 +5707,9 @@ class Server {
5748
5707
  let p2 = path.resolve(home, "prototype/system")
5749
5708
  await fse.remove(p2)
5750
5709
 
5710
+ let p3 = path.resolve(home, "plugin/code")
5711
+ await fse.remove(p3)
5712
+
5751
5713
  let p4 = path.resolve(home, "network/system")
5752
5714
  await fse.remove(p4)
5753
5715
 
@@ -5816,6 +5778,10 @@ class Server {
5816
5778
  await this.kernel.proto.init()
5817
5779
  }
5818
5780
  if (needsManagedRefresh) {
5781
+ const pluginReady = await this.kernel.exists("plugin/code")
5782
+ if (!pluginReady && this.kernel.plugin && typeof this.kernel.plugin.init === "function") {
5783
+ await this.kernel.plugin.init()
5784
+ }
5819
5785
  const networkReady = await this.kernel.exists("network/system")
5820
5786
  if (!networkReady && this.kernel.router && typeof this.kernel.router.init === "function") {
5821
5787
  await this.kernel.router.init()
@@ -5996,10 +5962,6 @@ class Server {
5996
5962
  })
5997
5963
  this.app.use(express.static(path.resolve(__dirname, 'public')));
5998
5964
  this.app.use("/web", express.static(path.resolve(__dirname, "..", "..", "web")))
5999
- this.app.use(PluginSources.SYSTEM_ASSET_PREFIX, express.static(PluginSources.systemRoot(this.kernel), {
6000
- index: false,
6001
- fallthrough: true,
6002
- }))
6003
5965
  this.app.set('view engine', 'ejs');
6004
5966
  this.app.use((req, res, next) => {
6005
5967
  const peerForwarded = (req.get('X-Pinokio-Peer') || '').trim().toLowerCase()
@@ -6782,7 +6744,24 @@ class Server {
6782
6744
  }
6783
6745
  }
6784
6746
  const normalizePluginPath = (value) => {
6785
- return PluginSources.normalizePluginPath(value)
6747
+ let normalized = typeof value === "string" ? value.trim() : ""
6748
+ if (!normalized) {
6749
+ return ""
6750
+ }
6751
+ normalized = normalized.replace(/\\/g, "/")
6752
+ if (/^https?:\/\//i.test(normalized)) {
6753
+ try {
6754
+ const parsed = new URL(normalized)
6755
+ normalized = parsed.pathname || ""
6756
+ } catch (_) {
6757
+ }
6758
+ }
6759
+ normalized = normalized.replace(/^\/run(?=\/)/, "")
6760
+ if (!normalized.startsWith("/")) {
6761
+ normalized = `/${normalized}`
6762
+ }
6763
+ normalized = normalized.replace(/\/{2,}/g, "/").replace(/\/+$/, "")
6764
+ return normalized
6786
6765
  }
6787
6766
  const normalizePluginLookupKey = (value) => {
6788
6767
  const normalized = normalizePluginPath(value)
@@ -6929,7 +6908,7 @@ class Server {
6929
6908
  index: -1,
6930
6909
  title: context.title || "Plugin",
6931
6910
  description: typeof config.description === "string" ? config.description : "",
6932
- href: PluginSources.pluginRunHrefForPath(normalizedPluginPath),
6911
+ href: `/run${normalizedPluginPath}`,
6933
6912
  link: typeof config.link === "string" ? config.link : "",
6934
6913
  image: context.image || null,
6935
6914
  icon: null,
@@ -6954,31 +6933,24 @@ class Server {
6954
6933
  }
6955
6934
  const resolvePluginLocalState = async (plugin) => {
6956
6935
  const pluginRoot = path.resolve(this.kernel.path("plugin"))
6936
+ const managedRoot = path.resolve(pluginRoot, "code")
6957
6937
  const normalizedPath = normalizePluginPath(plugin && plugin.pluginPath ? plugin.pluginPath : "")
6958
6938
  const emptyState = {
6959
6939
  ownership: "bundled",
6960
6940
  manageable: false,
6961
6941
  canOpenFolder: false,
6962
6942
  pluginRoot,
6943
+ managedRoot,
6963
6944
  pluginFilePath: "",
6964
6945
  pluginDir: "",
6965
6946
  relativeDir: "",
6966
6947
  relativeFile: "",
6967
6948
  localLabel: "",
6968
- }
6969
- if (PluginSources.isSystemPluginPath(normalizedPath)) {
6970
- return {
6971
- ...emptyState,
6972
- ownership: "system",
6973
- localLabel: normalizedPath.replace(/^\/pinokio\/run\//, ""),
6974
- }
6949
+ managedPrefix: "",
6975
6950
  }
6976
6951
  if (!normalizedPath.startsWith("/plugin/")) {
6977
6952
  return emptyState
6978
6953
  }
6979
- if (PluginSources.isLegacyPluginCodePath(normalizedPath)) {
6980
- return emptyState
6981
- }
6982
6954
  const pluginFilePath = path.resolve(this.kernel.path(normalizedPath.slice(1)))
6983
6955
  if (!isPathInsideRoot(pluginFilePath, pluginRoot)) {
6984
6956
  return emptyState
@@ -6998,16 +6970,22 @@ class Server {
6998
6970
  }
6999
6971
  const relativeFile = path.relative(pluginRoot, pluginFilePath).split(path.sep).join("/")
7000
6972
  const relativeDir = path.relative(pluginRoot, pluginDir).split(path.sep).join("/")
6973
+ const isManaged = isPathInsideRoot(pluginFilePath, managedRoot)
6974
+ const managedPrefix = isManaged
6975
+ ? path.relative(managedRoot, pluginDir).split(path.sep).join("/")
6976
+ : ""
7001
6977
  return {
7002
- ownership: "local",
7003
- manageable: Boolean(pluginFileExists && pluginDirExists),
6978
+ ownership: isManaged ? "managed" : "local",
6979
+ manageable: Boolean(pluginFileExists && pluginDirExists && !isManaged),
7004
6980
  canOpenFolder: Boolean(pluginFileExists && pluginDirExists),
7005
6981
  pluginRoot,
6982
+ managedRoot,
7006
6983
  pluginFilePath,
7007
6984
  pluginDir,
7008
6985
  relativeDir,
7009
6986
  relativeFile,
7010
6987
  localLabel: relativeDir ? `plugin/${relativeDir}` : "plugin",
6988
+ managedPrefix,
7011
6989
  }
7012
6990
  }
7013
6991
  const collectPluginApps = async (boundAppName = "") => {
@@ -7051,31 +7029,11 @@ class Server {
7051
7029
  })
7052
7030
  return apps
7053
7031
  }
7054
- const buildPluginShareState = async (plugin) => {
7055
- const localState = await resolvePluginLocalState(plugin)
7056
- if (localState.ownership === "system") {
7032
+ const buildPluginShareState = async (plugin) => {
7033
+ const localState = await resolvePluginLocalState(plugin)
7034
+ if (localState.ownership === "bundled") {
7057
7035
  return {
7058
- ownership: "system",
7059
- manageable: false,
7060
- canOpenFolder: false,
7061
- dir: "",
7062
- localLabel: localState.localLabel || "",
7063
- remoteUrl: "",
7064
- remoteWebUrl: "",
7065
- githubConnected: false,
7066
- gitInitialized: false,
7067
- hasCommit: false,
7068
- changeCount: 0,
7069
- changes: [],
7070
- branch: "HEAD",
7071
- commitUrl: "",
7072
- createUrl: "",
7073
- pushUrl: "",
7074
- }
7075
- }
7076
- if (localState.ownership === "bundled") {
7077
- return {
7078
- ownership: "bundled",
7036
+ ownership: "bundled",
7079
7037
  manageable: false,
7080
7038
  canOpenFolder: false,
7081
7039
  dir: "",
@@ -7095,21 +7053,49 @@ class Server {
7095
7053
  }
7096
7054
 
7097
7055
  if (localState.ownership === "managed") {
7056
+ let changes = []
7057
+ try {
7058
+ const headStatus = await this.getRepoHeadStatusByDir(localState.managedRoot)
7059
+ const allChanges = Array.isArray(headStatus && headStatus.changes) ? headStatus.changes : []
7060
+ const managedPrefix = typeof localState.managedPrefix === "string" ? localState.managedPrefix.trim() : ""
7061
+ changes = allChanges
7062
+ .filter((change) => {
7063
+ const file = change && typeof change.file === "string" ? change.file : ""
7064
+ if (!managedPrefix) {
7065
+ return true
7066
+ }
7067
+ return file === managedPrefix || file.startsWith(`${managedPrefix}/`)
7068
+ })
7069
+ .map((change) => {
7070
+ const file = change && typeof change.file === "string" ? change.file : ""
7071
+ if (!managedPrefix || !file) {
7072
+ return change
7073
+ }
7074
+ const relativeFile = file === managedPrefix
7075
+ ? path.posix.basename(managedPrefix)
7076
+ : file.slice(managedPrefix.length + 1)
7077
+ return {
7078
+ ...change,
7079
+ file: relativeFile || file
7080
+ }
7081
+ })
7082
+ } catch (_) {
7083
+ }
7098
7084
  return {
7099
- ownership: "bundled",
7085
+ ownership: "managed",
7100
7086
  manageable: false,
7101
- canOpenFolder: false,
7102
- dir: "",
7103
- localLabel: "",
7104
- relativeDir: "",
7105
- relativeFile: "",
7087
+ canOpenFolder: Boolean(localState.canOpenFolder),
7088
+ dir: localState.pluginDir,
7089
+ localLabel: localState.localLabel,
7090
+ relativeDir: localState.relativeDir,
7091
+ relativeFile: localState.relativeFile,
7106
7092
  remoteUrl: "",
7107
7093
  remoteWebUrl: "",
7108
7094
  githubConnected: false,
7109
7095
  gitInitialized: false,
7110
7096
  hasCommit: false,
7111
- changeCount: 0,
7112
- changes: [],
7097
+ changeCount: changes.length,
7098
+ changes,
7113
7099
  branch: "HEAD",
7114
7100
  commitUrl: "",
7115
7101
  createUrl: "",
@@ -7185,19 +7171,14 @@ class Server {
7185
7171
  : ""
7186
7172
  const remoteLabel = summarizeTaskRemoteLabel(remoteCandidate)
7187
7173
  const badges = []
7188
- if (ownership === "local") {
7189
- badges.push({
7190
- label: "Local plugin",
7191
- tone: "accent"
7192
- })
7193
- } else if (ownership === "system") {
7174
+ if (ownership === "local") {
7194
7175
  badges.push({
7195
- label: "Built-in plugin",
7196
- tone: "neutral"
7176
+ label: "Local plugin",
7177
+ tone: "accent"
7197
7178
  })
7198
- } else if (ownership === "managed") {
7199
- badges.push({
7200
- label: "Managed by Pinokio",
7179
+ } else if (ownership === "managed") {
7180
+ badges.push({
7181
+ label: "Managed by Pinokio",
7201
7182
  tone: "neutral"
7202
7183
  })
7203
7184
  } else {
@@ -7242,12 +7223,13 @@ class Server {
7242
7223
  : (shareState.gitInitialized ? "No local changes" : "Not version tracked yet")
7243
7224
  githubPanelTitle = "GitHub"
7244
7225
  githubPanelCopy = ""
7245
- } else if (ownership === "system") {
7246
- sourceLabel = "System plugin"
7247
- sourceValue = shareState.localLabel || sourceValue
7248
- statusValue = "Read-only"
7249
- githubPanelTitle = "Built in to Pinokio"
7250
- githubPanelCopy = "This plugin ships with Pinokio and is not editable from the local plugin workspace."
7226
+ } else if (ownership === "managed") {
7227
+ sourceLabel = "Managed folder"
7228
+ sourceValue = shareState.localLabel
7229
+ statusValue = changes.length > 0 ? pluralizeTaskFiles(changes.length) : "Updated with Pinokio"
7230
+ githubPanelTitle = "Managed by Pinokio"
7231
+ githubPanelCopy = "This plugin lives inside <code>plugin/code</code>, which Pinokio refreshes as part of its managed source. Open the folder if you need to inspect it, but don&apos;t treat it as your own publishable repo."
7232
+ localChangesCopy = "These edits live inside Pinokio-managed source and may be overwritten by future Pinokio updates."
7251
7233
  }
7252
7234
  const changePreview = changes.slice(0, 6).map((change) => ({
7253
7235
  file: change && change.file ? change.file : "",
@@ -8112,7 +8094,24 @@ class Server {
8112
8094
  }
8113
8095
  return targetPath
8114
8096
  }
8115
- const resolveUniversalLauncherPluginHref = PluginSources.resolveLauncherPluginHref
8097
+ const resolveUniversalLauncherPluginHref = (toolValue) => {
8098
+ let normalizedTool = typeof toolValue === "string" ? toolValue.trim() : ""
8099
+ normalizedTool = normalizedTool.replace(/^https?:\/\/[^/]+/i, "")
8100
+ normalizedTool = normalizedTool.replace(/^\/+|\/+$/g, "")
8101
+ normalizedTool = normalizedTool.replace(/^run\//, "")
8102
+ if (!normalizedTool || normalizedTool.includes("..") || !/^[A-Za-z0-9._/-]+$/.test(normalizedTool)) {
8103
+ const error = new Error("Invalid plugin.")
8104
+ error.status = 400
8105
+ throw error
8106
+ }
8107
+ if (normalizedTool.startsWith("plugin/") || normalizedTool.startsWith("api/")) {
8108
+ const scriptPath = normalizedTool.endsWith(".js")
8109
+ ? normalizedTool
8110
+ : `${normalizedTool}/pinokio.js`
8111
+ return `/run/${scriptPath}`
8112
+ }
8113
+ return `/run/plugin/${normalizedTool}/pinokio.js`
8114
+ }
8116
8115
  const persistLauncherPromptContext = async (targetPath, options = {}) => {
8117
8116
  const prompt = typeof options.prompt === "string" ? options.prompt.trim() : ""
8118
8117
  if (!prompt) {
@@ -8404,32 +8403,6 @@ class Server {
8404
8403
  const taskWorkspaceLinks = createTaskWorkspaceLinkService({
8405
8404
  kernel: this.kernel
8406
8405
  })
8407
- const workspaceRuntime = createWorkspaceRuntimeService({
8408
- kernel: this.kernel
8409
- })
8410
- this.workspaceRuntime = workspaceRuntime
8411
- const features = await mountFeatures({
8412
- app: this.app,
8413
- kernel: this.kernel,
8414
- taskWorkspaceLinks,
8415
- defaultRegistryUrl: DEFAULT_REGISTRY_URL
8416
- })
8417
- this.features = features
8418
- const drafts = features.drafts.service
8419
- this.drafts = drafts
8420
- const workspaceCatalog = createWorkspaceCatalogService({
8421
- kernel: this.kernel,
8422
- workspaceRuntime,
8423
- drafts
8424
- })
8425
- registerWorkspacesRoutes(this.app, {
8426
- workspaceCatalog,
8427
- composePeerAccessPayload: () => this.composePeerAccessPayload(),
8428
- getTheme: () => this.theme,
8429
- getPeers: () => this.getPeers(),
8430
- getCurrentHost: () => this.kernel.peer.host,
8431
- getPortal: () => this.portal
8432
- })
8433
8406
  const TASK_INPUT_NAME_PATTERN = /^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/
8434
8407
  const suggestTaskFolderName = async (rootDir, preferredName) => {
8435
8408
  const normalizedRoot = path.resolve(rootDir)
@@ -10100,8 +10073,7 @@ class Server {
10100
10073
  }
10101
10074
  }
10102
10075
 
10103
- const filledInputValues = filterFilledTaskInputValues(inputValues)
10104
- const prompt = taskPackages.applyTemplateValues(task.template, filledInputValues).trim()
10076
+ const prompt = taskPackages.applyTemplateValues(task.template, filterFilledTaskInputValues(inputValues)).trim()
10105
10077
  if (!prompt) {
10106
10078
  await renderTaskLaunchPage(req, res, task, {
10107
10079
  selectedTool,
@@ -10222,9 +10194,6 @@ class Server {
10222
10194
  params.set("cwd", targetPath)
10223
10195
  params.set("chrome", "full")
10224
10196
  params.set("prompt", prompt)
10225
- if (filledInputValues.url) {
10226
- params.set("url", filledInputValues.url)
10227
- }
10228
10197
  res.redirect(`${pluginHref}?${params.toString()}`)
10229
10198
  })
10230
10199
  this.app.post("/task/start", handleTaskStartRequest)
@@ -10531,8 +10500,7 @@ class Server {
10531
10500
  return
10532
10501
  }
10533
10502
 
10534
- const filledInputValues = filterFilledTaskInputValues(inputValues)
10535
- const prompt = taskPackages.applyTemplateValues(task.template, filledInputValues).trim()
10503
+ const prompt = taskPackages.applyTemplateValues(task.template, filterFilledTaskInputValues(inputValues)).trim()
10536
10504
  if (!prompt) {
10537
10505
  res.status(400).json({
10538
10506
  ok: false,
@@ -10632,9 +10600,6 @@ class Server {
10632
10600
  params.set("chrome", "full")
10633
10601
  params.set("session", createUniversalLauncherSessionId())
10634
10602
  params.set("prompt", prompt)
10635
- if (filledInputValues.url) {
10636
- params.set("url", filledInputValues.url)
10637
- }
10638
10603
 
10639
10604
  res.json({
10640
10605
  ok: true,
@@ -11886,14 +11851,11 @@ class Server {
11886
11851
  // but allow it when the request originates from the local machine
11887
11852
  if (payload.audience === 'device' && typeof payload.device_id === 'string' && payload.device_id) {
11888
11853
  try {
11889
- const remoteAddress = req.socket && req.socket.remoteAddress ? req.socket.remoteAddress : req.ip
11890
- const isLocalRequest = this.socket && typeof this.socket.isLocalAddress === 'function'
11891
- ? this.socket.isLocalAddress(remoteAddress)
11892
- : false
11893
- const isLocalDevice = this.socket && typeof this.socket.isLocalDevice === 'function'
11894
- ? this.socket.isLocalDevice(payload.device_id)
11895
- : false
11896
- payload.host = !!(isLocalRequest || isLocalDevice)
11854
+ if (this.socket && typeof this.socket.isLocalDevice === 'function') {
11855
+ payload.host = !!this.socket.isLocalDevice(payload.device_id)
11856
+ } else {
11857
+ payload.host = false
11858
+ }
11897
11859
  } catch (_) {
11898
11860
  payload.host = false
11899
11861
  }
@@ -12794,6 +12756,23 @@ class Server {
12794
12756
  })
12795
12757
  }
12796
12758
  }))
12759
+ this.app.post("/plugin/update", ex(async (req, res) => {
12760
+ try {
12761
+ await this.kernel.exec({
12762
+ message: "git pull",
12763
+ path: this.kernel.path("plugin/code")
12764
+ }, (e) => {
12765
+ console.log(e)
12766
+ })
12767
+ res.json({
12768
+ success: true
12769
+ })
12770
+ } catch (e) {
12771
+ res.json({
12772
+ error: e.stack
12773
+ })
12774
+ }
12775
+ }))
12797
12776
  this.app.post("/network/reset", ex(async (req, res) => {
12798
12777
  let caddy_path = this.kernel.path("cache/XDG_DATA_HOME/caddy")
12799
12778
  await rimraf(caddy_path)
@@ -14225,17 +14204,6 @@ class Server {
14225
14204
  res.status(404).send(e.message)
14226
14205
  }
14227
14206
  }))
14228
- this.app.get(`${PluginSources.SYSTEM_RUN_PREFIX}/*`, ex(async (req, res) => {
14229
- const runPath = typeof req.params[0] === "string" ? req.params[0] : ""
14230
- let pathComponents = runPath.split("/")
14231
- req.base = PluginSources.systemRoot(this.kernel)
14232
- req.pinokioSystem = true
14233
- try {
14234
- await this.render(req, res, pathComponents)
14235
- } catch (e) {
14236
- res.status(404).send(e.message)
14237
- }
14238
- }))
14239
14207
  this.app.get("/run/*", ex(async (req, res) => {
14240
14208
  const runPath = typeof req.params[0] === "string" ? req.params[0] : ""
14241
14209
  let pathComponents = runPath.split("/")
@@ -15661,7 +15629,12 @@ class Server {
15661
15629
  }))
15662
15630
  this.app.get("/bin_ready", ex(async (req, res) => {
15663
15631
  if (this.kernel.bin && !this.kernel.bin.requirements_pending) {
15664
- res.json({ success: true })
15632
+ let code_exists = await this.kernel.exists("plugin/code")
15633
+ if (code_exists) {
15634
+ res.json({ success: true })
15635
+ } else {
15636
+ res.json({ success: false })
15637
+ }
15665
15638
  } else {
15666
15639
  res.json({ success: false })
15667
15640
  }