QA on the VM showed two leaks in the effect:step tee: the host logger's
INFO lines (it always emits ANSI and defaults to info) landed on the
wizard screen, and the child's clack card drew colorless because
picocolors disables ANSI on a piped stdout, clashing with the wizard
theme.
hostExecStream now spawns steps with LOG_LEVEL=warn (operator-set level
wins; warnings/errors still pass) and FORCE_COLOR=1 when the operator's
terminal is a real TTY.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HB8rQxJN7itcFhNYVDntpm
SSF-002 — the telegram pairing card renders via clack's static note/log
primitives instead of bare console.log. hostExecStream tees non-status
lines verbatim, and static clack output is just lines — only
interactive/animated widgets need the TTY the piped child doesn't have.
SSF-003 — an either/or nc:prompt (validate:^(a|b)$) renders as an
arrow-key p.select; the options come from the validate regex itself
(literalChoices), so no grammar addition and zero skill edits. Prefixes
and format unions keep the text prompt. The `?` help-escape doesn't
apply to selects — every choice is valid and self-describing.
SSF-004 — a bounced step no longer dumps a raw stacktrace or the skill's
reference prose into the wizard. hostExec recomposes failures as
`exit <code>: <first stderr line>` (full stderr kept below for the
agentTask reason an agent fixes from); run-channel-skill shows one line
per bounce and writes the full text to a logs/setup-steps raw log, which
fail() forwards to the Claude handoff.
The directive engine (scripts/skill-apply.ts, skill-directives.ts) is
untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HB8rQxJN7itcFhNYVDntpm
'Subscribe to bot events' is shared by both delivery modes — only the
Request URL is webhook-specific. 2242f6c mis-sorted it into the webhook
operator block, so Socket Mode installs connected the socket but Slack
never pushed events: welcome DM sent, every reply dead on arrival.
Adds the Event Subscriptions step to the socket block (after Socket Mode
is enabled, so the page doesn't demand a Request URL) and corrects the
false "Socket Mode skips all of this" line. Audited the other when:-split
skills (imessage, whatsapp, teams) — no other mis-sorted shared steps.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HB8rQxJN7itcFhNYVDntpm
Upstream added Socket Mode to the guided setup (cf8478ff) in the bespoke
setup/channels/slack.ts this branch deleted. The port expresses it the way
the engine was built for: a `connection` prompt (socket|webhook) with
when:-guarded branches —
- socket: app-level token walkthrough (connections:write scope, Socket Mode
toggle), `nc:prompt app_token` (xapp-, reuse:SLACK_APP_TOKEN),
SLACK_APP_TOKEN env-set. The adapter enables Socket Mode purely from the
token's presence, so no public URL and no signing secret.
- webhook: the existing signing-secret + Event Subscriptions path, now
guard-scoped to its branch.
Gate-policy parity holds: all three operator blocks remain prompt-barriered
(no confirms), matching the §5.1 rules; the placeholder-URL negative fixture
moves to operator index 2. Structure-tracking tests updated (directive
order, operator/prompt/env-set inventories, Option-A inputs gain
connection:webhook).
Suite 827 passed | 1 skipped; add-slack lint exit 0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upstream removed every setup-side writer of data/env/env (c82f062d) because
nothing has read it since the container mount was dropped — before this
branch even forked. Our engine codified the dead pattern as a directive:
every apply copied the full .env (live tokens included) into a file nothing
consumes.
- engine: env-sync handler removed from selfStatus + applyOne
- grammar: dropped from KNOWN; a new RETIRED table gives a targeted lint
error ("delete the fence, the adapter reads .env directly") instead of a
generic unknown-directive message
- skills: fence stripped from the 14 converted skills; orphaned "sync to the
container" prose cleaned (incl. add-deltachat/add-wechat old-format prose
upstream's sweep missed); teams troubleshooting entry rewritten
- policy/spec doc lists updated
Suite 827 passed | 1 skipped; all nc: skills lint clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conflict resolutions:
- 9 SKILL.mds we rewrote in the nc: format: kept ours, then bumped every
@chat-adapter pin 4.26.0 -> 4.29.0 to match the merged chat core (the
lockstep lint enforces equality; pin-test expectation updated).
- 14 setup/add-*.sh, install-*.sh + setup/channels/{slack,signal,whatsapp}.ts:
stay deleted — replaced by the directive engine + runChannelSkill. Upstream's
Slack Socket Mode (cf8478ff, setup-side) will be ported into add-slack's
SKILL.md as a when:-guarded mode in a follow-up commit.
- src/cli/resources/groups.ts: fused create — upstream's --template branch
first, else our idempotent-on-folder create with ensureContainerConfig.
- src/cli/registry.ts + dispatch.test.ts: both sides' additions kept
(hostOnly field/doc + upstream's resource doc and approval-context fixture).
Known follow-ups (next commits): remove the now-dead nc:env-sync directive
(upstream removed the data/env/env mirror writers; the reader died pre-fork),
port Slack Socket Mode into the SKILL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>