agentclick 0.1.0 → 0.1.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/AGENTS.md CHANGED
@@ -132,10 +132,12 @@ Read `docs/dev-rules.md` before writing any code. Key rules:
132
132
  - Minimal CI build workflow (GitHub Actions: `npm ci && npm run build`)
133
133
  - Deployment guide (`docs/deployment.md`) for single-port runtime, env vars, reverse proxy, and Docker/OpenClaw notes
134
134
  - Global CLI packaging entrypoint (`bin/agentclick.mjs`) for `agentclick` command startup
135
+ - npm package published: `agentclick@0.1.0`
136
+ - CC suggestions checkbox UI (returns selected suggestions in review completion payload)
137
+ - Summary view fetches `/api/sessions/:id/summary` and renders mock summary response (backend endpoint included)
135
138
 
136
139
  **Pending:**
137
- - npm publish execution (`npm publish`) after final package review
138
- - CC suggestions as checkboxes (currently free-text input; agent can pass `ccSuggestions[]`)
140
+ - Replace mock summary endpoint with real agent-generated summaries
139
141
 
140
142
  ---
141
143
 
package/README.md CHANGED
@@ -69,6 +69,15 @@ agentclick
69
69
 
70
70
  This starts the AgentClick server on `http://localhost:3001` and serves the built web UI on the same port.
71
71
 
72
+ CLI options:
73
+
74
+ ```bash
75
+ agentclick --help
76
+ PORT=3002 agentclick
77
+ ```
78
+
79
+ By default, `agentclick` starts on port `3001`. If that port is in use, it automatically tries `3002`, `3003`, and so on.
80
+
72
81
  Optional server config (defaults shown in `.env.example`):
73
82
 
