pinokiod 7.3.15 → 7.4.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 (52) hide show
  1. package/kernel/api/index.js +111 -15
  2. package/kernel/api/script/index.js +10 -0
  3. package/kernel/autolaunch.js +111 -0
  4. package/kernel/bin/ffmpeg.js +9 -791
  5. package/kernel/environment.js +89 -1
  6. package/kernel/git.js +9 -19
  7. package/kernel/index.js +142 -43
  8. package/kernel/launch_requirements.js +1115 -0
  9. package/kernel/procs.js +1 -1
  10. package/kernel/ready.js +231 -0
  11. package/kernel/script.js +16 -0
  12. package/kernel/shells.js +9 -1
  13. package/kernel/workspace_status.js +111 -45
  14. package/package.json +2 -3
  15. package/server/autolaunch.js +725 -0
  16. package/server/index.js +244 -411
  17. package/server/views/app.ejs +267 -160
  18. package/server/views/autolaunch.ejs +363 -75
  19. package/server/views/index.ejs +550 -26
  20. package/server/views/partials/app_autolaunch_dependency_events.ejs +99 -0
  21. package/server/views/partials/app_autolaunch_dependency_save.ejs +10 -0
  22. package/server/views/partials/app_autolaunch_dependency_styles.ejs +357 -0
  23. package/server/views/partials/app_autolaunch_modal_helpers.ejs +347 -0
  24. package/server/views/partials/autolaunch_dependency_helpers.ejs +204 -0
  25. package/server/views/partials/autolaunch_dependency_save.ejs +13 -0
  26. package/server/views/partials/autolaunch_dependency_styles.ejs +347 -0
  27. package/server/views/partials/home_action_modal.ejs +4 -1
  28. package/server/views/partials/launch_requirements_status_client.ejs +271 -0
  29. package/server/views/partials/launch_requirements_status_styles.ejs +171 -0
  30. package/server/views/partials/launch_settings_dependency_save_factory.ejs +45 -0
  31. package/server/views/partials/launch_settings_dependency_script_loader_factory.ejs +25 -0
  32. package/server/views/terminal.ejs +196 -2
  33. package/test/home-autolaunch-live-ui.test.js +455 -0
  34. package/test/launch-requirements-browser.test.js +579 -0
  35. package/test/launch-requirements-contract-coverage.test.js +627 -0
  36. package/test/launch-requirements-real-browser.js +625 -0
  37. package/test/launch-requirements-status-client.test.js +132 -0
  38. package/test/launch-requirements.test.js +1806 -0
  39. package/test/launch-settings-ui.test.js +370 -0
  40. package/test/procs.test.js +49 -0
  41. package/test/ready-state.test.js +49 -0
  42. package/test/server-autolaunch.test.js +1052 -0
  43. package/test/startup-git-index-benchmark.js +409 -0
  44. package/test/startup-git-index-browser.js +320 -0
  45. package/test/startup-git-index-performance.test.js +380 -0
  46. package/test/startup-git-index-refactor.test.js +450 -0
  47. package/test/startup-git-index-route.test.js +588 -0
  48. package/test/universal-launcher.smoke.spec.js +10 -9
  49. package/test/workspace-gitignore-benchmark.js +815 -0
  50. package/test/workspace-gitignore-path-scoped.test.js +256 -0
  51. package/script/verify-ffmpeg.js +0 -459
  52. package/spec/INSTRUCTION_SYNC.md +0 -432
@@ -424,6 +424,9 @@ class Api {
424
424
  }
425
425
  this.running[id] = true
426
426
  this.done[id] = done
427
+ if (this.kernel && typeof this.kernel.markAppLaunchStarted === "function") {
428
+ this.kernel.markAppLaunchStarted(request.path)
429
+ }
427
430
  }
428
431
  isActionCandidate(action) {
429
432
  return (Array.isArray(action) && action.length > 0) || typeof action === "function"
@@ -509,6 +512,10 @@ class Api {
509
512
  let fullpath = path.resolve(cwd, ...args)
510
513
  return this.running[fullpath]
511
514
  },
515
+ ready: (...args) => {
516
+ let fullpath = path.resolve(cwd, ...args)
517
+ return this.kernel.isScriptReady(fullpath)
518
+ },
512
519
  name,
513
520
  self: script,
514
521
  port,
@@ -554,7 +561,7 @@ class Api {
554
561
  }
555
562
  return steps
556
563
  }
