pinokiod 7.2.17 → 7.2.18

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 (51) hide show
  1. package/kernel/agent_instructions.js +166 -0
  2. package/kernel/api/index.js +137 -12
  3. package/kernel/bin/huggingface.js +1 -1
  4. package/kernel/environment.js +23 -9
  5. package/kernel/plugin_sources.js +57 -4
  6. package/kernel/prototype.js +4 -0
  7. package/kernel/shell.js +2 -0
  8. package/kernel/watch/index.js +31 -4
  9. package/package.json +1 -1
  10. package/server/features/index.js +4 -4
  11. package/server/features/{drafts → notes}/index.js +9 -9
  12. package/server/features/{drafts → notes}/parser.js +12 -7
  13. package/server/features/notes/public/notes.css +955 -0
  14. package/server/features/notes/public/notes.js +1149 -0
  15. package/server/features/{drafts → notes}/registry_import.js +22 -22
  16. package/server/features/notes/routes.js +156 -0
  17. package/server/features/notes/service.js +326 -0
  18. package/server/features/{drafts → notes}/watcher.js +14 -16
  19. package/server/index.js +61 -30
  20. package/server/lib/content_validation.js +19 -8
  21. package/server/lib/workspace_catalog.js +18 -18
  22. package/server/public/task-launcher.css +11 -3
  23. package/server/public/tasker.css +336 -0
  24. package/server/public/tasker.js +407 -0
  25. package/server/views/d.ejs +33 -2
  26. package/server/views/partials/menu.ejs +1 -1
  27. package/server/views/partials/workspace_row.ejs +11 -11
  28. package/server/views/pre.ejs +1 -1
  29. package/server/views/task_launch.ejs +10 -10
  30. package/server/views/tasker.ejs +40 -0
  31. package/server/views/terminal.ejs +15 -6
  32. package/server/views/terminals.ejs +0 -1
  33. package/server/views/workspaces.ejs +2 -1
  34. package/system/plugin/antigravity/pinokio.js +2 -4
  35. package/system/plugin/claude/pinokio.js +2 -4
  36. package/system/plugin/claude-auto/pinokio.js +2 -4
  37. package/system/plugin/claude-desktop/pinokio.js +2 -4
  38. package/system/plugin/codex/pinokio.js +2 -4
  39. package/system/plugin/codex-auto/pinokio.js +2 -4
  40. package/system/plugin/codex-desktop/pinokio.js +2 -4
  41. package/system/plugin/crush/pinokio.js +2 -4
  42. package/system/plugin/cursor/pinokio.js +2 -4
  43. package/system/plugin/gemini/pinokio.js +2 -4
  44. package/system/plugin/gemini-auto/pinokio.js +2 -4
  45. package/system/plugin/qwen/pinokio.js +2 -4
  46. package/system/plugin/vscode/pinokio.js +2 -4
  47. package/system/plugin/windsurf/pinokio.js +2 -4
  48. package/test/plugin-sources.test.js +45 -0
  49. package/server/features/drafts/public/drafts.js +0 -1504
  50. package/server/features/drafts/routes.js +0 -68
  51. package/server/features/drafts/service.js +0 -261