74
83
  ```bash
@@ -4,11 +4,39 @@ import { existsSync } from 'node:fs'
4
4
  import { dirname, join } from 'node:path'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import { spawnSync } from 'node:child_process'
7
+ import net from 'node:net'
7
8
 
8
9
  const __filename = fileURLToPath(import.meta.url)
9
10
  const rootDir = dirname(dirname(__filename))
10
11
  const webDistIndex = join(rootDir, 'packages', 'web', 'dist', 'index.html')
11
12
  const serverDistEntry = join(rootDir, 'packages', 'server', 'dist', 'index.js')
13
+ const args = process.argv.slice(2)
14
+
15
+ function printHelp() {
16
+ console.log(`AgentClick CLI
17
+
18
+ Usage:
19
+ agentclick
20
+ agentclick --help
21
+
22
+ Options:
23
+ --help, -h Show this help message
24
+ `)
25
+ }
26
+
27
+ function parseArgs(argv) {
28
+ for (let i = 0; i < argv.length; i += 1) {
29
+ const arg = argv[i]
30
+ if (arg === '--help' || arg === '-h') {
31
+ printHelp()
32
+ process.exit(0)
33
+ }
34
+ console.error(`[agentclick] Unknown argument: ${arg}`)
35
+ console.error('[agentclick] Run "agentclick --help" for usage.')
36
+ process.exit(1)
37
+ }
38
+ return {}
39
+ }
12
40
 
13
41
  function run(command, args) {
14
42
  const result = spawnSync(command, args, {
@@ -25,6 +53,8 @@ function run(command, args) {
25
53
  }
26
54
  }
27
55
 
56
+ parseArgs(args)
57
+
28
58
  if (!existsSync(webDistIndex) || !existsSync(serverDistEntry)) {
29
59
  console.log('[agentclick] Build artifacts not found, running npm run build...')
30
60
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
@@ -36,4 +66,48 @@ if (!existsSync(serverDistEntry)) {
36
66
  process.exit(1)
37
67
  }
38
68
 
39
- run(process.execPath, [serverDistEntry])
69
+ async function canListen(port) {
70
+ return await new Promise(resolve => {
71
+ const server = net.createServer()
72
+ server.once('error', err => {
73
+ if ((err).code === 'EADDRINUSE') {
74
+ resolve(false)
75
+ return
76
+ }
77
+ console.error(`[agentclick] Port check failed for ${port}: ${err.message}`)
78
+ process.exit(1)
79
+ })
80
+ server.once('listening', () => {
81
+ server.close(() => resolve(true))
82
+ })
83
+ server.listen(port)
84
+ })
85
+ }
86
+
87
+ async function resolvePort() {
88
+ if (process.env.PORT) return process.env.PORT
89
+
90
+ let port = 3001
91
+ while (true) {
92
+ const available = await canListen(port)
93
+ if (available) return String(port)
94
+ console.log(`[agentclick] Port ${port} in use, trying ${port + 1}...`)
95
+ port += 1
96
+ }
97
+ }
98
+
99
+ const childEnv = { ...process.env }
100
+ childEnv.PORT = await resolvePort()
101
+
102
+ const result = spawnSync(process.execPath, [serverDistEntry], {
103
+ cwd: rootDir,
104
+ stdio: 'inherit',
105
+ env: childEnv,
106
+ })
107
+ if (result.error) {
108
+ console.error('[agentclick] Failed to start server:', result.error.message)
109
+ process.exit(1)
110
+ }
111
+ if (typeof result.status === 'number' && result.status !== 0) {
112
+ process.exit(result.status)
113
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentclick",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "bin": {
5
5
  "agentclick": "./bin/agentclick.mjs"
6
6
  },
@@ -74,6 +74,35 @@ app.get('/api/sessions/:id', (req, res) => {
74
74
  return res.status(404).json({ error: 'Session not found' });
75
75
  res.json(session);
76
76
  });
77
+ // Mock summary endpoint for inbox items (UI integration first)
78
+ app.get('/api/sessions/:id/summary', (req, res) => {
79
+ const session = getSession(req.params.id);
80
+ if (!session)
81
+ return res.status(404).json({ error: 'Session not found' });
82
+ const payload = session.payload;
83
+ const inbox = payload?.inbox ?? [];
84
+ const emailId = req.query.emailId;
85
+ const email = inbox.find(item => item.id === emailId);
86
+ if (!email) {
87
+ return res.status(404).json({ error: 'Email not found in session' });
88
+ }
89
+ const preview = String(email.preview ?? '');
90
+ const summaryText = preview.length > 0
91
+ ? `This email appears to be about: ${preview}`
92
+ : 'No preview text is available for this email yet.';
93
+ const from = String(email.from ?? 'Unknown sender');
94
+ const category = String(email.category ?? 'Unknown');
95
+ res.json({
96
+ emailId,
97
+ summary: summaryText,
98
+ bullets: [
99
+ `From: ${from}`,
100
+ `Category: ${category}`,
101
+ 'Source: mock summary endpoint (replace with agent summary later)',
102
+ ],
103
+ confidence: 'mock',
104
+ });
105
+ });
77
106
  // Long-poll: agent calls this and blocks until user completes review (up to 5 min)
78
107
  app.get('/api/sessions/:id/wait', async (req, res) => {
79
108
  const TIMEOUT_MS = 5 * 60 * 1000;
@@ -83,6 +83,40 @@ app.get('/api/sessions/:id', (req, res) => {
83
83
  res.json(session)
84
84
  })
85
85
 
86
+ // Mock summary endpoint for inbox items (UI integration first)
87
+ app.get('/api/sessions/:id/summary', (req, res) => {
88
+ const session = getSession(req.params.id)
89
+ if (!session) return res.status(404).json({ error: 'Session not found' })
90
+
91
+ const payload = session.payload as Record<string, unknown> | undefined
92
+ const inbox = (payload?.inbox as Array<Record<string, unknown>> | undefined) ?? []
93
+ const emailId = req.query.emailId as string | undefined
94
+ const email = inbox.find(item => item.id === emailId)
95
+
96
+ if (!email) {
97
+ return res.status(404).json({ error: 'Email not found in session' })
98
+ }
99
+
100
+ const preview = String(email.preview ?? '')
101
+ const summaryText = preview.length > 0
102
+ ? `This email appears to be about: ${preview}`
103
+ : 'No preview text is available for this email yet.'
104
+
105
+ const from = String(email.from ?? 'Unknown sender')
106
+ const category = String(email.category ?? 'Unknown')
107
+
108
+ res.json({
109
+ emailId,
110
+ summary: summaryText,
111
+ bullets: [
112
+ `From: ${from}`,
113
+ `Category: ${category}`,
114
+ 'Source: mock summary endpoint (replace with agent summary later)',
115
+ ],
116
+ confidence: 'mock',
117
+ })
118
+ })
119
+
86
120
  // Long-poll: agent calls this and blocks until user completes review (up to 5 min)
87
121
  app.get('/api/sessions/:id/wait', async (req, res) => {
88
122
  const TIMEOUT_MS = 5 * 60 * 1000