557
- async stop(req, ondata) {
564
+ async stop(req, ondata, options = {}) {
558
565
  // 1. set the "stop" flag for the uri, so the next execution in the queue for the uri will NOT queue another task
559
566
  // 2. stream a message closing the socket
560
567
 
@@ -586,10 +593,11 @@ class Api {
586
593
 
587
594
 
588
595
  // stop all shell processes connected to the uri
589
- if (req.params.id) {
590
- this.kernel.shell.kill({ group: req.params.id })
591
- } else {
592
- this.kernel.shell.kill({ group: requestPath })
596
+ const stopGroups = new Set()
597
+ if (req.params.id) stopGroups.add(req.params.id)
598
+ stopGroups.add(requestPath)
599
+ for (const group of stopGroups) {
600
+ this.kernel.shell.kill({ group })
593
601
  }
594
602
 
595
603
  // if any process is in a "wait" state, resume it
@@ -608,12 +616,17 @@ class Api {
608
616
  this.waiter[requestPath].reject()
609
617
  delete this.waiter[requestPath]
610
618
  }
611
- if (req.params.id) {
612
- delete this.running[req.params.id]
613
- delete this.kernel.memory.local[req.params.id]
614
- } else {
615
- delete this.running[requestPath]
616
- delete this.kernel.memory.local[requestPath]
619
+ const stoppedKeys = new Set()
620
+ if (req.params.id) stoppedKeys.add(req.params.id)
621
+ stoppedKeys.add(requestPath)
622
+ for (const key of stoppedKeys) {
623
+ delete this.running[key]
624
+ delete this.kernel.memory.local[key]
625
+ }
626
+ if (this.kernel && typeof this.kernel.markAppLaunchStopped === "function") {
627
+ this.kernel.markAppLaunchStopped(requestPath, {
628
+ internal_completion: !!(options && options.internal_completion)
629
+ })
617
630
  }
618
631
  this.ondata({
619
632
  id: req.params.id || requestPath,
@@ -1083,6 +1096,10 @@ class Api {
1083
1096
  let fullpath = path.resolve(cwd, ...args)
1084
1097
  return this.running[fullpath]
1085
1098
  },
1099
+ ready: (...args) => {
1100
+ let fullpath = path.resolve(cwd, ...args)
1101
+ return this.kernel.isScriptReady(fullpath)
1102
+ },
1086
1103
  name,
1087
1104
  self: script,
1088
1105
  port,
@@ -1235,6 +1252,9 @@ class Api {
1235
1252
 
1236
1253
  this.kernel.memory.rpc[id].current = rpc.current
1237
1254
  this.kernel.memory.rpc[id].total = rpc.total
1255
+ if (this.kernel && typeof this.kernel.markAppLaunchProgress === "function") {
1256
+ this.kernel.markAppLaunchProgress(request.path, rpc.current, rpc.total)
1257
+ }
1238
1258
 
1239
1259
  // this.kernel.memory.rpc[request.path] = rpc
1240
1260
  // this.kernel.memory.args[request.path] = args
@@ -1314,13 +1334,13 @@ class Api {
1314
1334
  params: {
1315
1335
  id: request.id
1316
1336
  }
1317
- })
1337
+ }, null, { internal_completion: true })
1318
1338
  } else {
1319
1339
  await this.stop({
1320
1340
  params: {
1321
1341
  uri: request.path
1322
1342
  }
1323
- })
1343
+ }, null, { internal_completion: true })
1324
1344
  }
1325
1345
  }
1326
1346
  return { request, input: null, step: rpc.next, total: totalSteps, args }
@@ -1545,13 +1565,13 @@ class Api {
1545
1565
  params: {
1546
1566
  id: request.id
1547
1567
  }
1548
- })
1568
+ }, null, { internal_completion: true })
1549
1569
  } else {
1550
1570
  await this.stop({
1551
1571
  params: {
1552
1572
  uri: request.path
1553
1573
  }
1554
- })
1574
+ }, null, { internal_completion: true })
1555
1575
  }
1556
1576
  return { request, input: result, step: rpc.next, total: totalSteps, args }
1557
1577
  }
