7Passing checks
9Active scripts shown
4Test files shown
31Functions and methods mapped
What This Skill Does
- Provides the ForgeFX Slack operating guide for ForgeBot, including access, safety, formatting, Canvas, mention, capture, and health-check rules.
- Uses a read-only TypeScript Slack helper for deterministic live reads through Doppler-managed credentials.
- Keeps Slack writes gated; the active helper intentionally blocks write and admin methods before any Slack request is sent.
- Includes contract tests with no network dependency plus live read-only tests against real Slack.
Test Run
PASS Scaffold, contract, and live read-only tests passed. The live tests exercised real Slack auth and channel metadata reads through Doppler.
(node:72656) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead. (Use `node --trace-deprecation ...` to show where the warning was created) ✔ slack skill scaffold check passes (0.747542ms) (node:72657) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead. (Use `node --trace-deprecation ...` to show where the warning was created) ✔ getSlackToken prefers the ForgeBot token name and falls back to legacy SLACK_BOT_TOKEN (0.550792ms) ✔ read-only method guard accepts only read methods (0.100333ms) ✔ read-only method guard rejects write and admin Slack methods (0.133417ms) ✔ client rejects write/admin methods before any Slack request can be built (0.177333ms) ℹ tests 5 ℹ suites 0 ℹ pass 5 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 120.360958 (node:72754) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead. (Use `node --trace-deprecation ...` to show where the warning was created) ✔ auth.test succeeds with the live Slack token (297.163ms) ✔ channel search reads real public and private channel metadata (1266.101916ms) ℹ tests 2 ℹ suites 0 ℹ pass 2 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 1689.96825
Scripts
| Script | Lines | Purpose |
|---|---|---|
| .forgebot/skills/slack/scripts/check-skill.ts | 112 | Supporting Slack skill script. |
| .forgebot/skills/slack/scripts/legacy/slack-readonly.ts | 455 | Read-only Slack Web API helper for the ForgeFX Slack skill. |
| .forgebot/skills/slack/scripts/legacy/slack-history.mjs | 101 | return new Date(Number(ts) * 1000).toLocaleTimeString(); |
| .forgebot/skills/slack/scripts/legacy/download-slack-files.sh | 91 | download_slack_files.sh |
| .forgebot/skills/slack/scripts/verify/verify.sh | 35 | verify.sh — ForgeBot Slack health check, tiers 1-4. No external posting. |
| .forgebot/skills/slack/scripts/verify/check-llm-auth.sh | 79 | check-llm-auth.sh — Tier 1+2: pooled LLM credentials AND a real model round-trip. |
| .forgebot/skills/slack/scripts/verify/check-gateway.sh | 44 | check-gateway.sh — Tier 3: is the Hermes Slack gateway alive and Slack-connected? |
| .forgebot/skills/slack/scripts/verify/check-slack-send.sh | 24 | check-slack-send.sh — Tier 4: does the bot-token Slack delivery path resolve? |
| .forgebot/skills/slack/scripts/verify/roundtrip.sh | 47 | roundtrip.sh — simulate posting to Slack and capturing a ForgeBot reply. |
Tests
| Test file | Lines | Cases |
|---|---|---|
| .forgebot/skills/slack/tests/check-skill.test.ts | 11 | slack skill scaffold check passes |
| .forgebot/skills/slack/tests/legacy/slack-readonly-contract.test.ts | 58 | getSlackToken prefers the ForgeBot token name and falls back to legacy SLACK_BOT_TOKEN read-only method guard accepts only read methods read-only method guard rejects write and admin Slack methods client rejects write/admin methods before any Slack request can be built |
| .forgebot/skills/slack/tests/legacy/slack-readonly-live.test.ts | 41 | auth.test succeeds with the live Slack token channel search reads real public and private channel metadata |
| .forgebot/skills/slack/tests/legacy/README.md | 194 | No node:test cases detected; support documentation or fixture file. |
Functions And Methods
local function
parseFrontmatter
.forgebot/skills/slack/scripts/check-skill.ts:16
function parseFrontmatter(markdown: string): {
exported function
checkSkill
.forgebot/skills/slack/scripts/check-skill.ts:65
export function checkSkill(skillDir = DEFAULT_SKILL_DIR): SkillCheckResult {
local function
isMain
.forgebot/skills/slack/scripts/check-skill.ts:100
function isMain(): boolean {
exported function
isReadOnlySlackMethod
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:114
export function isReadOnlySlackMethod(method: string): method is ReadOnlySlackMethod {
exported function
assertReadOnlySlackMethod
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:118
export function assertReadOnlySlackMethod(method: string): asserts method is ReadOnlySlackMethod {
exported function
getSlackToken
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:124
export function getSlackToken(env: SlackEnv = process.env): string {
class
SlackApiError
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:134
export class SlackApiError extends Error {
method
SlackApiError.constructor
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:140
constructor(method: string, errorCode: string, status: number, response: SlackApiResponse | null) {
local function
encodeParams
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:183
function encodeParams(params: SlackParams): URLSearchParams {
local function
normalizeLimit
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:192
function normalizeLimit(value: number | undefined, fallback: number, max: number): number {
local function
nextCursor
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:198
function nextCursor(response: SlackApiSuccess): string | undefined {
class
SlackReadOnlyClient
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:203
export class SlackReadOnlyClient {
method
SlackReadOnlyClient.constructor
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:211
constructor(options: SlackReadOnlyClientOptions = {}) {
method
SlackReadOnlyClient.authTest
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:259
authTest(): Promise<SlackApiSuccess> {
method
SlackReadOnlyClient.getChannelInfo
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:263
getChannelInfo(channel: string): Promise<SlackApiSuccess & { channel: SlackChannel }> {
method
SlackReadOnlyClient.listChannels
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:267
async listChannels(options: ListChannelsOptions = {}): Promise<SlackChannel[]> {
private method
SlackReadOnlyClient.listChannelsFromMethod
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:275
private async listChannelsFromMethod(
method
SlackReadOnlyClient.findChannelsByName
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:299
async findChannelsByName(query: string, options: ListChannelsOptions = {}): Promise<SlackChannel[]> {
method
SlackReadOnlyClient.getChannelHistory
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:305
getChannelHistory(channel: string, options: ChannelHistoryOptions = {}): Promise<SlackApiSuccess & { messages?: SlackMessage[] }> {
method
SlackReadOnlyClient.getThreadReplies
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:315
getThreadReplies(channel: string, ts: string, limit = 100): Promise<SlackApiSuccess & { messages?: SlackMessage[] }> {
method
SlackReadOnlyClient.getChannelMembers
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:323
getChannelMembers(channel: string, limit = 200, cursor?: string): Promise<SlackApiSuccess & { members?: string[] }> {
method
SlackReadOnlyClient.searchMessages
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:331
searchMessages(query: string, options: SearchMessagesOptions = {}): Promise<SlackApiSuccess> {
method
SlackReadOnlyClient.getUserInfo
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:340
getUserInfo(user: string): Promise<SlackApiSuccess & { user?: SlackUser }> {
method
SlackReadOnlyClient.listUsers
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:344
listUsers(limit = 200, cursor?: string): Promise<SlackApiSuccess & { members?: SlackUser[] }> {
method
SlackReadOnlyClient.lookupUserByEmail
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:351
lookupUserByEmail(email: string): Promise<SlackApiSuccess & { user?: SlackUser }> {
local function
parseSlackResponse
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:356
async function parseSlackResponse(response: Response): Promise<SlackApiResponse | null> {
local function
sleep
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:366
function sleep(ms: number): Promise<void> {
local function
usage
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:370
function usage(): string {
local function
main
.forgebot/skills/slack/scripts/legacy/slack-readonly.ts:387
async function main(args: string[]): Promise<void> {
local function
history
.forgebot/skills/slack/scripts/legacy/slack-history.mjs:33
async function history(limit = 20) {
local function
fmt
.forgebot/skills/slack/scripts/legacy/slack-history.mjs:43
function fmt(ts) {
Active Command Surface
auth— verify Slack token identity.channels <name-fragment>— find visible public/private channels.info <channel-id>— read channel metadata.history <channel-id> [limit]— read recent messages.members <channel-id> [limit]— read member IDs.user <user-id>— read user profile metadata.
Guardrails Verified
- Read-only allowlist accepts Slack read methods.
- Write/admin examples are rejected locally.
- Credential lookup prefers the ForgeBot bot token name, then legacy fallback.
- Live reads use Doppler; no token values are printed in this report.