pinokiod 7.2.18 → 7.3.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.
- package/Dockerfile +2 -0
- package/kernel/api/index.js +13 -179
- package/kernel/api/process/index.js +44 -99
- package/kernel/bin/conda-pins.js +53 -0
- package/kernel/bin/conda.js +35 -6
- package/kernel/bin/huggingface.js +1 -1
- package/kernel/bin/index.js +15 -2
- 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
package/kernel/plugin_sources.js
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
const fs = require("fs")
|
|
2
|
-
const path = require("path")
|
|
3
|
-
const { glob } = require("glob")
|
|
4
|
-
|
|
5
|
-
const LOCAL_RUN_PREFIX = "/run"
|
|
6
|
-
const LOCAL_ASSET_PREFIX = "/asset"
|
|
7
|
-
const SYSTEM_RUN_PREFIX = "/pinokio/run"
|
|
8
|
-
const SYSTEM_ASSET_PREFIX = "/pinokio/asset"
|
|
9
|
-
const LOCAL_PLUGIN_RUN_PREFIX = `${LOCAL_RUN_PREFIX}/plugin`
|
|
10
|
-
const LOCAL_PLUGIN_ASSET_PREFIX = `${LOCAL_ASSET_PREFIX}/plugin`
|
|
11
|
-
const SYSTEM_PLUGIN_RUN_PREFIX = `${SYSTEM_RUN_PREFIX}/plugin`
|
|
12
|
-
const SYSTEM_PLUGIN_ASSET_PREFIX = `${SYSTEM_ASSET_PREFIX}/plugin`
|
|
13
|
-
const ACTION_KEYS = new Set(["run", "install", "uninstall", "update"])
|
|
14
|
-
|
|
15
|
-
const toPathname = (value) => {
|
|
16
|
-
const raw = typeof value === "string" ? value.trim() : ""
|
|
17
|
-
if (!raw) return ""
|
|
18
|
-
try {
|
|
19
|
-
if (/^https?:\/\//i.test(raw)) return new URL(raw).pathname
|
|
20
|
-
if (raw.startsWith("/")) return new URL(`http://localhost${raw}`).pathname
|
|
21
|
-
} catch (_) {
|
|
22
|
-
}
|
|
23
|
-
return raw.split("?")[0].split("#")[0]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const normalizeSlashes = (value) => String(value || "").replace(/\\/g, "/").replace(/\/{2,}/g, "/")
|
|
27
|
-
|
|
28
|
-
const systemRoot = (kernel) => {
|
|
29
|
-
if (kernel && typeof kernel.systemPath === "function") {
|
|
30
|
-
return kernel.systemPath()
|
|
31
|
-
}
|
|
32
|
-
return path.resolve(__dirname, "..", "system")
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const systemPluginRoot = (kernel) => {
|
|
36
|
-
if (kernel && typeof kernel.systemPath === "function") {
|
|
37
|
-
return kernel.systemPath("plugin")
|
|
38
|
-
}
|
|
39
|
-
return path.resolve(__dirname, "..", "system", "plugin")
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const isSystemRunPath = (value) => toPathname(value).startsWith(`${SYSTEM_RUN_PREFIX}/`)
|
|
43
|
-
const isLocalRunPath = (value) => toPathname(value).startsWith(`${LOCAL_RUN_PREFIX}/`)
|
|
44
|
-
const isRunPath = (value) => isLocalRunPath(value) || isSystemRunPath(value)
|
|
45
|
-
const isSystemPluginPath = (value) => normalizeSlashes(value).startsWith(`${SYSTEM_PLUGIN_RUN_PREFIX}/`)
|
|
46
|
-
const isLegacyPluginCodePath = (value) => {
|
|
47
|
-
const normalized = normalizeSlashes(value).replace(/^\/+/, "")
|
|
48
|
-
return normalized.startsWith("plugin/code/") || normalized.startsWith("code/")
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const normalizePluginPath = (value) => {
|
|
52
|
-
let normalized = toPathname(value)
|
|
53
|
-
if (!normalized) return ""
|
|
54
|
-
normalized = normalizeSlashes(normalized)
|
|
55
|
-
if (!normalized.startsWith(`${SYSTEM_RUN_PREFIX}/`)) {
|
|
56
|
-
normalized = normalized.replace(/^\/run(?=\/)/, "")
|
|
57
|
-
}
|
|
58
|
-
if (!normalized.startsWith("/")) {
|
|
59
|
-
normalized = `/${normalized}`
|
|
60
|
-
}
|
|
61
|
-
normalized = normalized.replace(/\/+$/, "")
|
|
62
|
-
if (!normalized.endsWith("/pinokio.js")) {
|
|
63
|
-
normalized = `${normalized}/pinokio.js`
|
|
64
|
-
}
|
|
65
|
-
return normalized
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const pluginSelectionMatches = (src, selectedValue) => {
|
|
69
|
-
const selectedPlugin = normalizeSlashes(typeof selectedValue === "string" ? selectedValue.trim() : "")
|
|
70
|
-
if (!selectedPlugin || !src) return false
|
|
71
|
-
const selectedRunPath = selectedPlugin.startsWith(`${SYSTEM_RUN_PREFIX}/`)
|
|
72
|
-
? selectedPlugin
|
|
73
|
-
: `${LOCAL_RUN_PREFIX}${selectedPlugin}`
|
|
74
|
-
return src === selectedPlugin || src.startsWith(selectedRunPath)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const resolveRunPath = (kernel, value) => {
|
|
78
|
-
const pathname = toPathname(value)
|
|
79
|
-
if (isSystemRunPath(pathname)) {
|
|
80
|
-
const parts = pathname.split("/").filter(Boolean).slice(2)
|
|
81
|
-
return kernel.systemPath(...parts)
|
|
82
|
-
}
|
|
83
|
-
if (isLocalRunPath(pathname)) {
|
|
84
|
-
const parts = pathname.split("/").filter(Boolean).slice(1)
|
|
85
|
-
return kernel.path(...parts)
|
|
86
|
-
}
|
|
87
|
-
return ""
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const resolvePinokioPath = (kernel, value) => {
|
|
91
|
-
const runPath = resolveRunPath(kernel, value)
|
|
92
|
-
if (runPath) return runPath
|
|
93
|
-
const pathname = toPathname(value)
|
|
94
|
-
return pathname ? kernel.path(pathname.replace(/^\/+/, "")) : ""
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const systemRelativeFromPluginPath = (normalizedPath) => {
|
|
98
|
-
return normalizeSlashes(normalizedPath).replace(/^\/pinokio\/run\/+/, "")
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const pluginPathToAbsolute = (kernel, normalizedPath) => {
|
|
102
|
-
if (isSystemPluginPath(normalizedPath)) {
|
|
103
|
-
return kernel.systemPath(systemRelativeFromPluginPath(normalizedPath))
|
|
104
|
-
}
|
|
105
|
-
return kernel.path(normalizeSlashes(normalizedPath).replace(/^\/+/, ""))
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const pluginRunHrefForPath = (normalizedPath) => {
|
|
109
|
-
if (typeof normalizedPath !== "string" || !normalizedPath) return ""
|
|
110
|
-
if (isSystemPluginPath(normalizedPath)) return normalizedPath
|
|
111
|
-
return `${LOCAL_RUN_PREFIX}${normalizedPath}`
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const pluginAssetHrefForIcon = (normalizedPath, icon) => {
|
|
115
|
-
const trimmedIcon = typeof icon === "string" ? icon.trim() : ""
|
|
116
|
-
if (!trimmedIcon) return ""
|
|
117
|
-
if (isSystemPluginPath(normalizedPath)) {
|
|
118
|
-
const relativeDir = path.posix.dirname(systemRelativeFromPluginPath(normalizedPath))
|
|
119
|
-
return `${SYSTEM_ASSET_PREFIX}/${relativeDir}/${trimmedIcon}`
|
|
120
|
-
}
|
|
121
|
-
if (normalizeSlashes(normalizedPath).startsWith("/plugin/")) {
|
|
122
|
-
const relativeDir = path.posix.dirname(normalizeSlashes(normalizedPath).slice(1))
|
|
123
|
-
return `${LOCAL_ASSET_PREFIX}/${relativeDir}/${trimmedIcon}`
|
|
124
|
-
}
|
|
125
|
-
return ""
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const isAction = (value) => Array.isArray(value) || typeof value === "function"
|
|
129
|
-
const hasActionFunction = (config, key) => ACTION_KEYS.has(key) && typeof config[key] === "function"
|
|
130
|
-
const isPlainObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value)
|
|
131
|
-
const declaredPluginPath = (config) => typeof config.path === "string" ? config.path.trim() : ""
|
|
132
|
-
const hasInvalidTopLevelFunction = (config) => {
|
|
133
|
-
return Object.keys(config).some((key) => typeof config[key] === "function" && !hasActionFunction(config, key))
|
|
134
|
-
}
|
|
135
|
-
const hasInvalidAction = (config) => {
|
|
136
|
-
return Array.from(ACTION_KEYS).some((key) => key in config && !isAction(config[key]))
|
|
137
|
-
}
|
|
138
|
-
const isValidPluginConfig = (config, options = {}) => {
|
|
139
|
-
if (!isPlainObject(config) || !isAction(config.run)) {
|
|
140
|
-
return false
|
|
141
|
-
}
|
|
142
|
-
if (hasInvalidTopLevelFunction(config) || hasInvalidAction(config)) {
|
|
143
|
-
return false
|
|
144
|
-
}
|
|
145
|
-
if (options.standalone && declaredPluginPath(config) !== "plugin") {
|
|
146
|
-
return false
|
|
147
|
-
}
|
|
148
|
-
return true
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const normalizeLauncherTool = (toolValue) => {
|
|
152
|
-
let normalizedTool = typeof toolValue === "string" ? toolValue.trim() : ""
|
|
153
|
-
normalizedTool = normalizedTool.replace(/^https?:\/\/[^/]+/i, "")
|
|
154
|
-
normalizedTool = normalizedTool.replace(/^\/+|\/+$/g, "")
|
|
155
|
-
if (!normalizedTool || normalizedTool.includes("..") || !/^[A-Za-z0-9._/-]+$/.test(normalizedTool)) {
|
|
156
|
-
const error = new Error("Invalid plugin.")
|
|
157
|
-
error.status = 400
|
|
158
|
-
throw error
|
|
159
|
-
}
|
|
160
|
-
if (!normalizedTool.startsWith("pinokio/run/")) {
|
|
161
|
-
normalizedTool = normalizedTool.replace(/^run\//, "")
|
|
162
|
-
}
|
|
163
|
-
if (isLegacyPluginCodePath(normalizedTool)) {
|
|
164
|
-
const error = new Error("The managed plugin/code path is no longer used.")
|
|
165
|
-
error.status = 400
|
|
166
|
-
throw error
|
|
167
|
-
}
|
|
168
|
-
return normalizedTool
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const resolveLauncherPluginHref = (toolValue) => {
|
|
172
|
-
const normalizedTool = normalizeLauncherTool(toolValue)
|
|
173
|
-
if (normalizedTool.startsWith("pinokio/run/")) {
|
|
174
|
-
const scriptPath = normalizedTool.endsWith(".js")
|
|
175
|
-
? normalizedTool
|
|
176
|
-
: `${normalizedTool}/pinokio.js`
|
|
177
|
-
return `/${scriptPath}`
|
|
178
|
-
}
|
|
179
|
-
if (normalizedTool.startsWith("plugin/") || normalizedTool.startsWith("api/")) {
|
|
180
|
-
const scriptPath = normalizedTool.endsWith(".js")
|
|
181
|
-
? normalizedTool
|
|
182
|
-
: `${normalizedTool}/pinokio.js`
|
|
183
|
-
return `${LOCAL_RUN_PREFIX}/${scriptPath}`
|
|
184
|
-
}
|
|
185
|
-
return `${LOCAL_PLUGIN_RUN_PREFIX}/${normalizedTool}/pinokio.js`
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const resolveLauncherPluginSelection = (toolValue) => {
|
|
189
|
-
const href = resolveLauncherPluginHref(toolValue)
|
|
190
|
-
if (href.startsWith(`${LOCAL_RUN_PREFIX}/`)) {
|
|
191
|
-
return href.slice(LOCAL_RUN_PREFIX.length)
|
|
192
|
-
}
|
|
193
|
-
return href
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const normalizeLauncherSuccessPlugin = (successUrl, toolValue) => {
|
|
197
|
-
if (typeof successUrl !== "string" || typeof toolValue !== "string" || !toolValue.trim()) {
|
|
198
|
-
return successUrl
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
try {
|
|
202
|
-
const parsed = new URL(successUrl, "http://localhost")
|
|
203
|
-
if (!parsed.searchParams.has("plugin")) {
|
|
204
|
-
return successUrl
|
|
205
|
-
}
|
|
206
|
-
parsed.searchParams.set("plugin", resolveLauncherPluginSelection(toolValue))
|
|
207
|
-
return `${parsed.pathname}${parsed.search}${parsed.hash}`
|
|
208
|
-
} catch (_) {
|
|
209
|
-
return successUrl
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const loadPluginsFromRoot = async ({ kernel, root, runPrefix, assetPrefix, source, ignore = [], standalone = false }) => {
|
|
214
|
-
const exists = await fs.promises.stat(root).then((stat) => stat.isDirectory()).catch(() => false)
|
|
215
|
-
if (!exists) return []
|
|
216
|
-
|
|
217
|
-
const pluginPaths = await glob("**/pinokio.js", { cwd: root, ignore })
|
|
218
|
-
const plugins = []
|
|
219
|
-
for (const pluginPath of pluginPaths) {
|
|
220
|
-
const normalizedPluginPath = normalizeSlashes(pluginPath)
|
|
221
|
-
const config = await kernel.require(path.resolve(root, pluginPath))
|
|
222
|
-
if (!isValidPluginConfig(config, { standalone })) continue
|
|
223
|
-
|
|
224
|
-
const cwd = normalizedPluginPath.split("/").slice(0, -1).join("/")
|
|
225
|
-
const href = `${runPrefix}/${normalizedPluginPath}`
|
|
226
|
-
const image = config.icon ? `${assetPrefix}/${cwd}/${config.icon}` : config.image
|
|
227
|
-
plugins.push({
|
|
228
|
-
...config,
|
|
229
|
-
href,
|
|
230
|
-
src: href,
|
|
231
|
-
image,
|
|
232
|
-
source,
|
|
233
|
-
system: source === "system",
|
|
234
|
-
})
|
|
235
|
-
}
|
|
236
|
-
return plugins
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const loadPluginMenu = async (kernel) => {
|
|
240
|
-
const systemPlugins = await loadPluginsFromRoot({
|
|
241
|
-
kernel,
|
|
242
|
-
root: systemPluginRoot(kernel),
|
|
243
|
-
runPrefix: SYSTEM_PLUGIN_RUN_PREFIX,
|
|
244
|
-
assetPrefix: SYSTEM_PLUGIN_ASSET_PREFIX,
|
|
245
|
-
source: "system",
|
|
246
|
-
})
|
|
247
|
-
const localPlugins = await loadPluginsFromRoot({
|
|
248
|
-
kernel,
|
|
249
|
-
root: path.resolve(kernel.homedir, "plugin"),
|
|
250
|
-
runPrefix: LOCAL_PLUGIN_RUN_PREFIX,
|
|
251
|
-
assetPrefix: LOCAL_PLUGIN_ASSET_PREFIX,
|
|
252
|
-
source: "local",
|
|
253
|
-
ignore: ["code/**"],
|
|
254
|
-
standalone: true,
|
|
255
|
-
})
|
|
256
|
-
return systemPlugins.concat(localPlugins)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
module.exports = {
|
|
260
|
-
LOCAL_RUN_PREFIX,
|
|
261
|
-
LOCAL_ASSET_PREFIX,
|
|
262
|
-
SYSTEM_RUN_PREFIX,
|
|
263
|
-
SYSTEM_ASSET_PREFIX,
|
|
264
|
-
LOCAL_PLUGIN_RUN_PREFIX,
|
|
265
|
-
SYSTEM_PLUGIN_RUN_PREFIX,
|
|
266
|
-
SYSTEM_PLUGIN_ASSET_PREFIX,
|
|
267
|
-
systemRoot,
|
|
268
|
-
systemPluginRoot,
|
|
269
|
-
toPathname,
|
|
270
|
-
isSystemRunPath,
|
|
271
|
-
isLocalRunPath,
|
|
272
|
-
isRunPath,
|
|
273
|
-
isSystemPluginPath,
|
|
274
|
-
isLegacyPluginCodePath,
|
|
275
|
-
normalizePluginPath,
|
|
276
|
-
pluginSelectionMatches,
|
|
277
|
-
resolveRunPath,
|
|
278
|
-
resolvePinokioPath,
|
|
279
|
-
pluginPathToAbsolute,
|
|
280
|
-
pluginRunHrefForPath,
|
|
281
|
-
pluginAssetHrefForIcon,
|
|
282
|
-
resolveLauncherPluginHref,
|
|
283
|
-
resolveLauncherPluginSelection,
|
|
284
|
-
normalizeLauncherSuccessPlugin,
|
|
285
|
-
loadPluginMenu,
|
|
286
|
-
ACTION_KEYS,
|
|
287
|
-
isAction,
|
|
288
|
-
isValidPluginConfig,
|
|
289
|
-
}
|
package/kernel/watch/context.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const { watchFs } = require("./drivers/fs")
|
|
3
|
-
const { poll } = require("./drivers/poll")
|
|
4
|
-
|
|
5
|
-
class WatchContext {
|
|
6
|
-
constructor(options = {}) {
|
|
7
|
-
this.kernel = options.kernel
|
|
8
|
-
this.manager = options.manager
|
|
9
|
-
this.id = options.id
|
|
10
|
-
this.cwd = path.resolve(options.cwd)
|
|
11
|
-
this.dirname = path.resolve(options.dirname || options.cwd)
|
|
12
|
-
this.request = options.request
|
|
13
|
-
this.script = options.script
|
|
14
|
-
this.declaration = options.declaration
|
|
15
|
-
this.input = options.input || {}
|
|
16
|
-
this.args = options.args || this.input
|
|
17
|
-
this.watch = {
|
|
18
|
-
fs: (targetPath, callback, watchOptions = {}) => {
|
|
19
|
-
return watchFs(this.resolve(targetPath), callback, {
|
|
20
|
-
...watchOptions,
|
|
21
|
-
onError: watchOptions.onError || ((error) => {
|
|
22
|
-
console.warn("[watch.fs]", error && error.message ? error.message : error)
|
|
23
|
-
})
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
resolve(targetPath) {
|
|
30
|
-
return this.kernel.api.resolvePath(this.cwd, String(targetPath || "."))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
resolveModule(targetPath) {
|
|
34
|
-
return this.kernel.api.resolvePath(this.dirname, String(targetPath || "."))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
poll(interval, callback, options = {}) {
|
|
38
|
-
return poll(interval, callback, options)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
module.exports = WatchContext
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
const fs = require("fs")
|
|
2
|
-
const path = require("path")
|
|
3
|
-
const ParcelWatcher = require("@parcel/watcher")
|
|
4
|
-
|
|
5
|
-
const DEFAULT_IGNORE = [
|
|
6
|
-
"**/.git/**",
|
|
7
|
-
"**/node_modules/**",
|
|
8
|
-
"**/__pycache__/**",
|
|
9
|
-
"**/.venv/**",
|
|
10
|
-
"**/venv/**",
|
|
11
|
-
"**/env/**"
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
function isInside(candidate, parent) {
|
|
15
|
-
const relative = path.relative(parent, candidate)
|
|
16
|
-
return relative === "" || (!!relative && !relative.startsWith("..") && !path.isAbsolute(relative))
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async function nearestExistingDirectory(targetPath) {
|
|
20
|
-
let current = path.resolve(targetPath)
|
|
21
|
-
while (current && current !== path.dirname(current)) {
|
|
22
|
-
const stats = await fs.promises.stat(current).catch(() => null)
|
|
23
|
-
if (stats && stats.isDirectory()) {
|
|
24
|
-
return current
|
|
25
|
-
}
|
|
26
|
-
current = path.dirname(current)
|
|
27
|
-
}
|
|
28
|
-
return current || path.parse(path.resolve(targetPath)).root
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function watchFs(targetPath, callback, options = {}) {
|
|
32
|
-
const resolvedTarget = path.resolve(targetPath)
|
|
33
|
-
const targetStats = await fs.promises.stat(resolvedTarget).catch(() => null)
|
|
34
|
-
const watchRoot = targetStats && targetStats.isDirectory()
|
|
35
|
-
? resolvedTarget
|
|
36
|
-
: await nearestExistingDirectory(resolvedTarget)
|
|
37
|
-
const filterToTarget = watchRoot !== resolvedTarget
|
|
38
|
-
|
|
39
|
-
const subscription = await ParcelWatcher.subscribe(
|
|
40
|
-
watchRoot,
|
|
41
|
-
(error, events) => {
|
|
42
|
-
if (error) {
|
|
43
|
-
if (typeof options.onError === "function") {
|
|
44
|
-
options.onError(error)
|
|
45
|
-
}
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
const normalizedEvents = Array.isArray(events) ? events : []
|
|
49
|
-
const filteredEvents = filterToTarget
|
|
50
|
-
? normalizedEvents.filter((event) => event && event.path && isInside(path.resolve(event.path), resolvedTarget))
|
|
51
|
-
: normalizedEvents
|
|
52
|
-
if (filteredEvents.length === 0) {
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
callback(filteredEvents)
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
ignore: Array.isArray(options.ignore) ? options.ignore : DEFAULT_IGNORE
|
|
59
|
-
}
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
return async () => {
|
|
63
|
-
if (subscription && typeof subscription.unsubscribe === "function") {
|
|
64
|
-
await subscription.unsubscribe().catch(() => {})
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
module.exports = {
|
|
70
|
-
watchFs
|
|
71
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
function poll(interval, callback, options = {}) {
|
|
2
|
-
const delay = Math.max(100, Number(interval || options.interval || 1000))
|
|
3
|
-
let stopped = false
|
|
4
|
-
let running = false
|
|
5
|
-
|
|
6
|
-
const tick = async () => {
|
|
7
|
-
if (stopped || running) return
|
|
8
|
-
running = true
|
|
9
|
-
try {
|
|
10
|
-
await callback()
|
|
11
|
-
} catch (error) {
|
|
12
|
-
if (typeof options.onError === "function") {
|
|
13
|
-
options.onError(error)
|
|
14
|
-
}
|
|
15
|
-
} finally {
|
|
16
|
-
running = false
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (options.immediate !== false) {
|
|
21
|
-
setTimeout(tick, 0)
|
|
22
|
-
}
|
|
23
|
-
const timer = setInterval(tick, delay)
|
|
24
|
-
|
|
25
|
-
return async () => {
|
|
26
|
-
stopped = true
|
|
27
|
-
clearInterval(timer)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
module.exports = {
|
|
32
|
-
poll
|
|
33
|
-
}
|
package/kernel/watch/index.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const WatchContext = require("./context")
|
|
3
|
-
|
|
4
|
-
class WatchManager {
|
|
5
|
-
constructor(kernel) {
|
|
6
|
-
this.kernel = kernel
|
|
7
|
-
this.handlers = new Map()
|
|
8
|
-
this.sessions = new Map()
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
registerHandler(name, handler) {
|
|
12
|
-
const normalized = typeof name === "string" ? name.trim() : ""
|
|
13
|
-
if (!normalized) {
|
|
14
|
-
throw new Error("watch handler name is required")
|
|
15
|
-
}
|
|
16
|
-
this.handlers.set(normalized, handler)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
hasHandler(script, handlerName) {
|
|
20
|
-
const watches = script && Array.isArray(script.watch) ? script.watch : []
|
|
21
|
-
return watches.some((watch) => {
|
|
22
|
-
const resolved = this.resolveHandlerMethod(watch)
|
|
23
|
-
return resolved.handlerName === handlerName
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
resolveHandlerMethod(declaration) {
|
|
28
|
-
if (!declaration || typeof declaration !== "object") {
|
|
29
|
-
return { handlerName: "", methodName: "" }
|
|
30
|
-
}
|
|
31
|
-
const method = typeof declaration.method === "string" ? declaration.method.trim() : ""
|
|
32
|
-
if (declaration.handler) {
|
|
33
|
-
return {
|
|
34
|
-
handlerName: String(declaration.handler).trim(),
|
|
35
|
-
methodName: method
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (!declaration.uri && method.includes(".")) {
|
|
39
|
-
const parts = method.split(".")
|
|
40
|
-
return {
|
|
41
|
-
handlerName: parts.slice(0, -1).join(".").trim(),
|
|
42
|
-
methodName: parts[parts.length - 1].trim()
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
handlerName: "",
|
|
47
|
-
methodName: method
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
renderDeclaration(raw, memory) {
|
|
52
|
-
let rendered = raw
|
|
53
|
-
let pass = 0
|
|
54
|
-
while (true) {
|
|
55
|
-
rendered = this.kernel.template.render(rendered, memory)
|
|
56
|
-
if (this.kernel.template.istemplate(rendered)) {
|
|
57
|
-
pass += 1
|
|
58
|
-
if (pass >= 4) break
|
|
59
|
-
} else {
|
|
60
|
-
break
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return this.kernel.template.flatten(rendered)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
buildMemory({ request, script, cwd, dirname, input, args }) {
|
|
67
|
-
return {
|
|
68
|
-
script: this.kernel.script,
|
|
69
|
-
input,
|
|
70
|
-
args,
|
|
71
|
-
cwd,
|
|
72
|
-
dirname,
|
|
73
|
-
uri: request.uri,
|
|
74
|
-
self: script,
|
|
75
|
-
kernel: this.kernel,
|
|
76
|
-
...this.kernel.vars
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async resolveExternalHandler(ctx, uri) {
|
|
81
|
-
const modpath = ctx.resolveModule(uri)
|
|
82
|
-
const loaded = await this.kernel.loader.load(modpath)
|
|
83
|
-
let handler = loaded && loaded.resolved
|
|
84
|
-
if (typeof handler === "function") {
|
|
85
|
-
handler = new handler()
|
|
86
|
-
}
|
|
87
|
-
return handler
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async startForScript(options = {}) {
|
|
91
|
-
const script = options.script
|
|
92
|
-
const declarations = script && Array.isArray(script.watch) ? script.watch : []
|
|
93
|
-
if (declarations.length === 0) {
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const id = options.id
|
|
98
|
-
if (!id) {
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
await this.stop(id)
|
|
102
|
-
|
|
103
|
-
const input = options.input || {}
|
|
104
|
-
const args = options.args || input
|
|
105
|
-
const cwd = path.resolve(options.cwd)
|
|
106
|
-
const dirname = path.resolve(options.dirname || options.cwd)
|
|
107
|
-
const memory = this.buildMemory({
|
|
108
|
-
request: options.request || {},
|
|
109
|
-
script,
|
|
110
|
-
cwd,
|
|
111
|
-
dirname,
|
|
112
|
-
input,
|
|
113
|
-
args
|
|
114
|
-
})
|
|
115
|
-
const disposers = []
|
|
116
|
-
|
|
117
|
-
for (const rawDeclaration of declarations) {
|
|
118
|
-
if (!rawDeclaration || typeof rawDeclaration !== "object") {
|
|
119
|
-
continue
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
const declaration = this.renderDeclaration(rawDeclaration, memory)
|
|
123
|
-
const ctx = new WatchContext({
|
|
124
|
-
kernel: this.kernel,
|
|
125
|
-
manager: this,
|
|
126
|
-
id,
|
|
127
|
-
cwd,
|
|
128
|
-
dirname,
|
|
129
|
-
request: options.request,
|
|
130
|
-
script,
|
|
131
|
-
declaration,
|
|
132
|
-
input,
|
|
133
|
-
args
|
|
134
|
-
})
|
|
135
|
-
const { handlerName, methodName } = this.resolveHandlerMethod(declaration)
|
|
136
|
-
let handler = null
|
|
137
|
-
if (handlerName) {
|
|
138
|
-
handler = this.handlers.get(handlerName)
|
|
139
|
-
} else if (declaration.uri) {
|
|
140
|
-
handler = await this.resolveExternalHandler(ctx, declaration.uri)
|
|
141
|
-
}
|
|
142
|
-
if (!handler || !methodName || typeof handler[methodName] !== "function") {
|
|
143
|
-
console.warn("[watch] handler not found", declaration)
|
|
144
|
-
continue
|
|
145
|
-
}
|
|
146
|
-
const cleanup = await handler[methodName](ctx, declaration.params || {})
|
|
147
|
-
if (cleanup) {
|
|
148
|
-
disposers.push(cleanup)
|
|
149
|
-
}
|
|
150
|
-
} catch (error) {
|
|
151
|
-
console.warn("[watch] failed to start", error && error.message ? error.message : error)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (disposers.length > 0) {
|
|
156
|
-
this.sessions.set(id, disposers)
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async stop(id) {
|
|
161
|
-
const normalized = typeof id === "string" ? id : ""
|
|
162
|
-
if (!normalized || !this.sessions.has(normalized)) {
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
const disposers = this.sessions.get(normalized) || []
|
|
166
|
-
this.sessions.delete(normalized)
|
|
167
|
-
for (const disposer of disposers.reverse()) {
|
|
168
|
-
try {
|
|
169
|
-
if (typeof disposer === "function") {
|
|
170
|
-
await disposer()
|
|
171
|
-
} else if (disposer && typeof disposer.stop === "function") {
|
|
172
|
-
await disposer.stop()
|
|
173
|
-
} else if (disposer && typeof disposer.dispose === "function") {
|
|
174
|
-
await disposer.dispose()
|
|
175
|
-
} else if (disposer && typeof disposer.unsubscribe === "function") {
|
|
176
|
-
await disposer.unsubscribe()
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.warn("[watch] cleanup failed", error && error.message ? error.message : error)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
module.exports = WatchManager
|
package/server/features/index.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const { createNoteService } = require("./service")
|
|
2
|
-
const registerNoteRoutes = require("./routes")
|
|
3
|
-
const NoteWatcher = require("./watcher")
|
|
4
|
-
|
|
5
|
-
function createNoteFeature(options = {}) {
|
|
6
|
-
const { app, kernel } = options
|
|
7
|
-
if (!app) {
|
|
8
|
-
throw new Error("app is required")
|
|
9
|
-
}
|
|
10
|
-
if (!kernel) {
|
|
11
|
-
throw new Error("kernel is required")
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const service = createNoteService({
|
|
15
|
-
kernel,
|
|
16
|
-
taskWorkspaceLinks: options.taskWorkspaceLinks
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
registerNoteRoutes(app, {
|
|
20
|
-
...options,
|
|
21
|
-
notes: service
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
if (kernel.watch && typeof kernel.watch.registerHandler === "function") {
|
|
25
|
-
kernel.watch.registerHandler("note", new NoteWatcher({ notes: service }))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
service,
|
|
30
|
-
async start() {
|
|
31
|
-
await service.start()
|
|
32
|
-
},
|
|
33
|
-
async stop() {
|
|
34
|
-
await service.stop()
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = {
|
|
40
|
-
createNoteFeature
|
|
41
|
-
}
|