diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 65fa6a2..a61bcb0 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -11,7 +11,7 @@ { "name": "taskyou-os", "description": "Launch and manage AI agent teams on remote servers. Interactive setup walks you through everything — server provisioning, configuration, and deployment.", - "version": "1.3.0", + "version": "1.4.0", "author": { "name": "TaskYou" }, diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 7de9a1c..c0dbf57 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "taskyou-os", "description": "Launch and manage AI agent teams on remote servers. Interactive setup walks you through everything — server provisioning, configuration, and deployment.", - "version": "1.3.0", + "version": "1.4.0", "author": { "name": "TaskYou" }, @@ -9,5 +9,6 @@ "repository": "https://github.com/taskyou/taskyou-os", "license": "MIT", "keywords": ["agents", "automation", "taskyou", "remote", "productivity"], - "commands": "./.claude/commands" + "commands": "./.claude/commands", + "hooks": "./hooks/hooks.json" } diff --git a/README.md b/README.md index ed98aab..a22d29a 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,10 @@ The taskyou-os plugin updates through the Claude Code marketplace. Run: This pulls the latest version. Restart Claude Code afterward for changes to take effect. +**Tip: enable auto-update** so you get new features without checking manually. Auto-update is off by default for third-party marketplaces — turn it on via `/plugin` → **Marketplaces** → taskyou-os → *Enable auto-update*. Once on, Claude Code pulls new plugin versions for you and prompts you to `/reload-plugins`. + +When a new plugin version adds a feature your existing GM doesn't have yet (e.g. the task-event channel), the GM will **proactively offer to enable it** at launch — just say yes, and it runs `/gm-doctor` for you. No need to track releases. + ### Update a GM Installation Run `/taskyou-os:doctor` from any directory. It checks and updates everything automatically: diff --git a/hooks/channel-nudge.sh b/hooks/channel-nudge.sh new file mode 100755 index 0000000..942c8c9 --- /dev/null +++ b/hooks/channel-nudge.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# taskyou-os SessionStart hook (shipped by the plugin, so it reaches GMs that +# already exist once they update the plugin). +# +# Nudges a GM that predates the task-event channel to run /gm-doctor. It is: +# - SCOPED: only acts inside a rendered taskyou-os GM directory. +# - SELF-DISABLING: silent once the channel is deployed. +# Output: an `additionalContext` JSON object (exit 0) ONLY when the nudge +# applies; otherwise no output. The GM reads the note and surfaces it to the +# user conversationally. + +set -uo pipefail + +# SessionStart delivers JSON on stdin including `cwd`; prefer it, fall back to $PWD. +input="$(cat 2>/dev/null || true)" +cwd="$PWD" +if [ -n "$input" ] && command -v python3 >/dev/null 2>&1; then + parsed="$(printf '%s' "$input" | python3 -c 'import sys,json +try: print(json.load(sys.stdin).get("cwd","")) +except Exception: print("")' 2>/dev/null)" + [ -n "$parsed" ] && cwd="$parsed" +fi + +# Only act in a taskyou-os GM directory (rendered config + wrapper present). +[ -f "$cwd/config.env" ] || exit 0 +grep -q '^GM_ALIAS=' "$cwd/config.env" 2>/dev/null || exit 0 +[ -f "$cwd/bin/ty-remote" ] || exit 0 + +# Channel already deployed? Stay silent. +if [ -f "$cwd/channel/taskyou-channel.ts" ] && [ -f "$cwd/.mcp.json" ]; then + exit 0 +fi + +note='This taskyou-os GM does not have the task-event channel installed yet. Push notifications — task completed/blocked events that arrive automatically in this session instead of via a polling agent — are available in this plugin version. Briefly let the user know, once, that they can enable it by running /gm-doctor (it deploys the channel and updates the launch alias; the GM must then be restarted). If the user declines, do not bring it up again this session.' + +if command -v python3 >/dev/null 2>&1; then + printf '%s' "$note" | python3 -c 'import sys,json; print(json.dumps({"additionalContext": sys.stdin.read()}))' +else + printf '%s\n' "$note" +fi +exit 0 diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..3fe8085 --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/channel-nudge.sh" + } + ] + } + ] + } +} diff --git a/qa/run-qa.sh b/qa/run-qa.sh index d6bfd13..4102b45 100755 --- a/qa/run-qa.sh +++ b/qa/run-qa.sh @@ -97,6 +97,19 @@ grep -q 'The agents live on a remote server' "$GM_DIR/CLAUDE.md" && fail "CLAUDE grep -q 'daemon is running on this machine' "$SANDBOX/local.log" && pass "checklist shows local daemon step" || fail "checklist not local-aware" grep -q 'claude login' "$SANDBOX/local.log" && fail "checklist still tells you to 'claude login' on a server" || pass "checklist drops server-login steps" +# ── 1c. Plugin SessionStart nudge hook (existing-GM onboarding) ────────────── +echo; echo "[1c] plugin nudge hook — scoped + self-disabling" +NUDGE="$SRC/hooks/channel-nudge.sh" +# rendered GM HAS the channel → hook must stay silent +out=$(printf '{"cwd":"%s","source":"startup"}' "$GM_DIR" | bash "$NUDGE" 2>/dev/null) +[ -z "$out" ] && pass "nudge silent on a GM that already has the channel (self-disabling)" || fail "nudge fired on a channel-equipped GM" +# synthetic GM missing the channel → hook must nudge toward /gm-doctor +OLD="$SANDBOX/gm-old"; mkdir -p "$OLD/bin"; printf 'GM_ALIAS="x"\n' > "$OLD/config.env"; touch "$OLD/bin/ty-remote" +printf '{"cwd":"%s","source":"startup"}' "$OLD" | bash "$NUDGE" 2>/dev/null | grep -q 'gm-doctor' && pass "nudge fires on a GM missing the channel" || fail "nudge did not fire on a channel-less GM" +# non-GM dir → silent +out=$(printf '{"cwd":"%s","source":"startup"}' "$SANDBOX" | bash "$NUDGE" 2>/dev/null) +[ -z "$out" ] && pass "nudge silent outside a GM dir" || fail "nudge fired outside a GM dir" + # ── 2. Channel smoke test (PR #28's own test) ──────────────────────────────── echo; echo "[2] channel smoke-test (handshake + capabilities + tools)" cp "$SRC/templates/channel/smoke-test.ts" "$GM_DIR/channel/smoke-test.ts"