CtrlK
BlogDocsLog inGet started
Tessl Logo

ai-ecoverse/advanced-skills

Quarantined high-risk skills (browser session capture, WebSocket interception) for Slack and Microsoft Teams. Install only after reviewing the security implications.

76

Quality

96%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

argv.jsskills/slack/scripts/

// argv.js — argument-parsing utilities shared by slack-ext.jsh.
//
// Deliberately free of `sliccy:*`, `fs`, and `path` so the tst suite can
// import this module in the SLICC test realm (CLAUDE.md §16). Fatal parse
// errors throw a plain Error so the caller can handle them and so the tst
// realm's process.exitCode is not poisoned when throws() catches them.
// In slack-ext.jsh the top-level try/catch passes those errors to cli.die.
//
// Consumed by slack-ext.jsh via `const { BOOL_FLAGS, parseArgv, parseList } = require('./argv.js');`

// Flags that take no value (presence = true). This explicit set is required
// because the generic parser cannot distinguish a boolean flag from a
// value-less flag when the next token looks like a value.
// session / no-session pick the `slack-ext app` credential path; as booleans they
// can never swallow the app id that follows them (`app show --session A0...`).
const BOOL_FLAGS = new Set([
  'confirm',
  'json',
  'help',
  'h',
  'allow-deletions',
  'allow-shared',
  'detail',
  'session',
  'no-session',
]);

function parseArgv(argv) {
  const f = Object.create(null);
  const pos = [];
  for (let i = 0; i < argv.length; i += 1) {
    const a = argv[i];
    if (a === '--') {
      pos.push(...argv.slice(i + 1));
      break;
    }
    let m = /^--([^=]+)=([\s\S]*)$/.exec(a);
    if (m) {
      const bname = m[1];
      const bval = m[2];
      if (BOOL_FLAGS.has(bname)) {
        // FINDING 1 FIX: normalize boolean flags in --name=value form so that
        // --confirm=false stores a real boolean false (not the truthy string).
        // An unrecognised value (typo like --confirm=fasle) is fatal — it must
        // never accidentally authorise a mutation.
        const lc = bval.toLowerCase();
        if (lc === 'true' || lc === '1' || lc === 'yes' || lc === 'on') {
          f[bname] = true;
        } else if (lc === 'false' || lc === '0' || lc === 'no' || lc === 'off' || lc === '') {
          f[bname] = false;
        } else {
          throw new Error(
            '--' + bname + '=' + bval + ' is not a valid boolean value.' +
              ' Use --' + bname + ' (true) or --' + bname + '=false/true/yes/no/on/off/0/1.',
          );
        }
      } else {
        f[bname] = bval;
      }
      continue;
    }
    m = /^--(.+)$/.exec(a);
    if (m) {
      const name = m[1];
      const next = argv[i + 1];
      if (BOOL_FLAGS.has(name) || next === undefined || /^--/.test(next)) {
        f[name] = true;
        continue;
      }
      f[name] = next;
      i += 1;
      continue;
    }
    pos.push(a);
  }
  return { flags: f, positional: pos };
}

function parseList(raw, label) {
  if (raw === undefined) return [];
  if (raw === true) {
    // Valueless flag: throw so the caller (slack-ext.jsh's top-level catch ->
    // cli.die) can report it. Throwing keeps process.exitCode clean in tst.
    throw new Error('--' + label + ' needs a value, e.g. --' + label + '=channels:read');
  }
  const items = String(raw)
    .split(/[,\s]+/)
    .map((s) => s.trim())
    .filter((s) => s.length > 0);
  const seen = new Set();
  const out = [];
  for (const item of items) {
    if (seen.has(item)) continue;
    seen.add(item);
    out.push(item);
  }
  return out;
}

// When parseArgv itself throws (e.g. --allow-shared=maybe), no command has
// run yet, so nothing can emit the command's JSON result. This scans the RAW
// argv for a JSON-mode invocation of one of `commands` so the caller can emit
// a JSON error document instead of leaving stdout empty.
// Returns { command, channelId } or null. --json counts only as a bare flag or
// with a true value (--json=true/1/yes/on); a malformed --json value is itself
// the parse error and is answered in plain text.
function jsonInvocation(argv, commands) {
  const list = Array.isArray(argv) ? argv : [];
  const json = list.some((a) => a === '--json' || /^--json=(true|1|yes|on)$/i.test(a));
  if (!json) return null;
  const idx = list.findIndex((a) => commands.includes(a));
  if (idx < 0) return null;
  const next = list[idx + 1];
  return { command: list[idx], channelId: next && /^[CG][A-Z0-9]{6,}$/.test(next) ? next : null };
}

module.exports = { BOOL_FLAGS, parseArgv, parseList, jsonInvocation };

tile.json