@brianli/kimaki 0.4.72-brianli.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/bin.js +2 -0
- package/dist/ai-tool-to-genai.js +233 -0
- package/dist/ai-tool-to-genai.test.js +267 -0
- package/dist/ai-tool.js +6 -0
- package/dist/bin.js +87 -0
- package/dist/bot-token.js +121 -0
- package/dist/bot-token.test.js +134 -0
- package/dist/channel-management.js +101 -0
- package/dist/cli-parsing.test.js +89 -0
- package/dist/cli.js +2529 -0
- package/dist/commands/abort.js +82 -0
- package/dist/commands/action-buttons.js +257 -0
- package/dist/commands/add-project.js +114 -0
- package/dist/commands/agent.js +291 -0
- package/dist/commands/ask-question.js +223 -0
- package/dist/commands/compact.js +120 -0
- package/dist/commands/context-usage.js +140 -0
- package/dist/commands/create-new-project.js +118 -0
- package/dist/commands/diff.js +128 -0
- package/dist/commands/file-upload.js +275 -0
- package/dist/commands/fork.js +217 -0
- package/dist/commands/gemini-apikey.js +70 -0
- package/dist/commands/login.js +490 -0
- package/dist/commands/mention-mode.js +51 -0
- package/dist/commands/merge-worktree.js +124 -0
- package/dist/commands/model.js +694 -0
- package/dist/commands/permissions.js +163 -0
- package/dist/commands/queue.js +217 -0
- package/dist/commands/remove-project.js +115 -0
- package/dist/commands/restart-opencode-server.js +116 -0
- package/dist/commands/resume.js +159 -0
- package/dist/commands/run-command.js +79 -0
- package/dist/commands/session-id.js +78 -0
- package/dist/commands/session.js +192 -0
- package/dist/commands/share.js +80 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/undo-redo.js +159 -0
- package/dist/commands/unset-model.js +152 -0
- package/dist/commands/upgrade.js +42 -0
- package/dist/commands/user-command.js +148 -0
- package/dist/commands/verbosity.js +60 -0
- package/dist/commands/worktree-settings.js +50 -0
- package/dist/commands/worktree.js +299 -0
- package/dist/condense-memory.js +33 -0
- package/dist/config.js +110 -0
- package/dist/database.js +1050 -0
- package/dist/db.js +159 -0
- package/dist/db.test.js +49 -0
- package/dist/discord-api.js +28 -0
- package/dist/discord-auth.js +231 -0
- package/dist/discord-auth.test.js +80 -0
- package/dist/discord-bot.js +997 -0
- package/dist/discord-utils.js +560 -0
- package/dist/discord-utils.test.js +115 -0
- package/dist/errors.js +167 -0
- package/dist/escape-backticks.test.js +429 -0
- package/dist/format-tables.js +122 -0
- package/dist/format-tables.test.js +199 -0
- package/dist/forum-sync/config.js +79 -0
- package/dist/forum-sync/discord-operations.js +154 -0
- package/dist/forum-sync/index.js +5 -0
- package/dist/forum-sync/markdown.js +117 -0
- package/dist/forum-sync/sync-to-discord.js +417 -0
- package/dist/forum-sync/sync-to-files.js +190 -0
- package/dist/forum-sync/types.js +53 -0
- package/dist/forum-sync/watchers.js +307 -0
- package/dist/gateway-consumer.js +232 -0
- package/dist/gateway-consumer.test.js +18 -0
- package/dist/genai-worker-wrapper.js +111 -0
- package/dist/genai-worker.js +311 -0
- package/dist/genai.js +232 -0
- package/dist/generated/browser.js +17 -0
- package/dist/generated/client.js +35 -0
- package/dist/generated/commonInputTypes.js +10 -0
- package/dist/generated/enums.js +30 -0
- package/dist/generated/internal/class.js +41 -0
- package/dist/generated/internal/prismaNamespace.js +239 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +209 -0
- package/dist/generated/models/bot_api_keys.js +1 -0
- package/dist/generated/models/bot_tokens.js +1 -0
- package/dist/generated/models/channel_agents.js +1 -0
- package/dist/generated/models/channel_directories.js +1 -0
- package/dist/generated/models/channel_mention_mode.js +1 -0
- package/dist/generated/models/channel_models.js +1 -0
- package/dist/generated/models/channel_verbosity.js +1 -0
- package/dist/generated/models/channel_worktrees.js +1 -0
- package/dist/generated/models/forum_sync_configs.js +1 -0
- package/dist/generated/models/global_models.js +1 -0
- package/dist/generated/models/ipc_requests.js +1 -0
- package/dist/generated/models/part_messages.js +1 -0
- package/dist/generated/models/scheduled_tasks.js +1 -0
- package/dist/generated/models/session_agents.js +1 -0
- package/dist/generated/models/session_models.js +1 -0
- package/dist/generated/models/session_start_sources.js +1 -0
- package/dist/generated/models/thread_sessions.js +1 -0
- package/dist/generated/models/thread_worktrees.js +1 -0
- package/dist/generated/models.js +1 -0
- package/dist/heap-monitor.js +95 -0
- package/dist/hrana-server.js +416 -0
- package/dist/hrana-server.test.js +368 -0
- package/dist/image-utils.js +112 -0
- package/dist/interaction-handler.js +327 -0
- package/dist/ipc-polling.js +251 -0
- package/dist/kimaki-digital-twin.e2e.test.js +165 -0
- package/dist/limit-heading-depth.js +25 -0
- package/dist/limit-heading-depth.test.js +105 -0
- package/dist/logger.js +160 -0
- package/dist/markdown.js +342 -0
- package/dist/markdown.test.js +253 -0
- package/dist/message-formatting.js +433 -0
- package/dist/message-formatting.test.js +73 -0
- package/dist/openai-realtime.js +228 -0
- package/dist/opencode-plugin-loading.e2e.test.js +91 -0
- package/dist/opencode-plugin.js +536 -0
- package/dist/opencode-plugin.test.js +98 -0
- package/dist/opencode.js +409 -0
- package/dist/privacy-sanitizer.js +105 -0
- package/dist/runtime-mode.js +51 -0
- package/dist/runtime-mode.test.js +115 -0
- package/dist/sentry.js +127 -0
- package/dist/session-handler/state.js +151 -0
- package/dist/session-handler.js +1874 -0
- package/dist/session-search.js +100 -0
- package/dist/session-search.test.js +40 -0
- package/dist/startup-service.js +153 -0
- package/dist/system-message.js +499 -0
- package/dist/task-runner.js +282 -0
- package/dist/task-schedule.js +191 -0
- package/dist/task-schedule.test.js +71 -0
- package/dist/thinking-utils.js +35 -0
- package/dist/thread-message-queue.e2e.test.js +781 -0
- package/dist/tools.js +359 -0
- package/dist/unnest-code-blocks.js +136 -0
- package/dist/unnest-code-blocks.test.js +641 -0
- package/dist/upgrade.js +114 -0
- package/dist/utils.js +109 -0
- package/dist/voice-handler.js +606 -0
- package/dist/voice.js +304 -0
- package/dist/voice.test.js +187 -0
- package/dist/wait-session.js +94 -0
- package/dist/worker-types.js +4 -0
- package/dist/worktree-utils.js +727 -0
- package/dist/xml.js +92 -0
- package/dist/xml.test.js +32 -0
- package/package.json +82 -0
- package/schema.prisma +246 -0
- package/skills/batch/SKILL.md +87 -0
- package/skills/critique/SKILL.md +129 -0
- package/skills/errore/SKILL.md +589 -0
- package/skills/goke/.prettierrc +5 -0
- package/skills/goke/CHANGELOG.md +40 -0
- package/skills/goke/LICENSE +21 -0
- package/skills/goke/README.md +666 -0
- package/skills/goke/SKILL.md +458 -0
- package/skills/goke/package.json +43 -0
- package/skills/goke/src/__test__/coerce.test.ts +411 -0
- package/skills/goke/src/__test__/index.test.ts +1798 -0
- package/skills/goke/src/__test__/types.test-d.ts +111 -0
- package/skills/goke/src/coerce.ts +547 -0
- package/skills/goke/src/goke.ts +1362 -0
- package/skills/goke/src/index.ts +16 -0
- package/skills/goke/src/mri.ts +164 -0
- package/skills/goke/tsconfig.json +15 -0
- package/skills/jitter/EDITOR.md +219 -0
- package/skills/jitter/EXPORT-INTERNALS.md +309 -0
- package/skills/jitter/SKILL.md +158 -0
- package/skills/jitter/jitter-clipboard.json +1042 -0
- package/skills/jitter/package.json +14 -0
- package/skills/jitter/tsconfig.json +15 -0
- package/skills/jitter/utils/actions.ts +212 -0
- package/skills/jitter/utils/export.ts +114 -0
- package/skills/jitter/utils/index.ts +141 -0
- package/skills/jitter/utils/snapshot.ts +154 -0
- package/skills/jitter/utils/traverse.ts +246 -0
- package/skills/jitter/utils/types.ts +279 -0
- package/skills/jitter/utils/wait.ts +133 -0
- package/skills/playwriter/SKILL.md +31 -0
- package/skills/security-review/SKILL.md +208 -0
- package/skills/simplify/SKILL.md +58 -0
- package/skills/termcast/SKILL.md +945 -0
- package/skills/tuistory/SKILL.md +250 -0
- package/skills/zustand-centralized-state/SKILL.md +582 -0
- package/src/__snapshots__/compact-session-context-no-system.md +35 -0
- package/src/__snapshots__/compact-session-context.md +41 -0
- package/src/__snapshots__/first-session-no-info.md +17 -0
- package/src/__snapshots__/first-session-with-info.md +23 -0
- package/src/__snapshots__/session-1.md +17 -0
- package/src/__snapshots__/session-2.md +5871 -0
- package/src/__snapshots__/session-3.md +17 -0
- package/src/__snapshots__/session-with-tools.md +5871 -0
- package/src/ai-tool-to-genai.test.ts +296 -0
- package/src/ai-tool-to-genai.ts +282 -0
- package/src/ai-tool.ts +39 -0
- package/src/bin.ts +108 -0
- package/src/bot-token.test.ts +171 -0
- package/src/bot-token.ts +159 -0
- package/src/channel-management.ts +172 -0
- package/src/cli-parsing.test.ts +132 -0
- package/src/cli.ts +3605 -0
- package/src/commands/abort.ts +112 -0
- package/src/commands/action-buttons.ts +376 -0
- package/src/commands/add-project.ts +152 -0
- package/src/commands/agent.ts +404 -0
- package/src/commands/ask-question.ts +330 -0
- package/src/commands/compact.ts +157 -0
- package/src/commands/context-usage.ts +199 -0
- package/src/commands/create-new-project.ts +179 -0
- package/src/commands/diff.ts +165 -0
- package/src/commands/file-upload.ts +389 -0
- package/src/commands/fork.ts +320 -0
- package/src/commands/gemini-apikey.ts +104 -0
- package/src/commands/login.ts +634 -0
- package/src/commands/mention-mode.ts +77 -0
- package/src/commands/merge-worktree.ts +177 -0
- package/src/commands/model.ts +961 -0
- package/src/commands/permissions.ts +261 -0
- package/src/commands/queue.ts +296 -0
- package/src/commands/remove-project.ts +155 -0
- package/src/commands/restart-opencode-server.ts +162 -0
- package/src/commands/resume.ts +242 -0
- package/src/commands/run-command.ts +123 -0
- package/src/commands/session-id.ts +109 -0
- package/src/commands/session.ts +250 -0
- package/src/commands/share.ts +106 -0
- package/src/commands/types.ts +25 -0
- package/src/commands/undo-redo.ts +221 -0
- package/src/commands/unset-model.ts +189 -0
- package/src/commands/upgrade.ts +52 -0
- package/src/commands/user-command.ts +193 -0
- package/src/commands/verbosity.ts +88 -0
- package/src/commands/worktree-settings.ts +79 -0
- package/src/commands/worktree.ts +431 -0
- package/src/condense-memory.ts +36 -0
- package/src/config.ts +148 -0
- package/src/database.ts +1530 -0
- package/src/db.test.ts +60 -0
- package/src/db.ts +190 -0
- package/src/discord-api.ts +35 -0
- package/src/discord-bot.ts +1316 -0
- package/src/discord-utils.test.ts +132 -0
- package/src/discord-utils.ts +767 -0
- package/src/errors.ts +213 -0
- package/src/escape-backticks.test.ts +469 -0
- package/src/format-tables.test.ts +223 -0
- package/src/format-tables.ts +145 -0
- package/src/forum-sync/config.ts +92 -0
- package/src/forum-sync/discord-operations.ts +241 -0
- package/src/forum-sync/index.ts +9 -0
- package/src/forum-sync/markdown.ts +176 -0
- package/src/forum-sync/sync-to-discord.ts +595 -0
- package/src/forum-sync/sync-to-files.ts +294 -0
- package/src/forum-sync/types.ts +175 -0
- package/src/forum-sync/watchers.ts +454 -0
- package/src/genai-worker-wrapper.ts +164 -0
- package/src/genai-worker.ts +386 -0
- package/src/genai.ts +321 -0
- package/src/generated/browser.ts +109 -0
- package/src/generated/client.ts +131 -0
- package/src/generated/commonInputTypes.ts +512 -0
- package/src/generated/enums.ts +46 -0
- package/src/generated/internal/class.ts +362 -0
- package/src/generated/internal/prismaNamespace.ts +2251 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +308 -0
- package/src/generated/models/bot_api_keys.ts +1288 -0
- package/src/generated/models/bot_tokens.ts +1577 -0
- package/src/generated/models/channel_agents.ts +1256 -0
- package/src/generated/models/channel_directories.ts +2104 -0
- package/src/generated/models/channel_mention_mode.ts +1300 -0
- package/src/generated/models/channel_models.ts +1288 -0
- package/src/generated/models/channel_verbosity.ts +1224 -0
- package/src/generated/models/channel_worktrees.ts +1308 -0
- package/src/generated/models/forum_sync_configs.ts +1452 -0
- package/src/generated/models/global_models.ts +1288 -0
- package/src/generated/models/ipc_requests.ts +1485 -0
- package/src/generated/models/part_messages.ts +1302 -0
- package/src/generated/models/scheduled_tasks.ts +2320 -0
- package/src/generated/models/session_agents.ts +1086 -0
- package/src/generated/models/session_models.ts +1114 -0
- package/src/generated/models/session_start_sources.ts +1408 -0
- package/src/generated/models/thread_sessions.ts +1599 -0
- package/src/generated/models/thread_worktrees.ts +1352 -0
- package/src/generated/models.ts +29 -0
- package/src/heap-monitor.ts +121 -0
- package/src/hrana-server.test.ts +428 -0
- package/src/hrana-server.ts +547 -0
- package/src/image-utils.ts +149 -0
- package/src/interaction-handler.ts +461 -0
- package/src/ipc-polling.ts +325 -0
- package/src/kimaki-digital-twin.e2e.test.ts +201 -0
- package/src/limit-heading-depth.test.ts +116 -0
- package/src/limit-heading-depth.ts +26 -0
- package/src/logger.ts +203 -0
- package/src/markdown.test.ts +360 -0
- package/src/markdown.ts +410 -0
- package/src/message-formatting.test.ts +81 -0
- package/src/message-formatting.ts +549 -0
- package/src/openai-realtime.ts +362 -0
- package/src/opencode-plugin-loading.e2e.test.ts +112 -0
- package/src/opencode-plugin.test.ts +108 -0
- package/src/opencode-plugin.ts +652 -0
- package/src/opencode.ts +554 -0
- package/src/privacy-sanitizer.ts +142 -0
- package/src/schema.sql +158 -0
- package/src/sentry.ts +137 -0
- package/src/session-handler/state.ts +232 -0
- package/src/session-handler.ts +2668 -0
- package/src/session-search.test.ts +50 -0
- package/src/session-search.ts +148 -0
- package/src/startup-service.ts +200 -0
- package/src/system-message.ts +568 -0
- package/src/task-runner.ts +425 -0
- package/src/task-schedule.test.ts +84 -0
- package/src/task-schedule.ts +287 -0
- package/src/thinking-utils.ts +61 -0
- package/src/thread-message-queue.e2e.test.ts +997 -0
- package/src/tools.ts +432 -0
- package/src/unnest-code-blocks.test.ts +679 -0
- package/src/unnest-code-blocks.ts +168 -0
- package/src/upgrade.ts +127 -0
- package/src/utils.ts +145 -0
- package/src/voice-handler.ts +852 -0
- package/src/voice.test.ts +219 -0
- package/src/voice.ts +444 -0
- package/src/wait-session.ts +147 -0
- package/src/worker-types.ts +64 -0
- package/src/worktree-utils.ts +988 -0
- package/src/xml.test.ts +38 -0
- package/src/xml.ts +121 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// Tree traversal utilities for Jitter project structure
|
|
2
|
+
|
|
3
|
+
import type { JitterNode, JitterConf, LayerType } from './types'
|
|
4
|
+
|
|
5
|
+
function getConf(): JitterConf {
|
|
6
|
+
return window.app.props.observableImmutableConf.lastImmutableConf
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Find a node by its ID anywhere in the project tree
|
|
11
|
+
*/
|
|
12
|
+
export function findNodeById(nodeId: string): JitterNode | null {
|
|
13
|
+
const conf = getConf()
|
|
14
|
+
|
|
15
|
+
const search = (node: JitterNode): JitterNode | null => {
|
|
16
|
+
if (node.id === nodeId) {
|
|
17
|
+
return node
|
|
18
|
+
}
|
|
19
|
+
if (node.children) {
|
|
20
|
+
for (const child of node.children) {
|
|
21
|
+
const found = search(child)
|
|
22
|
+
if (found) {
|
|
23
|
+
return found
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const root of conf.roots || []) {
|
|
31
|
+
const found = search(root)
|
|
32
|
+
if (found) {
|
|
33
|
+
return found
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface MediaNodeInfo {
|
|
40
|
+
id: string
|
|
41
|
+
name: string | undefined
|
|
42
|
+
type: 'svg' | 'image' | 'video' | 'gif'
|
|
43
|
+
url: string
|
|
44
|
+
width: number | undefined
|
|
45
|
+
height: number | undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Find all media nodes (images, SVGs, videos, GIFs) in the project
|
|
50
|
+
*/
|
|
51
|
+
export function findAllMediaNodes(): MediaNodeInfo[] {
|
|
52
|
+
const conf = getConf()
|
|
53
|
+
const mediaNodes: MediaNodeInfo[] = []
|
|
54
|
+
const mediaTypes = new Set(['svg', 'image', 'video', 'gif'])
|
|
55
|
+
|
|
56
|
+
const search = (node: JitterNode): void => {
|
|
57
|
+
if (node.item && mediaTypes.has(node.item.type)) {
|
|
58
|
+
const item = node.item as {
|
|
59
|
+
type: 'svg' | 'image' | 'video' | 'gif'
|
|
60
|
+
url: string
|
|
61
|
+
name?: string
|
|
62
|
+
width?: number
|
|
63
|
+
height?: number
|
|
64
|
+
}
|
|
65
|
+
mediaNodes.push({
|
|
66
|
+
id: node.id,
|
|
67
|
+
name: item.name,
|
|
68
|
+
type: item.type,
|
|
69
|
+
url: item.url,
|
|
70
|
+
width: item.width,
|
|
71
|
+
height: item.height,
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
if (node.children) {
|
|
75
|
+
node.children.forEach(search)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
;(conf.roots || []).forEach(search)
|
|
80
|
+
return mediaNodes
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface TextNodeInfo {
|
|
84
|
+
id: string
|
|
85
|
+
name: string | undefined
|
|
86
|
+
text: string
|
|
87
|
+
fontSize: number | undefined
|
|
88
|
+
fontFamily: string | undefined
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find all text nodes in the project
|
|
93
|
+
*/
|
|
94
|
+
export function findAllTextNodes(): TextNodeInfo[] {
|
|
95
|
+
const conf = getConf()
|
|
96
|
+
const textNodes: TextNodeInfo[] = []
|
|
97
|
+
|
|
98
|
+
const search = (node: JitterNode): void => {
|
|
99
|
+
if (node.item?.type === 'text') {
|
|
100
|
+
const item = node.item as {
|
|
101
|
+
type: 'text'
|
|
102
|
+
text: string
|
|
103
|
+
name?: string
|
|
104
|
+
fontSize?: number
|
|
105
|
+
font?: { name: string }
|
|
106
|
+
}
|
|
107
|
+
textNodes.push({
|
|
108
|
+
id: node.id,
|
|
109
|
+
name: item.name,
|
|
110
|
+
text: item.text,
|
|
111
|
+
fontSize: item.fontSize,
|
|
112
|
+
fontFamily: item.font?.name,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
if (node.children) {
|
|
116
|
+
node.children.forEach(search)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
;(conf.roots || []).forEach(search)
|
|
121
|
+
return textNodes
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface ArtboardInfo {
|
|
125
|
+
id: string
|
|
126
|
+
name: string | undefined
|
|
127
|
+
width: number
|
|
128
|
+
height: number
|
|
129
|
+
duration: number | undefined
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get all artboards in the project
|
|
134
|
+
*/
|
|
135
|
+
export function getArtboards(): ArtboardInfo[] {
|
|
136
|
+
const conf = getConf()
|
|
137
|
+
return conf.roots
|
|
138
|
+
.filter((r) => r.item?.type === 'artboard')
|
|
139
|
+
.map((r) => {
|
|
140
|
+
const item = r.item as {
|
|
141
|
+
type: 'artboard'
|
|
142
|
+
name?: string
|
|
143
|
+
width: number
|
|
144
|
+
height: number
|
|
145
|
+
duration?: number
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
id: r.id,
|
|
149
|
+
name: item.name,
|
|
150
|
+
width: item.width,
|
|
151
|
+
height: item.height,
|
|
152
|
+
duration: item.duration,
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Find all nodes of a specific type
|
|
159
|
+
*/
|
|
160
|
+
export function findNodesByType(type: LayerType): JitterNode[] {
|
|
161
|
+
const conf = getConf()
|
|
162
|
+
const nodes: JitterNode[] = []
|
|
163
|
+
|
|
164
|
+
const search = (node: JitterNode): void => {
|
|
165
|
+
if (node.item?.type === type) {
|
|
166
|
+
nodes.push(node)
|
|
167
|
+
}
|
|
168
|
+
if (node.children) {
|
|
169
|
+
node.children.forEach(search)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
;(conf.roots || []).forEach(search)
|
|
174
|
+
return nodes
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Find nodes by name (partial match, case-insensitive)
|
|
179
|
+
*/
|
|
180
|
+
export function findNodesByName(name: string): JitterNode[] {
|
|
181
|
+
const conf = getConf()
|
|
182
|
+
const nodes: JitterNode[] = []
|
|
183
|
+
const lowerName = name.toLowerCase()
|
|
184
|
+
|
|
185
|
+
const search = (node: JitterNode): void => {
|
|
186
|
+
const nodeName = (node.item as { name?: string })?.name
|
|
187
|
+
if (nodeName && nodeName.toLowerCase().includes(lowerName)) {
|
|
188
|
+
nodes.push(node)
|
|
189
|
+
}
|
|
190
|
+
if (node.children) {
|
|
191
|
+
node.children.forEach(search)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
;(conf.roots || []).forEach(search)
|
|
196
|
+
return nodes
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get the parent node of a given node
|
|
201
|
+
*/
|
|
202
|
+
export function getParentNode(nodeId: string): JitterNode | null {
|
|
203
|
+
const node = findNodeById(nodeId)
|
|
204
|
+
if (!node?.position?.parentId) {
|
|
205
|
+
return null
|
|
206
|
+
}
|
|
207
|
+
return findNodeById(node.position.parentId)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get all ancestor nodes from a node up to the root
|
|
212
|
+
*/
|
|
213
|
+
export function getAncestors(nodeId: string): JitterNode[] {
|
|
214
|
+
const ancestors: JitterNode[] = []
|
|
215
|
+
let current = findNodeById(nodeId)
|
|
216
|
+
|
|
217
|
+
while (current?.position?.parentId) {
|
|
218
|
+
const parent = findNodeById(current.position.parentId)
|
|
219
|
+
if (parent) {
|
|
220
|
+
ancestors.push(parent)
|
|
221
|
+
current = parent
|
|
222
|
+
} else {
|
|
223
|
+
break
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return ancestors
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Flatten the entire node tree into a single array
|
|
232
|
+
*/
|
|
233
|
+
export function flattenTree(): JitterNode[] {
|
|
234
|
+
const conf = getConf()
|
|
235
|
+
const nodes: JitterNode[] = []
|
|
236
|
+
|
|
237
|
+
const collect = (node: JitterNode): void => {
|
|
238
|
+
nodes.push(node)
|
|
239
|
+
if (node.children) {
|
|
240
|
+
node.children.forEach(collect)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
;(conf.roots || []).forEach(collect)
|
|
245
|
+
return nodes
|
|
246
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// Jitter type definitions extracted from the editor API
|
|
2
|
+
|
|
3
|
+
export type LayerType =
|
|
4
|
+
| 'artboard'
|
|
5
|
+
| 'text'
|
|
6
|
+
| 'image'
|
|
7
|
+
| 'svg'
|
|
8
|
+
| 'video'
|
|
9
|
+
| 'gif'
|
|
10
|
+
| 'rect'
|
|
11
|
+
| 'ellipse'
|
|
12
|
+
| 'star'
|
|
13
|
+
| 'layerGrp'
|
|
14
|
+
|
|
15
|
+
export type ExportProfile =
|
|
16
|
+
| 'lottie'
|
|
17
|
+
| 'mp4'
|
|
18
|
+
| 'gif'
|
|
19
|
+
| 'webm'
|
|
20
|
+
| 'prores4444'
|
|
21
|
+
| 'pngs'
|
|
22
|
+
|
|
23
|
+
export interface JitterFont {
|
|
24
|
+
name: string
|
|
25
|
+
type: 'googlefont' | 'system' | 'custom'
|
|
26
|
+
weight: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface GradientStop {
|
|
30
|
+
id: string
|
|
31
|
+
position: number
|
|
32
|
+
color: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface GradientTransform {
|
|
36
|
+
angle?: number
|
|
37
|
+
sx: number
|
|
38
|
+
tx: number
|
|
39
|
+
ty: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface Gradient {
|
|
43
|
+
type: 'GRADIENT_LINEAR' | 'GRADIENT_RADIAL'
|
|
44
|
+
stops: GradientStop[]
|
|
45
|
+
transform: GradientTransform
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type FillColor = string | Gradient
|
|
49
|
+
|
|
50
|
+
export interface BaseLayerProperties {
|
|
51
|
+
name?: string
|
|
52
|
+
x?: number
|
|
53
|
+
y?: number
|
|
54
|
+
width?: number
|
|
55
|
+
height?: number
|
|
56
|
+
angle?: number
|
|
57
|
+
scale?: number
|
|
58
|
+
opacity?: number
|
|
59
|
+
shadowEnabled?: boolean
|
|
60
|
+
strokeEnabled?: boolean
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ArtboardProperties extends BaseLayerProperties {
|
|
64
|
+
type: 'artboard'
|
|
65
|
+
background?: boolean
|
|
66
|
+
fillColor?: FillColor
|
|
67
|
+
duration?: number
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface TextProperties extends BaseLayerProperties {
|
|
71
|
+
type: 'text'
|
|
72
|
+
text: string
|
|
73
|
+
font?: JitterFont
|
|
74
|
+
fontSize?: number
|
|
75
|
+
fillColor?: FillColor
|
|
76
|
+
textAlign?: 'left' | 'center' | 'right'
|
|
77
|
+
verticalAlign?: 'top' | 'middle' | 'bottom'
|
|
78
|
+
lineHeight?: number
|
|
79
|
+
letterSpacing?: number
|
|
80
|
+
kerning?: boolean
|
|
81
|
+
ligatures?: boolean
|
|
82
|
+
case?: 'normal' | 'upper' | 'lower'
|
|
83
|
+
dir?: 'ltr' | 'rtl'
|
|
84
|
+
autoResize?: 'none' | 'height' | 'width'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ImageProperties extends BaseLayerProperties {
|
|
88
|
+
type: 'image'
|
|
89
|
+
url: string
|
|
90
|
+
mediaName?: string
|
|
91
|
+
cornerRadius?: number
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface SvgProperties extends BaseLayerProperties {
|
|
95
|
+
type: 'svg'
|
|
96
|
+
url: string
|
|
97
|
+
mediaName?: string
|
|
98
|
+
cornerRadius?: number
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface VideoProperties extends BaseLayerProperties {
|
|
102
|
+
type: 'video'
|
|
103
|
+
url: string
|
|
104
|
+
mediaName?: string
|
|
105
|
+
audioUrl?: string | null
|
|
106
|
+
cornerRadius?: number
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface GifProperties extends BaseLayerProperties {
|
|
110
|
+
type: 'gif'
|
|
111
|
+
url: string
|
|
112
|
+
mediaName?: string
|
|
113
|
+
cornerRadius?: number
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface RectProperties extends BaseLayerProperties {
|
|
117
|
+
type: 'rect'
|
|
118
|
+
fillColor?: FillColor
|
|
119
|
+
cornerRadius?: number
|
|
120
|
+
strokeColor?: string
|
|
121
|
+
strokeWidth?: number
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface EllipseProperties extends BaseLayerProperties {
|
|
125
|
+
type: 'ellipse'
|
|
126
|
+
fillColor?: FillColor
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface StarProperties extends BaseLayerProperties {
|
|
130
|
+
type: 'star'
|
|
131
|
+
fillColor?: FillColor
|
|
132
|
+
points?: number
|
|
133
|
+
innerRadius?: number
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface LayerGrpProperties extends BaseLayerProperties {
|
|
137
|
+
type: 'layerGrp'
|
|
138
|
+
clipsContent?: boolean
|
|
139
|
+
background?: boolean
|
|
140
|
+
cornerRadius?: number
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type LayerProperties =
|
|
144
|
+
| ArtboardProperties
|
|
145
|
+
| TextProperties
|
|
146
|
+
| ImageProperties
|
|
147
|
+
| SvgProperties
|
|
148
|
+
| VideoProperties
|
|
149
|
+
| GifProperties
|
|
150
|
+
| RectProperties
|
|
151
|
+
| EllipseProperties
|
|
152
|
+
| StarProperties
|
|
153
|
+
| LayerGrpProperties
|
|
154
|
+
|
|
155
|
+
export interface JitterNode {
|
|
156
|
+
id: string
|
|
157
|
+
item: LayerProperties
|
|
158
|
+
position?: {
|
|
159
|
+
parentId: string
|
|
160
|
+
index: string
|
|
161
|
+
}
|
|
162
|
+
children?: JitterNode[]
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface JitterConf {
|
|
166
|
+
roots: JitterNode[]
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface FileMeta {
|
|
170
|
+
id: string
|
|
171
|
+
name: string
|
|
172
|
+
bucket: string
|
|
173
|
+
teamId?: string
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface EasingConfig {
|
|
177
|
+
name: string
|
|
178
|
+
schema: string
|
|
179
|
+
config: Record<string, number>
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface AnimationOperation {
|
|
183
|
+
type: string
|
|
184
|
+
targetId: string
|
|
185
|
+
startTime: number
|
|
186
|
+
endTime: number
|
|
187
|
+
fromValue?: number | { x: number; y: number }
|
|
188
|
+
toValue?: number | { x: number; y: number }
|
|
189
|
+
easing?: EasingConfig
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Action types for dispatchAction
|
|
193
|
+
export interface UpdateAction {
|
|
194
|
+
type: 'updateObjWithUndo'
|
|
195
|
+
objId: string
|
|
196
|
+
data: Partial<LayerProperties> & { url?: string; text?: string }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface AddAction {
|
|
200
|
+
type: 'addObjWithUndo'
|
|
201
|
+
parentId: string
|
|
202
|
+
objData: {
|
|
203
|
+
id: string
|
|
204
|
+
item: LayerProperties
|
|
205
|
+
}
|
|
206
|
+
index?: string
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface RemoveAction {
|
|
210
|
+
type: 'removeObjWithUndo'
|
|
211
|
+
objIds: string[]
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface SetSelectionAction {
|
|
215
|
+
type: 'setSelection'
|
|
216
|
+
selection: {
|
|
217
|
+
nodesIds: string[]
|
|
218
|
+
}
|
|
219
|
+
saveInCmdHistory?: boolean
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type JitterAction =
|
|
223
|
+
| UpdateAction
|
|
224
|
+
| AddAction
|
|
225
|
+
| RemoveAction
|
|
226
|
+
| SetSelectionAction
|
|
227
|
+
| { type: 'undo' }
|
|
228
|
+
| { type: 'redo' }
|
|
229
|
+
| { type: 'saveSelectionForUndo' }
|
|
230
|
+
| { type: 'emptySelection' }
|
|
231
|
+
| { type: 'deleteCurrentSelection' }
|
|
232
|
+
|
|
233
|
+
// Jitter app interface (available as window.app)
|
|
234
|
+
export interface JitterApp {
|
|
235
|
+
props: {
|
|
236
|
+
fileMeta: FileMeta
|
|
237
|
+
observableImmutableConf: {
|
|
238
|
+
lastImmutableConf: JitterConf
|
|
239
|
+
subscribe: (callback: () => void) => () => void
|
|
240
|
+
}
|
|
241
|
+
observableEditorState: {
|
|
242
|
+
getSnapshot: () => {
|
|
243
|
+
selection: { nodesIds: string[] }
|
|
244
|
+
base: { artboardTimes: Record<string, number> }
|
|
245
|
+
toolbox: { currentMode: { mode: { name: string } } }
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
rendererRuntime: {
|
|
249
|
+
getAssetStore: () => Map<string, unknown>
|
|
250
|
+
}
|
|
251
|
+
fileActions: {
|
|
252
|
+
duplicateFile: (fileId: string) => Promise<string>
|
|
253
|
+
deleteFile: (fileId: string) => Promise<void>
|
|
254
|
+
renameFile: (name: string) => Promise<void>
|
|
255
|
+
saveFile: () => Promise<void>
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
dispatchAction: (action: JitterAction | Record<string, unknown>) => void
|
|
259
|
+
addArtboard: () => void
|
|
260
|
+
addText: (source: 'toolbar' | 'keyboard') => void
|
|
261
|
+
addRectShape: (source: string) => void
|
|
262
|
+
addEllipseShape: (source: string) => void
|
|
263
|
+
addMedia: (source: string) => void
|
|
264
|
+
play: () => void
|
|
265
|
+
stopPlayback: () => void
|
|
266
|
+
moveCursor: (timeInMs: number) => void
|
|
267
|
+
renameFile: (name: string) => void
|
|
268
|
+
deleteFile: () => void
|
|
269
|
+
downloadProject: () => void
|
|
270
|
+
scheduleSave: () => void
|
|
271
|
+
getState: () => unknown
|
|
272
|
+
isReadOnly: () => boolean
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
declare global {
|
|
276
|
+
interface Window {
|
|
277
|
+
app: JitterApp
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Waiting utilities for Jitter app initialization and sync
|
|
2
|
+
|
|
3
|
+
import type { JitterApp } from './types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wait for the Jitter app to be fully loaded and ready
|
|
7
|
+
* Call this after navigating to a project URL
|
|
8
|
+
*/
|
|
9
|
+
export function waitForApp(timeoutMs = 30000): Promise<JitterApp> {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const startTime = Date.now()
|
|
12
|
+
|
|
13
|
+
const check = (): void => {
|
|
14
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
15
|
+
reject(new Error('Timeout waiting for Jitter app to load'))
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const app = window.app
|
|
20
|
+
if (app?.props?.observableImmutableConf?.lastImmutableConf) {
|
|
21
|
+
resolve(app)
|
|
22
|
+
} else {
|
|
23
|
+
setTimeout(check, 100)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
check()
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Wait for changes to sync to the server
|
|
33
|
+
* Call this after making modifications before exporting
|
|
34
|
+
*/
|
|
35
|
+
export function waitForSync(delayMs = 2000): Promise<void> {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
setTimeout(resolve, delayMs)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Wait for a specific condition to be true
|
|
43
|
+
*/
|
|
44
|
+
export function waitFor(
|
|
45
|
+
condition: () => boolean,
|
|
46
|
+
options: { timeout?: number; interval?: number } = {},
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
const { timeout = 30000, interval = 100 } = options
|
|
49
|
+
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const startTime = Date.now()
|
|
52
|
+
|
|
53
|
+
const check = (): void => {
|
|
54
|
+
if (Date.now() - startTime > timeout) {
|
|
55
|
+
reject(new Error('Timeout waiting for condition'))
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (condition()) {
|
|
60
|
+
resolve()
|
|
61
|
+
} else {
|
|
62
|
+
setTimeout(check, interval)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
check()
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Wait for a specific node to exist in the project
|
|
72
|
+
*/
|
|
73
|
+
export function waitForNode(nodeId: string, timeoutMs = 10000): Promise<void> {
|
|
74
|
+
return waitFor(
|
|
75
|
+
() => {
|
|
76
|
+
const conf = window.app?.props?.observableImmutableConf?.lastImmutableConf
|
|
77
|
+
if (!conf) {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const search = (node: { id: string; children?: unknown[] }): boolean => {
|
|
82
|
+
if (node.id === nodeId) {
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
if (node.children) {
|
|
86
|
+
return (node.children as (typeof node)[]).some(search)
|
|
87
|
+
}
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (conf.roots || []).some(search)
|
|
92
|
+
},
|
|
93
|
+
{ timeout: timeoutMs },
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Wait for the project configuration to change
|
|
99
|
+
* Useful after making updates to detect when they've been applied
|
|
100
|
+
*/
|
|
101
|
+
export function waitForConfigChange(timeoutMs = 5000): Promise<void> {
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
const timeout = setTimeout(() => {
|
|
104
|
+
unsubscribe()
|
|
105
|
+
reject(new Error('Timeout waiting for config change'))
|
|
106
|
+
}, timeoutMs)
|
|
107
|
+
|
|
108
|
+
const unsubscribe = window.app.props.observableImmutableConf.subscribe(
|
|
109
|
+
() => {
|
|
110
|
+
clearTimeout(timeout)
|
|
111
|
+
unsubscribe()
|
|
112
|
+
resolve()
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if the app is currently in read-only mode
|
|
120
|
+
*/
|
|
121
|
+
export function isReadOnly(): boolean {
|
|
122
|
+
return window.app?.isReadOnly?.() ?? false
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Check if the app is ready for interaction
|
|
127
|
+
*/
|
|
128
|
+
export function isAppReady(): boolean {
|
|
129
|
+
return !!(
|
|
130
|
+
window.app?.props?.observableImmutableConf?.lastImmutableConf &&
|
|
131
|
+
window.app?.props?.fileMeta?.id
|
|
132
|
+
)
|
|
133
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwriter
|
|
3
|
+
description: Control the user own Chrome browser via Playwriter extension with Playwright code snippets in a stateful local js sandbox via playwriter cli. Use this over other Playwright MCPs to automate the browser — it connects to the user's existing Chrome instead of launching a new one. Use this for JS-heavy websites (Instagram, Twitter, cookie/login walls, lazy-loaded UIs) instead of webfetch/curl. Run `playwriter skill` command to read the complete up to date skill
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## REQUIRED: Read Full Documentation First
|
|
7
|
+
|
|
8
|
+
**Before using playwriter, you MUST run this command:**
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
playwriter skill
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This outputs the complete documentation including:
|
|
15
|
+
|
|
16
|
+
- Session management and timeout configuration
|
|
17
|
+
- Selector strategies (and which ones to AVOID)
|
|
18
|
+
- Rules to prevent timeouts and failures
|
|
19
|
+
- Best practices for slow pages and SPAs
|
|
20
|
+
- Context variables, utility functions, and more
|
|
21
|
+
|
|
22
|
+
**Do NOT skip this step.** The quick examples below will fail without understanding timeouts, selector rules, and common pitfalls from the full docs.
|
|
23
|
+
|
|
24
|
+
## Minimal Example (after reading full docs)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
playwriter session new
|
|
28
|
+
playwriter -s 1 -e "await page.goto('https://example.com')"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If `playwriter` is not found, use `npx playwriter@latest` or `bunx playwriter@latest`.
|