@@ -1,68 +0,0 @@
1
- const express = require("express")
2
- const path = require("path")
3
- const registerDraftImportRoutes = require("./registry_import")
4
-
5
- function asyncHandler(fn) {
6
- return (req, res, next) => {
7
- Promise.resolve(fn(req, res, next)).catch(next)
8
- }
9
- }
10
-
11
- function registerDraftRoutes(app, options = {}) {
12
- const drafts = options.drafts
13
- if (!drafts) {
14
- throw new Error("drafts is required")
15
- }
16
-
17
- const router = express.Router()
18
- router.get("/drafts", asyncHandler(async (req, res) => {
19
- const cwd = typeof req.query.cwd === "string" ? req.query.cwd : ""
20
- const items = await drafts.listPending({ cwd })
21
- res.json({
22
- ok: true,
23
- items
24
- })
25
- }))
26
-
27
- router.post("/drafts/:id/dismiss", asyncHandler(async (req, res) => {
28
- const ok = await drafts.dismiss(req.params.id, req.body && req.body.revision)
29
- res.json({ ok })
30
- }))
31
-
32
- router.get("/drafts/:id/media/:index", asyncHandler(async (req, res) => {
33
- const item = typeof drafts.getPendingById === "function"
34
- ? await drafts.getPendingById(req.params.id)
35
- : null
36
- if (!item) {
37
- res.status(404).send("Draft not found")
38
- return
39
- }
40
- const index = Number(req.params.index)
41
- const media = Array.isArray(item.media) && Number.isInteger(index)
42
- ? item.media[index]
43
- : null
44
- if (!media || !media.exists || !media.path) {
45
- res.status(404).send("Media not found")
46
- return
47
- }
48
- const filePath = path.resolve(media.path)
49
- const basePath = path.resolve(item.resultDir)
50
- const relative = path.relative(basePath, filePath)
51
- if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
52
- res.status(403).send("Media path is outside the draft")
53
- return
54
- }
55
- res.setHeader("Cache-Control", "no-store")
56
- res.sendFile(filePath)
57
- }))
58
-
59
- router.get("/drafts.js", (req, res) => {
60
- res.setHeader("Cache-Control", "no-store")
61
- res.sendFile(path.resolve(__dirname, "public", "drafts.js"))
62
- })
63
-
64
- app.use(router)
65
- registerDraftImportRoutes(app, options)
66
- }
67
-
68
- module.exports = registerDraftRoutes
@@ -1,261 +0,0 @@
1
- const fs = require("fs")
2
- const path = require("path")
3
- const crypto = require("crypto")
4
- const {
5
- RESULT_RELATIVE_DIR,
6
- POST_FILENAME,
7
- DEFAULT_READY_FILENAME,
8
- buildExcerpt,
9
- describeMediaRefs,
10
- extractTitle,
11
- parseDraftMetadata
12
- } = require("./parser")
13
-
14
- const STATE_FILENAME = "drafts.json"
15
- const MAX_PREVIEW_BYTES = 256 * 1024
16
-
17
- function createHash(value) {
18
- return crypto.createHash("sha256").update(String(value)).digest("hex").slice(0, 24)
19
- }
20
-
21
- function dismissalKey(id, revision) {
22
- const normalizedId = typeof id === "string" ? id.trim() : ""
23
- const normalizedRevision = typeof revision === "string" ? revision.trim() : ""
24
- return normalizedRevision ? `${normalizedId}:${normalizedRevision}` : normalizedId
25
- }
26
-
27
- function clonePlainObject(value) {
28
- if (!value || typeof value !== "object" || Array.isArray(value)) {
29
- return null
30
- }
31
- try {
32
- return JSON.parse(JSON.stringify(value))
33
- } catch (_) {
34
- return null
35
- }
36
- }
37
-
38
- function normalizeRelativePath(value, fallback) {
39
- const raw = String(value || fallback || "").trim().replace(/\\/g, "/")
40
- if (raw.startsWith("/") || /^[a-zA-Z]:/.test(raw)) {
41
- return fallback
42
- }
43
- const normalized = path.posix.normalize(raw)
44
- if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../") || normalized.includes("/../")) {
45
- return fallback
46
- }
47
- return normalized
48
- }
49
-
50
- function normalizeDraftConfig(config = {}) {
51
- const params = config && typeof config === "object" ? config : {}
52
- return {
53
- path: normalizeRelativePath(params.path, RESULT_RELATIVE_DIR),
54
- content: normalizeRelativePath(params.content || params.post, POST_FILENAME),
55
- ready: normalizeRelativePath(params.ready, DEFAULT_READY_FILENAME),
56
- description: typeof params.description === "string" ? params.description.trim() : "",
57
- publish: clonePlainObject(params.publish)
58
- }
59
- }
60
-
61
- function createDraftService({ kernel, taskWorkspaceLinks } = {}) {
62
- if (!kernel) {
63
- throw new Error("kernel is required")
64
- }
65
-
66
- const statePath = () => path.resolve(kernel.path("tasks"), STATE_FILENAME)
67
- const resultsByWorkspace = new Map()
68
- const dismissedIds = new Set()
69
- let started = false
70
- let stateLoaded = false
71
-
72
- async function ensureStateLoaded() {
73
- if (stateLoaded) return
74
- stateLoaded = true
75
- try {
76
- const raw = await fs.promises.readFile(statePath(), "utf8")
77
- const parsed = JSON.parse(raw)
78
- if (parsed && Array.isArray(parsed.dismissed)) {
79
- parsed.dismissed.forEach((id) => {
80
- if (typeof id === "string" && id.trim()) {
81
- dismissedIds.add(id.trim())
82
- }
83
- })
84
- }
85
- } catch (_) {
86
- }
87
- }
88
-
89
- async function saveState() {
90
- await fs.promises.mkdir(path.dirname(statePath()), { recursive: true })
91
- const payload = {
92
- version: 1,
93
- dismissed: Array.from(dismissedIds).slice(-500)
94
- }
95
- await fs.promises.writeFile(statePath(), JSON.stringify(payload, null, 2))
96
- }
97
-
98
- async function readMarkdownPreview(postPath) {
99
- const handle = await fs.promises.open(postPath, "r")
100
- try {
101
- const buffer = Buffer.alloc(MAX_PREVIEW_BYTES)
102
- const read = await handle.read(buffer, 0, MAX_PREVIEW_BYTES, 0)
103
- return buffer.slice(0, read.bytesRead).toString("utf8")
104
- } finally {
105
- await handle.close().catch(() => {})
106
- }
107
- }
108
-
109
- async function readDraftMetadata(metadataPath) {
110
- if (path.extname(metadataPath).toLowerCase() !== ".json") {
111
- return {}
112
- }
113
- const raw = await fs.promises.readFile(metadataPath, "utf8")
114
- return parseDraftMetadata(raw)
115
- }
116
-
117
- async function inspectWorkspace({ taskId, ref, cwd, draft } = {}) {
118
- await ensureStateLoaded()
119
- if (typeof cwd !== "string" || !cwd.trim()) {
120
- return null
121
- }
122
- const workspacePath = path.resolve(cwd.trim())
123
- const draftConfig = normalizeDraftConfig(draft)
124
- const resultDir = path.resolve(workspacePath, draftConfig.path)
125
- const readyPath = path.resolve(resultDir, draftConfig.ready)
126
- const postPath = path.resolve(resultDir, draftConfig.content)
127
- const readyStats = await fs.promises.stat(readyPath).catch(() => null)
128
- const postStats = await fs.promises.stat(postPath).catch(() => null)
129
- if (!readyStats || !readyStats.isFile() || !postStats || !postStats.isFile()) {
130
- resultsByWorkspace.delete(workspacePath)
131
- return null
132
- }
133
- let metadata = {}
134
- try {
135
- metadata = await readDraftMetadata(readyPath)
136
- } catch (_) {
137
- resultsByWorkspace.delete(workspacePath)
138
- return null
139
- }
140
-
141
- const markdown = await readMarkdownPreview(postPath)
142
- const workspaceName = path.basename(workspacePath)
143
- const media = await describeMediaRefs(markdown, resultDir)
144
- const updatedAtMs = Math.max(readyStats.mtimeMs || 0, postStats.mtimeMs || 0)
145
- const id = createHash(`${workspacePath}|${resultDir}|${postPath}|${readyPath}`)
146
- const mediaRevision = media
147
- .map((item) => `${item.ref}:${item.exists ? item.bytes : "missing"}:${item.mtimeMs || 0}`)
148
- .join("|")
149
- const revision = createHash(`${postStats.size}|${postStats.mtimeMs}|${readyStats.size}|${readyStats.mtimeMs}|${mediaRevision}`)
150
- const result = {
151
- id,
152
- revision,
153
- taskId,
154
- ref,
155
- cwd: workspacePath,
156
- workspaceName,
157
- title: metadata.title || extractTitle(markdown, workspaceName),
158
- markdown,
159
- excerpt: buildExcerpt(markdown),
160
- resultDir,
161
- postPath,
162
- contentPath: postPath,
163
- readyPath,
164
- metadataPath: readyPath,
165
- metadata,
166
- publish: draftConfig.publish,
167
- description: draftConfig.description,
168
- postBytes: postStats.size,
169
- media: media.map((item, index) => ({
170
- index,
171
- ref: item.ref,
172
- path: item.path,
173
- bytes: item.bytes,
174
- mtimeMs: item.mtimeMs,
175
- exists: item.exists,
176
- ext: path.extname(item.ref || "").toLowerCase()
177
- })),
178
- mediaCount: media.length,
179
- missingMediaCount: media.filter((item) => !item.exists).length,
180
- mediaBytes: media.reduce((total, item) => total + (Number.isFinite(item.bytes) ? item.bytes : 0), 0),
181
- updatedAt: new Date(updatedAtMs || Date.now()).toISOString()
182
- }
183
- resultsByWorkspace.set(workspacePath, result)
184
- return result
185
- }
186
-
187
- async function trackWorkspace({ taskId, ref, cwd } = {}) {
188
- let resolvedCwd = cwd
189
- if (!resolvedCwd && ref && taskWorkspaceLinks && typeof taskWorkspaceLinks.resolveWorkspaceRef === "function") {
190
- resolvedCwd = taskWorkspaceLinks.resolveWorkspaceRef(ref)
191
- }
192
- if (!resolvedCwd) {
193
- return null
194
- }
195
- return inspectWorkspace({ taskId, ref, cwd: resolvedCwd })
196
- }
197
-
198
- async function listPending(options = {}) {
199
- await ensureStateLoaded()
200
- const filterCwd = typeof options.cwd === "string" && options.cwd.trim()
201
- ? path.resolve(options.cwd.trim())
202
- : ""
203
- return Array.from(resultsByWorkspace.values())
204
- .filter((result) => !dismissedIds.has(dismissalKey(result.id, result.revision)) && !dismissedIds.has(result.id))
205
- .filter((result) => !filterCwd || result.cwd === filterCwd)
206
- .sort((a, b) => String(b.updatedAt).localeCompare(String(a.updatedAt)))
207
- }
208
-
209
- async function getPendingById(id) {
210
- await ensureStateLoaded()
211
- const normalizedId = typeof id === "string" ? id.trim() : ""
212
- if (!normalizedId) {
213
- return null
214
- }
215
- const result = Array.from(resultsByWorkspace.values()).find((item) => item.id === normalizedId) || null
216
- if (!result || dismissedIds.has(dismissalKey(result.id, result.revision)) || dismissedIds.has(result.id)) {
217
- return null
218
- }
219
- return result
220
- }
221
-
222
- async function dismiss(id, revision) {
223
- await ensureStateLoaded()
224
- const normalizedId = typeof id === "string" ? id.trim() : ""
225
- if (!normalizedId) {
226
- return false
227
- }
228
- dismissedIds.add(dismissalKey(normalizedId, revision))
229
- await saveState()
230
- return true
231
- }
232
-
233
- async function refreshLinkedWorkspaces() {
234
- await ensureStateLoaded()
235
- }
236
-
237
- async function start() {
238
- if (started) return
239
- started = true
240
- await ensureStateLoaded()
241
- }
242
-
243
- async function stop() {
244
- }
245
-
246
- return {
247
- RESULT_RELATIVE_DIR,
248
- dismiss,
249
- getPendingById,
250
- inspectWorkspace,
251
- listPending,
252
- refreshLinkedWorkspaces,
253
- start,
254
- stop,
255
- trackWorkspace
256
- }
257
- }
258
-
259
- module.exports = {
260
- createDraftService
261
- }