@@ -1631,6 +1651,9 @@ class Api {
1631
1651
  this.queue(response.request, response.rawrpc, response.input, response.step, response.total, cwd, args)
1632
1652
  } else {
1633
1653
  let id = response.request.id || response.request.path
1654
+ if (this.kernel && typeof this.kernel.markAppLaunchReady === "function") {
1655
+ this.kernel.markAppLaunchReady(response.request.path)
1656
+ }
1634
1657
  if (response.request.caller) {
1635
1658
  if (this.done[response.request.path]) {
1636
1659
  this.done[response.request.path]({
@@ -1655,6 +1678,9 @@ class Api {
1655
1678
  // this.kernel.refresh(true)
1656
1679
  } catch (e) {
1657
1680
  this.clearResolvedAction(request)
1681
+ if (this.kernel && typeof this.kernel.markAppLaunchFailed === "function") {
1682
+ this.kernel.markAppLaunchFailed(request.path, e)
1683
+ }
1658
1684
  ondata({ raw: e.toString() })
1659
1685
  }
1660
1686
  }, concurrency)
@@ -1838,8 +1864,72 @@ class Api {
1838
1864
 
1839
1865
  // 3. Check if the resolved endpoint has the requested action attribute and resolve it to steps.
1840
1866
  if (this.isActionCandidate(action)) {
1867
+ const emitLaunchRequirementsControl = (result) => {
1868
+ if (!result || !result.action || result.action === "continue") {
1869
+ return
1870
+ }
1871
+ this.ondata({
1872
+ id: request.id || request.path,
1873
+ type: "launch.requirements.control",
1874
+ data: result
1875
+ })
1876
+ }
1877
+ let launchOperation = null
1878
+ const releaseLaunchOperation = () => {
1879
+ if (launchOperation && this.kernel && typeof this.kernel.endLaunchOperation === "function") {
1880
+ this.kernel.endLaunchOperation(launchOperation)
1881
+ }
1882
+ launchOperation = null
1883
+ }
1884
+ const shouldCheckLaunchRequirements = !request.skip_requirements &&
1885
+ this.kernel &&
1886
+ typeof this.kernel.ensureLaunchRequirements === "function" &&
1887
+ (typeof this.kernel.hasLaunchRequirementConfig === "function"
1888
+ ? await this.kernel.hasLaunchRequirementConfig(request.path)
1889
+ : true)
1890
+ if (shouldCheckLaunchRequirements && request.path && this.kernel && typeof this.kernel.beginLaunchOperation === "function") {
1891
+ launchOperation = this.kernel.beginLaunchOperation(request.path, { request })
1892
+ }
1893
+ if (shouldCheckLaunchRequirements) {
1894
+ let requirementResult
1895
+ try {
1896
+ requirementResult = await this.kernel.ensureLaunchRequirements(request.path, {
1897
+ request,
1898
+ owner: launchOperation
1899
+ })
1900
+ } catch (e) {
1901
+ releaseLaunchOperation()
1902
+ if (e && (e.cancelled || e.blocked_reason)) {
1903
+ const control = {
1904
+ action: e.cancelled ? "cancelled" : "blocked",
1905
+ app_id: e.app_id || "",
1906
+ reason: e.blocked_reason || ""
1907
+ }
1908
+ emitLaunchRequirementsControl(control)
1909
+ return {
1910
+ request,
1911
+ launch_requirements: control
1912
+ }
1913
+ }
1914
+ this.ondata({
1915
+ id: request.id || request.path,
1916
+ type: "error",
1917
+ data: e && e.stack ? e.stack : String(e || "Launch requirements failed"),
1918
+ })
1919
+ return
1920
+ }
1921
+ if (requirementResult && requirementResult.action && requirementResult.action !== "continue") {
1922
+ releaseLaunchOperation()
1923
+ emitLaunchRequirementsControl(requirementResult)
1924
+ return {
1925
+ request,
1926
+ launch_requirements: requirementResult
1927
+ }
1928
+ }
1929
+ }
1841
1930
 
1842
1931
  this.setRunning(request, done)
1932
+ releaseLaunchOperation()
1843
1933
 
1844
1934
  // set DNS
1845
1935
 
@@ -1865,6 +1955,9 @@ class Api {
1865
1955
  } catch (e) {
1866
1956
  this.clearResolvedAction(request)
1867
1957
  delete this.running[this.requestId(request)]
1958
+ if (this.kernel && typeof this.kernel.markAppLaunchFailed === "function") {
1959
+ this.kernel.markAppLaunchFailed(request.path, e)
1960
+ }
1868
1961
  this.ondata({
1869
1962
  id: request.id || request.path,
1870
1963
  type: "error",
@@ -1876,6 +1969,9 @@ class Api {
1876
1969
  if (!Array.isArray(steps) || steps.length === 0) {
1877
1970
  this.clearResolvedAction(request)
1878
1971
  delete this.running[this.requestId(request)]
1972
+ if (this.kernel && typeof this.kernel.markAppLaunchFailed === "function") {
1973
+ this.kernel.markAppLaunchFailed(request.path, new Error(`missing or invalid attribute: ${actionKey}`))
1974
+ }
1879
1975
  this.ondata({
1880
1976
  id: request.id || request.path,
1881
1977
  type: "error",
@@ -160,6 +160,16 @@ class Script {
160
160
  ondata({ raw: `\r\nStopped ${uri}\r\n` })
161
161
  }
162
162
  }
163
+ async ready(req, ondata, kernel) {
164
+ const params = req && req.params
165
+ let uri = this.currentPath(req)
166
+ if (typeof params === "string") {
167
+ uri = params
168
+ } else if (params && typeof params === "object") {
169
+ uri = params.uri || params.path || params.script || uri
170
+ }
171
+ return kernel.isScriptReady(kernel.resolveReadyScriptPath(uri, req && req.cwd))
172
+ }
163
173
  async run(req, ondata, kernel) {
164
174
  /*
165
175
  {
@@ -0,0 +1,111 @@
1
+ const path = require('path')
2
+ const Environment = require('./environment')
3
+
4
+ class Autolaunch {
5
+ constructor(kernel) {
6
+ this.kernel = kernel
7
+ this.kernel.autolaunch_status = this.startupStatus()
8
+ }
9
+ startupStatus() {
10
+ return this.kernel.launchRequirements && typeof this.kernel.launchRequirements.startupHomeStatus === "function"
11
+ ? this.kernel.launchRequirements.startupHomeStatus()
12
+ : (this.kernel.autolaunch_status || { running: false, apps: {} })
13
+ }
14
+ setStatus(status) {
15
+ const nextStatus = this.kernel.launchRequirements && typeof this.kernel.launchRequirements.replaceStartupHomeStatus === "function"
16
+ ? this.kernel.launchRequirements.replaceStartupHomeStatus(status)
17
+ : status
18
+ this.kernel.autolaunch_status = nextStatus
19
+ return nextStatus
20
+ }
21
+ async collectCandidates() {
22
+ const apis = this.kernel.i && Array.isArray(this.kernel.i.api) ? this.kernel.i.api : []
23
+ const candidates = []
24
+ for (const api of apis) {
25
+ if (!api || !api.path) {
26
+ continue
27
+ }
28
+ const envPath = path.resolve(this.kernel.api.userdir, api.path)
29
+ const env = await Environment.get(envPath, this.kernel)
30
+ const script = Environment.getScriptAutolaunch(env)
31
+ if (!script || !Environment.getScriptAutolaunchEnabled(env)) {
32
+ continue
33
+ }
34
+ const autolaunchPath = path.resolve(this.kernel.api.userdir, api.path, script)
35
+ const exists = !!(autolaunchPath && await this.kernel.exists(autolaunchPath))
36
+ const dependencies = Environment.getScriptRequirements(env)
37
+ candidates.push({
38
+ id: api.path,
39
+ title: api.title || api.path,
40
+ script,
41
+ autolaunchPath,
42
+ dependencies,
43
+ exists
44
+ })
45
+ }
46
+ return candidates
47
+ }
48
+ async runScheduler() {
49
+ const startedAt = Date.now()
50
+ const candidates = await this.collectCandidates()
51
+ const status = this.kernel.launchRequirements && typeof this.kernel.launchRequirements.seedStartupHomeStatus === "function"
52
+ ? await this.kernel.launchRequirements.seedStartupHomeStatus(candidates, startedAt)
53
+ : this.setStatus({
54
+ running: true,
55
+ started_at: startedAt,
56
+ apps: {}
57
+ })
58
+ this.kernel.autolaunch_status = status
59
+ for (const candidate of candidates) {
60
+ if (!status.apps[candidate.id]) {
61
+ status.apps[candidate.id] = {
62
+ id: candidate.id,
63
+ title: candidate.title,
64
+ script: candidate.script,
65
+ launch_path: candidate.autolaunchPath,
66
+ state: "pending",
67
+ dependencies: candidate.dependencies,
68
+ waiting_for: candidate.dependencies,
69
+ startup_root: true
70
+ }
71
+ }
72
+ if (!candidate.exists) {
73
+ status.apps[candidate.id].state = "blocked"
74
+ status.apps[candidate.id].blocked_reason = candidate.script ? "Launch script does not exist" : "No launch script selected"
75
+ status.apps[candidate.id].waiting_for = []
76
+ }
77
+ status.apps[candidate.id].startup_root = true
78
+ }
79
+ const launchable = candidates.filter((candidate) => {
80
+ const row = status.apps[candidate.id]
81
+ if (!row || !candidate.exists) {
82
+ if (!candidate.exists) {
83
+ console.log("SCRIPT DOES NOT EXIST. Ignoring.", candidate.autolaunchPath)
84
+ }
85
+ return false
86
+ }
87
+ return row.state !== "blocked"
88
+ })
89
+ await Promise.all(launchable.map((candidate) => {
90
+ return this.kernel.api.process({
91
+ uri: candidate.autolaunchPath,
92
+ input: {},
93
+ startup: true
94
+ }).catch((err) => {
95
+ console.warn('[Kernel.init] startup process failed:', err && err.message ? err.message : err)
96
+ const row = status.apps[candidate.id]
97
+ if (row && row.state !== "ready") {
98
+ delete status.apps[candidate.id]
99
+ }
100
+ })
101
+ }))
102
+ status.running = false
103
+ status.completed_at = Date.now()
104
+ setTimeout(() => {
105
+ this.kernel.launch_complete = true
106
+ console.log("SETTING launch complete", this.kernel.launch_complete)
107
+ }, 2000)
108
+ }
109
+ }
110
+
111
+ module.exports = Autolaunch