mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-07-12 19:00:58 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 38eb5a44df | |||
| 6d397fc116 | |||
| cb2bbcc7aa | |||
| b9998a4bf1 | |||
| 0d41f0ef94 | |||
| 3363a0be0f | |||
| 05cf44035e | |||
| c1eb1079cc | |||
| 1725d86fbd | |||
| df4929d61d |
@@ -18,6 +18,7 @@ Skip to **Credentials** if all of these are already in place:
|
||||
- `src/channels/slack.ts` exists
|
||||
- `src/channels/slack-registration.test.ts` exists
|
||||
- `src/channels/index.ts` contains `import './slack.js';`
|
||||
- `container/skills/slack-formatting/SKILL.md` exists
|
||||
- `@chat-adapter/slack` is listed in `package.json` dependencies
|
||||
|
||||
Otherwise continue. Every step below is safe to re-run.
|
||||
@@ -33,8 +34,15 @@ git fetch origin channels
|
||||
```bash
|
||||
git show origin/channels:src/channels/slack.ts > src/channels/slack.ts
|
||||
git show origin/channels:src/channels/slack-registration.test.ts > src/channels/slack-registration.test.ts
|
||||
mkdir -p container/skills/slack-formatting
|
||||
git show origin/channels:container/skills/slack-formatting/SKILL.md > container/skills/slack-formatting/SKILL.md
|
||||
```
|
||||
|
||||
The `slack-formatting` container skill is part of the channel payload: it
|
||||
reaches agents via `~/.claude/skills` (synced at spawn) and teaches Slack's
|
||||
mrkdwn syntax. Trunk does not ship it — without this copy step agents send
|
||||
Slack messages with generic markdown that renders literally.
|
||||
|
||||
### 3. Append the self-registration import
|
||||
|
||||
Append to `src/channels/index.ts` (skip if the line is already present):
|
||||
|
||||
@@ -20,6 +20,7 @@ Skip to **Credentials** if all of these are already in place:
|
||||
- `src/channels/whatsapp.test.ts` exists
|
||||
- `src/channels/index.ts` contains `import './whatsapp.js';`
|
||||
- `setup/whatsapp-auth.ts` and `setup/groups.ts` both exist
|
||||
- `container/skills/whatsapp-formatting/instructions.md` exists
|
||||
- `setup/index.ts`'s `STEPS` map contains both `'whatsapp-auth':` and `groups:`
|
||||
- `@whiskeysockets/baileys`, `qrcode`, `pino` are listed in `package.json` dependencies
|
||||
- `.claude/skills/add-whatsapp/scripts/wa-qr-browser.ts` exists (ships with this skill)
|
||||
@@ -40,8 +41,17 @@ git show origin/channels:src/channels/whatsapp-registration.test.ts > src/cha
|
||||
git show origin/channels:src/channels/whatsapp.test.ts > src/channels/whatsapp.test.ts
|
||||
git show origin/channels:setup/whatsapp-auth.ts > setup/whatsapp-auth.ts
|
||||
git show origin/channels:setup/groups.ts > setup/groups.ts
|
||||
mkdir -p container/skills/whatsapp-formatting
|
||||
git show origin/channels:container/skills/whatsapp-formatting/SKILL.md > container/skills/whatsapp-formatting/SKILL.md
|
||||
git show origin/channels:container/skills/whatsapp-formatting/instructions.md > container/skills/whatsapp-formatting/instructions.md
|
||||
```
|
||||
|
||||
The `whatsapp-formatting` container skill is part of the channel payload: its
|
||||
`instructions.md` becomes the `skill-whatsapp-formatting.md` fragment in every
|
||||
group's composed CLAUDE.md (see `src/claude-md-compose.ts`), teaching agents
|
||||
WhatsApp's formatting syntax. Trunk does not ship it — without this copy step
|
||||
agents format WhatsApp messages with generic markdown that renders literally.
|
||||
|
||||
### 3. Append the self-registration import
|
||||
|
||||
Append to `src/channels/index.ts` (skip if already present):
|
||||
|
||||
@@ -4,6 +4,7 @@ All notable changes to NanoClaw will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- [BREAKING] **`whatsapp-formatting` and `slack-formatting` container skills moved from trunk to the `channels` branch.** They now install with their channel — `/add-whatsapp` / `/add-slack` and the setup installers copy them in — so installs without those channels stop carrying channel-specific formatting instructions in every agent's context. **Migration — only if this install has the channel wired** (check `src/channels/whatsapp.ts` / `src/channels/slack.ts`): updating removes both skills from the working tree — WhatsApp agents lose the formatting fragment from their composed CLAUDE.md on next spawn, Slack agents lose the mrkdwn skill from `~/.claude/skills`. Re-run the matching skill, `/add-whatsapp` or `/add-slack` (idempotent), to restore. Installs without the channel need nothing — do NOT run the add-skill just in case; it installs the full channel adapter.
|
||||
- **Pre-task script failures back their series off instead of spinning.** A `--script` that errors lands the occurrence as a failed run (`script-skip:error` ack → `failed` status); recurrence reads the series' trailing failed streak and re-arms at `max(cron next, now + 2·2^(n−1) min, cap 60)`; after 8 consecutive failures the series is auto-paused with a host-written note in its run log (`ncl tasks resume` revives it). A deliberate `wakeAgent:false` gate is a normal run and never backs off. Also fixed: an explicitly-addressed `<message to>` in a task fire's final text now delivers as a deliberate send (previously suppressed as a turn-reply echo → zero delivery when the agent skipped the MCP tool); identical echoes of an MCP send are dropped in the runner, where the duplication originates.
|
||||
- [BREAKING] **Scheduled tasks moved from MCP tools to `ncl tasks`.** The six scheduling MCP tools are no longer exposed to agent containers; agents and operators manage tasks with `ncl tasks list/get/create/update/cancel/pause/resume/delete`. New tasks run from a per-agent-group system session rather than waking the chat session that created them, and task writes are not approval-gated inside the owning group. **Migration:** [docs/ncl-tasks-migration.md](docs/ncl-tasks-migration.md).
|
||||
- **Optional per-container resource caps.** `CONTAINER_CPU_LIMIT` and `CONTAINER_MEMORY_LIMIT` pass through to `docker run` as `--cpus` / `--memory` (`container-runner.ts`). Both empty by default — no flag added, spawn args byte-identical to today — so existing installs are unaffected. Set them to cap an agent container's CPU/memory so one agent can't monopolize the host (e.g. `CONTAINER_CPU_LIMIT=2`, `CONTAINER_MEMORY_LIMIT=8g`). Swap is intentionally not managed here: `--memory` is a hard cap on a swapless host.
|
||||
|
||||
@@ -79,7 +79,7 @@ For ad-hoc queries from skills or scripts, use the in-tree wrapper rather than t
|
||||
| `src/channels/` | Channel adapter infra (registry, Chat SDK bridge); specific channel adapters are skill-installed from the `channels` branch |
|
||||
| `src/providers/` | Host-side provider container-config (`claude` baked in; `opencode` etc. installed from the `providers` branch) |
|
||||
| `container/agent-runner/src/` | Agent-runner: poll loop, formatter, provider abstraction, MCP tools, destinations |
|
||||
| `container/skills/` | Container skills mounted into every agent session (`agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `slack-formatting`, `vercel-cli`, `welcome`, `whatsapp-formatting`) |
|
||||
| `container/skills/` | Container skills mounted into every agent session (`agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `vercel-cli`, `welcome`; channel-specific skills like `slack-formatting` and `whatsapp-formatting` install with their channel) |
|
||||
| `groups/<folder>/` | Per-agent-group filesystem (CLAUDE.md, skills) — agent-runner source is a shared read-only mount, not copied per group |
|
||||
| `scripts/init-first-agent.ts` | Bootstrap the first DM-wired agent (used by `/init-first-agent` skill) |
|
||||
| `migrate-v2.sh` + `setup/migrate-v2/` | v1→v2 migration. Standalone script: `bash migrate-v2.sh`. Seeds DB, copies groups/sessions, installs channels, builds container, offers service switchover, then hands off to `/migrate-from-v1` skill for owner setup and CLAUDE.md cleanup. See [docs/migration-dev.md](docs/migration-dev.md). |
|
||||
@@ -183,7 +183,7 @@ Four types of skills. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full taxono
|
||||
- **Channel/provider install skills** — copy the relevant module(s) in from the `channels` or `providers` branch, wire imports, install pinned deps (e.g. `/add-discord`, `/add-slack`, `/add-whatsapp`, `/add-opencode`).
|
||||
- **Utility skills** — ship code files alongside `SKILL.md` (e.g. a `scripts/` CLI or helper).
|
||||
- **Operational skills** — instruction-only workflows (`/setup`, `/debug`, `/customize`, `/init-first-agent`, `/manage-channels`, `/init-onecli`, `/update-nanoclaw`).
|
||||
- **Container skills** — loaded inside agent containers at runtime (`container/skills/`: `agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `slack-formatting`, `vercel-cli`, `welcome`, `whatsapp-formatting`).
|
||||
- **Container skills** — loaded inside agent containers at runtime (`container/skills/`: `agent-browser`, `frontend-engineer`, `onecli-gateway`, `self-customize`, `vercel-cli`, `welcome`; channel-specific skills like `slack-formatting` and `whatsapp-formatting` are copied in by their `/add-<channel>` skill).
|
||||
|
||||
| Skill | When to Use |
|
||||
|-------|-------------|
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ Skills that run inside the agent container, not on the host. These teach the Nan
|
||||
|
||||
**Location:** `container/skills/<name>/`
|
||||
|
||||
**Examples:** `agent-browser` (web browsing), `frontend-engineer`, `onecli-gateway` (OneCLI proxy usage), `self-customize`, `slack-formatting` (Slack mrkdwn syntax), `vercel-cli`, `welcome`, `whatsapp-formatting`
|
||||
**Examples:** `agent-browser` (web browsing), `frontend-engineer`, `onecli-gateway` (OneCLI proxy usage), `self-customize`, `vercel-cli`, `welcome`; channel-specific: `slack-formatting` (Slack mrkdwn syntax) and `whatsapp-formatting` (channels branch; installed by `/add-slack` / `/add-whatsapp`)
|
||||
|
||||
**Key difference:** You never invoke these from a coding-agent session on the host, the way you run `/setup` or `/update-nanoclaw` in Claude Code/Codex/OpenCode. They're mounted into the sandbox and loaded by the NanoClaw agent itself, shaping how it behaves when you chat with it.
|
||||
|
||||
|
||||
@@ -92,6 +92,41 @@ agent-browser wait --url "**/dashboard" # Wait for URL pattern
|
||||
agent-browser wait --load networkidle # Wait for network idle
|
||||
```
|
||||
|
||||
### Waiting for a custom condition — ALWAYS bound it
|
||||
|
||||
Prefer the built-in `wait` subcommands above. Only fall back to `eval`-polling
|
||||
when you must wait on a custom JS condition (e.g. a spinner disappearing or a
|
||||
"Send" button re-enabling in a chat UI).
|
||||
|
||||
**Never write an unbounded wait loop.** A bare `until … do sleep; done` that
|
||||
polls a page condition will loop *forever* if the condition never becomes true
|
||||
(page failed to load, selector changed, network stalled). That does not just
|
||||
fail the command — it wedges the entire agent turn: the runner keeps the model
|
||||
stream open, later messages get silently swallowed, and the container can hang
|
||||
for hours without the host's stuck-detection firing.
|
||||
|
||||
Always cap the wait with BOTH a wall-clock `timeout` and a max-attempts counter,
|
||||
and always exit the loop (never leave a `sleep` loop as the last thing running):
|
||||
|
||||
```bash
|
||||
# Bounded wait: succeeds when the condition is met, gives up after ~90s.
|
||||
timeout 90 bash -c '
|
||||
for i in $(seq 1 30); do
|
||||
if agent-browser eval "document.querySelector(\".loading\") === null" 2>/dev/null | grep -q true; then
|
||||
echo READY; exit 0
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
echo TIMEOUT; exit 1
|
||||
'
|
||||
# Check the exit status / output: on TIMEOUT, snapshot the page and decide —
|
||||
# do NOT re-enter another unbounded wait.
|
||||
```
|
||||
|
||||
If the wait times out, treat it as a real failure: take a `snapshot -i` or
|
||||
`screenshot` to see the actual page state, report what you found, and move on.
|
||||
Retrying the same unbounded wait is what causes the hang.
|
||||
|
||||
### Semantic locators (alternative to refs)
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
---
|
||||
name: slack-formatting
|
||||
description: Format messages for Slack using mrkdwn syntax. Use when responding to Slack channels (folder starts with "slack_" or JID contains slack identifiers).
|
||||
---
|
||||
|
||||
# Slack Message Formatting (mrkdwn)
|
||||
|
||||
When responding to Slack channels, use Slack's mrkdwn syntax instead of standard Markdown.
|
||||
|
||||
## How to detect Slack context
|
||||
|
||||
Check your group folder name or workspace path:
|
||||
- Folder starts with `slack_` (e.g., `slack_engineering`, `slack_general`)
|
||||
- Or check `/workspace/group/` path for `slack_` prefix
|
||||
|
||||
## Formatting reference
|
||||
|
||||
### Text styles
|
||||
|
||||
| Style | Syntax | Example |
|
||||
|-------|--------|---------|
|
||||
| Bold | `*text*` | *bold text* |
|
||||
| Italic | `_text_` | _italic text_ |
|
||||
| Strikethrough | `~text~` | ~strikethrough~ |
|
||||
| Code (inline) | `` `code` `` | `inline code` |
|
||||
| Code block | ` ```code``` ` | Multi-line code |
|
||||
|
||||
### Links and mentions
|
||||
|
||||
```
|
||||
<https://example.com|Link text> # Named link
|
||||
<https://example.com> # Auto-linked URL
|
||||
<@U1234567890> # Mention user by ID
|
||||
<#C1234567890> # Mention channel by ID
|
||||
<!here> # @here
|
||||
<!channel> # @channel
|
||||
```
|
||||
|
||||
### Lists
|
||||
|
||||
Slack supports simple bullet lists but NOT numbered lists:
|
||||
|
||||
```
|
||||
• First item
|
||||
• Second item
|
||||
• Third item
|
||||
```
|
||||
|
||||
Use `•` (bullet character) or `- ` or `* ` for bullets.
|
||||
|
||||
### Block quotes
|
||||
|
||||
```
|
||||
> This is a block quote
|
||||
> It can span multiple lines
|
||||
```
|
||||
|
||||
### Emoji
|
||||
|
||||
Use standard emoji shortcodes: `:white_check_mark:`, `:x:`, `:rocket:`, `:tada:`
|
||||
|
||||
## What NOT to use
|
||||
|
||||
- **NO** `##` headings (use `*Bold text*` for headers instead)
|
||||
- **NO** `**double asterisks**` for bold (use `*single asterisks*`)
|
||||
- **NO** `[text](url)` links (use `<url|text>` instead)
|
||||
- **NO** `1.` numbered lists (use bullets with numbers: `• 1. First`)
|
||||
- **NO** tables (use code blocks or plain text alignment)
|
||||
- **NO** `---` horizontal rules
|
||||
|
||||
## Example message
|
||||
|
||||
```
|
||||
*Daily Standup Summary*
|
||||
|
||||
_March 21, 2026_
|
||||
|
||||
• *Completed:* Fixed authentication bug in login flow
|
||||
• *In Progress:* Building new dashboard widgets
|
||||
• *Blocked:* Waiting on API access from DevOps
|
||||
|
||||
> Next sync: Monday 10am
|
||||
|
||||
:white_check_mark: All tests passing | <https://ci.example.com/builds/123|View Build>
|
||||
```
|
||||
|
||||
## Quick rules
|
||||
|
||||
1. Use `*bold*` not `**bold**`
|
||||
2. Use `<url|text>` not `[text](url)`
|
||||
3. Use `•` bullets, avoid numbered lists
|
||||
4. Use `:emoji:` shortcodes
|
||||
5. Quote blocks with `>`
|
||||
6. Skip headings — use bold text instead
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
name: whatsapp-formatting
|
||||
description: Format messages for WhatsApp, including mentions that render as real WhatsApp tags. Use when responding in a WhatsApp conversation (platform_id / chatJid ends with @s.whatsapp.net or @g.us).
|
||||
---
|
||||
|
||||
# WhatsApp Message Formatting
|
||||
|
||||
WhatsApp uses its own lightweight markup and a phone-number-based mention syntax. The host's WhatsApp adapter (Baileys) handles markdown conversion automatically, but **mentions are only protocol-level mentions if you use the right syntax** — otherwise they render as plain text and don't notify the recipient.
|
||||
|
||||
## How to detect WhatsApp context
|
||||
|
||||
You're in a WhatsApp conversation when any of these are true:
|
||||
- The chat JID / platform id ends with `@s.whatsapp.net` (1-on-1 DM)
|
||||
- The chat JID / platform id ends with `@g.us` (group)
|
||||
- Your inbound message metadata has `chatJid` matching the above
|
||||
|
||||
## Mentions — the important part
|
||||
|
||||
To tag a user so their name appears **bold and clickable** in WhatsApp and they get a push notification, write the `@` followed by their phone number digits (no `+`, no spaces, no display name):
|
||||
|
||||
```
|
||||
@15551234567 can you confirm?
|
||||
```
|
||||
|
||||
The adapter scans your outgoing text for `@<digits>` (5–15 digits, optional leading `+` is stripped) and tells WhatsApp to render them as real mention tags.
|
||||
|
||||
**The sender's phone JID is always in your inbound message metadata.** When a user writes to you, inbound `content.sender` looks like `15551234567@s.whatsapp.net`. The part before the `@` is exactly what you put after `@` when tagging them back.
|
||||
|
||||
### Wrong vs right
|
||||
|
||||
| You write | What recipients see |
|
||||
|-----------|---------------------|
|
||||
| `@Adam can you...` | Plain text `@Adam`. No tag, no notification. |
|
||||
| `@15551234567 can you...` | Bold/blue **@Adam** (or whatever name they're saved as), notification fires. |
|
||||
| `@+15551234567 ...` | Same as above — adapter strips the `+`. |
|
||||
|
||||
### Picking who to tag
|
||||
|
||||
- In a DM, there's no real need to tag the recipient (they already see every message), but tagging still works if you want emphasis.
|
||||
- In a group, look at the `participants` / inbound `content.sender` to find the JID of the person you mean. Don't guess from display names — pushNames can collide and are not reliable.
|
||||
- If you don't know the JID, just refer to the person by name in plain prose. Don't write `@<name>` — it won't tag and it will look like a tag that failed.
|
||||
|
||||
## Text styles
|
||||
|
||||
WhatsApp uses single-character delimiters, *not* doubled like standard Markdown.
|
||||
|
||||
| Style | Syntax | Renders as |
|
||||
|-------|--------|------------|
|
||||
| Bold | `*bold*` | **bold** |
|
||||
| Italic | `_italic_` | *italic* |
|
||||
| Strikethrough | `~strike~` | ~strike~ |
|
||||
| Monospace | `` `code` `` | `code` |
|
||||
| Block monospace | ```` ```block``` ```` | preformatted block |
|
||||
|
||||
The adapter converts standard Markdown (`**bold**`, `[link](url)`, `# heading`) to the WhatsApp-native form automatically, so you don't have to think about it — but be aware that single asterisks become italics, not bold.
|
||||
|
||||
## What not to do
|
||||
|
||||
- Don't write `<@U123>` (that's Slack), `<@!123>` (Discord), or any other channel's mention syntax.
|
||||
- Don't paste a full JID like `@15551234567@s.whatsapp.net` in the text — only the digits before the JID's `@` go after your `@`.
|
||||
- Don't try to tag display names. WhatsApp has no display-name-based mention API.
|
||||
@@ -1,19 +0,0 @@
|
||||
## WhatsApp mentions — always use phone digits
|
||||
|
||||
When you are replying in a WhatsApp conversation (the inbound message's `chatJid` ends with `@s.whatsapp.net` for a DM or `@g.us` for a group), and you want to tag a person so their name appears **bold and clickable** with a push notification, write `@` followed by their phone-number digits — never the display name.
|
||||
|
||||
**The sender's phone JID is in your inbound message metadata** at `content.sender` (e.g. `15551234567@s.whatsapp.net`). The part before the `@` is exactly what you put after `@` when tagging them.
|
||||
|
||||
| You write | What recipients see |
|
||||
|-----------|---------------------|
|
||||
| `@Adam, can you...` | Plain text. No tag, no notification. |
|
||||
| `@15551234567, can you...` | Bold/blue **@Adam** (whatever name they're saved as), notification fires. |
|
||||
| `@+15551234567 ...` | Same as above — the adapter strips the `+` automatically. |
|
||||
|
||||
The host adapter scans your outbound text for `@<5–15 digits>` (with optional leading `+`) and tells WhatsApp to render those as real mention tags. If the digits aren't in the text, the tag doesn't render — no exceptions.
|
||||
|
||||
### In groups
|
||||
|
||||
Tag the person you're addressing using their JID from inbound metadata (look at the most recent message from them). Don't guess — pushNames collide and aren't reliable.
|
||||
|
||||
If you don't know someone's JID, refer to them by name in plain prose. Do not write `@<displayname>` hoping it works.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nanoclaw",
|
||||
"version": "2.1.43",
|
||||
"version": "2.1.44",
|
||||
"description": "Personal Claude assistant. Lightweight, secure, customizable.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.33.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="224k tokens, 112% of context window">
|
||||
<title>224k tokens, 112% of context window</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="225k tokens, 113% of context window">
|
||||
<title>225k tokens, 113% of context window</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
@@ -15,8 +15,8 @@
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11">
|
||||
<text aria-hidden="true" x="26" y="15" fill="#010101" fill-opacity=".3">tokens</text>
|
||||
<text x="26" y="14">tokens</text>
|
||||
<text aria-hidden="true" x="71" y="15" fill="#010101" fill-opacity=".3">224k</text>
|
||||
<text x="71" y="14">224k</text>
|
||||
<text aria-hidden="true" x="71" y="15" fill="#010101" fill-opacity=".3">225k</text>
|
||||
<text x="71" y="14">225k</text>
|
||||
</g>
|
||||
</g>
|
||||
</a>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -51,6 +51,7 @@ fi
|
||||
|
||||
need_install() {
|
||||
[ ! -f src/channels/slack.ts ] && return 0
|
||||
[ ! -f container/skills/slack-formatting/SKILL.md ] && return 0
|
||||
! grep -q "^import './slack.js';" src/channels/index.ts 2>/dev/null && return 0
|
||||
return 1
|
||||
}
|
||||
@@ -67,6 +68,10 @@ if need_install; then
|
||||
log "Copying adapter from ${CHANNELS_BRANCH}…"
|
||||
git show "${CHANNELS_BRANCH}:src/channels/slack.ts" > src/channels/slack.ts
|
||||
|
||||
# Slack formatting container skill — reaches agents via ~/.claude/skills.
|
||||
mkdir -p container/skills/slack-formatting
|
||||
git show "${CHANNELS_BRANCH}:container/skills/slack-formatting/SKILL.md" > container/skills/slack-formatting/SKILL.md
|
||||
|
||||
# Append self-registration import if missing.
|
||||
if ! grep -q "^import './slack.js';" src/channels/index.ts; then
|
||||
echo "import './slack.js';" >> src/channels/index.ts
|
||||
|
||||
@@ -43,6 +43,7 @@ log() { echo "[add-whatsapp] $*" >&2; }
|
||||
need_install() {
|
||||
[ ! -f src/channels/whatsapp.ts ] && return 0
|
||||
[ ! -f setup/groups.ts ] && return 0
|
||||
[ ! -f container/skills/whatsapp-formatting/instructions.md ] && return 0
|
||||
! grep -q "^import './whatsapp.js';" src/channels/index.ts 2>/dev/null && return 0
|
||||
! grep -q "'whatsapp-auth':" setup/index.ts 2>/dev/null && return 0
|
||||
! grep -q "^ groups:" setup/index.ts 2>/dev/null && return 0
|
||||
@@ -64,6 +65,12 @@ if need_install; then
|
||||
git show "${CHANNELS_BRANCH}:src/channels/whatsapp.ts" > src/channels/whatsapp.ts
|
||||
git show "${CHANNELS_BRANCH}:setup/groups.ts" > setup/groups.ts
|
||||
|
||||
# WhatsApp formatting container skill — feeds the composed CLAUDE.md
|
||||
# (skill-whatsapp-formatting.md fragment) and ~/.claude/skills.
|
||||
mkdir -p container/skills/whatsapp-formatting
|
||||
git show "${CHANNELS_BRANCH}:container/skills/whatsapp-formatting/SKILL.md" > container/skills/whatsapp-formatting/SKILL.md
|
||||
git show "${CHANNELS_BRANCH}:container/skills/whatsapp-formatting/instructions.md" > container/skills/whatsapp-formatting/instructions.md
|
||||
|
||||
# Append self-registration import if missing.
|
||||
if ! grep -q "^import './whatsapp.js';" src/channels/index.ts; then
|
||||
echo "import './whatsapp.js';" >> src/channels/index.ts
|
||||
|
||||
@@ -15,6 +15,7 @@ echo "=== NANOCLAW SETUP: INSTALL_SLACK ==="
|
||||
|
||||
needs_install=false
|
||||
[[ -f src/channels/slack.ts ]] || needs_install=true
|
||||
[[ -f container/skills/slack-formatting/SKILL.md ]] || needs_install=true
|
||||
grep -q "import './slack.js';" src/channels/index.ts || needs_install=true
|
||||
grep -q '"@chat-adapter/slack"' package.json || needs_install=true
|
||||
[[ -d node_modules/@chat-adapter/slack ]] || needs_install=true
|
||||
@@ -30,6 +31,8 @@ git fetch origin channels
|
||||
|
||||
echo "STEP: copy-files"
|
||||
git show origin/channels:src/channels/slack.ts > src/channels/slack.ts
|
||||
mkdir -p container/skills/slack-formatting
|
||||
git show origin/channels:container/skills/slack-formatting/SKILL.md > container/skills/slack-formatting/SKILL.md
|
||||
|
||||
echo "STEP: register-import"
|
||||
if ! grep -q "import './slack.js';" src/channels/index.ts; then
|
||||
|
||||
@@ -20,6 +20,8 @@ CHANNEL_FILES=(
|
||||
src/channels/whatsapp.ts
|
||||
setup/whatsapp-auth.ts
|
||||
setup/groups.ts
|
||||
container/skills/whatsapp-formatting/SKILL.md
|
||||
container/skills/whatsapp-formatting/instructions.md
|
||||
)
|
||||
|
||||
needs_install=false
|
||||
@@ -45,6 +47,7 @@ git fetch origin channels
|
||||
|
||||
echo "STEP: copy-files"
|
||||
for f in "${CHANNEL_FILES[@]}"; do
|
||||
mkdir -p "$(dirname "$f")"
|
||||
git show "origin/channels:$f" > "$f"
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user