pinokiod 3.107.0 → 3.109.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.
@@ -23,6 +23,26 @@ class Caddy {
23
23
  }
24
24
  }
25
25
  async start() {
26
+ // if peer.https_active is true,
27
+ // 1. kill existing caddy
28
+ // 2. start caddy
29
+ if (!this.kernel.peer || !("https_active" in this.kernel.peer)) {
30
+ // wait until they are available
31
+ await new Promise((resolve, reject) => {
32
+ let interval = setInterval(() => {
33
+ console.log("wait until peer becomes available")
34
+ if (this.kernel.peer && "https_active" in this.kernel.peer) {
35
+ console.log("peer ready")
36
+ clearInterval(interval)
37
+ resolve()
38
+ }
39
+ }, 1000)
40
+ })
41
+ }
42
+ if (!this.kernel.peer.https_active) {
43
+ console.log("https_active false")
44
+ return
45
+ }
26
46
  // console.log("Existing caddy pid?", this.kernel.processes.caddy_pid)
27
47
  let running = await this.running()
28
48
  console.log("Caddy running?", running)
@@ -31,6 +51,7 @@ class Caddy {
31
51
  console.log("kill existing caddy before restarting")
32
52
  await new Promise((resolve, reject) => {
33
53
  let interval = setInterval(() => {
54
+ console.log("CADDY_PID", this.kernel.processes.caddy_pid)
34
55
  if (this.kernel.processes.caddy_pid) {
35
56
  try {
36
57
  console.log("kill caddy", this.kernel.processes.caddy_pid)
@@ -39,10 +60,12 @@ class Caddy {
39
60
  clearInterval(interval)
40
61
  resolve()
41
62
  } catch (error) {
63
+ console.log("ERROR", error)
42
64
  clearInterval(interval)
43
65
  reject(error)
44
66
  }
45
67
  } else {
68
+ //clearInterval(interval)
46
69
  console.log("try killing existing caddy again in 1 sec")
47
70
  }
48
71
  }, 1000)
@@ -76,6 +99,7 @@ class Caddy {
76
99
  this.kernel.peer.announce()
77
100
  console.log("announced to peers")
78
101
  // this.kernel.refresh(true)
102
+ } else {
79
103
  }
80
104
  }
81
105
  async install(req, ondata, kernel, id) {
package/kernel/bin/git.js CHANGED
@@ -49,6 +49,13 @@ class Git {
49
49
  }
50
50
 
51
51
  await fs.promises.mkdir(this.kernel.path("scripts/git"), { recursive: true }).catch((e) => { })
52
+
53
+ let gitfork_path = path.resolve(this.kernel.homedir, "scripts/git/fork.json")
54
+ await fs.promises.copyFile(
55
+ path.resolve(__dirname, "..", "scripts/git/fork"),
56
+ gitfork_path
57
+ )
58
+
52
59
  let gitpush_path = path.resolve(this.kernel.homedir, "scripts/git/push.json")
53
60
  await fs.promises.copyFile(
54
61
  path.resolve(__dirname, "..", "scripts/git/push"),
@@ -106,6 +113,11 @@ class Git {
106
113
  if (!exists4) {
107
114
  return false;
108
115
  }
116
+ let gitfork_path = path.resolve(this.kernel.homedir, "scripts/git/fork.json")
117
+ let exists5 = await this.kernel.api.exists(gitfork_path)
118
+ if (!exists5) {
119
+ return false;
120
+ }
109
121
 
110
122
  if (this.kernel.platform === "darwin") {
111
123
  let gh_config_exists = await this.kernel.exists("config/gh")
@@ -557,6 +557,82 @@ const init = async (options, kernel) => {
557
557
  }
558
558
  }
559
559
  }
560
+
561
+ const agentTemplatePath = kernel.path("prototype/system/AGENTS.md")
562
+ const agentTemplateExists = await kernel.exists(agentTemplatePath)
563
+ if (agentTemplateExists) {
564
+ const agentFiles = [
565
+ "AGENTS.md",
566
+ "CLAUDE.md",
567
+ "GEMINI.md",
568
+ "QWEN.md",
569
+ ".windsurfrules",
570
+ ".cursorrules",
571
+ ".clinerules"
572
+ ]
573
+ const structure_path = kernel.path("prototype/system/structure/clone")
574
+ const structure_content = await fs.promises.readFile(structure_path, "utf-8")
575
+ const rendered_recipe = await kernel.renderFile(agentTemplatePath, {
576
+ structure: structure_content,
577
+ examples: kernel.path("prototype/system/examples"),
578
+ browser_logs: kernel.path("logs/browser.log"),
579
+ PINOKIO_DOCUMENTATION: kernel.path("prototype/PINOKIO.md"),
580
+ PTERM_DOCUMENTATION: kernel.path("prototype/PTERM.md"),
581
+ app_root: root
582
+ })
583
+ for (const filename of agentFiles) {
584
+ const destination = path.resolve(root, filename)
585
+ const destinationExists = await kernel.exists(destination)
586
+ if (!destinationExists) {
587
+ await fs.promises.writeFile(destination, rendered_recipe)
588
+ }
589
+ }
590
+ }
591
+
592
+ const gitDir = path.resolve(root, ".git")
593
+ const gitDirExists = await kernel.exists(gitDir)
594
+ if (gitDirExists) {
595
+ const excludePath = path.resolve(gitDir, "info/exclude")
596
+ await fs.promises.mkdir(path.dirname(excludePath), { recursive: true })
597
+
598
+ let excludeContent = ""
599
+ try {
600
+ excludeContent = await fs.promises.readFile(excludePath, "utf8")
601
+ } catch (error) {
602
+ if (error.code !== "ENOENT") {
603
+ throw error
604
+ }
605
+ }
606
+
607
+ const existingEntries = new Set(
608
+ excludeContent
609
+ .split(/\r?\n/)
610
+ .map(line => line.trim())
611
+ .filter(line => line.length > 0)
612
+ )
613
+
614
+ const entriesToEnsure = [
615
+ "ENVIRONMENT",
616
+ ".*",
617
+ "~*",
618
+ "/logs/",
619
+ "/cache/",
620
+ "/AGENTS.md",
621
+ "/CLAUDE.md",
622
+ "/GEMINI.md",
623
+ "/QWEN.md"
624
+ ]
625
+
626
+ const missingEntries = entriesToEnsure.filter(entry => !existingEntries.has(entry))
627
+ if (missingEntries.length > 0) {
628
+ let appendContent = ""
629
+ if (excludeContent.length > 0 && !excludeContent.endsWith("\n")) {
630
+ appendContent += "\n"
631
+ }
632
+ appendContent += missingEntries.join("\n") + "\n"
633
+ await fs.promises.appendFile(excludePath, appendContent)
634
+ }
635
+ }
560
636
  return {
561
637
  relpath,
562
638
  root_path: root,
package/kernel/git.js CHANGED
@@ -67,41 +67,39 @@ class Git {
67
67
  display_name = `${name}/${gitRelPathSansGit}`
68
68
  main = false
69
69
  }
70
+ let gitRemote = null
70
71
  try {
71
- let gitRemote = await git.getConfig({
72
+ gitRemote = await git.getConfig({
72
73
  fs,
73
74
  http,
74
75
  dir,
75
76
  path: 'remote.origin.url'
76
77
  })
77
- repos.push({
78
- main,
79
- name: display_name,
80
- gitPath,
81
- gitRelPath,
82
- gitParentPath,
83
- gitParentRelPath,
84
- dir,
85
- url: gitRemote,
86
- })
87
- if (!this.mapping[gitRemote]) {
78
+ } catch (_) {}
79
+
80
+ const repoEntry = {
81
+ main,
82
+ name: display_name,
83
+ gitPath,
84
+ gitRelPath,
85
+ gitParentPath,
86
+ gitParentRelPath,
87
+ dir,
88
+ }
89
+ if (gitRemote) {
90
+ repoEntry.url = gitRemote
91
+ }
92
+ repos.push(repoEntry)
93
+
94
+ if (gitRemote && !this.mapping[gitRemote]) {
95
+ try {
88
96
  let head = await this.getHead(gitParentPath)
89
97
  this.mapping[gitRemote] = {
90
98
  main,
91
99
  path: gitParentPath,
92
100
  head
93
101
  }
94
- }
95
- } catch (e) {
96
- repos.push({
97
- main,
98
- name: display_name,
99
- gitPath,
100
- gitRelPath,
101
- gitParentPath,
102
- gitParentRelPath,
103
- dir,
104
- })
102
+ } catch (_) {}
105
103
  }
106
104
  this.dirs.add(dir)
107
105
  }
@@ -0,0 +1,21 @@
1
+ {
2
+ "run": [{
3
+ "when": "{{args.org}}",
4
+ "method": "shell.run",
5
+ "params": {
6
+ "path": "{{args.cwd}}",
7
+ "message": [
8
+ "gh repo fork --remote=true --clone=false --fork-name {{args.name}} --org {{args.org}}"
9
+ ]
10
+ }
11
+ }, {
12
+ "when": "{{!args.org}}",
13
+ "method": "shell.run",
14
+ "params": {
15
+ "path": "{{args.cwd}}",
16
+ "message": [
17
+ "gh repo fork --remote=true --clone=false --fork-name {{args.name}}"
18
+ ]
19
+ }
20
+ }]
21
+ }
@@ -5,7 +5,7 @@
5
5
  "chain": "*",
6
6
  "path": "{{args.cwd}}",
7
7
  "message": [
8
- "git push -u"
8
+ "git push -u origin"
9
9
  ]
10
10
  }
11
11
  }]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.107.0",
3
+ "version": "3.109.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server/index.js CHANGED
@@ -484,98 +484,112 @@ class Server {
484
484
  }
485
485
  }
486
486
  async getGit(ref, filepath) {
487
- let dir = this.kernel.path("api", filepath)
488
- let branches = await git.listBranches({ fs, dir });
489
- // no branch, means no git repo => initialize
490
- if (branches.length === 0) {
491
- return {}
492
- // const defaultBranch = 'main';
493
- // await git.init({ fs, dir, defaultBranch });
494
- // branches = await git.listBranches({ fs, dir });
495
- // const current = await git.currentBranch({ fs, dir, fullname: false }) || defaultBranch;
496
- // if (!branches.includes(current)) {
497
- // branches.unshift(current);
498
- // }
499
- // if (!ref || ref === 'HEAD') {
500
- // ref = current;
501
- // }
502
- }
503
- let log = []
487
+ const dir = this.kernel.path("api", filepath)
488
+
489
+ let branchList = []
504
490
  try {
505
- log = await git.log({ fs, dir, depth: 50, ref: ref }); // fetch last 50 commits
506
- log.forEach((item) => {
491
+ branchList = await git.listBranches({ fs, dir })
492
+ } catch (_) {}
493
+
494
+ const collectLog = async (targetRef) => {
495
+ const entries = await git.log({ fs, dir, depth: 50, ref: targetRef })
496
+ entries.forEach((item) => {
507
497
  item.info = `/gitcommit/${item.oid}/${filepath}`
508
498
  })
509
- } catch (e) {
510
- console.log("Log error", e)
499
+ return entries
500
+ }
501
+
502
+ let log = []
503
+ let logError = null
504
+ if (ref) {
505
+ try {
506
+ log = await collectLog(ref)
507
+ } catch (error) {
508
+ logError = error
509
+ }
510
+ }
511
+ if (log.length === 0) {
512
+ try {
513
+ log = await collectLog('HEAD')
514
+ } catch (error) {
515
+ if (!logError) {
516
+ logError = error
517
+ }
518
+ }
519
+ }
520
+
521
+ let currentBranch = null
522
+ try {
523
+ currentBranch = await git.currentBranch({ fs, dir, fullname: false })
524
+ } catch (_) {}
525
+
526
+ let branches = []
527
+ if (branchList.length > 0) {
528
+ branches = branchList.map((name) => ({
529
+ branch: name,
530
+ selected: currentBranch ? name === currentBranch : false
531
+ }))
532
+ if (!currentBranch && log.length > 0) {
533
+ const headOid = log[0].oid
534
+ branches = [{ branch: headOid, selected: true }, ...branches.map((entry) => ({ ...entry, selected: false }))]
535
+ currentBranch = headOid
536
+ }
537
+ } else {
538
+ if (currentBranch) {
539
+ branches = [{ branch: currentBranch, selected: true }]
540
+ } else if (log.length > 0) {
541
+ const headOid = log[0].oid
542
+ branches = [{ branch: headOid, selected: true }]
543
+ currentBranch = headOid
544
+ }
545
+ }
546
+
547
+ if (!currentBranch && log.length > 0) {
548
+ currentBranch = log[0].oid
511
549
  }
512
550
 
513
- let config = await this.kernel.git.config(dir)
551
+ if (branches.length === 0) {
552
+ branches = [{ branch: currentBranch || 'HEAD', selected: true }]
553
+ }
554
+
555
+ const config = await this.kernel.git.config(dir)
514
556
 
515
557
  let hosts = ""
516
- let hosts_file = this.kernel.path("config/gh/hosts.yml")
517
- let e = await this.exists(hosts_file)
518
- if (e) {
519
- hosts = await fs.promises.readFile(hosts_file, "utf8")
558
+ const hostsFile = this.kernel.path("config/gh/hosts.yml")
559
+ if (await this.exists(hostsFile)) {
560
+ hosts = await fs.promises.readFile(hostsFile, "utf8")
520
561
  if (hosts.startsWith("{}")) {
521
562
  hosts = ""
522
563
  }
523
564
  }
524
- let connected = (hosts.length > 0)
565
+ const connected = hosts.length > 0
566
+
525
567
  let remote = null
526
- if (config["remote \"origin\""]) {
568
+ if (config && config["remote \"origin\""]) {
527
569
  remote = config["remote \"origin\""].url
528
570
  }
529
571
 
530
- // Get all remotes
531
572
  let remotes = []
532
573
  try {
533
574
  remotes = await git.listRemotes({ fs, dir, verbose: true })
534
- } catch (e) {
535
- console.log("Remotes error", e)
536
- }
575
+ } catch (_) {}
537
576
 
538
- let branch = await git.currentBranch({ fs, dir, fullname: false });
577
+ if (!currentBranch) {
578
+ currentBranch = 'HEAD'
579
+ }
539
580
 
540
- const remote2 = await git.getConfig({
541
- fs,
581
+ return {
582
+ ref,
583
+ config,
584
+ remote,
585
+ remotes,
586
+ connected,
587
+ log,
588
+ branch: currentBranch,
589
+ branches,
542
590
  dir,
543
- path: `branch.${branch}.remote`
544
- });
545
-
546
- // if current branch exitss => currengt branch is selected
547
- // if current branch does not exist => get logs[0].oid
548
- if (branch) {
549
- branches = branches.map((b) => {
550
- if (b === branch) {
551
- return {
552
- branch: b,
553
- selected: true
554
- }
555
- } else {
556
- return {
557
- branch: b,
558
- selected: false
559
- }
560
- }
561
- })
562
- } else {
563
- branches.push(log[0].oid)
564
- branches = branches.map((b) => {
565
- if (b === log[0].oid) {
566
- return {
567
- branch: b,
568
- selected: true
569
- }
570
- } else {
571
- return {
572
- branch: b,
573
- selected: false
574
- }
575
- }
576
- })
591
+ logError: logError ? String(logError.message || logError) : null
577
592
  }
578
- return { ref, config, remote, remotes, connected, log, branch, branches, dir }
579
593
  }
580
594
  async init_env(env_dir_path, options) {
581
595
  let current = this.kernel.path(env_dir_path, "ENVIRONMENT")
@@ -696,25 +710,28 @@ class Server {
696
710
 
697
711
  await Environment.init({ name }, this.kernel)
698
712
 
699
- // copy gitignore from ~pinokio/prototype/system/gitignore if it doesn't exist
700
-
701
-
702
- let gitignore_path = this.kernel.path("api/" + name + "/.gitignore")
703
- let dot_path = this.kernel.path("api", name, "pinokio")
704
- let gitignore_template_path = this.kernel.path("prototype/system/gitignore")
705
- let template_exists = await this.exists(gitignore_template_path)
706
- if (template_exists) {
707
- let exists = await this.exists(dot_path)
708
- if (exists) {
709
- // 1. when importing existing projects (.pinokio exists), don't mess with .gitignore
710
- } else {
711
- // 2. otherwise, merge gitignore
712
- await Util.mergeLines(
713
- gitignore_path, // existing path
714
- gitignore_template_path // overwrite with template
715
- )
716
- }
717
- }
713
+ /*
714
+ REPLACED OUT WITH using .git/info/exclude instead in order to not mess with 3rd party project .gitignore files but still exclude
715
+ */
716
+ // // copy gitignore from ~pinokio/prototype/system/gitignore if it doesn't exist
717
+ //
718
+ //
719
+ // let gitignore_path = this.kernel.path("api/" + name + "/.gitignore")
720
+ // let dot_path = this.kernel.path("api", name, "pinokio")
721
+ // let gitignore_template_path = this.kernel.path("prototype/system/gitignore")
722
+ // let template_exists = await this.exists(gitignore_template_path)
723
+ // if (template_exists) {
724
+ // let exists = await this.exists(dot_path)
725
+ // if (exists) {
726
+ // // 1. when importing existing projects (.pinokio exists), don't mess with .gitignore
727
+ // } else {
728
+ // // 2. otherwise, merge gitignore
729
+ // await Util.mergeLines(
730
+ // gitignore_path, // existing path
731
+ // gitignore_template_path // overwrite with template
732
+ // )
733
+ // }
734
+ // }
718
735
 
719
736
 
720
737
 
@@ -848,7 +865,8 @@ class Server {
848
865
  git_history_url: `/info/git/HEAD/${name}`,
849
866
  git_status_url: `/info/gitstatus/${name}`,
850
867
  git_push_url: `/run/scripts/git/push.json?cwd=${encodeURIComponent(this.kernel.path('api', name))}`,
851
- git_create_url: `/run/scripts/git/create.json?cwd=${encodeURIComponent(this.kernel.path('api', name))}`
868
+ git_create_url: `/run/scripts/git/create.json?cwd=${encodeURIComponent(this.kernel.path('api', name))}`,
869
+ git_fork_url: `/run/scripts/git/fork.json?cwd=${encodeURIComponent(this.kernel.path('api', name))}`
852
870
  // rawpath,
853
871
  }
854
872
  // if (!this.kernel.proto.config) {
@@ -1202,10 +1220,15 @@ class Server {
1202
1220
 
1203
1221
  const repoHistoryUrl = repoParam ? `/info/git/HEAD/${repoParam}` : null
1204
1222
 
1223
+ const forkUrl = `/run/scripts/git/fork.json?cwd=${encodeURIComponent(dir)}`
1224
+ const pushUrl = `/run/scripts/git/push.json?cwd=${encodeURIComponent(dir)}`
1225
+
1205
1226
  return {
1206
1227
  changes,
1207
1228
  git_commit_url: `/run/scripts/git/commit.json?cwd=${dir}&callback_target=parent&callback=$location.href`,
1208
1229
  git_history_url: repoHistoryUrl,
1230
+ git_fork_url: forkUrl,
1231
+ git_push_url: pushUrl,
1209
1232
  }
1210
1233
  }
1211
1234
  async computeWorkspaceGitStatus(workspaceName) {
@@ -1218,7 +1241,7 @@ class Server {
1218
1241
  for (const repo of repos) {
1219
1242
  const repoParam = repo.gitParentRelPath || workspaceName
1220
1243
  try {
1221
- const { changes, git_commit_url, git_history_url } = await this.getRepoHeadStatus(repoParam)
1244
+ const { changes, git_commit_url, git_history_url, git_fork_url, git_push_url } = await this.getRepoHeadStatus(repoParam)
1222
1245
  const historyUrl = git_history_url || (repoParam ? `/info/git/HEAD/${repoParam}` : `/info/git/HEAD/${workspaceName}`)
1223
1246
  statuses.push({
1224
1247
  name: repo.name,
@@ -1229,6 +1252,8 @@ class Server {
1229
1252
  changes,
1230
1253
  git_commit_url,
1231
1254
  git_history_url: historyUrl,
1255
+ git_fork_url,
1256
+ git_push_url,
1232
1257
  url: repo.url || null,
1233
1258
  })
1234
1259
  } catch (error) {
@@ -1243,6 +1268,8 @@ class Server {
1243
1268
  changes: [],
1244
1269
  git_commit_url: null,
1245
1270
  git_history_url: historyUrl,
1271
+ git_fork_url: `/run/scripts/git/fork.json?cwd=${encodeURIComponent(this.kernel.path('api', repoParam))}`,
1272
+ git_push_url: `/run/scripts/git/push.json?cwd=${encodeURIComponent(this.kernel.path('api', repoParam))}`,
1246
1273
  url: repo.url || null,
1247
1274
  error: error ? String(error.message || error) : 'unknown',
1248
1275
  })
@@ -4071,11 +4098,14 @@ class Server {
4071
4098
  defaultUrl.searchParams.set('mode', 'settings')
4072
4099
  }
4073
4100
 
4101
+ const initialPath = initialUrl.pathname + initialUrl.search + initialUrl.hash
4102
+ const defaultPath = defaultUrl.pathname + defaultUrl.search + defaultUrl.hash
4103
+
4074
4104
  res.render('layout', {
4075
4105
  theme: this.theme,
4076
4106
  agent: req.agent,
4077
- initialPath: initialUrl.pathname + initialUrl.search + initialUrl.hash,
4078
- defaultPath: defaultUrl.pathname + defaultUrl.search + defaultUrl.hash,
4107
+ initialPath,
4108
+ defaultPath,
4079
4109
  sessionId: typeof req.query.session === 'string' ? req.query.session : null
4080
4110
  })
4081
4111
  }))
@@ -5519,7 +5549,6 @@ class Server {
5519
5549
  // }))
5520
5550
  this.app.post("/env", ex(async (req, res) => {
5521
5551
  let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
5522
- console.log({ fullpath })
5523
5552
  let updated = req.body.vals
5524
5553
  let hosts = req.body.hosts
5525
5554
  await Util.update_env(fullpath, updated)
@@ -37,6 +37,26 @@
37
37
  const leafElements = new Map();
38
38
  const gutterElements = new Map();
39
39
  const layoutCache = new Map();
40
+ const PRESERVED_QUERY_PARAMS = new Set(['session']);
41
+
42
+ function stripTransientQueryParams() {
43
+ try {
44
+ const url = new URL(window.location.href);
45
+ let changed = false;
46
+ const keys = Array.from(url.searchParams.keys());
47
+ keys.forEach((key) => {
48
+ if (!PRESERVED_QUERY_PARAMS.has(key)) {
49
+ url.searchParams.delete(key);
50
+ changed = true;
51
+ }
52
+ });
53
+ if (changed) {
54
+ window.history.replaceState(window.history.state, '', url.toString());
55
+ }
56
+ } catch (_) {
57
+ // ignore malformed URLs
58
+ }
59
+ }
40
60
 
41
61
  function normalizeSrc(raw) {
42
62
  if (!raw || typeof raw !== 'string') {
@@ -698,6 +718,7 @@
698
718
  applyLayout();
699
719
  attachGutterHandlers();
700
720
  broadcastLayoutState();
721
+ stripTransientQueryParams();
701
722
  }
702
723
 
703
724
  function onResize() {