@xiaotianxt/skills 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.
Files changed (120) hide show
  1. package/EXCLUDED.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +165 -0
  4. package/SECURITY.md +23 -0
  5. package/SOURCES.md +45 -0
  6. package/bin/skills.mjs +241 -0
  7. package/package.json +38 -0
  8. package/skills/1password/SKILL.md +94 -0
  9. package/skills/1password/agents/openai.yaml +4 -0
  10. package/skills/1password/references/item-management.md +80 -0
  11. package/skills/1password/references/op-cli.md +107 -0
  12. package/skills/apple-calendar-event/SKILL.md +81 -0
  13. package/skills/apple-calendar-event/agents/openai.yaml +4 -0
  14. package/skills/apple-calendar-event/scripts/calendar_audit.py +201 -0
  15. package/skills/apple-calendar-event/scripts/calendar_event.py +164 -0
  16. package/skills/bro-browser/SKILL.md +118 -0
  17. package/skills/bro-browser/agents/openai.yaml +4 -0
  18. package/skills/bro-browser/references/tool-map.md +102 -0
  19. package/skills/bro-browser/references/workflows.md +146 -0
  20. package/skills/bro-browser/scripts/bro-call.mjs +189 -0
  21. package/skills/calendar/SKILL.md +182 -0
  22. package/skills/calendar/agents/openai.yaml +4 -0
  23. package/skills/calendar/references/operations.md +255 -0
  24. package/skills/calendar/scripts/calendar_list_review.py +157 -0
  25. package/skills/calendar/scripts/event_dedupe_preview.py +155 -0
  26. package/skills/canvas/SKILL.md +70 -0
  27. package/skills/canvas/agents/openai.yaml +4 -0
  28. package/skills/canvas/references/canvas-api.md +76 -0
  29. package/skills/course-exam-review-planner/SKILL.md +127 -0
  30. package/skills/cx/SKILL.md +25 -0
  31. package/skills/gh-fix-ci/LICENSE.txt +201 -0
  32. package/skills/gh-fix-ci/SKILL.md +81 -0
  33. package/skills/gh-fix-ci/agents/openai.yaml +6 -0
  34. package/skills/gh-fix-ci/assets/github-small.svg +3 -0
  35. package/skills/gh-fix-ci/assets/github.png +0 -0
  36. package/skills/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
  37. package/skills/gh-review-workflow/SKILL.md +61 -0
  38. package/skills/gh-review-workflow/agents/openai.yaml +4 -0
  39. package/skills/gh-review-workflow/references/workflow.md +48 -0
  40. package/skills/gh-review-workflow/scripts/fetch_review_state.py +222 -0
  41. package/skills/gh-review-workflow/scripts/resolve_review_threads.py +83 -0
  42. package/skills/github/SKILL.md +74 -0
  43. package/skills/github/agents/openai.yaml +6 -0
  44. package/skills/github/assets/github-small.svg +3 -0
  45. package/skills/github/assets/github.png +0 -0
  46. package/skills/gws-calendar/SKILL.md +126 -0
  47. package/skills/gws-calendar-agenda/SKILL.md +52 -0
  48. package/skills/gws-calendar-insert/SKILL.md +66 -0
  49. package/skills/gws-docs/SKILL.md +48 -0
  50. package/skills/gws-docs-write/SKILL.md +49 -0
  51. package/skills/gws-drive/SKILL.md +137 -0
  52. package/skills/gws-drive-upload/SKILL.md +52 -0
  53. package/skills/gws-gmail/SKILL.md +62 -0
  54. package/skills/gws-gmail-forward/SKILL.md +55 -0
  55. package/skills/gws-gmail-reply/SKILL.md +58 -0
  56. package/skills/gws-gmail-reply-all/SKILL.md +62 -0
  57. package/skills/gws-gmail-send/SKILL.md +57 -0
  58. package/skills/gws-gmail-triage/SKILL.md +50 -0
  59. package/skills/gws-gmail-watch/SKILL.md +58 -0
  60. package/skills/gws-shared/SKILL.md +27 -0
  61. package/skills/helium-browser-mcp/SKILL.md +137 -0
  62. package/skills/helium-browser-mcp/agents/openai.yaml +4 -0
  63. package/skills/helium-browser-mcp/scripts/obmcp.mjs +92 -0
  64. package/skills/helium-browser-mcp/scripts/openbrowsermcp-stdio-proxy.mjs +170 -0
  65. package/skills/learn/SKILL.md +122 -0
  66. package/skills/learn/agents/openai.yaml +7 -0
  67. package/skills/learn/assets/AGENTS.template.md +33 -0
  68. package/skills/learn/assets/errorlog.template.typ +61 -0
  69. package/skills/learn/assets/reading-sequence.template.md +23 -0
  70. package/skills/learn/assets/source-index.template.md +17 -0
  71. package/skills/learn/assets/tasklog.template.typ +57 -0
  72. package/skills/learn/assets/workbook.template.typ +60 -0
  73. package/skills/learn/references/learning-science.md +103 -0
  74. package/skills/learn/scripts/init_learning_workspace.py +70 -0
  75. package/skills/macos-messages/SKILL.md +258 -0
  76. package/skills/memory/SKILL.md +33 -0
  77. package/skills/memory/codex.md +186 -0
  78. package/skills/memory/opencode.md +164 -0
  79. package/skills/mimestreamctl/SKILL.md +170 -0
  80. package/skills/mimestreamctl/agents/openai.yaml +4 -0
  81. package/skills/mimestreamctl/scripts/mimestreamctl +33 -0
  82. package/skills/mon/SKILL.md +51 -0
  83. package/skills/mon/scripts/mon_spend_review.py +458 -0
  84. package/skills/ocr/SKILL.md +136 -0
  85. package/skills/ocr/agents/openai.yaml +4 -0
  86. package/skills/ocr/references/local-ocr-best-practices.md +297 -0
  87. package/skills/ocr/references/mineru-api.md +159 -0
  88. package/skills/ocr/scripts/ocr-router +22 -0
  89. package/skills/ocr/scripts/ocr_router.py +741 -0
  90. package/skills/panopto-mp4-bulk-download/SKILL.md +57 -0
  91. package/skills/panopto-mp4-bulk-download/agents/openai.yaml +4 -0
  92. package/skills/panopto-mp4-bulk-download/references/url-patterns.md +26 -0
  93. package/skills/panopto-mp4-bulk-download/scripts/panopto_bulk_mp4.sh +213 -0
  94. package/skills/rust-systems-style/SKILL.md +109 -0
  95. package/skills/rust-systems-style/agents/openai.yaml +4 -0
  96. package/skills/rust-systems-style/references/rust-review-checklist.md +77 -0
  97. package/skills/rust-systems-style/references/style-sources.md +68 -0
  98. package/skills/ship-ai-native-cli/SKILL.md +76 -0
  99. package/skills/ship-ai-native-cli/agents/openai.yaml +4 -0
  100. package/skills/ship-ai-native-cli/references/case-notes.md +83 -0
  101. package/skills/ship-ai-native-cli/references/product-method.md +82 -0
  102. package/skills/ship-ai-native-cli/references/release-checklist.md +147 -0
  103. package/skills/ship-ai-native-cli/references/rust-cli-shape.md +111 -0
  104. package/skills/telegram-mtproto-session/SKILL.md +125 -0
  105. package/skills/telegram-mtproto-session/agents/openai.yaml +4 -0
  106. package/skills/telegram-mtproto-session/scripts/telegram_session.py +687 -0
  107. package/skills/tg/SKILL.md +173 -0
  108. package/skills/things3-manager/SKILL.md +116 -0
  109. package/skills/things3-manager/scripts/things +42 -0
  110. package/skills/things3-manager/scripts/things_cli.py +514 -0
  111. package/skills/web-artifacts-builder/LICENSE.txt +202 -0
  112. package/skills/web-artifacts-builder/SKILL.md +74 -0
  113. package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  114. package/skills/web-artifacts-builder/scripts/init-artifact.sh +379 -0
  115. package/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  116. package/skills/yeet/LICENSE.txt +201 -0
  117. package/skills/yeet/SKILL.md +71 -0
  118. package/skills/yeet/agents/openai.yaml +6 -0
  119. package/skills/yeet/assets/yeet-small.svg +3 -0
  120. package/skills/yeet/assets/yeet.png +0 -0
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: gws-gmail-watch
3
+ version: 1.0.0
4
+ description: "Gmail: Watch for new emails and stream them as NDJSON."
5
+ metadata:
6
+ openclaw:
7
+ category: "productivity"
8
+ requires:
9
+ bins: ["gws"]
10
+ cliHelp: "gws gmail +watch --help"
11
+ ---
12
+
13
+ # gmail +watch
14
+
15
+ > **PREREQUISITE:** Read `../gws-shared/SKILL.md` for auth, global flags, and security rules. If missing, run `gws generate-skills` to create it.
16
+
17
+ Watch for new emails and stream them as NDJSON
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ gws gmail +watch
23
+ ```
24
+
25
+ ## Flags
26
+
27
+ | Flag | Required | Default | Description |
28
+ |------|----------|---------|-------------|
29
+ | `--project` | — | — | GCP project ID for Pub/Sub resources |
30
+ | `--subscription` | — | — | Existing Pub/Sub subscription name (skip setup) |
31
+ | `--topic` | — | — | Existing Pub/Sub topic with Gmail push permission already granted |
32
+ | `--label-ids` | — | — | Comma-separated Gmail label IDs to filter (e.g., INBOX,UNREAD) |
33
+ | `--max-messages` | — | 10 | Max messages per pull batch |
34
+ | `--poll-interval` | — | 5 | Seconds between pulls |
35
+ | `--msg-format` | — | full | Gmail message format: full, metadata, minimal, raw |
36
+ | `--once` | — | — | Pull once and exit |
37
+ | `--cleanup` | — | — | Delete created Pub/Sub resources on exit |
38
+ | `--output-dir` | — | — | Write each message to a separate JSON file in this directory |
39
+
40
+ ## Examples
41
+
42
+ ```bash
43
+ gws gmail +watch --project my-gcp-project
44
+ gws gmail +watch --project my-project --label-ids INBOX --once
45
+ gws gmail +watch --subscription projects/p/subscriptions/my-sub
46
+ gws gmail +watch --project my-project --cleanup --output-dir ./emails
47
+ ```
48
+
49
+ ## Tips
50
+
51
+ - Gmail watch expires after 7 days — re-run to renew.
52
+ - Without --cleanup, Pub/Sub resources persist for reconnection.
53
+ - Press Ctrl-C to stop gracefully.
54
+
55
+ ## See Also
56
+
57
+ - [gws-shared](../gws-shared/SKILL.md) — Global flags and auth
58
+ - [gws-gmail](../gws-gmail/SKILL.md) — All send, read, and manage email commands
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: gws-shared
3
+ description: Shared authentication, security, and command conventions for locally generated Google Workspace gws skills.
4
+ ---
5
+
6
+ # gws-shared
7
+
8
+ Use this reference before running any `gws-*` skill.
9
+
10
+ ## Auth
11
+
12
+ - Use the local `gws` CLI auth state. Do not print tokens, refresh tokens, cookies, or raw credential files.
13
+ - If authentication is missing, run the narrowest relevant login flow, for example `gws auth login --services gmail`.
14
+ - Prefer read-only scopes unless the user explicitly asks to send, create, update, delete, or watch resources.
15
+
16
+ ## Command Safety
17
+
18
+ - Inspect command shape with `gws <service> --help` and method schemas with `gws schema <service>.<resource>.<method>`.
19
+ - Prefer `--json` output for agent workflows and summarize only the fields needed for the task.
20
+ - For email and document content, avoid dumping full bodies unless the user asked for exact content.
21
+ - For write operations, state the target account, recipient, calendar, document, or Drive path before executing.
22
+
23
+ ## Data Handling
24
+
25
+ - Treat Gmail messages, Calendar events, Docs content, Drive files, and contact-like metadata as private.
26
+ - Keep exports local by default.
27
+ - Do not include user data, OAuth files, cache directories, or raw API responses in commits.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: helium-browser-mcp
3
+ description: Use when Codex needs to control or inspect the user's logged-in Helium browser through the locally installed OpenBrowserMCP extension. Trigger for requests about OpenBrowserMCP, Helium tabs, reading current browser tabs, browser MCP, openbrowsermcp, webpage interaction, or testing this local browser stack.
4
+ ---
5
+
6
+ # Helium Browser MCP
7
+
8
+ Use this skill for the local OpenBrowserMCP + Helium setup.
9
+
10
+ ## Local Services
11
+
12
+ - OpenBrowserMCP project: `/Users/yupeit/dev/openbrowsermcp`
13
+ - OpenBrowserMCP server: `http://127.0.0.1:3500`
14
+ - OpenBrowserMCP MCP endpoint: `http://127.0.0.1:3500/mcp`
15
+ - OpenBrowserMCP WebSocket bridge: `ws://127.0.0.1:3500/ws`
16
+ - Helium extension id: `ocjmfbmadhimfjoonaljbmpcfnbgiolc`
17
+ - OpenBrowserMCP token: `~/openbrowsermcp/settings.json`
18
+ Important: use `127.0.0.1`, not `localhost`, for OpenBrowserMCP. `localhost`
19
+ can resolve to IPv6 `::1`, while the server listens on IPv4.
20
+
21
+ ## Privacy And Safety
22
+
23
+ Helium is the user's real browser profile. Treat tab URLs, page text, screenshots,
24
+ cookies, account state, and extension state as sensitive.
25
+
26
+ - Do not print the OpenBrowserMCP bearer token.
27
+ - Prefer read-only inspection first: `browsers_context`, `tabs_context`,
28
+ `get_page_text`, `read_page`.
29
+ - Before submitting forms, sending messages, uploading files, making purchases,
30
+ changing account settings, or reading highly sensitive pages, ask for explicit
31
+ confirmation.
32
+ - For demos, create a new tab on `https://example.com` and operate only there.
33
+
34
+ ## Quick Checks
35
+
36
+ ```bash
37
+ curl -sS http://127.0.0.1:3500/status
38
+ ```
39
+
40
+ If OpenBrowserMCP shows no connected extension, open the options page:
41
+
42
+ ```bash
43
+ /usr/bin/open -b net.imput.helium chrome-extension://ocjmfbmadhimfjoonaljbmpcfnbgiolc/options.html
44
+ ```
45
+
46
+ Then set:
47
+
48
+ - Server URL: `ws://127.0.0.1:3500/ws`
49
+ - Token: value from `~/openbrowsermcp/settings.json`
50
+
51
+ ## Calling OpenBrowserMCP
52
+
53
+ Use the bundled helper so the token is read locally and not printed:
54
+
55
+ ```bash
56
+ /Users/yupeit/dev/skills/skills/helium-browser-mcp/scripts/obmcp.mjs browsers_context
57
+ /Users/yupeit/dev/skills/skills/helium-browser-mcp/scripts/obmcp.mjs tabs_context '{"all":true}'
58
+ /Users/yupeit/dev/skills/skills/helium-browser-mcp/scripts/obmcp.mjs get_page_text '{"tabId":123,"browserId":"..."}'
59
+ ```
60
+
61
+ ## OpenCode Integration
62
+
63
+ OpenCode is configured globally in `/Users/yupeit/.config/opencode/opencode.json`
64
+ with an `openbrowsermcp` local MCP entry. It runs this stdio proxy:
65
+
66
+ ```bash
67
+ /Users/yupeit/dev/skills/skills/helium-browser-mcp/scripts/openbrowsermcp-stdio-proxy.mjs
68
+ ```
69
+
70
+ The proxy reads `~/openbrowsermcp/settings.json` locally and forwards to
71
+ `http://127.0.0.1:3500/mcp`, so the bearer token is not stored in OpenCode's
72
+ config file.
73
+
74
+ Verify OpenCode sees it:
75
+
76
+ ```bash
77
+ opencode mcp list
78
+ ```
79
+
80
+ Common tools:
81
+
82
+ - `browsers_context` lists connected Helium browser instances.
83
+ - `tabs_context` lists tabs. Pass `{"all":true,"browserId":"..."}`.
84
+ After an agent has chosen a tab, pass `tabId` too so context is anchored to
85
+ that tab's window/group instead of the user's foreground tab.
86
+ - `tabs_create` creates a new background tab by default. Pass
87
+ `{"url":"https://example.com","browserId":"..."}` and keep the returned
88
+ numeric tab ID for all later calls. Use `active:true` only when the user
89
+ explicitly wants the tab brought to the foreground.
90
+ - `navigate` changes an existing tab. Pass
91
+ `{"url":"https://example.com","tabId":123,"browserId":"..."}` when the
92
+ current target tab can be overwritten instead of creating another tab.
93
+ - `tabs_close` closes a tab by ID. Use it for task-owned temporary tabs once
94
+ they are no longer needed.
95
+ - `read_page` reads the accessibility tree. Requires `tabId`.
96
+ - `get_page_text` extracts `document.body.innerText`. Requires `tabId`.
97
+ - `find` searches accessible elements by description. Requires `tabId`.
98
+ - `click_element` clicks a ref from `find`/`read_page`. Requires `tabId`.
99
+ - `javascript_tool` evaluates page JavaScript. Requires `tabId`.
100
+
101
+ ## Stable Tab Targeting
102
+
103
+ Do not operate by "whatever tab is active" after the first discovery step.
104
+ Helium is the user's real browser and they may continue using it while Codex is
105
+ working.
106
+
107
+ - Create or identify a target tab first, record both `browserId` and `tabId`,
108
+ and pass them explicitly to every tab-targeted tool.
109
+ - For monitoring, call `read_network_requests`, `read_console_messages`, and
110
+ `get_response_body` with the pinned `tabId`.
111
+ - When refreshing tab context during a task, use
112
+ `tabs_context {"all":true,"tabId":123,"browserId":"..."}` so the listing is
113
+ resolved relative to the pinned tab, not the user's current foreground tab.
114
+ - Avoid `tabs_activate` unless foreground focus is part of the user's request.
115
+ CDP-backed tools such as `javascript_tool`, `read_page`, and monitoring work
116
+ on background tabs.
117
+
118
+ ## Tab Lifecycle
119
+
120
+ Keep the user's browser tidy.
121
+
122
+ - Track every tab created for the task. Before finishing, close task-owned tabs
123
+ with `tabs_close` unless the user asked to keep them open or the tab now
124
+ contains useful state the user expects to inspect.
125
+ - Prefer reusing the current target tab with `navigate` when moving to the next
126
+ website and the current page can be safely overwritten. Do this for agent-
127
+ created scratch tabs and for user-approved disposable pages.
128
+ - Do not overwrite or close tabs that existed before the task unless the user
129
+ explicitly says the current page can be reused or closed.
130
+
131
+ For a safe smoke test:
132
+
133
+ ```bash
134
+ scripts/obmcp.mjs browsers_context
135
+ scripts/obmcp.mjs tabs_context '{"all":true}'
136
+ scripts/obmcp.mjs tabs_create '{"url":"https://example.com"}'
137
+ ```
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Helium Browser MCP"
3
+ short_description: "Control Helium through the local OpenBrowserMCP extension."
4
+ default_prompt: "Show my current Helium tabs using OpenBrowserMCP."
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+
4
+ const endpoint = 'http://127.0.0.1:3500/mcp';
5
+ const tokenPath = `${process.env.HOME}/openbrowsermcp/settings.json`;
6
+
7
+ function usage() {
8
+ console.error('usage: obmcp.mjs <tool-name> [json-arguments]');
9
+ console.error('example: obmcp.mjs tabs_context \'{"all":true}\'');
10
+ process.exit(2);
11
+ }
12
+
13
+ const toolName = process.argv[2];
14
+ if (!toolName) usage();
15
+
16
+ let args = {};
17
+ if (process.argv[3]) {
18
+ try {
19
+ args = JSON.parse(process.argv[3]);
20
+ } catch (err) {
21
+ console.error(`invalid JSON arguments: ${err.message}`);
22
+ process.exit(2);
23
+ }
24
+ }
25
+
26
+ const token = JSON.parse(fs.readFileSync(tokenPath, 'utf8')).token;
27
+ if (!token) {
28
+ console.error(`missing token in ${tokenPath}`);
29
+ process.exit(1);
30
+ }
31
+
32
+ const baseHeaders = {
33
+ 'content-type': 'application/json',
34
+ accept: 'application/json, text/event-stream',
35
+ authorization: `Bearer ${token}`,
36
+ };
37
+
38
+ function parseSseOrJson(text) {
39
+ for (const line of text.split('\n')) {
40
+ if (!line.startsWith('data: ')) continue;
41
+ const payload = line.slice(6).trim();
42
+ if (!payload) continue;
43
+ return JSON.parse(payload);
44
+ }
45
+ return JSON.parse(text);
46
+ }
47
+
48
+ async function rpc(sessionId, id, method, params) {
49
+ const headers = sessionId
50
+ ? { ...baseHeaders, 'mcp-session-id': sessionId }
51
+ : baseHeaders;
52
+ const response = await fetch(endpoint, {
53
+ method: 'POST',
54
+ headers,
55
+ body: JSON.stringify({ jsonrpc: '2.0', id, method, params }),
56
+ });
57
+ const text = await response.text();
58
+ if (!response.ok) {
59
+ throw new Error(`HTTP ${response.status}: ${text}`);
60
+ }
61
+ return {
62
+ sessionId: response.headers.get('mcp-session-id'),
63
+ body: parseSseOrJson(text),
64
+ };
65
+ }
66
+
67
+ const init = await rpc(null, 1, 'initialize', {
68
+ protocolVersion: '2024-11-05',
69
+ capabilities: {},
70
+ clientInfo: { name: 'codex-obmcp-helper', version: '0' },
71
+ });
72
+
73
+ const sessionId = init.sessionId;
74
+ if (!sessionId) {
75
+ throw new Error('OpenBrowserMCP did not return an MCP session id');
76
+ }
77
+
78
+ const result = await rpc(sessionId, 2, 'tools/call', {
79
+ name: toolName,
80
+ arguments: args,
81
+ });
82
+
83
+ const body = result.body;
84
+ const content = body.result?.content;
85
+ if (Array.isArray(content)) {
86
+ for (const item of content) {
87
+ if (item?.type === 'text') console.log(item.text);
88
+ else console.log(JSON.stringify(item));
89
+ }
90
+ } else {
91
+ console.log(JSON.stringify(body, null, 2));
92
+ }
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+
4
+ const endpoint = process.env.OPENBROWSERMCP_MCP_URL || 'http://127.0.0.1:3500/mcp';
5
+ const tokenPath = process.env.OPENBROWSERMCP_SETTINGS || `${process.env.HOME}/openbrowsermcp/settings.json`;
6
+ const logPath = process.env.OPENBROWSERMCP_PROXY_LOG || '';
7
+
8
+ let sessionId = null;
9
+ let input = Buffer.alloc(0);
10
+ let chain = Promise.resolve();
11
+ let framing = null;
12
+
13
+ function log(message) {
14
+ if (!logPath) return;
15
+ fs.appendFileSync(logPath, `${new Date().toISOString()} ${message}\n`);
16
+ }
17
+
18
+ function readToken() {
19
+ const settings = JSON.parse(fs.readFileSync(tokenPath, 'utf8'));
20
+ if (typeof settings.token !== 'string' || settings.token.length === 0) {
21
+ throw new Error(`missing token in ${tokenPath}`);
22
+ }
23
+ return settings.token;
24
+ }
25
+
26
+ function writeMessage(message) {
27
+ const body = JSON.stringify(message);
28
+ if (framing === 'ndjson') {
29
+ process.stdout.write(`${body}\n`);
30
+ return;
31
+ }
32
+ process.stdout.write(`Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`);
33
+ }
34
+
35
+ function parseSseOrJson(text) {
36
+ const trimmed = text.trim();
37
+ if (!trimmed) return null;
38
+
39
+ const dataLines = [];
40
+ for (const line of trimmed.split(/\r?\n/)) {
41
+ if (line.startsWith('data:')) dataLines.push(line.slice(5).trimStart());
42
+ }
43
+ if (dataLines.length > 0) {
44
+ return JSON.parse(dataLines.join('\n'));
45
+ }
46
+ return JSON.parse(trimmed);
47
+ }
48
+
49
+ async function forward(message) {
50
+ log(`forward ${message.method || '<response>'} id=${Object.prototype.hasOwnProperty.call(message, 'id') ? message.id : '<none>'}`);
51
+ const token = readToken();
52
+ const headers = {
53
+ 'content-type': 'application/json',
54
+ accept: 'application/json, text/event-stream',
55
+ authorization: `Bearer ${token}`,
56
+ };
57
+ if (sessionId) headers['mcp-session-id'] = sessionId;
58
+
59
+ const response = await fetch(endpoint, {
60
+ method: 'POST',
61
+ headers,
62
+ body: JSON.stringify(message),
63
+ });
64
+
65
+ const nextSessionId = response.headers.get('mcp-session-id');
66
+ if (nextSessionId) sessionId = nextSessionId;
67
+
68
+ const text = await response.text();
69
+ log(`response status=${response.status} bytes=${Buffer.byteLength(text)} session=${sessionId ? 'yes' : 'no'}`);
70
+ if (!response.ok) {
71
+ throw new Error(`OpenBrowserMCP HTTP ${response.status}: ${text}`);
72
+ }
73
+
74
+ const body = parseSseOrJson(text);
75
+ if (body) writeMessage(body);
76
+ }
77
+
78
+ function jsonRpcError(id, error) {
79
+ writeMessage({
80
+ jsonrpc: '2.0',
81
+ id,
82
+ error: {
83
+ code: -32000,
84
+ message: error instanceof Error ? error.message : String(error),
85
+ },
86
+ });
87
+ }
88
+
89
+ function handle(message) {
90
+ chain = chain.then(async () => {
91
+ try {
92
+ await forward(message);
93
+ } catch (error) {
94
+ if (Object.prototype.hasOwnProperty.call(message, 'id')) {
95
+ jsonRpcError(message.id, error);
96
+ } else {
97
+ console.error(error instanceof Error ? error.message : String(error));
98
+ }
99
+ }
100
+ });
101
+ }
102
+
103
+ function drain() {
104
+ if (framing === null && input.length > 0) {
105
+ const first = input.subarray(0, 1).toString('utf8');
106
+ framing = first === '{' ? 'ndjson' : 'headers';
107
+ log(`framing=${framing}`);
108
+ }
109
+
110
+ if (framing === 'ndjson') {
111
+ while (true) {
112
+ const lineEnd = input.indexOf('\n');
113
+ if (lineEnd === -1) return;
114
+
115
+ const line = input.subarray(0, lineEnd).toString('utf8').trim();
116
+ input = input.subarray(lineEnd + 1);
117
+ if (!line) continue;
118
+
119
+ try {
120
+ handle(JSON.parse(line));
121
+ } catch (error) {
122
+ console.error(error instanceof Error ? error.message : String(error));
123
+ }
124
+ }
125
+ }
126
+
127
+ while (true) {
128
+ let headerEnd = input.indexOf('\r\n\r\n');
129
+ let separatorLength = 4;
130
+ if (headerEnd === -1) {
131
+ headerEnd = input.indexOf('\n\n');
132
+ separatorLength = 2;
133
+ }
134
+ if (headerEnd === -1) return;
135
+
136
+ const header = input.subarray(0, headerEnd).toString('latin1');
137
+ const match = header.match(/content-length:\s*(\d+)/i);
138
+ if (!match) {
139
+ console.error('missing Content-Length header');
140
+ process.exit(1);
141
+ }
142
+
143
+ const length = Number(match[1]);
144
+ const bodyStart = headerEnd + separatorLength;
145
+ const bodyEnd = bodyStart + length;
146
+ if (input.length < bodyEnd) return;
147
+
148
+ const body = input.subarray(bodyStart, bodyEnd).toString('utf8');
149
+ input = input.subarray(bodyEnd);
150
+
151
+ try {
152
+ handle(JSON.parse(body));
153
+ } catch (error) {
154
+ console.error(error instanceof Error ? error.message : String(error));
155
+ }
156
+ }
157
+ }
158
+
159
+ process.stdin.on('data', (chunk) => {
160
+ log(`stdin bytes=${chunk.length}`);
161
+ if (process.env.OPENBROWSERMCP_PROXY_PREVIEW === '1') {
162
+ log(`stdin preview=${JSON.stringify(chunk.subarray(0, 200).toString('utf8'))}`);
163
+ }
164
+ input = Buffer.concat([input, chunk]);
165
+ drain();
166
+ });
167
+
168
+ process.stdin.on('end', () => {
169
+ chain.finally(() => process.exit(0));
170
+ });
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: learn
3
+ description: Build and run evidence-based learning workflows. Use when Codex needs to create or continue a study workspace, collect and convert learning materials, design goals, teach from sources, quiz the user, score answers, track progress, maintain an error log, or run spaced review for subjects such as courses, books, technical topics, exams, or career prep.
4
+ ---
5
+
6
+ # Learn
7
+
8
+ Use this skill to turn a topic into a source-grounded, interactive learning system.
9
+
10
+ ## Core Principles
11
+
12
+ - Start from a learning goal, but allow it to change as evidence of the learner's needs emerges.
13
+ - Prefer source-grounded teaching over generic explanation. Identify the exact source chunk before teaching.
14
+ - Teach in small units, then ask retrieval questions before marking progress.
15
+ - Treat mistakes as the main signal. Log wrong, vague, overconfident, or ungrounded answers.
16
+ - Use spaced review, but usually only when the user asks to review or when resuming after a noticeable gap.
17
+ - Avoid material hoarding. Collect enough sources to cover the goal; do not delay learning indefinitely.
18
+
19
+ Read `references/learning-science.md` when designing a new workflow, defending the method, or revising the learning loop.
20
+
21
+ ## New Learning Workspace
22
+
23
+ When creating a new study workspace, use:
24
+
25
+ ```bash
26
+ python3 /path/to/learn/scripts/init_learning_workspace.py TOPIC --path /target/parent --goal "..."
27
+ ```
28
+
29
+ The script creates:
30
+
31
+ - `materials/` for source files and web caches
32
+ - `notes/` for lesson plans and ordinary notes
33
+ - `cases/` for worked examples or problem traces
34
+ - `outputs/` for compiled PDFs or exports
35
+ - `AGENTS.md` for local study rules
36
+ - `tasklog.typ` for progress, scores, and next steps
37
+ - `errorlog.typ` for misconceptions and review actions
38
+ - `workbook.typ` for worked examples, section notes, verification questions, and corrections
39
+ - `materials/source-index.md` for collected sources
40
+ - `notes/reading-sequence.md` for the first pass route
41
+
42
+ If the workspace already exists, inspect `AGENTS.md`, then `tasklog.typ`, then `errorlog.typ` before teaching.
43
+
44
+ ## Source Collection
45
+
46
+ For each topic, build a source index before deep teaching:
47
+
48
+ 1. Gather likely authoritative materials: books, official docs, papers, syllabi, lectures, slides, assignments, transcripts, examples, and prior notes.
49
+ 2. Prefer primary sources: official docs, textbook chapters, course pages, papers, source code, specs.
50
+ 3. Convert materials into AI-readable form:
51
+ - PDFs/books: text extraction or OCR as needed.
52
+ - Videos/audio: transcripts with timestamps when possible.
53
+ - Slides/images: OCR plus image references.
54
+ - Web pages: URL plus local cache or concise source notes.
55
+ 4. Record every source in `materials/source-index.md` with purpose, priority, and local path.
56
+ 5. Do not copy large copyrighted texts into notes. Store local references and write original summaries.
57
+
58
+ Use specialized skills when appropriate, for example OCR/document skills for PDFs or screenshots.
59
+
60
+ ## Tracking Files
61
+
62
+ Use `tasklog.typ` for:
63
+
64
+ - learning goal and current assumptions
65
+ - scoring rubric
66
+ - lesson/chapter table
67
+ - session log
68
+ - next action
69
+
70
+ Use `errorlog.typ` for:
71
+
72
+ - misconception category
73
+ - original question
74
+ - learner answer, preserving the error
75
+ - correction
76
+ - domain-specific consequence or rule
77
+ - review action and status
78
+
79
+ Use `workbook.typ` for:
80
+
81
+ - section-level notes
82
+ - worked examples
83
+ - verification questions
84
+ - corrected explanations
85
+ - drills or transfer exercises
86
+
87
+ ## Teaching Loop
88
+
89
+ For each section, chapter, lecture, or case:
90
+
91
+ 1. Select a small unit from the reading sequence.
92
+ 2. Read the relevant source material first.
93
+ 3. Explain in the learner's language with all essential knowledge points for that unit.
94
+ 4. Include at least one concrete example or system mapping.
95
+ 5. Name common wrong interpretations before the quiz.
96
+ 6. Ask verification questions that require retrieval and transfer, not just recognition.
97
+ 7. Stop and wait for the learner's answer.
98
+ 8. Score answers using the local rubric.
99
+ 9. Update `tasklog.typ`.
100
+ 10. Add or update `errorlog.typ` for every weak answer.
101
+ 11. Only mark a unit `done` when the learner can explain, apply, and avoid the key trap.
102
+
103
+ ## Review Loop
104
+
105
+ When the user asks to review, or resumes after a meaningful gap:
106
+
107
+ 1. Read open/review items in `errorlog.typ`.
108
+ 2. Ask questions that test the old misconception without showing the correction first.
109
+ 3. If answered correctly twice across separate reviews, mark the item `closed`.
110
+ 4. If still weak, keep it `review` and add a sharper review action.
111
+
112
+ Avoid unsolicited heavy review sessions; offer a brief review option when stale errors are visible.
113
+
114
+ ## Failure Modes To Avoid
115
+
116
+ - Turning learning into passive summaries.
117
+ - Collecting too many materials before starting.
118
+ - Rigid goals that ignore what the learner discovers.
119
+ - Overly broad lessons with no retrieval.
120
+ - Marking progress without questions.
121
+ - Logging every tiny imperfection until the workflow becomes maintenance-heavy.
122
+ - Letting AI answer from memory when source grounding is available.
@@ -0,0 +1,7 @@
1
+ interface:
2
+ display_name: "Learn"
3
+ short_description: "Evidence-based study workflows"
4
+ default_prompt: "Use $learn to create a source-grounded study workspace with progress tracking, retrieval questions, and an error log."
5
+
6
+ policy:
7
+ allow_implicit_invocation: true
@@ -0,0 +1,33 @@
1
+ # {TOPIC} Learning Instructions
2
+
3
+ Use this file whenever the user asks to study, review, explain, quiz, or continue `{TOPIC}` in this workspace.
4
+
5
+ ## Local Context
6
+
7
+ - Current learning goal: {GOAL}
8
+ - Goals may evolve as weak points are discovered.
9
+ - Prefer source-grounded teaching over generic explanation.
10
+ - Use retrieval questions and error logging before marking progress.
11
+
12
+ ## Primary Files
13
+
14
+ - `materials/source-index.md`: collected sources and local paths.
15
+ - `notes/reading-sequence.md`: lesson order.
16
+ - `tasklog.typ`: progress, scores, and next actions.
17
+ - `errorlog.typ`: misconceptions, corrections, and review status.
18
+ - `workbook.typ`: worked examples, section notes, verification questions, and corrections.
19
+
20
+ ## Default Study Method
21
+
22
+ 1. Inspect `tasklog.typ`, then `errorlog.typ`, before teaching.
23
+ 2. Select the next `doing`, `review`, or `todo` item.
24
+ 3. Read relevant source material.
25
+ 4. Explain the unit with all essential knowledge points.
26
+ 5. Ask verification questions.
27
+ 6. Wait for the learner answer.
28
+ 7. Score answers using `tasklog.typ`.
29
+ 8. Update `tasklog.typ`.
30
+ 9. Add or update `errorlog.typ` for wrong, vague, or ungrounded answers.
31
+ 10. Update `workbook.typ` for worked examples, lesson notes, or corrected explanations.
32
+
33
+ Do not mark a unit `done` until the learner can explain, apply, and avoid the key misconception.