poke-gate 0.1.1 → 0.1.5
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/.github/workflows/docs.yml +56 -0
- package/README.md +8 -4
- package/assets/screenshots/agents-editor.png +0 -0
- package/clients/Poke macOS Gate/Poke macOS Gate/AgentsView.swift +540 -0
- package/clients/Poke macOS Gate/Poke macOS Gate/GateService.swift +83 -17
- package/clients/Poke macOS Gate/Poke macOS Gate/Poke_macOS_GateApp.swift +10 -0
- package/clients/Poke macOS Gate/Poke macOS Gate.xcodeproj/project.pbxproj +8 -2
- package/clients/Poke macOS Gate/Poke macOS Gate.xcodeproj/project.xcworkspace/xcuserdata/fka.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/docs/.vitepress/config.mts +75 -0
- package/docs/agents/beeper.md +107 -0
- package/docs/agents/community.md +77 -0
- package/docs/agents/creating.md +132 -0
- package/docs/agents/index.md +85 -0
- package/docs/agents/installing.md +66 -0
- package/docs/agents/sharing.md +97 -0
- package/docs/cli.md +73 -0
- package/docs/getting-started.md +62 -0
- package/docs/how-it-works.md +56 -0
- package/docs/index.md +63 -0
- package/docs/macos-app.md +74 -0
- package/docs/package-lock.json +3629 -0
- package/docs/package.json +15 -0
- package/docs/public/CNAME +1 -0
- package/docs/public/agents-editor.png +0 -0
- package/docs/public/logo.png +0 -0
- package/docs/security.md +35 -0
- package/docs/tools.md +101 -0
- package/examples/agents/battery.30m.js +78 -0
- package/examples/agents/screentime.24h.js +86 -0
- package/examples/agents/wifi.30m.js +85 -0
- package/package.json +1 -1
- package/src/agents.js +20 -1
|
@@ -32,12 +32,13 @@ class GateService: ObservableObject {
|
|
|
32
32
|
|
|
33
33
|
func runPokeLogin() {
|
|
34
34
|
let fullPath = shellPath()
|
|
35
|
+
let npxBin = findNpx()
|
|
35
36
|
let proc = Process()
|
|
36
37
|
proc.executableURL = URL(fileURLWithPath: "/bin/zsh")
|
|
37
|
-
proc.arguments = ["-c", "
|
|
38
|
+
proc.arguments = ["-c", "\(npxBin) -y poke@latest login"]
|
|
38
39
|
proc.environment = ["HOME": NSHomeDirectory(), "PATH": fullPath]
|
|
39
40
|
try? proc.run()
|
|
40
|
-
appendLog("Launched poke login — check your browser.")
|
|
41
|
+
appendLog("Launched poke login (npx: \(npxBin)) — check your browser.")
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
func autoStartIfNeeded() {
|
|
@@ -90,19 +91,82 @@ class GateService: ObservableObject {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
let
|
|
95
|
-
let
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
94
|
+
func shellPath() -> String {
|
|
95
|
+
let home = NSHomeDirectory()
|
|
96
|
+
let fallback = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin"
|
|
97
|
+
|
|
98
|
+
// Try multiple shells/strategies to get PATH
|
|
99
|
+
let strategies: [(String, [String])] = [
|
|
100
|
+
("/bin/zsh", ["-ilc", "echo $PATH"]),
|
|
101
|
+
("/bin/zsh", ["-lc", "echo $PATH"]),
|
|
102
|
+
("/bin/bash", ["-lc", "echo $PATH"]),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
for (shell, args) in strategies {
|
|
106
|
+
let proc = Process()
|
|
107
|
+
let pipe = Pipe()
|
|
108
|
+
proc.executableURL = URL(fileURLWithPath: shell)
|
|
109
|
+
proc.arguments = args
|
|
110
|
+
proc.standardOutput = pipe
|
|
111
|
+
proc.standardError = FileHandle.nullDevice
|
|
112
|
+
proc.environment = ["HOME": home]
|
|
113
|
+
do {
|
|
114
|
+
try proc.run()
|
|
115
|
+
proc.waitUntilExit()
|
|
116
|
+
if proc.terminationStatus == 0 {
|
|
117
|
+
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
|
118
|
+
if let path = String(data: data, encoding: .utf8)?
|
|
119
|
+
.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
120
|
+
!path.isEmpty {
|
|
121
|
+
return path
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
continue
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Fallback: build PATH from common locations
|
|
130
|
+
var paths = fallback.split(separator: ":").map(String.init)
|
|
131
|
+
|
|
132
|
+
let commonDirs = [
|
|
133
|
+
"\(home)/.nvm/versions/node",
|
|
134
|
+
"\(home)/.volta/bin",
|
|
135
|
+
"\(home)/.fnm/aliases/default/bin",
|
|
136
|
+
"\(home)/.local/bin",
|
|
137
|
+
"\(home)/.cargo/bin",
|
|
138
|
+
"/opt/homebrew/bin",
|
|
139
|
+
"/usr/local/bin",
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
for dir in commonDirs {
|
|
143
|
+
if FileManager.default.fileExists(atPath: dir) {
|
|
144
|
+
if dir.contains(".nvm") {
|
|
145
|
+
// Find the latest node version in nvm
|
|
146
|
+
if let versions = try? FileManager.default.contentsOfDirectory(atPath: dir) {
|
|
147
|
+
if let latest = versions.sorted().last {
|
|
148
|
+
let binPath = "\(dir)/\(latest)/bin"
|
|
149
|
+
if !paths.contains(binPath) { paths.insert(binPath, at: 0) }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} else if !paths.contains(dir) {
|
|
153
|
+
paths.insert(dir, at: 0)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return paths.joined(separator: ":")
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private func findNpx() -> String {
|
|
162
|
+
let path = shellPath()
|
|
163
|
+
for dir in path.split(separator: ":") {
|
|
164
|
+
let npxPath = "\(dir)/npx"
|
|
165
|
+
if FileManager.default.isExecutableFile(atPath: npxPath) {
|
|
166
|
+
return npxPath
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return "npx"
|
|
106
170
|
}
|
|
107
171
|
|
|
108
172
|
private func launchProcess() {
|
|
@@ -112,15 +176,17 @@ class GateService: ObservableObject {
|
|
|
112
176
|
appendLog("Starting poke-gate…")
|
|
113
177
|
|
|
114
178
|
let fullPath = shellPath()
|
|
179
|
+
let npxBin = findNpx()
|
|
180
|
+
|
|
181
|
+
appendLog("Using npx at: \(npxBin)")
|
|
115
182
|
|
|
116
183
|
let proc = Process()
|
|
117
184
|
let pipe = Pipe()
|
|
118
185
|
|
|
119
186
|
proc.executableURL = URL(fileURLWithPath: "/bin/zsh")
|
|
120
|
-
proc.arguments = ["-c", "
|
|
187
|
+
proc.arguments = ["-c", "\(npxBin) -y poke-gate --verbose"]
|
|
121
188
|
proc.environment = ProcessInfo.processInfo.environment.merging(
|
|
122
189
|
[
|
|
123
|
-
"POKE_API_KEY": resolveToken() ?? "",
|
|
124
190
|
"PATH": fullPath,
|
|
125
191
|
],
|
|
126
192
|
uniquingKeysWith: { _, new in new }
|
|
@@ -23,6 +23,11 @@ struct Poke_macOS_GateApp: App {
|
|
|
23
23
|
}
|
|
24
24
|
.windowResizability(.contentSize)
|
|
25
25
|
|
|
26
|
+
Window("Agents", id: "agents") {
|
|
27
|
+
AgentsView()
|
|
28
|
+
}
|
|
29
|
+
.defaultSize(width: 700, height: 480)
|
|
30
|
+
|
|
26
31
|
Window("About", id: "about") {
|
|
27
32
|
AboutView()
|
|
28
33
|
}
|
|
@@ -110,6 +115,11 @@ struct PopoverContent: View {
|
|
|
110
115
|
openWindow(id: "logs")
|
|
111
116
|
}
|
|
112
117
|
|
|
118
|
+
ActionButton(icon: "bolt.fill", label: "Agents") {
|
|
119
|
+
NSApp.activate(ignoringOtherApps: true)
|
|
120
|
+
openWindow(id: "agents")
|
|
121
|
+
}
|
|
122
|
+
|
|
113
123
|
ActionButton(icon: "gearshape", label: "Settings") {
|
|
114
124
|
NSApp.activate(ignoringOtherApps: true)
|
|
115
125
|
openWindow(id: "settings")
|
|
@@ -259,12 +259,15 @@
|
|
|
259
259
|
ENABLE_PREVIEWS = YES;
|
|
260
260
|
GENERATE_INFOPLIST_FILE = YES;
|
|
261
261
|
INFOPLIST_FILE = "Poke macOS Gate/Info.plist";
|
|
262
|
+
INFOPLIST_KEY_CFBundleDisplayName = "Poke macOS Gate";
|
|
263
|
+
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
|
|
262
264
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
|
263
265
|
LD_RUNPATH_SEARCH_PATHS = (
|
|
264
266
|
"$(inherited)",
|
|
265
267
|
"@executable_path/../Frameworks",
|
|
266
268
|
);
|
|
267
|
-
|
|
269
|
+
MACOSX_DEPLOYMENT_TARGET = 26.0;
|
|
270
|
+
MARKETING_VERSION = 0.1.5;
|
|
268
271
|
PRODUCT_BUNDLE_IDENTIFIER = "dev.fka.Poke-macOS-Gate";
|
|
269
272
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
270
273
|
REGISTER_APP_GROUPS = YES;
|
|
@@ -291,12 +294,15 @@
|
|
|
291
294
|
ENABLE_PREVIEWS = YES;
|
|
292
295
|
GENERATE_INFOPLIST_FILE = YES;
|
|
293
296
|
INFOPLIST_FILE = "Poke macOS Gate/Info.plist";
|
|
297
|
+
INFOPLIST_KEY_CFBundleDisplayName = "Poke macOS Gate";
|
|
298
|
+
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
|
|
294
299
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
|
295
300
|
LD_RUNPATH_SEARCH_PATHS = (
|
|
296
301
|
"$(inherited)",
|
|
297
302
|
"@executable_path/../Frameworks",
|
|
298
303
|
);
|
|
299
|
-
|
|
304
|
+
MACOSX_DEPLOYMENT_TARGET = 26.0;
|
|
305
|
+
MARKETING_VERSION = 0.1.5;
|
|
300
306
|
PRODUCT_BUNDLE_IDENTIFIER = "dev.fka.Poke-macOS-Gate";
|
|
301
307
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
302
308
|
REGISTER_APP_GROUPS = YES;
|
|
Binary file
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { defineConfig } from 'vitepress'
|
|
2
|
+
import { withMermaid } from 'vitepress-plugin-mermaid'
|
|
3
|
+
|
|
4
|
+
export default withMermaid(
|
|
5
|
+
defineConfig({
|
|
6
|
+
title: 'Poke Gate',
|
|
7
|
+
description: 'Let your Poke AI assistant access your machine',
|
|
8
|
+
head: [
|
|
9
|
+
['link', { rel: 'icon', href: '/logo.png' }],
|
|
10
|
+
],
|
|
11
|
+
themeConfig: {
|
|
12
|
+
logo: '/logo.png',
|
|
13
|
+
nav: [
|
|
14
|
+
{ text: 'Guide', link: '/getting-started' },
|
|
15
|
+
{ text: 'Agents', link: '/agents/' },
|
|
16
|
+
{ text: 'CLI', link: '/cli' },
|
|
17
|
+
{
|
|
18
|
+
text: 'Download',
|
|
19
|
+
items: [
|
|
20
|
+
{ text: 'macOS App', link: 'https://github.com/f/poke-gate/releases/latest' },
|
|
21
|
+
{ text: 'Homebrew', link: '/getting-started#homebrew' },
|
|
22
|
+
{ text: 'npm', link: 'https://www.npmjs.com/package/poke-gate' },
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
sidebar: [
|
|
27
|
+
{
|
|
28
|
+
text: 'Guide',
|
|
29
|
+
items: [
|
|
30
|
+
{ text: 'Getting Started', link: '/getting-started' },
|
|
31
|
+
{ text: 'How It Works', link: '/how-it-works' },
|
|
32
|
+
{ text: 'Tools', link: '/tools' },
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
text: 'Agents',
|
|
37
|
+
items: [
|
|
38
|
+
{ text: 'Overview', link: '/agents/' },
|
|
39
|
+
{ text: 'Creating Agents', link: '/agents/creating' },
|
|
40
|
+
{ text: 'Installing Agents', link: '/agents/installing' },
|
|
41
|
+
{ text: 'Community Agents', link: '/agents/community' },
|
|
42
|
+
{ text: 'Beeper Example', link: '/agents/beeper' },
|
|
43
|
+
{ text: 'Sharing Agents', link: '/agents/sharing' },
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
text: 'Reference',
|
|
48
|
+
items: [
|
|
49
|
+
{ text: 'macOS App', link: '/macos-app' },
|
|
50
|
+
{ text: 'CLI Reference', link: '/cli' },
|
|
51
|
+
{ text: 'Security', link: '/security' },
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
socialLinks: [
|
|
56
|
+
{ icon: 'github', link: 'https://github.com/f/poke-gate' },
|
|
57
|
+
{ icon: 'npm', link: 'https://www.npmjs.com/package/poke-gate' },
|
|
58
|
+
],
|
|
59
|
+
footer: {
|
|
60
|
+
message: 'Community project — not affiliated with Poke or The Interaction Company.',
|
|
61
|
+
copyright: 'Released under the MIT License.',
|
|
62
|
+
},
|
|
63
|
+
editLink: {
|
|
64
|
+
pattern: 'https://github.com/f/poke-gate/edit/main/docs/:path',
|
|
65
|
+
text: 'Edit this page on GitHub',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
mermaid: {
|
|
69
|
+
theme: 'neutral',
|
|
70
|
+
themeVariables: {
|
|
71
|
+
fontSize: '13px',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Beeper Agent
|
|
2
|
+
|
|
3
|
+
The Beeper agent fetches messages from the last hour via [Beeper Desktop](https://beeper.com)'s local API, groups them by sender, and sends a summary to your Poke agent.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Every hour:
|
|
8
|
+
|
|
9
|
+
1. Calls Beeper's local API at `http://localhost:23373`
|
|
10
|
+
2. Searches for messages from the last 60 minutes
|
|
11
|
+
3. Filters out messages you sent (only shows incoming)
|
|
12
|
+
4. Groups messages by sender name
|
|
13
|
+
5. Formats a summary with sender name, message count, and last 3 messages
|
|
14
|
+
6. Sends the summary to Poke via `sendMessage`
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
- [Beeper Desktop](https://beeper.com) running on your machine
|
|
19
|
+
- Beeper API token (find it in Beeper Desktop > Settings > API)
|
|
20
|
+
- Signed in to Poke (`npx poke login`)
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx poke-gate agent get beeper
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When prompted, paste your Beeper token:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
BEEPER_TOKEN (Find it in Beeper Desktop > Settings > API): <paste>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Test
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx poke-gate run-agent beeper
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Expected output:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
[agents] Running agent: beeper (beeper.1h.js)
|
|
44
|
+
[agents] [beeper] Fetching messages from the last hour...
|
|
45
|
+
[agents] [beeper] Found 42 messages
|
|
46
|
+
[agents] [beeper] Sending summary to Poke...
|
|
47
|
+
[agents] [beeper] Summary sent to Poke.
|
|
48
|
+
[agents] [beeper] completed
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## What Poke receives
|
|
52
|
+
|
|
53
|
+
Your Poke agent gets a message like:
|
|
54
|
+
|
|
55
|
+
> Messages from the last hour (3 people):
|
|
56
|
+
>
|
|
57
|
+
> Alice (5 messages):
|
|
58
|
+
> - Hey, are you free for lunch?
|
|
59
|
+
> - The meeting got moved to 3pm
|
|
60
|
+
> - Can you review my PR?
|
|
61
|
+
>
|
|
62
|
+
> Bob (2 messages):
|
|
63
|
+
> - Deployed the fix
|
|
64
|
+
> - All tests passing now
|
|
65
|
+
>
|
|
66
|
+
> Mom (1 messages):
|
|
67
|
+
> - Don't forget dinner tonight!
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
### Env variables
|
|
72
|
+
|
|
73
|
+
| Variable | Required | Description |
|
|
74
|
+
|----------|----------|-------------|
|
|
75
|
+
| `BEEPER_TOKEN` | yes | Beeper Desktop API token |
|
|
76
|
+
| `BEEPER_BASE_URL` | no | Override default `http://localhost:23373` |
|
|
77
|
+
|
|
78
|
+
Edit: `~/.config/poke-gate/agents/.env.beeper`
|
|
79
|
+
|
|
80
|
+
### Change the interval
|
|
81
|
+
|
|
82
|
+
Rename the file to change how often it runs:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Every 30 minutes
|
|
86
|
+
mv ~/.config/poke-gate/agents/beeper.1h.js ~/.config/poke-gate/agents/beeper.30m.js
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or use the macOS Agents editor.
|
|
90
|
+
|
|
91
|
+
## Frontmatter
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
/**
|
|
95
|
+
* @agent beeper
|
|
96
|
+
* @name Beeper Message Digest
|
|
97
|
+
* @description Fetches messages from the last hour via Beeper Desktop and sends a summary to Poke.
|
|
98
|
+
* @interval 1h
|
|
99
|
+
* @env BEEPER_TOKEN - Beeper Desktop local API token (Settings > API)
|
|
100
|
+
* @env BEEPER_BASE_URL - (optional) Override default http://localhost:23373
|
|
101
|
+
* @author f
|
|
102
|
+
*/
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Source
|
|
106
|
+
|
|
107
|
+
[View on GitHub](https://github.com/f/poke-gate/blob/main/examples/agents/beeper.1h.js)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Community Agents
|
|
2
|
+
|
|
3
|
+
Ready-to-use agents you can install with a single command. All agents are open source and included in the [Poke Gate repository](https://github.com/f/poke-gate/tree/main/examples/agents).
|
|
4
|
+
|
|
5
|
+
## Beeper Message Digest
|
|
6
|
+
|
|
7
|
+
Fetches messages from the last hour via [Beeper Desktop](https://beeper.com)'s local API, groups them by sender, and sends a summary to Poke. Great for staying on top of conversations across all your messaging platforms without checking each one.
|
|
8
|
+
|
|
9
|
+
| | |
|
|
10
|
+
|---|---|
|
|
11
|
+
| **File** | `beeper.1h.js` |
|
|
12
|
+
| **Interval** | Every hour |
|
|
13
|
+
| **Requires** | Beeper Desktop running, API token |
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx poke-gate agent get beeper
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
[Full documentation →](/agents/beeper)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Screen Time Report
|
|
24
|
+
|
|
25
|
+
Sends a daily summary of your Mac usage — currently running apps, uptime, and top processes. Poke learns your work patterns and can answer questions like "what was I doing yesterday?" or "how long have I been working today?".
|
|
26
|
+
|
|
27
|
+
| | |
|
|
28
|
+
|---|---|
|
|
29
|
+
| **File** | `screentime.24h.js` |
|
|
30
|
+
| **Interval** | Every 24 hours |
|
|
31
|
+
| **Requires** | Nothing — works out of the box |
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx poke-gate agent get screentime
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Battery Guardian
|
|
40
|
+
|
|
41
|
+
Monitors your battery and alerts you via Poke when it drops below 20% on battery power. Only alerts once per discharge cycle — won't spam you. Resets when you plug in.
|
|
42
|
+
|
|
43
|
+
| | |
|
|
44
|
+
|---|---|
|
|
45
|
+
| **File** | `battery.30m.js` |
|
|
46
|
+
| **Interval** | Every 30 minutes |
|
|
47
|
+
| **Requires** | Nothing — works out of the box |
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx poke-gate agent get battery
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
::: tip Custom threshold
|
|
54
|
+
Set `BATTERY_THRESHOLD` in `.env.battery` to change the alert level (default: 20%).
|
|
55
|
+
:::
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## WiFi Logger
|
|
60
|
+
|
|
61
|
+
Tracks which WiFi network you're on and notifies Poke when you switch networks or disconnect. This gives Poke passive context about your location — it knows if you're at home, at the office, or at a cafe without you telling it.
|
|
62
|
+
|
|
63
|
+
| | |
|
|
64
|
+
|---|---|
|
|
65
|
+
| **File** | `wifi.30m.js` |
|
|
66
|
+
| **Interval** | Every 30 minutes |
|
|
67
|
+
| **Requires** | Nothing — works out of the box |
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx poke-gate agent get wifi
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Want more?
|
|
76
|
+
|
|
77
|
+
Check the [Sharing Agents](/agents/sharing) page for ideas and instructions on contributing your own agent to the community.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Creating Agents
|
|
2
|
+
|
|
3
|
+
This guide walks you through creating an agent from scratch.
|
|
4
|
+
|
|
5
|
+
## Step 1: Create the file
|
|
6
|
+
|
|
7
|
+
Agents live in `~/.config/poke-gate/agents/`. Create a file with the naming convention `name.interval.js`:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
touch ~/.config/poke-gate/agents/hello.1h.js
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This creates an agent called "hello" that runs every hour.
|
|
14
|
+
|
|
15
|
+
## Step 2: Add frontmatter
|
|
16
|
+
|
|
17
|
+
Start with the frontmatter block. This is optional but recommended — it's displayed in the macOS Agents editor.
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
/**
|
|
21
|
+
* @agent hello
|
|
22
|
+
* @name Hello World
|
|
23
|
+
* @description Sends a greeting to Poke every hour.
|
|
24
|
+
* @interval 1h
|
|
25
|
+
* @author you
|
|
26
|
+
*/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Step 3: Write your logic
|
|
30
|
+
|
|
31
|
+
Agents are standard Node.js ESM scripts. They can import the Poke SDK and any globally installed packages.
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
/**
|
|
35
|
+
* @agent hello
|
|
36
|
+
* @name Hello World
|
|
37
|
+
* @description Sends a greeting to Poke every hour.
|
|
38
|
+
* @interval 1h
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { Poke, getToken } from "poke";
|
|
42
|
+
|
|
43
|
+
const token = getToken();
|
|
44
|
+
if (!token) {
|
|
45
|
+
console.error("Not signed in. Run: npx poke login");
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const poke = new Poke({ apiKey: token });
|
|
50
|
+
await poke.sendMessage("Hello! This is an automated message from my Hello agent.");
|
|
51
|
+
|
|
52
|
+
console.log("Sent greeting to Poke.");
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Step 4: Add env variables (optional)
|
|
56
|
+
|
|
57
|
+
If your agent needs secrets (API tokens, URLs, etc.), create a `.env.<name>` file:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
nano ~/.config/poke-gate/agents/.env.hello
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```env
|
|
64
|
+
# My custom config
|
|
65
|
+
MY_API_KEY=secret_123
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then read them in your script:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
const apiKey = process.env.MY_API_KEY;
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Step 5: Test it
|
|
75
|
+
|
|
76
|
+
Run your agent manually:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx poke-gate run-agent hello
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You should see:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
[agents] Running agent: hello (hello.1h.js)
|
|
86
|
+
[agents] [hello] Sent greeting to Poke.
|
|
87
|
+
[agents] [hello] completed
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Step 6: Let it run
|
|
91
|
+
|
|
92
|
+
Start Poke Gate normally. Your agent will be discovered and scheduled:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npx poke-gate
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
[agents] Found 1 agent(s):
|
|
100
|
+
Hello World (every 1h)
|
|
101
|
+
[agents] Running agent: hello (hello.1h.js)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Tips
|
|
105
|
+
|
|
106
|
+
- **Keep agents fast.** They have a 5-minute timeout. If your agent takes longer, it'll be killed.
|
|
107
|
+
- **Use `console.log`** for debugging. Output appears in the Poke Gate logs.
|
|
108
|
+
- **Handle errors gracefully.** If your agent throws, it logs the error and continues to the next scheduled run.
|
|
109
|
+
- **Change the interval** by renaming the file (e.g. `hello.1h.js` → `hello.30m.js`) or using the macOS Agents editor.
|
|
110
|
+
|
|
111
|
+
## Template
|
|
112
|
+
|
|
113
|
+
Here's a minimal template to copy:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
/**
|
|
117
|
+
* @agent my-agent
|
|
118
|
+
* @name My Agent
|
|
119
|
+
* @description What this agent does.
|
|
120
|
+
* @interval 1h
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
import { Poke, getToken } from "poke";
|
|
124
|
+
|
|
125
|
+
const poke = new Poke({ apiKey: getToken() });
|
|
126
|
+
|
|
127
|
+
// Your logic here
|
|
128
|
+
const result = "Something useful";
|
|
129
|
+
|
|
130
|
+
await poke.sendMessage(result);
|
|
131
|
+
console.log("Done.");
|
|
132
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Agents
|
|
2
|
+
|
|
3
|
+
Agents are scheduled scripts that **push information from your computer to Poke**. They run in the background, gather data from local sources (APIs, files, services), and send it to your Poke agent — so Poke learns about what's happening on your machine without you asking.
|
|
4
|
+
|
|
5
|
+
Think of it this way: **Tools** let Poke pull from your machine (you ask, Poke acts). **Agents** let your machine push to Poke (your computer tells Poke, Poke learns and replies).
|
|
6
|
+
|
|
7
|
+
::: tip Secure and deterministic
|
|
8
|
+
Agents are **push-only** — they send data to Poke, but Poke cannot reach back into the agent or your computer through them. Each agent is a plain JavaScript file that you write and control. It runs the same way every time, with no AI decision-making involved. The agent doesn't "try" to access your machine — it only does exactly what the script says. This makes agents predictable, auditable, and safe.
|
|
9
|
+
:::
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
flowchart LR
|
|
13
|
+
subgraph YourMac ["Your Mac"]
|
|
14
|
+
Agent["Agent script"]
|
|
15
|
+
Local["Local data source"]
|
|
16
|
+
Local -->|reads| Agent
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Agent -->|sendMessage| Poke["Poke Agent"]
|
|
20
|
+
Poke -->|replies| You["You"]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Example:** A Beeper agent runs every hour, fetches your unread messages, and sends a digest to Poke. Now Poke knows who messaged you — and can answer "did anyone text me?" without needing your machine in real time.
|
|
24
|
+
|
|
25
|
+
## How agents work
|
|
26
|
+
|
|
27
|
+
1. You place a `.js` file in `~/.config/poke-gate/agents/`
|
|
28
|
+
2. The filename defines the schedule: `name.interval.js`
|
|
29
|
+
3. When Poke Gate connects, it discovers all agents and starts their timers
|
|
30
|
+
4. Each agent runs once immediately, then repeats on schedule
|
|
31
|
+
5. Agents use the Poke SDK to send messages — pushing data to your agent
|
|
32
|
+
|
|
33
|
+
## Naming convention
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
<name>.<interval>.js
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| File | Runs |
|
|
40
|
+
|------|------|
|
|
41
|
+
| `beeper.1h.js` | Every hour |
|
|
42
|
+
| `backup.2h.js` | Every 2 hours |
|
|
43
|
+
| `health.10m.js` | Every 10 minutes |
|
|
44
|
+
| `cleanup.30m.js` | Every 30 minutes |
|
|
45
|
+
| `digest.24h.js` | Every 24 hours |
|
|
46
|
+
|
|
47
|
+
**Intervals:** `Nm` (minutes) or `Nh` (hours). Minimum is **10 minutes**.
|
|
48
|
+
|
|
49
|
+
## Frontmatter
|
|
50
|
+
|
|
51
|
+
Each agent starts with a JSDoc-style frontmatter block:
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
/**
|
|
55
|
+
* @agent beeper
|
|
56
|
+
* @name Beeper Message Digest
|
|
57
|
+
* @description Fetches messages from the last hour and sends a summary.
|
|
58
|
+
* @interval 1h
|
|
59
|
+
* @env BEEPER_TOKEN - Beeper Desktop local API token
|
|
60
|
+
* @author f
|
|
61
|
+
*/
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The `@name` and `@description` are shown in the macOS app's Agents editor and in the scheduler logs.
|
|
65
|
+
|
|
66
|
+
## Per-agent env files
|
|
67
|
+
|
|
68
|
+
Each agent can have a `.env.<name>` file in the same directory:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
~/.config/poke-gate/agents/.env.beeper
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```env
|
|
75
|
+
BEEPER_TOKEN=your_token_here
|
|
76
|
+
BEEPER_BASE_URL=http://localhost:23373
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Variables are injected into the agent's environment automatically. The agent reads them via `process.env.BEEPER_TOKEN`.
|
|
80
|
+
|
|
81
|
+
## What's next?
|
|
82
|
+
|
|
83
|
+
- [Creating Agents](/agents/creating) — write your first agent from scratch
|
|
84
|
+
- [Installing Agents](/agents/installing) — download community agents
|
|
85
|
+
- [Beeper Example](/agents/beeper) — full walkthrough of a real agent
|