pptclaw 0.1.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/.output/nitro.json +15 -0
- package/.output/public/_nuxt/BAtwhwpp.js +1 -0
- package/.output/public/_nuxt/BEQoYl5X.js +2616 -0
- package/.output/public/_nuxt/BMr1Z083.js +1 -0
- package/.output/public/_nuxt/BXBiPOBE.js +1 -0
- package/.output/public/_nuxt/BuUsXmAh.js +1 -0
- package/.output/public/_nuxt/CPsbnj8a.js +1 -0
- package/.output/public/_nuxt/D9BEMGXo.js +1 -0
- package/.output/public/_nuxt/DQNz2huy.js +1 -0
- package/.output/public/_nuxt/DQxlKO7N.js +1 -0
- package/.output/public/_nuxt/_id_.C3K2GZV8.css +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -0
- package/.output/public/_nuxt/builds/meta/e405cd67-1e23-4b39-85e1-217b00c69ec7.json +1 -0
- package/.output/public/_nuxt/entry.BqkL7BC_.css +1 -0
- package/.output/public/_nuxt/error-404.BzoSHD6c.css +1 -0
- package/.output/public/_nuxt/error-500.DwAqVzgo.css +1 -0
- package/.output/public/_nuxt/j2eJltcB.js +2614 -0
- package/.output/public/alipay.svg +27 -0
- package/.output/public/android-chrome-192x192.png +0 -0
- package/.output/public/android-chrome-512x512.png +0 -0
- package/.output/public/animations/arrow.lottie +0 -0
- package/.output/public/animations/cubes.lottie +0 -0
- package/.output/public/animations/stars.lottie +0 -0
- package/.output/public/apple-touch-icon.png +0 -0
- package/.output/public/auth-bg.svg +30 -0
- package/.output/public/auth-logo.svg +4 -0
- package/.output/public/cursor.png +0 -0
- package/.output/public/customerServiceQr.png +0 -0
- package/.output/public/favicon-16x16.png +0 -0
- package/.output/public/favicon-32x32.png +0 -0
- package/.output/public/favicon.ico +0 -0
- package/.output/public/logo.svg +4 -0
- package/.output/public/rect.svg +9 -0
- package/.output/public/site.webmanifest +1 -0
- package/.output/public/templates.json +1623 -0
- package/.output/public/watermark.svg +7 -0
- package/.output/public/wechat-pay-sm.svg +9 -0
- package/.output/public/wechat-pay.svg +21 -0
- package/.output/server/chunks/_/error-500.mjs +1 -0
- package/.output/server/chunks/_/shared.cjs.prod.mjs +1 -0
- package/.output/server/chunks/build/client.precomputed.mjs +1 -0
- package/.output/server/chunks/nitro/nitro.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/_...path_.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/login.post.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/logout.post.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/user.get.mjs +1 -0
- package/.output/server/chunks/routes/api/cloud/_...path_.mjs +1 -0
- package/.output/server/chunks/routes/api/credits/_...path_.mjs +1 -0
- package/.output/server/chunks/routes/api/images/_...path_.mjs +1 -0
- package/.output/server/chunks/routes/api/payments/_...path_.mjs +1 -0
- package/.output/server/chunks/routes/api/public/ping.mjs +1 -0
- package/.output/server/chunks/routes/api/public/test.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/assets/_session/_...filename_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/close.post.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/open.post.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/sessions.get.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/switch.post.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/upload.post.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/validate.post.mjs +1 -0
- package/.output/server/chunks/routes/api/sync/ws.mjs +1 -0
- package/.output/server/chunks/routes/renderer.mjs +1 -0
- package/.output/server/chunks/virtual/_virtual_spa-template.mjs +1 -0
- package/.output/server/index.mjs +1 -0
- package/README.md +49 -0
- package/bin/pptclaw.mjs +165 -0
- package/package.json +130 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o="";export{o as template};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import o from"node:process";globalThis._importMeta_={url:import.meta.url,env:o.env};import"node:http";import"node:https";export{R as default}from"./chunks/nitro/nitro.mjs";import"node:crypto";import"stream";import"events";import"http";import"crypto";import"buffer";import"zlib";import"https";import"net";import"tls";import"url";import"node:events";import"node:buffer";import"node:fs";import"node:path";import"node:fs/promises";import"fs";import"fs/promises";import"path";import"node:stream";import"os";import"node:os";import"node:url";
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# PPTClaw
|
|
2
|
+
|
|
3
|
+
Local-first presentation editor for AI coding tools. Edit slides on your machine with a browser-based editor, synced bidirectionally via WebSocket.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g pptclaw
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Start the editor server
|
|
15
|
+
pptclaw serve
|
|
16
|
+
|
|
17
|
+
# Start and open a deck
|
|
18
|
+
pptclaw serve ./my-deck
|
|
19
|
+
|
|
20
|
+
# Open a deck in a running server
|
|
21
|
+
pptclaw open ./my-deck
|
|
22
|
+
|
|
23
|
+
# Validate a deck folder
|
|
24
|
+
pptclaw validate ./my-deck
|
|
25
|
+
|
|
26
|
+
# List active sessions
|
|
27
|
+
pptclaw list-decks
|
|
28
|
+
|
|
29
|
+
# Install the Claude Code skill
|
|
30
|
+
pptclaw init
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Deck Format
|
|
34
|
+
|
|
35
|
+
A deck is a folder containing:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
my-deck/
|
|
39
|
+
manifest.json
|
|
40
|
+
slides/
|
|
41
|
+
001-abc.json
|
|
42
|
+
002-def.json
|
|
43
|
+
assets/
|
|
44
|
+
image.png
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
Proprietary
|
package/bin/pptclaw.mjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander'
|
|
3
|
+
import { spawn } from 'node:child_process'
|
|
4
|
+
import { resolve, join } from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { existsSync, mkdirSync, copyFileSync } from 'node:fs'
|
|
7
|
+
|
|
8
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
9
|
+
const program = new Command()
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('pptclaw')
|
|
13
|
+
.description('Local-first presentation editor for AI coding tools')
|
|
14
|
+
.version('0.1.0')
|
|
15
|
+
|
|
16
|
+
// pptclaw serve [deck] --port <port>
|
|
17
|
+
program
|
|
18
|
+
.command('serve')
|
|
19
|
+
.description('Start the PPTClaw editor server')
|
|
20
|
+
.argument('[deck]', 'Deck folder to open immediately')
|
|
21
|
+
.option('-p, --port <port>', 'Port number', '3009')
|
|
22
|
+
.action(async (deck, opts) => {
|
|
23
|
+
const serverEntry = join(__dirname, '..', '.output', 'server', 'index.mjs')
|
|
24
|
+
if (!existsSync(serverEntry)) {
|
|
25
|
+
console.error('Server not built. Run `nuxt build` first.')
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const env = { ...process.env, PORT: opts.port, NUXT_PORT: opts.port }
|
|
30
|
+
const child = spawn('node', [serverEntry], { env, stdio: 'inherit' })
|
|
31
|
+
|
|
32
|
+
// If a deck path was provided, open it after server starts
|
|
33
|
+
if (deck) {
|
|
34
|
+
const deckPath = resolve(deck)
|
|
35
|
+
try {
|
|
36
|
+
await waitForServer(opts.port)
|
|
37
|
+
const result = await openDeck(deckPath, opts.port)
|
|
38
|
+
console.log(`Deck opened: ${result.sessionId}`)
|
|
39
|
+
console.log(` Path: ${result.deckPath}`)
|
|
40
|
+
console.log(` Slides: ${result.slideCount}`)
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.error('Failed to open deck after server start:', err.message)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
child.on('exit', (code) => process.exit(code ?? 0))
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// pptclaw open <path> --session <id>
|
|
51
|
+
program
|
|
52
|
+
.command('open')
|
|
53
|
+
.description('Open a deck folder in the running editor')
|
|
54
|
+
.argument('<path>', 'Path to deck folder')
|
|
55
|
+
.option('-s, --session <id>', 'Session ID (auto-generated if omitted)')
|
|
56
|
+
.option('-p, --port <port>', 'Server port', '3009')
|
|
57
|
+
.action(async (path, opts) => {
|
|
58
|
+
const deckPath = resolve(path)
|
|
59
|
+
try {
|
|
60
|
+
const result = await openDeck(deckPath, opts.port, opts.session)
|
|
61
|
+
console.log(`Deck opened: ${result.sessionId}`)
|
|
62
|
+
console.log(` Path: ${result.deckPath}`)
|
|
63
|
+
console.log(` Slides: ${result.slideCount}`)
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
console.error('Failed to open deck. Is the server running?')
|
|
67
|
+
console.error('Start it with: pptclaw serve')
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// pptclaw validate <path>
|
|
73
|
+
program
|
|
74
|
+
.command('validate')
|
|
75
|
+
.description('Validate a deck folder')
|
|
76
|
+
.argument('<path>', 'Path to deck folder')
|
|
77
|
+
.option('-p, --port <port>', 'Server port', '3009')
|
|
78
|
+
.action(async (path, opts) => {
|
|
79
|
+
const deckPath = resolve(path)
|
|
80
|
+
try {
|
|
81
|
+
const res = await fetch(`http://localhost:${opts.port}/api/sync/validate`, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: { 'Content-Type': 'application/json' },
|
|
84
|
+
body: JSON.stringify({ path: deckPath }),
|
|
85
|
+
})
|
|
86
|
+
const result = await res.json()
|
|
87
|
+
console.log(JSON.stringify(result, null, 2))
|
|
88
|
+
process.exit(result.valid ? 0 : 1)
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
console.error('Server not running. Start it with: pptclaw serve')
|
|
92
|
+
process.exit(1)
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// pptclaw list-decks
|
|
97
|
+
program
|
|
98
|
+
.command('list-decks')
|
|
99
|
+
.description('List active sessions (open decks)')
|
|
100
|
+
.option('-p, --port <port>', 'Server port', '3009')
|
|
101
|
+
.action(async (opts) => {
|
|
102
|
+
try {
|
|
103
|
+
const res = await fetch(`http://localhost:${opts.port}/api/sync/sessions`)
|
|
104
|
+
const sessions = await res.json()
|
|
105
|
+
if (sessions.length === 0) {
|
|
106
|
+
console.log('No active sessions. Open a deck with: pptclaw open <path>')
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
console.log('Active sessions:')
|
|
110
|
+
for (const s of sessions) {
|
|
111
|
+
const active = s.activeInEditor ? ' (active)' : ''
|
|
112
|
+
console.log(` ${s.id}${active} — ${s.deckPath} (${s.slideCount} slides)`)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
console.error('Server not running. Start it with: pptclaw serve')
|
|
117
|
+
process.exit(1)
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// pptclaw init
|
|
122
|
+
program
|
|
123
|
+
.command('init')
|
|
124
|
+
.description('Copy the PPTClaw skill file to .claude/skills/')
|
|
125
|
+
.action(() => {
|
|
126
|
+
const skillSrc = join(__dirname, '..', 'skill', 'pptclaw.md')
|
|
127
|
+
const skillDest = join(process.cwd(), '.claude', 'skills', 'pptclaw.md')
|
|
128
|
+
|
|
129
|
+
if (!existsSync(skillSrc)) {
|
|
130
|
+
console.error('Skill file not found in package.')
|
|
131
|
+
process.exit(1)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
mkdirSync(join(process.cwd(), '.claude', 'skills'), { recursive: true })
|
|
135
|
+
copyFileSync(skillSrc, skillDest)
|
|
136
|
+
console.log(`Skill file installed: ${skillDest}`)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
program.parse()
|
|
140
|
+
|
|
141
|
+
// --- Helper functions ---
|
|
142
|
+
|
|
143
|
+
async function waitForServer(port, maxRetries = 30) {
|
|
144
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
145
|
+
try {
|
|
146
|
+
const res = await fetch(`http://localhost:${port}/api/public/ping`)
|
|
147
|
+
if (res.ok) return
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Server not ready yet
|
|
151
|
+
}
|
|
152
|
+
await new Promise(r => setTimeout(r, 1000))
|
|
153
|
+
}
|
|
154
|
+
throw new Error('Server did not start in time')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function openDeck(deckPath, port, sessionId) {
|
|
158
|
+
const res = await fetch(`http://localhost:${port}/api/sync/open`, {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: { 'Content-Type': 'application/json' },
|
|
161
|
+
body: JSON.stringify({ path: deckPath, ...(sessionId && { sessionId }) }),
|
|
162
|
+
})
|
|
163
|
+
if (!res.ok) throw new Error(await res.text())
|
|
164
|
+
return res.json()
|
|
165
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pptclaw",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Local-first presentation editor for AI coding tools",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"files": [
|
|
8
|
+
"bin/",
|
|
9
|
+
".output/",
|
|
10
|
+
"skill/"
|
|
11
|
+
],
|
|
12
|
+
"bin": {
|
|
13
|
+
"pptclaw": "bin/pptclaw.mjs"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"dev": "nuxi prepare && nuxi dev",
|
|
18
|
+
"debug": "nuxi prepare && nuxi dev --inspect=9340",
|
|
19
|
+
"build": "nuxi build",
|
|
20
|
+
"start": "nuxi preview",
|
|
21
|
+
"generate": "nuxi generate",
|
|
22
|
+
"postinstall": "nuxt prepare"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"commander": "^13.1.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@ai-sdk/openai": "^3.0.28",
|
|
29
|
+
"@ai-sdk/vue": "3.0.41",
|
|
30
|
+
"@antv/infographic": "^0.2.1",
|
|
31
|
+
"@icon-park/vue-next": "^1.4.2",
|
|
32
|
+
"@launchdarkly/observability": "^1.0.3",
|
|
33
|
+
"@launchdarkly/session-replay": "^1.0.3",
|
|
34
|
+
"@nuxt/eslint": "1.13.0",
|
|
35
|
+
"@openrouter/ai-sdk-provider": "^1.2.0",
|
|
36
|
+
"@primeuix/themes": "^1.0.0",
|
|
37
|
+
"@tanstack/vue-query": "^5.91.1",
|
|
38
|
+
"@vueuse/core": "^11.1.0",
|
|
39
|
+
"@vueuse/integrations": "^13.3.0",
|
|
40
|
+
"@zumer/snapdom": "^2.0.1",
|
|
41
|
+
"ai": "6.0.81",
|
|
42
|
+
"animate.css": "^4.1.1",
|
|
43
|
+
"axios": "^1.7.7",
|
|
44
|
+
"chokidar": "^4.0.3",
|
|
45
|
+
"chroma-js": "^3.1.2",
|
|
46
|
+
"class-variance-authority": "^0.7.1",
|
|
47
|
+
"clipboard": "^2.0.11",
|
|
48
|
+
"clsx": "^2.1.1",
|
|
49
|
+
"crypto-js": "^4.2.0",
|
|
50
|
+
"dayjs": "^1.11.13",
|
|
51
|
+
"dexie": "^4.2.0",
|
|
52
|
+
"dom-to-svg": "^0.12.2",
|
|
53
|
+
"echarts": "^5.5.1",
|
|
54
|
+
"eslint": "^9.0.0",
|
|
55
|
+
"file-saver": "^2.0.5",
|
|
56
|
+
"gsap": "^3.12.7",
|
|
57
|
+
"hfmath": "^0.0.2",
|
|
58
|
+
"html-to-image": "^1.11.13",
|
|
59
|
+
"html-to-text": "^9.0.5",
|
|
60
|
+
"jszip": "^3.10.1",
|
|
61
|
+
"launchdarkly-vue-client-sdk": "^2.4.1",
|
|
62
|
+
"lodash-es": "^4.17.21",
|
|
63
|
+
"lucide-vue-next": "^0.563.0",
|
|
64
|
+
"lz-string": "^1.5.0",
|
|
65
|
+
"mitt": "^3.0.1",
|
|
66
|
+
"motion-v": "1.0.0-beta.2",
|
|
67
|
+
"nanoid": "^5.1.4",
|
|
68
|
+
"number-precision": "^1.6.0",
|
|
69
|
+
"nuxt": "^4.3.0",
|
|
70
|
+
"openai": "^5.10.2",
|
|
71
|
+
"pptxtojson": "^1.6.0",
|
|
72
|
+
"primeicons": "^7.0.0",
|
|
73
|
+
"primevue": "^4.3.6",
|
|
74
|
+
"prosemirror-commands": "^1.7.1",
|
|
75
|
+
"prosemirror-dropcursor": "^1.8.2",
|
|
76
|
+
"prosemirror-gapcursor": "^1.3.2",
|
|
77
|
+
"prosemirror-history": "^1.4.1",
|
|
78
|
+
"prosemirror-inputrules": "^1.5.0",
|
|
79
|
+
"prosemirror-keymap": "^1.2.3",
|
|
80
|
+
"prosemirror-model": "^1.25.3",
|
|
81
|
+
"prosemirror-schema-basic": "^1.2.4",
|
|
82
|
+
"prosemirror-schema-list": "^1.5.1",
|
|
83
|
+
"prosemirror-state": "^1.4.3",
|
|
84
|
+
"prosemirror-view": "^1.41.2",
|
|
85
|
+
"qrcode": "^1.5.4",
|
|
86
|
+
"reka-ui": "^2.8.0",
|
|
87
|
+
"sanitize-html": "^2.17.0",
|
|
88
|
+
"shiki": "^3.22.0",
|
|
89
|
+
"svg-arc-to-cubic-bezier": "^3.2.0",
|
|
90
|
+
"svg-pathdata": "^8.0.0",
|
|
91
|
+
"tailwind-merge": "^3.4.0",
|
|
92
|
+
"tinycolor2": "^1.6.0",
|
|
93
|
+
"tippy.js": "^6.3.7",
|
|
94
|
+
"vue": "^3.5.27",
|
|
95
|
+
"vue-draggable-plus": "^0.6.0",
|
|
96
|
+
"vue-echarts": "^7.0.3",
|
|
97
|
+
"vue-router": "^4.6.4",
|
|
98
|
+
"vue-stick-to-bottom": "^0.1.0",
|
|
99
|
+
"vue-stream-markdown": "^0.3.4",
|
|
100
|
+
"vuedraggable": "^4.1.0",
|
|
101
|
+
"zod": "^4.1.12",
|
|
102
|
+
"@iconify-json/icon-park-outline": "^1.2.4",
|
|
103
|
+
"@iconify-json/icon-park-twotone": "^1.2.4",
|
|
104
|
+
"@iconify-json/material-symbols": "^1.2.5",
|
|
105
|
+
"@iconify-json/ph": "^1.2.1",
|
|
106
|
+
"@pinia/nuxt": "^0.11.3",
|
|
107
|
+
"@primevue/auto-import-resolver": "^4.3.6",
|
|
108
|
+
"@primevue/nuxt-module": "^4.3.6",
|
|
109
|
+
"@types/chroma-js": "^2.4.4",
|
|
110
|
+
"@types/crypto-js": "^4.2.2",
|
|
111
|
+
"@types/file-saver": "^2.0.7",
|
|
112
|
+
"@types/lodash-es": "^4.17.12",
|
|
113
|
+
"@types/node": "^18.19.44",
|
|
114
|
+
"@types/svg-arc-to-cubic-bezier": "^3.2.3",
|
|
115
|
+
"@types/tinycolor2": "^1.4.6",
|
|
116
|
+
"@unocss/nuxt": "^66.6.0",
|
|
117
|
+
"@unocss/preset-wind3": "^66.6.0",
|
|
118
|
+
"@unocss/reset": "^66.3.3",
|
|
119
|
+
"sass": "^1.93.2",
|
|
120
|
+
"shadcn-nuxt": "^2.4.3",
|
|
121
|
+
"typescript": "^5.5.4",
|
|
122
|
+
"unocss": "^66.3.3",
|
|
123
|
+
"unocss-preset-animations": "^1.3.0",
|
|
124
|
+
"unocss-preset-shadcn": "^1.0.1",
|
|
125
|
+
"unplugin-vue-components": "^28.8.0",
|
|
126
|
+
"vite-bundle-analyzer": "^1.1.0",
|
|
127
|
+
"vue-tsc": "^2.0.29"
|
|
128
|
+
},
|
|
129
|
+
"packageManager": "pnpm@10.32.1"
|
|
130
|
+
}
|