pinokiod 7.2.18 → 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.
- package/Dockerfile +2 -0
- package/kernel/api/index.js +13 -179
- package/kernel/api/process/index.js +44 -99
- package/kernel/bin/conda-python.js +30 -0
- package/kernel/bin/conda.js +22 -3
- package/kernel/bin/huggingface.js +1 -1
- package/kernel/bin/index.js +11 -1
- package/kernel/environment.js +11 -205
- package/kernel/git.js +13 -0
- package/kernel/index.js +1 -64
- package/kernel/plugin.js +58 -6
- package/kernel/prototype.js +0 -4
- package/kernel/shell.js +2 -23
- package/kernel/util.js +0 -60
- package/package.json +1 -1
- package/server/index.js +171 -229
- package/server/lib/content_validation.js +33 -47
- package/server/public/common.js +29 -103
- package/server/public/create-launcher.js +31 -4
- package/server/public/electron.css +6 -0
- package/server/public/style.css +0 -337
- package/server/public/task-launcher.css +3 -11
- package/server/public/task-launcher.js +32 -5
- package/server/public/universal-launcher.js +26 -3
- package/server/socket.js +11 -22
- package/server/views/app.ejs +30 -167
- package/server/views/d.ejs +35 -33
- package/server/views/editor.ejs +4 -25
- package/server/views/partials/main_sidebar.ejs +0 -1
- package/server/views/partials/menu.ejs +1 -1
- package/server/views/pre.ejs +1 -1
- package/server/views/shell.ejs +3 -11
- package/server/views/task_launch.ejs +10 -10
- package/server/views/terminal.ejs +5 -34
- package/spec/INSTRUCTION_SYNC.md +5 -5
- package/kernel/agent_instructions.js +0 -166
- package/kernel/api/shell_run_template.js +0 -273
- package/kernel/api/uri/index.js +0 -51
- package/kernel/plugin_sources.js +0 -289
- package/kernel/watch/context.js +0 -42
- package/kernel/watch/drivers/fs.js +0 -71
- package/kernel/watch/drivers/poll.js +0 -33
- package/kernel/watch/index.js +0 -185
- package/server/features/index.js +0 -13
- package/server/features/notes/index.js +0 -41
- package/server/features/notes/parser.js +0 -174
- package/server/features/notes/public/notes.css +0 -955
- package/server/features/notes/public/notes.js +0 -1149
- package/server/features/notes/registry_import.js +0 -412
- package/server/features/notes/routes.js +0 -156
- package/server/features/notes/service.js +0 -326
- package/server/features/notes/watcher.js +0 -74
- package/server/lib/workspace_catalog.js +0 -151
- package/server/lib/workspace_runtime.js +0 -390
- package/server/public/tasker.css +0 -336
- package/server/public/tasker.js +0 -407
- package/server/routes/workspaces.js +0 -44
- package/server/views/partials/workspace_row.ejs +0 -61
- package/server/views/tasker.ejs +0 -40
- package/server/views/workspaces.ejs +0 -813
- package/system/plugin/antigravity/antigravity.png +0 -0
- package/system/plugin/antigravity/pinokio.js +0 -35
- package/system/plugin/claude/claude.png +0 -0
- package/system/plugin/claude/pinokio.js +0 -61
- package/system/plugin/claude-auto/claude.png +0 -0
- package/system/plugin/claude-auto/pinokio.js +0 -72
- package/system/plugin/claude-desktop/icon.jpeg +0 -0
- package/system/plugin/claude-desktop/pinokio.js +0 -37
- package/system/plugin/codex/openai.webp +0 -0
- package/system/plugin/codex/pinokio.js +0 -56
- package/system/plugin/codex-auto/openai.webp +0 -0
- package/system/plugin/codex-auto/pinokio.js +0 -63
- package/system/plugin/codex-desktop/icon.png +0 -0
- package/system/plugin/codex-desktop/pinokio.js +0 -37
- package/system/plugin/crush/crush.png +0 -0
- package/system/plugin/crush/pinokio.js +0 -29
- package/system/plugin/cursor/cursor.jpeg +0 -0
- package/system/plugin/cursor/pinokio.js +0 -37
- package/system/plugin/gemini/gemini.jpeg +0 -0
- package/system/plugin/gemini/pinokio.js +0 -38
- package/system/plugin/gemini-auto/gemini.jpeg +0 -0
- package/system/plugin/gemini-auto/pinokio.js +0 -41
- package/system/plugin/qwen/pinokio.js +0 -48
- package/system/plugin/qwen/qwen.png +0 -0
- package/system/plugin/vscode/pinokio.js +0 -34
- package/system/plugin/vscode/vscode.png +0 -0
- package/system/plugin/windsurf/pinokio.js +0 -37
- package/system/plugin/windsurf/windsurf.png +0 -0
- package/test/plugin-sources.test.js +0 -45
|
@@ -895,7 +895,6 @@ const createPluginTerminalDiscoveryRefresher = (context = {}) => {
|
|
|
895
895
|
const enabled = (() => {
|
|
896
896
|
try {
|
|
897
897
|
return window.location.pathname.startsWith("/run/plugin/")
|
|
898
|
-
|| window.location.pathname.startsWith("/pinokio/run/plugin/")
|
|
899
898
|
|| (window.location.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(window.location.pathname))
|
|
900
899
|
} catch (_) {
|
|
901
900
|
return false
|
|
@@ -1233,10 +1232,6 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1233
1232
|
const scriptAction = <% if (typeof action !== 'undefined') { %><%- JSON.stringify(action) %><% } else { %>null<% } %>
|
|
1234
1233
|
const protectionAppId = <% if (typeof protection_app_id !== 'undefined' && protection_app_id) { %><%- JSON.stringify(protection_app_id) %><% } else { %>""<% } %>
|
|
1235
1234
|
const initialProtectionEnabled = <% if (typeof protection_enabled !== 'undefined') { %><%- JSON.stringify(protection_enabled === true) %><% } else { %>false<% } %>
|
|
1236
|
-
const activeProcessWait = <% if (typeof active_process_wait !== 'undefined' && active_process_wait) { %><%- JSON.stringify(active_process_wait) %><% } else { %>null<% } %>
|
|
1237
|
-
if (activeProcessWait && (activeProcessWait.title || activeProcessWait.description) && window.PinokioWaitFooterStatus) {
|
|
1238
|
-
window.PinokioWaitFooterStatus.show(activeProcessWait)
|
|
1239
|
-
}
|
|
1240
1235
|
const shouldBypassAiConsent = () => {
|
|
1241
1236
|
const normalize = (value) => (typeof value === "string" ? value.replace(/\\/g, "/") : "")
|
|
1242
1237
|
const uri = normalize(scriptUri || "")
|
|
@@ -1495,17 +1490,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1495
1490
|
refreshParent(packet)
|
|
1496
1491
|
reloadMemory()
|
|
1497
1492
|
runControls.set("running")
|
|
1498
|
-
if (packet.data &&
|
|
1493
|
+
if (packet.data && packet.data.description) {
|
|
1499
1494
|
if ('current' in packet.data) {
|
|
1500
1495
|
document.querySelector("#status-window").innerHTML = `<b>
|
|
1501
1496
|
<i class="fa-solid fa-circle-notch fa-spin"></i>(${packet.data.current+1}/${packet.data.total}) ${packet.data.title ? packet.data.title : ''}
|
|
1502
1497
|
</b>
|
|
1503
|
-
<div class='flexible content'>${packet.data.description
|
|
1498
|
+
<div class='flexible content'>${packet.data.description}</div>`
|
|
1504
1499
|
} else {
|
|
1505
1500
|
document.querySelector("#status-window").innerHTML = `<b>
|
|
1506
1501
|
<i class="fa-solid fa-circle-notch fa-spin"></i> ${packet.data.title ? packet.data.title : ''}
|
|
1507
1502
|
</b>
|
|
1508
|
-
<div class='flexible content'
|
|
1503
|
+
<div class='flexible content'></div>`
|
|
1509
1504
|
// <div class='toggle-expand'>
|
|
1510
1505
|
// <i class="fa-solid fa-circle-chevron-up"></i>
|
|
1511
1506
|
// </div>`
|
|
@@ -1683,14 +1678,6 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1683
1678
|
// uri: "~" + location.pathname,
|
|
1684
1679
|
uri: packet.id
|
|
1685
1680
|
})
|
|
1686
|
-
} else if (packet.type === "process.wait.start") {
|
|
1687
|
-
if (window.PinokioWaitFooterStatus) {
|
|
1688
|
-
window.PinokioWaitFooterStatus.show(packet.data)
|
|
1689
|
-
}
|
|
1690
|
-
} else if (packet.type === "process.wait.end") {
|
|
1691
|
-
if (window.PinokioWaitFooterStatus) {
|
|
1692
|
-
window.PinokioWaitFooterStatus.hide()
|
|
1693
|
-
}
|
|
1694
1681
|
} else if (packet.type === 'wait') {
|
|
1695
1682
|
await WaitModal(packet.data)
|
|
1696
1683
|
} else if (packet.type === "htmlmodal") {
|
|
@@ -2784,10 +2771,6 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
2784
2771
|
this.resizeSync.sendResize(this.term.cols, this.term.rows)
|
|
2785
2772
|
});
|
|
2786
2773
|
this.observer.observe(document.body)
|
|
2787
|
-
const terminalContainer = document.querySelector(".terminal-container")
|
|
2788
|
-
if (terminalContainer) {
|
|
2789
|
-
this.observer.observe(terminalContainer)
|
|
2790
|
-
}
|
|
2791
2774
|
}
|
|
2792
2775
|
}
|
|
2793
2776
|
<% if (!install_required) { %>
|
|
@@ -2933,9 +2916,9 @@ const reloadMemory = async () => {
|
|
|
2933
2916
|
</script>
|
|
2934
2917
|
</head>
|
|
2935
2918
|
<% if (install_required) { %>
|
|
2936
|
-
<body class='terminal-page frozen <%=theme%> <%= locals.full_navbar ? "has-full-navbar" : "" %>' data-
|
|
2919
|
+
<body class='terminal-page frozen <%=theme%> <%= locals.full_navbar ? "has-full-navbar" : "" %>' data-task-save-cwd="<%= cwd || '' %>" data-task-save-workspaces-root="<%= taskSaveWorkspacesRoot || '' %>">
|
|
2937
2920
|
<% } else { %>
|
|
2938
|
-
<body class='terminal-page <%=theme%> <%= locals.full_navbar ? "has-full-navbar" : "" %>' data-
|
|
2921
|
+
<body class='terminal-page <%=theme%> <%= locals.full_navbar ? "has-full-navbar" : "" %>' data-task-save-cwd="<%= cwd || '' %>" data-task-save-workspaces-root="<%= taskSaveWorkspacesRoot || '' %>">
|
|
2939
2922
|
<% } %>
|
|
2940
2923
|
<% if (locals.full_navbar) { %>
|
|
2941
2924
|
<header class="navheader grabbable">
|
|
@@ -2965,9 +2948,6 @@ const reloadMemory = async () => {
|
|
|
2965
2948
|
</h1>
|
|
2966
2949
|
</header>
|
|
2967
2950
|
<% } %>
|
|
2968
|
-
<% if (!install_required && typeof note_watch_enabled !== 'undefined' && note_watch_enabled) { %>
|
|
2969
|
-
<div id="pinokio-notes-slot" class="pinokio-notes-slot" aria-live="polite"></div>
|
|
2970
|
-
<% } %>
|
|
2971
2951
|
<% if (!install_required) { %>
|
|
2972
2952
|
<header class='navheader2'>
|
|
2973
2953
|
<div class='runner'>
|
|
@@ -3106,14 +3086,5 @@ const reloadMemory = async () => {
|
|
|
3106
3086
|
</a>
|
|
3107
3087
|
</div>
|
|
3108
3088
|
</div>
|
|
3109
|
-
<% if (typeof note_watch_enabled !== 'undefined' && note_watch_enabled) { %>
|
|
3110
|
-
<script>
|
|
3111
|
-
window.PinokioNoteContext = {
|
|
3112
|
-
cwd: <%- JSON.stringify((typeof note_watch_cwd !== 'undefined' && note_watch_cwd) ? note_watch_cwd : '').replace(/</g, '\\u003c') %>
|
|
3113
|
-
};
|
|
3114
|
-
</script>
|
|
3115
|
-
<link rel="stylesheet" href="/notes.css?v=flow-footer-fullscreen">
|
|
3116
|
-
<script src="/notes.js?v=flow-footer-fullscreen"></script>
|
|
3117
|
-
<% } %>
|
|
3118
3089
|
</body>
|
|
3119
3090
|
</html>
|
package/spec/INSTRUCTION_SYNC.md
CHANGED
|
@@ -18,6 +18,7 @@ Fix three related problems with minimal behavioral change:
|
|
|
18
18
|
|
|
19
19
|
Paths:
|
|
20
20
|
|
|
21
|
+
- `PINOKIO_HOME/plugin/code`
|
|
21
22
|
- `PINOKIO_HOME/prototype/system`
|
|
22
23
|
- `PINOKIO_HOME/network/system`
|
|
23
24
|
|
|
@@ -31,8 +32,6 @@ Policy:
|
|
|
31
32
|
- On normal startup, bootstrap only if missing.
|
|
32
33
|
- At runtime, if a needed file inside one of these repos is missing, attempt a targeted Git restore for that path only.
|
|
33
34
|
|
|
34
|
-
Built-in plugins are packaged under `pinokiod/system/plugin` and are not cloned, refreshed, or repaired inside `PINOKIO_HOME`.
|
|
35
|
-
|
|
36
35
|
### 2. Managed downloaded instruction sources
|
|
37
36
|
|
|
38
37
|
Paths:
|
|
@@ -110,7 +109,7 @@ Policy:
|
|
|
110
109
|
|
|
111
110
|
Paths:
|
|
112
111
|
|
|
113
|
-
- everything under `PINOKIO_HOME/plugin/*`
|
|
112
|
+
- everything under `PINOKIO_HOME/plugin/*` except `plugin/code`
|
|
114
113
|
- everything under `PINOKIO_HOME/prototype/*` except `prototype/system`, `prototype/PINOKIO.md`, and `prototype/PTERM.md`
|
|
115
114
|
- everything under `PINOKIO_HOME/network/*` except `network/system`
|
|
116
115
|
|
|
@@ -130,6 +129,7 @@ Policy:
|
|
|
130
129
|
|
|
131
130
|
Required behavior:
|
|
132
131
|
|
|
132
|
+
- refresh `plugin/code`
|
|
133
133
|
- refresh `prototype/system`
|
|
134
134
|
- refresh `network/system`
|
|
135
135
|
- refresh `prototype/PINOKIO.md`
|
|
@@ -164,7 +164,7 @@ Ordering requirement:
|
|
|
164
164
|
|
|
165
165
|
- After a version-change cleanup, Pinokio must not rely on the current startup order where `Environment.init({}, kernel)` can run before the async reclone/redownload of managed repos/docs completes.
|
|
166
166
|
- Home output regeneration must either:
|
|
167
|
-
- run after `prototype/system`, `network/system`, `PINOKIO.md`, and `PTERM.md` have been restored
|
|
167
|
+
- run after `plugin/code`, `prototype/system`, `network/system`, `PINOKIO.md`, and `PTERM.md` have been restored
|
|
168
168
|
- or be rerun once those managed inputs are restored
|
|
169
169
|
|
|
170
170
|
### C. Runtime missing-file repair
|
|
@@ -298,7 +298,7 @@ File:
|
|
|
298
298
|
|
|
299
299
|
Changes:
|
|
300
300
|
|
|
301
|
-
-
|
|
301
|
+
- replace whole-folder refresh of `PINOKIO_HOME/plugin` with refresh of `PINOKIO_HOME/plugin/code` only
|
|
302
302
|
- replace whole-folder refresh of `PINOKIO_HOME/prototype` with refresh of:
|
|
303
303
|
- `PINOKIO_HOME/prototype/system`
|
|
304
304
|
- `PINOKIO_HOME/prototype/PINOKIO.md`
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
const fs = require("fs")
|
|
2
|
-
const path = require("path")
|
|
3
|
-
const PluginSources = require("./plugin_sources")
|
|
4
|
-
|
|
5
|
-
const NOTES_BEGIN = "<!-- PINOKIO:NOTES:BEGIN -->"
|
|
6
|
-
const NOTES_END = "<!-- PINOKIO:NOTES:END -->"
|
|
7
|
-
const LEGACY_DRAFTS_BEGIN = "<!-- PINOKIO:DRAFTS:BEGIN -->"
|
|
8
|
-
const LEGACY_DRAFTS_END = "<!-- PINOKIO:DRAFTS:END -->"
|
|
9
|
-
|
|
10
|
-
const AGENT_INSTRUCTION_FILES = [
|
|
11
|
-
"AGENTS.md",
|
|
12
|
-
"CLAUDE.md",
|
|
13
|
-
"GEMINI.md",
|
|
14
|
-
"QWEN.md",
|
|
15
|
-
".windsurfrules",
|
|
16
|
-
".cursorrules",
|
|
17
|
-
".clinerules",
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
const escapeRegExp = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
21
|
-
|
|
22
|
-
const normalizeBlock = (block) => `${String(block || "").trim()}\n`
|
|
23
|
-
|
|
24
|
-
const extractManagedBlock = (content, begin = NOTES_BEGIN, end = NOTES_END) => {
|
|
25
|
-
const text = String(content || "")
|
|
26
|
-
const start = text.indexOf(begin)
|
|
27
|
-
const finish = text.indexOf(end, start + begin.length)
|
|
28
|
-
if (start < 0 || finish < 0) {
|
|
29
|
-
return ""
|
|
30
|
-
}
|
|
31
|
-
return text.slice(start, finish + end.length)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const insertionIndex = (content) => {
|
|
35
|
-
const text = String(content || "")
|
|
36
|
-
let offset = 0
|
|
37
|
-
|
|
38
|
-
if (text.startsWith("---\n")) {
|
|
39
|
-
const frontmatterEnd = text.indexOf("\n---\n", 4)
|
|
40
|
-
if (frontmatterEnd >= 0) {
|
|
41
|
-
offset = frontmatterEnd + "\n---\n".length
|
|
42
|
-
while (text[offset] === "\n") {
|
|
43
|
-
offset += 1
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const rest = text.slice(offset)
|
|
49
|
-
const h1 = rest.match(/^# .*(?:\n|$)/)
|
|
50
|
-
if (h1) {
|
|
51
|
-
return offset + h1[0].length
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return offset
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const insertManagedBlock = (content, block) => {
|
|
58
|
-
const text = String(content || "").replace(/\r\n/g, "\n")
|
|
59
|
-
const noteBlock = normalizeBlock(block)
|
|
60
|
-
if (!text.trim()) {
|
|
61
|
-
return noteBlock
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const index = insertionIndex(text)
|
|
65
|
-
const before = text.slice(0, index)
|
|
66
|
-
const after = text.slice(index).replace(/^\n+/, "")
|
|
67
|
-
const beforeGap = before.endsWith("\n\n") ? "" : before.endsWith("\n") ? "\n" : "\n\n"
|
|
68
|
-
const afterGap = after ? "\n" : ""
|
|
69
|
-
|
|
70
|
-
return `${before}${beforeGap}${noteBlock}${afterGap}${after}`
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const upsertManagedBlock = (content, block, begin = NOTES_BEGIN, end = NOTES_END) => {
|
|
74
|
-
let text = String(content || "").replace(/\r\n/g, "\n")
|
|
75
|
-
const noteBlock = normalizeBlock(block)
|
|
76
|
-
const pattern = new RegExp(`${escapeRegExp(begin)}[\\s\\S]*?${escapeRegExp(end)}\\n?`)
|
|
77
|
-
const legacyPattern = new RegExp(`${escapeRegExp(LEGACY_DRAFTS_BEGIN)}[\\s\\S]*?${escapeRegExp(LEGACY_DRAFTS_END)}\\n?`)
|
|
78
|
-
|
|
79
|
-
if (pattern.test(text)) {
|
|
80
|
-
return text.replace(pattern, `${noteBlock}\n`)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
text = text.replace(legacyPattern, "")
|
|
84
|
-
return insertManagedBlock(text, noteBlock)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const containedBy = (child, parent) => {
|
|
88
|
-
const relative = path.relative(path.resolve(parent), path.resolve(child))
|
|
89
|
-
return relative === "" || (!!relative && !relative.startsWith("..") && !path.isAbsolute(relative))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const isPluginScriptPath = (kernel, scriptPath) => {
|
|
93
|
-
if (!kernel || !scriptPath) {
|
|
94
|
-
return false
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const absolutePath = path.resolve(scriptPath)
|
|
98
|
-
if (containedBy(absolutePath, kernel.path("plugin", "code"))) {
|
|
99
|
-
return false
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const roots = [
|
|
103
|
-
PluginSources.systemPluginRoot(kernel),
|
|
104
|
-
kernel.path("plugin"),
|
|
105
|
-
].filter(Boolean)
|
|
106
|
-
|
|
107
|
-
return roots.some((root) => containedBy(absolutePath, root))
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const ensureManagedBlockInFile = async (filePath, block) => {
|
|
111
|
-
let content = ""
|
|
112
|
-
try {
|
|
113
|
-
content = await fs.promises.readFile(filePath, "utf8")
|
|
114
|
-
} catch (e) {
|
|
115
|
-
if (!e || e.code !== "ENOENT") {
|
|
116
|
-
throw e
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const nextContent = upsertManagedBlock(content, block)
|
|
121
|
-
if (nextContent !== content) {
|
|
122
|
-
await fs.promises.writeFile(filePath, nextContent, "utf8")
|
|
123
|
-
return true
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return false
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const ensureNoteInstructionsForCwd = async ({ kernel, cwd }) => {
|
|
130
|
-
if (!kernel || !cwd) {
|
|
131
|
-
return { updated: [], skipped: "missing-cwd" }
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const targetDir = path.resolve(cwd)
|
|
135
|
-
const stat = await fs.promises.stat(targetDir).catch(() => null)
|
|
136
|
-
if (!stat || !stat.isDirectory()) {
|
|
137
|
-
return { updated: [], skipped: "invalid-cwd" }
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const sourcePath = kernel.path("prototype", "system", "AGENTS.md")
|
|
141
|
-
const source = await fs.promises.readFile(sourcePath, "utf8").catch(() => "")
|
|
142
|
-
const block = extractManagedBlock(source)
|
|
143
|
-
if (!block) {
|
|
144
|
-
return { updated: [], skipped: "missing-block" }
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const updated = []
|
|
148
|
-
for (const filename of AGENT_INSTRUCTION_FILES) {
|
|
149
|
-
const filePath = path.join(targetDir, filename)
|
|
150
|
-
if (await ensureManagedBlockInFile(filePath, block)) {
|
|
151
|
-
updated.push(filePath)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return { updated, skipped: null }
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
module.exports = {
|
|
159
|
-
NOTES_BEGIN,
|
|
160
|
-
NOTES_END,
|
|
161
|
-
AGENT_INSTRUCTION_FILES,
|
|
162
|
-
extractManagedBlock,
|
|
163
|
-
upsertManagedBlock,
|
|
164
|
-
isPluginScriptPath,
|
|
165
|
-
ensureNoteInstructionsForCwd,
|
|
166
|
-
}
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
function isCmdShellName(shellName) {
|
|
2
|
-
const name = (shellName || '').toLowerCase()
|
|
3
|
-
return name.includes('cmd.exe') || name === 'cmd'
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
function isPowerShellName(shellName) {
|
|
7
|
-
const name = (shellName || '').toLowerCase()
|
|
8
|
-
return name.includes('powershell') || name.includes('pwsh')
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const ENV_ARG_MARKER_RE = /__PINOKIO_ENVARG_(\d+)__/g
|
|
12
|
-
|
|
13
|
-
function envArgMarker(index) {
|
|
14
|
-
return `__PINOKIO_ENVARG_${index}__`
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function isPinokioEnvArgKey(key) {
|
|
18
|
-
return /^PINOKIO_ARG_\d+$/.test(key || "")
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function hasEnvArgMarker(value) {
|
|
22
|
-
ENV_ARG_MARKER_RE.lastIndex = 0
|
|
23
|
-
return ENV_ARG_MARKER_RE.test(String(value))
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function quotePosixLiteral(value) {
|
|
27
|
-
const input = value == null ? "" : String(value)
|
|
28
|
-
return `'${input.split("'").join("'\"'\"'")}'`
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function quotePowerShellComposite(value) {
|
|
32
|
-
const input = value == null ? "" : String(value)
|
|
33
|
-
ENV_ARG_MARKER_RE.lastIndex = 0
|
|
34
|
-
let output = '"'
|
|
35
|
-
let lastIndex = 0
|
|
36
|
-
for (const match of input.matchAll(ENV_ARG_MARKER_RE)) {
|
|
37
|
-
const literal = input.slice(lastIndex, match.index)
|
|
38
|
-
output += literal.replace(/[`"$]/g, (char) => "`" + char)
|
|
39
|
-
output += "${env:PINOKIO_ARG_" + match[1] + "}"
|
|
40
|
-
lastIndex = match.index + match[0].length
|
|
41
|
-
}
|
|
42
|
-
output += input.slice(lastIndex).replace(/[`"$]/g, (char) => "`" + char)
|
|
43
|
-
output += '"'
|
|
44
|
-
return output
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function quoteCmdComposite(value) {
|
|
48
|
-
const input = value == null ? "" : String(value)
|
|
49
|
-
ENV_ARG_MARKER_RE.lastIndex = 0
|
|
50
|
-
let output = '"'
|
|
51
|
-
let lastIndex = 0
|
|
52
|
-
for (const match of input.matchAll(ENV_ARG_MARKER_RE)) {
|
|
53
|
-
const literal = input.slice(lastIndex, match.index)
|
|
54
|
-
output += literal.replace(/([()%!^"<>&|])/g, '^$1')
|
|
55
|
-
output += "!PINOKIO_ARG_" + match[1] + "!"
|
|
56
|
-
lastIndex = match.index + match[0].length
|
|
57
|
-
}
|
|
58
|
-
output += input.slice(lastIndex).replace(/([()%!^"<>&|])/g, '^$1')
|
|
59
|
-
output += '"'
|
|
60
|
-
return output
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function quoteEnvArgComposite(value, shellName) {
|
|
64
|
-
const input = value == null ? "" : String(value)
|
|
65
|
-
if (isCmdShellName(shellName)) {
|
|
66
|
-
return quoteCmdComposite(input)
|
|
67
|
-
}
|
|
68
|
-
if (isPowerShellName(shellName)) {
|
|
69
|
-
return quotePowerShellComposite(input)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
ENV_ARG_MARKER_RE.lastIndex = 0
|
|
73
|
-
const parts = []
|
|
74
|
-
let lastIndex = 0
|
|
75
|
-
for (const match of input.matchAll(ENV_ARG_MARKER_RE)) {
|
|
76
|
-
const literal = input.slice(lastIndex, match.index)
|
|
77
|
-
if (literal) {
|
|
78
|
-
parts.push(quotePosixLiteral(literal))
|
|
79
|
-
}
|
|
80
|
-
parts.push('"$PINOKIO_ARG_' + match[1] + '"')
|
|
81
|
-
lastIndex = match.index + match[0].length
|
|
82
|
-
}
|
|
83
|
-
const tail = input.slice(lastIndex)
|
|
84
|
-
if (tail) {
|
|
85
|
-
parts.push(quotePosixLiteral(tail))
|
|
86
|
-
}
|
|
87
|
-
return parts.length > 0 ? parts.join("") : "''"
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function shellNameFor(kernel, params) {
|
|
91
|
-
let shellName = kernel && kernel.platform === "win32" ? "cmd.exe" : "bash"
|
|
92
|
-
if (params && typeof params.shell === "string" && params.shell.trim()) {
|
|
93
|
-
shellName = params.shell
|
|
94
|
-
}
|
|
95
|
-
return shellName
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function isPlainObject(value) {
|
|
99
|
-
return value && value.constructor === Object
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function hasMultiline(value) {
|
|
103
|
-
return typeof value === "string" && /[\r\n]/.test(value)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function isStructuredArgvMessage(value) {
|
|
107
|
-
return isPlainObject(value) && Array.isArray(value._)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function hasStructuredArgvMessage(value) {
|
|
111
|
-
if (isStructuredArgvMessage(value)) {
|
|
112
|
-
return true
|
|
113
|
-
}
|
|
114
|
-
if (Array.isArray(value)) {
|
|
115
|
-
return value.some((item) => isStructuredArgvMessage(item))
|
|
116
|
-
}
|
|
117
|
-
return false
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function protectStructuredString(value, state) {
|
|
121
|
-
if (!hasMultiline(value)) {
|
|
122
|
-
return value
|
|
123
|
-
}
|
|
124
|
-
const name = `PINOKIO_ARG_${state.args.length}`
|
|
125
|
-
state.args.push({
|
|
126
|
-
name,
|
|
127
|
-
value: value == null ? "" : String(value)
|
|
128
|
-
})
|
|
129
|
-
return envArgMarker(state.args.length - 1)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function protectStructuredValue(value, state) {
|
|
133
|
-
if (typeof value === "string") {
|
|
134
|
-
return protectStructuredString(value, state)
|
|
135
|
-
}
|
|
136
|
-
if (Array.isArray(value)) {
|
|
137
|
-
return value.map((item) => protectStructuredValue(item, state))
|
|
138
|
-
}
|
|
139
|
-
if (isPlainObject(value)) {
|
|
140
|
-
const rendered = {}
|
|
141
|
-
for (const [key, item] of Object.entries(value)) {
|
|
142
|
-
rendered[key] = protectStructuredValue(item, state)
|
|
143
|
-
}
|
|
144
|
-
return rendered
|
|
145
|
-
}
|
|
146
|
-
return value
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function protectStructuredMessage(value, state) {
|
|
150
|
-
if (isStructuredArgvMessage(value)) {
|
|
151
|
-
return protectStructuredValue(value, state)
|
|
152
|
-
}
|
|
153
|
-
if (Array.isArray(value)) {
|
|
154
|
-
return value.map((item) => isStructuredArgvMessage(item) ? protectStructuredValue(item, state) : item)
|
|
155
|
-
}
|
|
156
|
-
return value
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function renderEnvArgs(kernel, rpc, memory) {
|
|
160
|
-
if (!rpc || rpc.method !== "shell.run" || !rpc.params || !hasStructuredArgvMessage(rpc.params.message)) {
|
|
161
|
-
return rpc
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const shellName = shellNameFor(kernel, rpc.params)
|
|
165
|
-
const state = { args: [] }
|
|
166
|
-
const message = protectStructuredMessage(rpc.params.message, state)
|
|
167
|
-
|
|
168
|
-
if (state.args.length === 0) {
|
|
169
|
-
return rpc
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const env = Object.assign({}, rpc.params.env || {})
|
|
173
|
-
for (const arg of state.args) {
|
|
174
|
-
env[arg.name] = arg.value
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
...rpc,
|
|
179
|
-
params: {
|
|
180
|
-
...rpc.params,
|
|
181
|
-
message,
|
|
182
|
-
env,
|
|
183
|
-
_pinokio_env_args: state.args,
|
|
184
|
-
_pinokio_cmd_delayed_expansion: isCmdShellName(shellName)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function envArgDetails(value) {
|
|
190
|
-
const normalized = String(value == null ? "" : value)
|
|
191
|
-
.replace(/\r\n/g, "\n")
|
|
192
|
-
.replace(/\r/g, "\n")
|
|
193
|
-
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "?")
|
|
194
|
-
const lines = normalized.split("\n")
|
|
195
|
-
const previewLines = []
|
|
196
|
-
const maxLines = 8
|
|
197
|
-
const maxChars = 800
|
|
198
|
-
let used = 0
|
|
199
|
-
|
|
200
|
-
for (const line of lines.slice(0, maxLines)) {
|
|
201
|
-
const remaining = maxChars - used
|
|
202
|
-
if (remaining <= 0) {
|
|
203
|
-
break
|
|
204
|
-
}
|
|
205
|
-
if (line.length > remaining) {
|
|
206
|
-
previewLines.push(line.slice(0, remaining) + "...")
|
|
207
|
-
used = maxChars
|
|
208
|
-
break
|
|
209
|
-
}
|
|
210
|
-
previewLines.push(line)
|
|
211
|
-
used += line.length + 1
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const preview = previewLines.join("\n")
|
|
215
|
-
const truncated = lines.length > previewLines.length || normalized.length > preview.length
|
|
216
|
-
if (truncated && previewLines[previewLines.length - 1] !== "...") {
|
|
217
|
-
previewLines.push("...")
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
lineCount: normalized.length === 0 ? 0 : lines.length,
|
|
222
|
-
previewLines,
|
|
223
|
-
truncated
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function formatEnvArgsPreview(args) {
|
|
228
|
-
if (!Array.isArray(args) || args.length === 0) {
|
|
229
|
-
return ""
|
|
230
|
-
}
|
|
231
|
-
const lines = ["\r\nPinokio shell args", ""]
|
|
232
|
-
for (const arg of args) {
|
|
233
|
-
const details = envArgDetails(arg.value)
|
|
234
|
-
lines.push(`${arg.name} ${details.lineCount} lines`)
|
|
235
|
-
for (const previewLine of details.previewLines) {
|
|
236
|
-
lines.push(` ${previewLine}`)
|
|
237
|
-
}
|
|
238
|
-
lines.push("")
|
|
239
|
-
}
|
|
240
|
-
return lines.join("\r\n") + "\r\n"
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function envArgSummary(value) {
|
|
244
|
-
const details = envArgDetails(value)
|
|
245
|
-
return {
|
|
246
|
-
type: "pinokio env arg",
|
|
247
|
-
lines: details.lineCount,
|
|
248
|
-
preview: details.previewLines.join("\n"),
|
|
249
|
-
truncated: details.truncated
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function redactEnvArgs(env) {
|
|
254
|
-
if (!env || typeof env !== "object") {
|
|
255
|
-
return env
|
|
256
|
-
}
|
|
257
|
-
const redacted = { ...env }
|
|
258
|
-
for (const key of Object.keys(redacted)) {
|
|
259
|
-
if (isPinokioEnvArgKey(key)) {
|
|
260
|
-
redacted[key] = envArgSummary(redacted[key])
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return redacted
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
module.exports = {
|
|
267
|
-
renderEnvArgs,
|
|
268
|
-
quoteEnvArgComposite,
|
|
269
|
-
hasEnvArgMarker,
|
|
270
|
-
isPinokioEnvArgKey,
|
|
271
|
-
formatEnvArgsPreview,
|
|
272
|
-
redactEnvArgs
|
|
273
|
-
}
|
package/kernel/api/uri/index.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
const Util = require('../../util')
|
|
2
|
-
|
|
3
|
-
const appendQueryParams = (uri, params) => {
|
|
4
|
-
if (!params || typeof params !== 'object' || Array.isArray(params)) {
|
|
5
|
-
return uri
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const entries = []
|
|
9
|
-
for (const [key, value] of Object.entries(params)) {
|
|
10
|
-
const values = Array.isArray(value) ? value : [value]
|
|
11
|
-
for (const item of values) {
|
|
12
|
-
if (item === undefined || item === null) {
|
|
13
|
-
continue
|
|
14
|
-
}
|
|
15
|
-
const serialized = typeof item === 'object' ? JSON.stringify(item) : String(item)
|
|
16
|
-
entries.push(`${encodeURIComponent(key)}=${encodeURIComponent(serialized)}`)
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (entries.length === 0) {
|
|
21
|
-
return uri
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const hashIndex = uri.indexOf('#')
|
|
25
|
-
const base = hashIndex === -1 ? uri : uri.slice(0, hashIndex)
|
|
26
|
-
const hash = hashIndex === -1 ? '' : uri.slice(hashIndex)
|
|
27
|
-
const separator = base.includes('?')
|
|
28
|
-
? (base.endsWith('?') || base.endsWith('&') ? '' : '&')
|
|
29
|
-
: '?'
|
|
30
|
-
|
|
31
|
-
return `${base}${separator}${entries.join('&')}${hash}`
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
class URI {
|
|
35
|
-
build(params = {}) {
|
|
36
|
-
const uri = typeof params.uri === 'string' ? params.uri.trim() : ''
|
|
37
|
-
if (!uri) {
|
|
38
|
-
throw new Error('uri.open requires params.uri')
|
|
39
|
-
}
|
|
40
|
-
return appendQueryParams(uri, params.params)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async open(req, ondata, kernel) {
|
|
44
|
-
const uri = this.build(req.params)
|
|
45
|
-
ondata({ raw: `\r\nopening uri: ${uri}\r\n` })
|
|
46
|
-
const result = await Util.openURI(uri)
|
|
47
|
-
return { uri, result }
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
module.exports = URI
|