@zaly/agent 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/agent-BaD2kax9.mjs +68 -0
  4. package/dist/agent-BaD2kax9.mjs.map +1 -0
  5. package/dist/agent-GDLdDc2w.mjs +902 -0
  6. package/dist/agent-GDLdDc2w.mjs.map +1 -0
  7. package/dist/bash-QNMTQ1PD.mjs +142 -0
  8. package/dist/bash-QNMTQ1PD.mjs.map +1 -0
  9. package/dist/compactions-3AjPqjeZ.mjs +190 -0
  10. package/dist/compactions-3AjPqjeZ.mjs.map +1 -0
  11. package/dist/edit-Qxl4w1C2.mjs +170 -0
  12. package/dist/edit-Qxl4w1C2.mjs.map +1 -0
  13. package/dist/env-UUFv5Mye.mjs +30 -0
  14. package/dist/env-UUFv5Mye.mjs.map +1 -0
  15. package/dist/fetch-D8cmmA3E.mjs +111 -0
  16. package/dist/fetch-D8cmmA3E.mjs.map +1 -0
  17. package/dist/find-Bah9SKWX.mjs +87 -0
  18. package/dist/find-Bah9SKWX.mjs.map +1 -0
  19. package/dist/grep-B2Ax7ewy.mjs +244 -0
  20. package/dist/grep-B2Ax7ewy.mjs.map +1 -0
  21. package/dist/index-node-esm-D6YQRKEz.mjs +1537 -0
  22. package/dist/index-node-esm-D6YQRKEz.mjs.map +1 -0
  23. package/dist/index.d.mts +1605 -0
  24. package/dist/index.d.mts.map +1 -0
  25. package/dist/index.mjs +948 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/jsonl-Dw_VBp46.mjs +134 -0
  28. package/dist/jsonl-Dw_VBp46.mjs.map +1 -0
  29. package/dist/manager-D-lWBTHG.mjs +271 -0
  30. package/dist/manager-D-lWBTHG.mjs.map +1 -0
  31. package/dist/markdown-Bv4J8cg3.mjs +53 -0
  32. package/dist/markdown-Bv4J8cg3.mjs.map +1 -0
  33. package/dist/masker-Bv9KjkDF.mjs +396 -0
  34. package/dist/masker-Bv9KjkDF.mjs.map +1 -0
  35. package/dist/model-_3ZA2xqm.mjs +27 -0
  36. package/dist/model-_3ZA2xqm.mjs.map +1 -0
  37. package/dist/notify-DpG_m9iP.mjs +96 -0
  38. package/dist/notify-DpG_m9iP.mjs.map +1 -0
  39. package/dist/read-Djsx2NZl.mjs +205 -0
  40. package/dist/read-Djsx2NZl.mjs.map +1 -0
  41. package/dist/registry-CFmR5G3J.mjs +564 -0
  42. package/dist/registry-CFmR5G3J.mjs.map +1 -0
  43. package/dist/search-CRw247ES.mjs +121 -0
  44. package/dist/search-CRw247ES.mjs.map +1 -0
  45. package/dist/session/claude.d.mts +59 -0
  46. package/dist/session/claude.d.mts.map +1 -0
  47. package/dist/session/claude.mjs +455 -0
  48. package/dist/session/claude.mjs.map +1 -0
  49. package/dist/session-CUUdWFC5.mjs +450 -0
  50. package/dist/session-CUUdWFC5.mjs.map +1 -0
  51. package/dist/session-Ds5nJz5A.d.mts +346 -0
  52. package/dist/session-Ds5nJz5A.d.mts.map +1 -0
  53. package/dist/session.d.mts +37 -0
  54. package/dist/session.d.mts.map +1 -0
  55. package/dist/session.mjs +106 -0
  56. package/dist/session.mjs.map +1 -0
  57. package/dist/subagent-baqzjRMc.mjs +136 -0
  58. package/dist/subagent-baqzjRMc.mjs.map +1 -0
  59. package/dist/swarm-BJ3gQA1Z.mjs +194 -0
  60. package/dist/swarm-BJ3gQA1Z.mjs.map +1 -0
  61. package/dist/swarm-BuFx_xeY.mjs +109 -0
  62. package/dist/swarm-BuFx_xeY.mjs.map +1 -0
  63. package/dist/tasks-D8rARHZ1.mjs +65 -0
  64. package/dist/tasks-D8rARHZ1.mjs.map +1 -0
  65. package/dist/tasks-WmC270X2.mjs +615 -0
  66. package/dist/tasks-WmC270X2.mjs.map +1 -0
  67. package/dist/tools-DW1dbcCz.mjs +695 -0
  68. package/dist/tools-DW1dbcCz.mjs.map +1 -0
  69. package/dist/truncate-BSMXgiXj.mjs +102 -0
  70. package/dist/truncate-BSMXgiXj.mjs.map +1 -0
  71. package/dist/uuid-ByXP5SO5.mjs +59 -0
  72. package/dist/uuid-ByXP5SO5.mjs.map +1 -0
  73. package/dist/wakeup-BYqTnfSp.mjs +29 -0
  74. package/dist/wakeup-BYqTnfSp.mjs.map +1 -0
  75. package/dist/write-D3L-92vj.mjs +89 -0
  76. package/dist/write-D3L-92vj.mjs.map +1 -0
  77. package/package.json +63 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-CFmR5G3J.mjs","names":["resolveRule"],"sources":["../src/permissions/handlers/bash.ts","../../../node_modules/.bun/ignore@7.0.5/node_modules/ignore/index.js","../src/permissions/handlers/files.ts","../src/permissions/handlers/tool.ts","../src/permissions/handlers/registry.ts"],"sourcesContent":["import type { Segment } from \"../../utils/bash/parser.ts\"\nimport type { CheckResult, PermissionHandler, Rule, Suggestion, Verdict } from \"../types.ts\"\n\nimport { parseBash } from \"../../utils/bash/parser.ts\"\nimport { TOOLS } from \"../../utils/bash/tools.ts\"\n\n/**\n * Handler for `Rule<\"bash\">` — evaluates a bash command line against\n * pattern rules, then delegates each segment's inferred and explicit\n * file paths to the file handler via `ctx.validate(\"read\"|\"write\", …)`.\n *\n * Composition keeps file-rule logic in one place: the bash handler\n * doesn't know about workspaces, sensitive files, or path-pattern\n * matching — it just asks the registered handler for those scopes.\n *\n * Sources of file paths per segment:\n * - `seg.reads` / `seg.writes` — explicit `<` / `>` / `>>` redirects\n * extracted by the parser.\n * - `TOOLS[cmd].reads/writes(args)` — inferred from built-in tool\n * specs (e.g. `cat foo.txt` reads `foo.txt`, `tee out` writes `out`).\n *\n * Suggestions and reasons from inner `validate` calls bubble up so the\n * prompt UI can offer \"allow `Bash(cat:*)`\" alongside \"add ~/Documents\n * as workspace\" in a single ask.\n */\nexport const bashHandler: PermissionHandler<\"bash\"> = {\n validate(input, ctx): CheckResult {\n const parsed = parseBash(input)\n if (!parsed.ok) {\n return {\n ask: `Allow this bash command? (${parsed.reason})`,\n reason: parsed.reason,\n verdict: \"ask\",\n }\n }\n\n let verdict: Verdict = \"allow\"\n let reason: string | undefined\n const suggestions: Suggestion[] = []\n\n for (const seg of parsed.segments) {\n // Bash rule match for the command itself. Resolve this before the\n // conservative safety checks so explicit allow-all presets like yolo can\n // mean exactly that instead of degrading to an unimplemented ask prompt.\n const cmdVerdict = resolveRules(ctx.rules, seg) ?? \"ask\"\n if (seg.hasCommandSubst && cmdVerdict !== \"allow\") {\n return {\n ask: `Allow command substitution in \\`${seg.cmd}\\`?`,\n reason: \"command substitution not allowed\",\n verdict: \"ask\",\n }\n }\n const spec = TOOLS[seg.cmd]\n if (spec?.unsafe?.(seg.args) && cmdVerdict !== \"allow\") {\n return {\n ask: `Allow invocation of \\`${seg.cmd}\\`? (unsafe)`,\n reason: `${seg.cmd}: invocation mode not safely modelled`,\n verdict: \"ask\",\n }\n }\n\n let segVerdict: Verdict = cmdVerdict\n let segReason: string | undefined =\n cmdVerdict === \"allow\" ? undefined : `segment \"${seg.cmd}\" → ${cmdVerdict}`\n if (cmdVerdict === \"ask\") {\n suggestions.push({\n kind: \"rule\",\n pattern: seg.args.length > 0 ? `${seg.cmd}:*` : seg.cmd,\n scope: \"bash\",\n })\n }\n\n // Delegate file paths to the file handler. Reads first, then\n // writes; both contribute to this segment's verdict via combine.\n const reads = [...(spec?.reads?.(seg.args) ?? []), ...seg.reads]\n const writes = [...(spec?.writes?.(seg.args) ?? []), ...seg.writes.map((w) => w.path)]\n\n for (const path of reads) {\n if (seg.dyn?.has(path)) {\n segVerdict = combine(segVerdict, \"ask\")\n segReason ??= `${seg.cmd}: read ${path}: dynamic path`\n suggestions.push({\n kind: \"rule\",\n pattern: `${seg.cmd}:*`,\n scope: \"bash\",\n })\n continue\n }\n const r = ctx.validate(\"read\", path)\n segVerdict = combine(segVerdict, r.verdict)\n if (r.verdict !== \"allow\") {\n segReason ??= `${seg.cmd}: read ${path}: ${r.reason}`\n if (r.suggestions) suggestions.push(...r.suggestions)\n }\n if (segVerdict === \"deny\") break\n }\n if (segVerdict !== \"deny\") {\n for (const path of writes) {\n if (seg.dyn?.has(path)) {\n segVerdict = combine(segVerdict, \"ask\")\n segReason ??= `${seg.cmd}: write ${path}: dynamic path`\n suggestions.push({\n kind: \"rule\",\n pattern: `${seg.cmd}:*`,\n scope: \"bash\",\n })\n continue\n }\n const w = ctx.validate(\"write\", path)\n segVerdict = combine(segVerdict, w.verdict)\n if (w.verdict !== \"allow\") {\n segReason ??= `${seg.cmd}: write ${path}: ${w.reason}`\n if (w.suggestions) suggestions.push(...w.suggestions)\n }\n if (segVerdict === \"deny\") break\n }\n }\n\n verdict = combine(verdict, segVerdict)\n if (verdict !== \"allow\" && reason === undefined) reason = segReason\n if (verdict === \"deny\") break\n }\n\n return verdict === \"allow\"\n ? { verdict: \"allow\" }\n : {\n ask: `Allow this bash command?`,\n reason: reason ?? \"no rule matched\",\n suggestions: suggestions.length > 0 ? suggestions : undefined,\n verdict,\n }\n },\n}\n\n// ── Pattern matching ─────────────────────────────────────────────────────\n\n/** A command-pattern rule.\n *\n * Pattern syntax:\n * \"cmd\" → cmd alone, no args\n * \"cmd:*\" → cmd with any args (trailing wildcard)\n * \"cmd a\" → cmd with arg \"a\", no other args\n * \"cmd a:*\" → cmd with arg \"a\" plus any others\n * \"cmd a b\" → cmd with exact args [a, b]\n * \"cmd --flag*\" → cmd with arg starting with \"--flag\" (per-arg prefix)\n * \"bun test:node:*\" → cmd \"bun\", arg \"test:node\", any others\n *\n * Whitespace separates the cmd from its args, and args from each\n * other. The `:` character is only meaningful as the trailing `:*`\n * wildcard suffix — anywhere else (including inside an arg like\n * `test:node`) it's a literal character. */\n\ninterface ParsedPattern {\n cmd: string\n /** Arg-position match tokens. Each may end with `*` for prefix match. */\n parts: string[]\n /** Set when the pattern ends with `:*`, allowing arbitrary further args. */\n trailingWildcard: boolean\n}\n\n/** Combine two verdicts: deny dominates, ask beats allow. */\nfunction combine(a: Verdict, b: Verdict): Verdict {\n if (a === \"deny\" || b === \"deny\") return \"deny\"\n if (a === \"ask\" || b === \"ask\") return \"ask\"\n return \"allow\"\n}\n\nconst patternCache = new Map<string, ParsedPattern>()\n\nfunction parsePattern(pattern: string): ParsedPattern {\n const cached = patternCache.get(pattern)\n if (cached) return cached\n\n let body = pattern.trim()\n let trailingWildcard = false\n if (body.endsWith(\":*\")) {\n trailingWildcard = true\n body = body.slice(0, -2)\n }\n\n const tokens = body.split(/\\s+/).filter((s) => s.length > 0)\n const cmd = tokens[0] ?? \"\"\n const result: ParsedPattern = {\n cmd,\n parts: tokens.slice(1),\n trailingWildcard,\n }\n patternCache.set(pattern, result)\n return result\n}\n\nfunction matchPart(part: string, value: string): boolean {\n if (part.endsWith(\"*\")) {\n return value.startsWith(part.slice(0, -1))\n }\n return part === value\n}\n\n/** Test whether a parsed segment matches a rule pattern. */\nexport function matchRule(rule: Rule, seg: Segment): boolean {\n const p = parsePattern(rule.pattern)\n // Bare `*` (e.g. from a `Bash` rule with no parens) matches any command.\n if (p.cmd === \"*\" && p.parts.length === 0) return true\n if (p.cmd !== seg.cmd) return false\n if (seg.args.length < p.parts.length) return false\n for (let i = 0; i < p.parts.length; i++) {\n if (!matchPart(p.parts[i], seg.args[i])) return false\n }\n if (p.trailingWildcard) return true\n return seg.args.length === p.parts.length\n}\n\n/** First-match-wins resolution. Returns `undefined` if no rule matches. */\nfunction resolveRules(rules: readonly Rule[], seg: Segment): Verdict | undefined {\n for (const r of rules) {\n if (matchRule(r, seg)) return r.policy\n }\n return undefined\n}\n","// A simple implementation of make-array\nfunction makeArray (subject) {\n return Array.isArray(subject)\n ? subject\n : [subject]\n}\n\nconst UNDEFINED = undefined\nconst EMPTY = ''\nconst SPACE = ' '\nconst ESCAPE = '\\\\'\nconst REGEX_TEST_BLANK_LINE = /^\\s+$/\nconst REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\\\]|^)\\\\$/\nconst REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\\\!/\nconst REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\\\#/\nconst REGEX_SPLITALL_CRLF = /\\r?\\n/g\n\n// Invalid:\n// - /foo,\n// - ./foo,\n// - ../foo,\n// - .\n// - ..\n// Valid:\n// - .foo\nconst REGEX_TEST_INVALID_PATH = /^\\.{0,2}\\/|^\\.{1,2}$/\n\nconst REGEX_TEST_TRAILING_SLASH = /\\/$/\n\nconst SLASH = '/'\n\n// Do not use ternary expression here, since \"istanbul ignore next\" is buggy\nlet TMP_KEY_IGNORE = 'node-ignore'\n/* istanbul ignore else */\nif (typeof Symbol !== 'undefined') {\n TMP_KEY_IGNORE = Symbol.for('node-ignore')\n}\nconst KEY_IGNORE = TMP_KEY_IGNORE\n\nconst define = (object, key, value) => {\n Object.defineProperty(object, key, {value})\n return value\n}\n\nconst REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g\n\nconst RETURN_FALSE = () => false\n\n// Sanitize the range of a regular expression\n// The cases are complicated, see test cases for details\nconst sanitizeRange = range => range.replace(\n REGEX_REGEXP_RANGE,\n (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)\n ? match\n // Invalid range (out of order) which is ok for gitignore rules but\n // fatal for JavaScript regular expression, so eliminate it.\n : EMPTY\n)\n\n// See fixtures #59\nconst cleanRangeBackSlash = slashes => {\n const {length} = slashes\n return slashes.slice(0, length - length % 2)\n}\n\n// > If the pattern ends with a slash,\n// > it is removed for the purpose of the following description,\n// > but it would only find a match with a directory.\n// > In other words, foo/ will match a directory foo and paths underneath it,\n// > but will not match a regular file or a symbolic link foo\n// > (this is consistent with the way how pathspec works in general in Git).\n// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'\n// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call\n// you could use option `mark: true` with `glob`\n\n// '`foo/`' should not continue with the '`..`'\nconst REPLACERS = [\n\n [\n // Remove BOM\n // TODO:\n // Other similar zero-width characters?\n /^\\uFEFF/,\n () => EMPTY\n ],\n\n // > Trailing spaces are ignored unless they are quoted with backslash (\"\\\")\n [\n // (a\\ ) -> (a )\n // (a ) -> (a)\n // (a ) -> (a)\n // (a \\ ) -> (a )\n /((?:\\\\\\\\)*?)(\\\\?\\s+)$/,\n (_, m1, m2) => m1 + (\n m2.indexOf('\\\\') === 0\n ? SPACE\n : EMPTY\n )\n ],\n\n // Replace (\\ ) with ' '\n // (\\ ) -> ' '\n // (\\\\ ) -> '\\\\ '\n // (\\\\\\ ) -> '\\\\ '\n [\n /(\\\\+?)\\s/g,\n (_, m1) => {\n const {length} = m1\n return m1.slice(0, length - length % 2) + SPACE\n }\n ],\n\n // Escape metacharacters\n // which is written down by users but means special for regular expressions.\n\n // > There are 12 characters with special meanings:\n // > - the backslash \\,\n // > - the caret ^,\n // > - the dollar sign $,\n // > - the period or dot .,\n // > - the vertical bar or pipe symbol |,\n // > - the question mark ?,\n // > - the asterisk or star *,\n // > - the plus sign +,\n // > - the opening parenthesis (,\n // > - the closing parenthesis ),\n // > - and the opening square bracket [,\n // > - the opening curly brace {,\n // > These special characters are often called \"metacharacters\".\n [\n /[\\\\$.|*+(){^]/g,\n match => `\\\\${match}`\n ],\n\n [\n // > a question mark (?) matches a single character\n /(?!\\\\)\\?/g,\n () => '[^/]'\n ],\n\n // leading slash\n [\n\n // > A leading slash matches the beginning of the pathname.\n // > For example, \"/*.c\" matches \"cat-file.c\" but not \"mozilla-sha1/sha1.c\".\n // A leading slash matches the beginning of the pathname\n /^\\//,\n () => '^'\n ],\n\n // replace special metacharacter slash after the leading slash\n [\n /\\//g,\n () => '\\\\/'\n ],\n\n [\n // > A leading \"**\" followed by a slash means match in all directories.\n // > For example, \"**/foo\" matches file or directory \"foo\" anywhere,\n // > the same as pattern \"foo\".\n // > \"**/foo/bar\" matches file or directory \"bar\" anywhere that is directly\n // > under directory \"foo\".\n // Notice that the '*'s have been replaced as '\\\\*'\n /^\\^*\\\\\\*\\\\\\*\\\\\\//,\n\n // '**/foo' <-> 'foo'\n () => '^(?:.*\\\\/)?'\n ],\n\n // starting\n [\n // there will be no leading '/'\n // (which has been replaced by section \"leading slash\")\n // If starts with '**', adding a '^' to the regular expression also works\n /^(?=[^^])/,\n function startingReplacer () {\n // If has a slash `/` at the beginning or middle\n return !/\\/(?!$)/.test(this)\n // > Prior to 2.22.1\n // > If the pattern does not contain a slash /,\n // > Git treats it as a shell glob pattern\n // Actually, if there is only a trailing slash,\n // git also treats it as a shell glob pattern\n\n // After 2.22.1 (compatible but clearer)\n // > If there is a separator at the beginning or middle (or both)\n // > of the pattern, then the pattern is relative to the directory\n // > level of the particular .gitignore file itself.\n // > Otherwise the pattern may also match at any level below\n // > the .gitignore level.\n ? '(?:^|\\\\/)'\n\n // > Otherwise, Git treats the pattern as a shell glob suitable for\n // > consumption by fnmatch(3)\n : '^'\n }\n ],\n\n // two globstars\n [\n // Use lookahead assertions so that we could match more than one `'/**'`\n /\\\\\\/\\\\\\*\\\\\\*(?=\\\\\\/|$)/g,\n\n // Zero, one or several directories\n // should not use '*', or it will be replaced by the next replacer\n\n // Check if it is not the last `'/**'`\n (_, index, str) => index + 6 < str.length\n\n // case: /**/\n // > A slash followed by two consecutive asterisks then a slash matches\n // > zero or more directories.\n // > For example, \"a/**/b\" matches \"a/b\", \"a/x/b\", \"a/x/y/b\" and so on.\n // '/**/'\n ? '(?:\\\\/[^\\\\/]+)*'\n\n // case: /**\n // > A trailing `\"/**\"` matches everything inside.\n\n // #21: everything inside but it should not include the current folder\n : '\\\\/.+'\n ],\n\n // normal intermediate wildcards\n [\n // Never replace escaped '*'\n // ignore rule '\\*' will match the path '*'\n\n // 'abc.*/' -> go\n // 'abc.*' -> skip this rule,\n // coz trailing single wildcard will be handed by [trailing wildcard]\n /(^|[^\\\\]+)(\\\\\\*)+(?=.+)/g,\n\n // '*.js' matches '.js'\n // '*.js' doesn't match 'abc'\n (_, p1, p2) => {\n // 1.\n // > An asterisk \"*\" matches anything except a slash.\n // 2.\n // > Other consecutive asterisks are considered regular asterisks\n // > and will match according to the previous rules.\n const unescaped = p2.replace(/\\\\\\*/g, '[^\\\\/]*')\n return p1 + unescaped\n }\n ],\n\n [\n // unescape, revert step 3 except for back slash\n // For example, if a user escape a '\\\\*',\n // after step 3, the result will be '\\\\\\\\\\\\*'\n /\\\\\\\\\\\\(?=[$.|*+(){^])/g,\n () => ESCAPE\n ],\n\n [\n // '\\\\\\\\' -> '\\\\'\n /\\\\\\\\/g,\n () => ESCAPE\n ],\n\n [\n // > The range notation, e.g. [a-zA-Z],\n // > can be used to match one of the characters in a range.\n\n // `\\` is escaped by step 3\n /(\\\\)?\\[([^\\]/]*?)(\\\\*)($|\\])/g,\n (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE\n // '\\\\[bar]' -> '\\\\\\\\[bar\\\\]'\n ? `\\\\[${range}${cleanRangeBackSlash(endEscape)}${close}`\n : close === ']'\n ? endEscape.length % 2 === 0\n // A normal case, and it is a range notation\n // '[bar]'\n // '[bar\\\\\\\\]'\n ? `[${sanitizeRange(range)}${endEscape}]`\n // Invalid range notaton\n // '[bar\\\\]' -> '[bar\\\\\\\\]'\n : '[]'\n : '[]'\n ],\n\n // ending\n [\n // 'js' will not match 'js.'\n // 'ab' will not match 'abc'\n /(?:[^*])$/,\n\n // WTF!\n // https://git-scm.com/docs/gitignore\n // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)\n // which re-fixes #24, #38\n\n // > If there is a separator at the end of the pattern then the pattern\n // > will only match directories, otherwise the pattern can match both\n // > files and directories.\n\n // 'js*' will not match 'a.js'\n // 'js/' will not match 'a.js'\n // 'js' will match 'a.js' and 'a.js/'\n match => /\\/$/.test(match)\n // foo/ will not match 'foo'\n ? `${match}$`\n // foo matches 'foo' and 'foo/'\n : `${match}(?=$|\\\\/$)`\n ]\n]\n\nconst REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\\\\/)?\\\\\\*$/\nconst MODE_IGNORE = 'regex'\nconst MODE_CHECK_IGNORE = 'checkRegex'\nconst UNDERSCORE = '_'\n\nconst TRAILING_WILD_CARD_REPLACERS = {\n [MODE_IGNORE] (_, p1) {\n const prefix = p1\n // '\\^':\n // '/*' does not match EMPTY\n // '/*' does not match everything\n\n // '\\\\\\/':\n // 'abc/*' does not match 'abc/'\n ? `${p1}[^/]+`\n\n // 'a*' matches 'a'\n // 'a*' matches 'aa'\n : '[^/]*'\n\n return `${prefix}(?=$|\\\\/$)`\n },\n\n [MODE_CHECK_IGNORE] (_, p1) {\n // When doing `git check-ignore`\n const prefix = p1\n // '\\\\\\/':\n // 'abc/*' DOES match 'abc/' !\n ? `${p1}[^/]*`\n\n // 'a*' matches 'a'\n // 'a*' matches 'aa'\n : '[^/]*'\n\n return `${prefix}(?=$|\\\\/$)`\n }\n}\n\n// @param {pattern}\nconst makeRegexPrefix = pattern => REPLACERS.reduce(\n (prev, [matcher, replacer]) =>\n prev.replace(matcher, replacer.bind(pattern)),\n pattern\n)\n\nconst isString = subject => typeof subject === 'string'\n\n// > A blank line matches no files, so it can serve as a separator for readability.\nconst checkPattern = pattern => pattern\n && isString(pattern)\n && !REGEX_TEST_BLANK_LINE.test(pattern)\n && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern)\n\n // > A line starting with # serves as a comment.\n && pattern.indexOf('#') !== 0\n\nconst splitPattern = pattern => pattern\n.split(REGEX_SPLITALL_CRLF)\n.filter(Boolean)\n\nclass IgnoreRule {\n constructor (\n pattern,\n mark,\n body,\n ignoreCase,\n negative,\n prefix\n ) {\n this.pattern = pattern\n this.mark = mark\n this.negative = negative\n\n define(this, 'body', body)\n define(this, 'ignoreCase', ignoreCase)\n define(this, 'regexPrefix', prefix)\n }\n\n get regex () {\n const key = UNDERSCORE + MODE_IGNORE\n\n if (this[key]) {\n return this[key]\n }\n\n return this._make(MODE_IGNORE, key)\n }\n\n get checkRegex () {\n const key = UNDERSCORE + MODE_CHECK_IGNORE\n\n if (this[key]) {\n return this[key]\n }\n\n return this._make(MODE_CHECK_IGNORE, key)\n }\n\n _make (mode, key) {\n const str = this.regexPrefix.replace(\n REGEX_REPLACE_TRAILING_WILDCARD,\n\n // It does not need to bind pattern\n TRAILING_WILD_CARD_REPLACERS[mode]\n )\n\n const regex = this.ignoreCase\n ? new RegExp(str, 'i')\n : new RegExp(str)\n\n return define(this, key, regex)\n }\n}\n\nconst createRule = ({\n pattern,\n mark\n}, ignoreCase) => {\n let negative = false\n let body = pattern\n\n // > An optional prefix \"!\" which negates the pattern;\n if (body.indexOf('!') === 0) {\n negative = true\n body = body.substr(1)\n }\n\n body = body\n // > Put a backslash (\"\\\") in front of the first \"!\" for patterns that\n // > begin with a literal \"!\", for example, `\"\\!important!.txt\"`.\n .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!')\n // > Put a backslash (\"\\\") in front of the first hash for patterns that\n // > begin with a hash.\n .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#')\n\n const regexPrefix = makeRegexPrefix(body)\n\n return new IgnoreRule(\n pattern,\n mark,\n body,\n ignoreCase,\n negative,\n regexPrefix\n )\n}\n\nclass RuleManager {\n constructor (ignoreCase) {\n this._ignoreCase = ignoreCase\n this._rules = []\n }\n\n _add (pattern) {\n // #32\n if (pattern && pattern[KEY_IGNORE]) {\n this._rules = this._rules.concat(pattern._rules._rules)\n this._added = true\n return\n }\n\n if (isString(pattern)) {\n pattern = {\n pattern\n }\n }\n\n if (checkPattern(pattern.pattern)) {\n const rule = createRule(pattern, this._ignoreCase)\n this._added = true\n this._rules.push(rule)\n }\n }\n\n // @param {Array<string> | string | Ignore} pattern\n add (pattern) {\n this._added = false\n\n makeArray(\n isString(pattern)\n ? splitPattern(pattern)\n : pattern\n ).forEach(this._add, this)\n\n return this._added\n }\n\n // Test one single path without recursively checking parent directories\n //\n // - checkUnignored `boolean` whether should check if the path is unignored,\n // setting `checkUnignored` to `false` could reduce additional\n // path matching.\n // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`\n\n // @returns {TestResult} true if a file is ignored\n test (path, checkUnignored, mode) {\n let ignored = false\n let unignored = false\n let matchedRule\n\n this._rules.forEach(rule => {\n const {negative} = rule\n\n // | ignored : unignored\n // -------- | ---------------------------------------\n // negative | 0:0 | 0:1 | 1:0 | 1:1\n // -------- | ------- | ------- | ------- | --------\n // 0 | TEST | TEST | SKIP | X\n // 1 | TESTIF | SKIP | TEST | X\n\n // - SKIP: always skip\n // - TEST: always test\n // - TESTIF: only test if checkUnignored\n // - X: that never happen\n if (\n unignored === negative && ignored !== unignored\n || negative && !ignored && !unignored && !checkUnignored\n ) {\n return\n }\n\n const matched = rule[mode].test(path)\n\n if (!matched) {\n return\n }\n\n ignored = !negative\n unignored = negative\n\n matchedRule = negative\n ? UNDEFINED\n : rule\n })\n\n const ret = {\n ignored,\n unignored\n }\n\n if (matchedRule) {\n ret.rule = matchedRule\n }\n\n return ret\n }\n}\n\nconst throwError = (message, Ctor) => {\n throw new Ctor(message)\n}\n\nconst checkPath = (path, originalPath, doThrow) => {\n if (!isString(path)) {\n return doThrow(\n `path must be a string, but got \\`${originalPath}\\``,\n TypeError\n )\n }\n\n // We don't know if we should ignore EMPTY, so throw\n if (!path) {\n return doThrow(`path must not be empty`, TypeError)\n }\n\n // Check if it is a relative path\n if (checkPath.isNotRelative(path)) {\n const r = '`path.relative()`d'\n return doThrow(\n `path should be a ${r} string, but got \"${originalPath}\"`,\n RangeError\n )\n }\n\n return true\n}\n\nconst isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path)\n\ncheckPath.isNotRelative = isNotRelative\n\n// On windows, the following function will be replaced\n/* istanbul ignore next */\ncheckPath.convert = p => p\n\n\nclass Ignore {\n constructor ({\n ignorecase = true,\n ignoreCase = ignorecase,\n allowRelativePaths = false\n } = {}) {\n define(this, KEY_IGNORE, true)\n\n this._rules = new RuleManager(ignoreCase)\n this._strictPathCheck = !allowRelativePaths\n this._initCache()\n }\n\n _initCache () {\n // A cache for the result of `.ignores()`\n this._ignoreCache = Object.create(null)\n\n // A cache for the result of `.test()`\n this._testCache = Object.create(null)\n }\n\n add (pattern) {\n if (this._rules.add(pattern)) {\n // Some rules have just added to the ignore,\n // making the behavior changed,\n // so we need to re-initialize the result cache\n this._initCache()\n }\n\n return this\n }\n\n // legacy\n addPattern (pattern) {\n return this.add(pattern)\n }\n\n // @returns {TestResult}\n _test (originalPath, cache, checkUnignored, slices) {\n const path = originalPath\n // Supports nullable path\n && checkPath.convert(originalPath)\n\n checkPath(\n path,\n originalPath,\n this._strictPathCheck\n ? throwError\n : RETURN_FALSE\n )\n\n return this._t(path, cache, checkUnignored, slices)\n }\n\n checkIgnore (path) {\n // If the path doest not end with a slash, `.ignores()` is much equivalent\n // to `git check-ignore`\n if (!REGEX_TEST_TRAILING_SLASH.test(path)) {\n return this.test(path)\n }\n\n const slices = path.split(SLASH).filter(Boolean)\n slices.pop()\n\n if (slices.length) {\n const parent = this._t(\n slices.join(SLASH) + SLASH,\n this._testCache,\n true,\n slices\n )\n\n if (parent.ignored) {\n return parent\n }\n }\n\n return this._rules.test(path, false, MODE_CHECK_IGNORE)\n }\n\n _t (\n // The path to be tested\n path,\n\n // The cache for the result of a certain checking\n cache,\n\n // Whether should check if the path is unignored\n checkUnignored,\n\n // The path slices\n slices\n ) {\n if (path in cache) {\n return cache[path]\n }\n\n if (!slices) {\n // path/to/a.js\n // ['path', 'to', 'a.js']\n slices = path.split(SLASH).filter(Boolean)\n }\n\n slices.pop()\n\n // If the path has no parent directory, just test it\n if (!slices.length) {\n return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE)\n }\n\n const parent = this._t(\n slices.join(SLASH) + SLASH,\n cache,\n checkUnignored,\n slices\n )\n\n // If the path contains a parent directory, check the parent first\n return cache[path] = parent.ignored\n // > It is not possible to re-include a file if a parent directory of\n // > that file is excluded.\n ? parent\n : this._rules.test(path, checkUnignored, MODE_IGNORE)\n }\n\n ignores (path) {\n return this._test(path, this._ignoreCache, false).ignored\n }\n\n createFilter () {\n return path => !this.ignores(path)\n }\n\n filter (paths) {\n return makeArray(paths).filter(this.createFilter())\n }\n\n // @returns {TestResult}\n test (path) {\n return this._test(path, this._testCache, true)\n }\n}\n\nconst factory = options => new Ignore(options)\n\nconst isPathValid = path =>\n checkPath(path && checkPath.convert(path), path, RETURN_FALSE)\n\n/* istanbul ignore next */\nconst setupWindows = () => {\n /* eslint no-control-regex: \"off\" */\n const makePosix = str => /^\\\\\\\\\\?\\\\/.test(str)\n || /[\"<>|\\u0000-\\u001F]+/u.test(str)\n ? str\n : str.replace(/\\\\/g, '/')\n\n checkPath.convert = makePosix\n\n // 'C:\\\\foo' <- 'C:\\\\foo' has been converted to 'C:/'\n // 'd:\\\\foo'\n const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\\//i\n checkPath.isNotRelative = path =>\n REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path)\n || isNotRelative(path)\n}\n\n\n// Windows\n// --------------------------------------------------------------\n/* istanbul ignore next */\nif (\n // Detect `process` so that it can run in browsers.\n typeof process !== 'undefined'\n && process.platform === 'win32'\n) {\n setupWindows()\n}\n\n// COMMONJS_EXPORTS ////////////////////////////////////////////////////////////\n\nmodule.exports = factory\n\n// Although it is an anti-pattern,\n// it is still widely misused by a lot of libraries in github\n// Ref: https://github.com/search?q=ignore.default%28%29&type=code\nfactory.default = factory\n\nmodule.exports.isPathValid = isPathValid\n\n// For testing purposes\ndefine(module.exports, Symbol.for('setupWindows'), setupWindows)\n","import type { CheckResult, PermissionHandler, Rule } from \"../types.ts\"\n\nimport { normPath, prettyPath } from \"@zaly/shared\"\nimport ignore from \"ignore\"\nimport { dirname, isAbsolute, relative } from \"pathe\"\n\n/**\n * Handler for `Rule<\"read\" | \"write\">` — one impl serves both scopes\n * because they share the same matcher and the same workspace state.\n *\n * Algorithm:\n * 1. Normalize candidate to an absolute path.\n * 2. Sensitive-file check (env, ssh keys, credentials) → deny.\n * 3. Find the longest-prefix workspace containing the path. None →\n * ask, with a `kind: \"workspace\"` suggestion for the containing\n * directory.\n * 4. Inside a workspace: resolve the first matching rule against the\n * workspace-relative path. Earlier rules win.\n * 5. Default when no rule matches but the path is inside a workspace:\n * `allow` for reads (workspace = trust signal), `ask` for writes\n * (mutating ops escalate by default; users add `Write(...)` rules\n * to whitelist).\n *\n * Pattern grammar (per Claude-Code conventions):\n * //abs/path absolute filesystem path\n * ~/path path under home directory\n * /path or path workspace-relative (passed through to gitignore)\n */\nexport const fileHandler: PermissionHandler<\"read\" | \"write\"> = {\n validate(input, ctx): CheckResult {\n const abs = normPath(ctx.cwd, input)\n\n if (isSensitiveFile(abs)) {\n return { reason: `${abs}: sensitive file`, verdict: \"deny\" }\n }\n\n const ws = longestWorkspace(abs, ctx.workspaces)\n const inWorkspace = ws !== undefined\n\n // Inside-workspace + path === root: the workspace itself (e.g. `find .`\n // resolved to cwd). Workspace containment alone is enough to allow.\n if (inWorkspace && abs === ws) return { verdict: \"allow\" }\n\n // Outside any workspace, fall through to rule matching with `/` as\n // synthetic root. Lets blanket rules like `read(*)` (yolo preset)\n // override the default \"ask outside workspace\" verdict, while\n // narrower presets keep the safer default.\n const base = ws ?? \"/\"\n const rel = relative(base, abs)\n\n const verb = ctx.scope === \"read\" ? \"reading\" : \"writing\"\n\n const rule = resolveRule(base, rel, ctx.rules)\n if (rule?.policy === \"deny\") return { reason: `${abs}: denied by rule`, verdict: \"deny\" }\n if (rule?.policy === \"ask\") {\n return {\n ask: `Allow ${verb} ${prettyPath(abs)}?`,\n reason: `${abs}: rule requires confirmation`,\n suggestions: [{ kind: \"rule\", pattern: `/${rel}`, scope: ctx.scope }],\n verdict: \"ask\",\n }\n }\n if (rule?.policy === \"allow\") return { verdict: \"allow\" }\n\n // No rule matched. Defaults differ by location:\n // - Inside a workspace: reads ride on workspace trust → allow;\n // writes escalate → ask.\n // - Outside any workspace: always ask, and surface a\n // workspace-add suggestion so the user can promote the parent\n // dir without composing a rule by hand.\n if (!inWorkspace) {\n const parent = dirname(abs)\n return {\n ask: `Allow ${verb} ${prettyPath(abs)}? (not in any workspace)`,\n reason: `${abs}: outside any workspace`,\n suggestions: [\n { description: `add ${parent} as workspace`, kind: \"workspace\", path: parent },\n ],\n verdict: \"ask\",\n }\n }\n if (ctx.scope === \"read\") return { verdict: \"allow\" }\n return {\n ask: `Allow ${verb} ${prettyPath(abs)}?`,\n reason: `${abs}: write requires confirmation`,\n suggestions: [{ kind: \"rule\", pattern: `/${rel}`, scope: \"write\" }],\n verdict: \"ask\",\n }\n },\n}\n\n/** True if `path` looks like a credentials/keys file we shouldn't\n * expose to the model by default. Conservative — false positives are\n * fine here, and users can override via `allow` rules. */\nexport function isSensitiveFile(path: string): boolean {\n return SENSITIVE_PATTERNS.some((re) => re.test(path))\n}\n\n/** Common locations for credentials, keys, and other sensitive data.\n * Matched against the path string directly — covers both absolute and\n * relative inputs. Add to this list as new gotchas surface. */\nconst SENSITIVE_PATTERNS: RegExp[] = [\n /(?:^|\\/)\\.env(?:\\.|$)/, // .env, .env.local, .env.production, ...\n /(?:^|\\/)\\.git\\/(?!hooks\\/)/, // .git/* but not hooks (commonly inspected)\n /(?:^|\\/)\\.ssh\\//, // ssh keys + config\n /(?:^|\\/)\\.aws\\/credentials/,\n /(?:^|\\/)\\.netrc$/,\n /(?:^|\\/)id_(?:rsa|dsa|ed25519|ecdsa)(?:\\.pub)?$/,\n /(?:^|\\/)\\.npmrc$/, // can hold auth tokens\n /(?:^|\\/)\\.pypirc$/,\n /(?:^|\\/)secrets?\\//,\n /(?:^|\\/)credentials?(?:\\.|\\/)/,\n]\n\n/** Longest-prefix match against the workspace list — returns the\n * containing workspace's absolute path, or undefined if none contain\n * the candidate. Workspaces arrive pre-normalized from the manager. */\nfunction longestWorkspace(abs: string, workspaces: readonly string[]): string | undefined {\n let best: string | undefined\n for (const root of workspaces) {\n if (abs === root || abs.startsWith(root.endsWith(\"/\") ? root : `${root}/`)) {\n if (best === undefined || root.length > best.length) best = root\n }\n }\n return best\n}\n\n/** Resolve the first matching rule.\n * Patterns get normalized (`//abs`, `~/`, `/rel`, `rel`) into\n * workspace-rooted gitignore syntax; patterns that resolve outside the\n * candidate's workspace are dropped (they don't apply here). */\nfunction resolveRule(\n workspace: string,\n rel: string,\n rules: readonly Rule<\"read\" | \"write\">[]\n): Rule<\"read\" | \"write\"> | undefined {\n if (rel === \"\") return undefined\n for (const rule of rules) {\n const norm = normalizePattern(rule.pattern, workspace)\n if (norm === undefined) continue\n try {\n if (ignore().add(norm).ignores(rel)) return rule\n } catch {\n // Skip invalid rels.\n }\n }\n}\n\nfunction normalizePattern(pattern: string, workspace: string): string | undefined {\n if (pattern.startsWith(\"//\")) {\n return relativizeToWorkspace(pattern.slice(1), workspace)\n }\n if (pattern.startsWith(\"~/\")) {\n return relativizeToWorkspace(normPath(pattern), workspace)\n }\n // /pattern or pattern → already workspace-relative gitignore syntax.\n return pattern\n}\n\nfunction relativizeToWorkspace(absPattern: string, workspace: string): string | undefined {\n const rel = relative(workspace, absPattern)\n if (rel === \"\" || rel.startsWith(\"..\") || isAbsolute(rel)) return undefined\n return `/${rel}`\n}\n","import type { CheckResult, PermissionHandler, Rule } from \"../types.ts\"\n\nimport ignore from \"ignore\"\n\n/**\n * Generic tool-scope handler.\n *\n * Used by `Tasks` to gate every tool dispatch on the tool name, and\n * available to tools themselves for richer checks (e.g. fetch passing\n * `fetch:example.com` so users can ask-for-domain).\n *\n * Pattern grammar is gitignore-style — reuses the `ignore` package so\n * the syntax matches `read` / `write` patterns. Common shapes:\n *\n * \"tool\" → bare scope; matches every input (default-allow)\n * \"tool(bash)\" → exact match for `\"bash\"`\n * \"tool(fetch:*)\" → glob match `\"fetch:...\"`\n * \"tool(task_*)\" → glob match `\"task_...\"`\n *\n * Resolution is first-match-wins. Default verdict when no rule matches is\n * `allow` — an unconfigured `tool` scope should not surprise users by\n * gating ordinary tool calls.\n */\nexport const toolHandler: PermissionHandler<\"tool\"> = {\n validate(input, ctx): CheckResult {\n const rule = resolveRule(input, ctx.rules)\n if (rule?.policy === \"deny\") {\n return { reason: `tool ${input}: denied by rule`, verdict: \"deny\" }\n }\n if (rule?.policy === \"ask\") {\n return {\n ask: `Allow tool ${input}?`,\n reason: `tool ${input}: rule requires confirmation`,\n suggestions: [{ kind: \"rule\", pattern: input, scope: \"tool\" }],\n verdict: \"ask\",\n }\n }\n return { verdict: \"allow\" }\n },\n}\n\nfunction resolveRule(input: string, rules: readonly Rule<\"tool\">[]): Rule<\"tool\"> | undefined {\n for (const rule of rules) {\n if (ignore().add(rule.pattern).ignores(input)) return rule\n }\n}\n","import type { PermissionHandler } from \"../types.ts\"\n\nimport { createRegistry } from \"@zaly/shared/registry\"\nimport { bashHandler } from \"./bash.ts\"\nimport { fileHandler } from \"./files.ts\"\nimport { toolHandler } from \"./tool.ts\"\n\nexport type HandlerLoader = () => PermissionHandler<string>\n\nconst builtin = {\n bash: () => bashHandler,\n read: () => fileHandler,\n tool: () => toolHandler,\n write: () => fileHandler,\n} as const satisfies Record<string, HandlerLoader>\n\n/** Open registry of permission scopes — declaration-merge to add your\n * own. The keys give `ctx.need(\"…\", input)` typed autocomplete and\n * catch typos at compile time. The value carries the *input* type for\n * that scope (almost always `string` — files take paths, bash takes\n * commands, the generic `tool` scope takes the tool name).\n *\n * Built-ins:\n * - `bash` → command string\n * - `read` → absolute path\n * - `write` → absolute path\n * - `tool` → tool name (or richer `name:arg` shape per tool)\n *\n * Add your own scope:\n *\n * ```ts\n * declare module \"@zaly/agent\" {\n * interface PermissionScopes {\n * fetch: string // expects a domain (or \"*\" for any)\n * }\n * }\n * ```\n *\n * Then `ctx.need(\"fetch\", domain)` is typed end-to-end. You still need\n * to register a runtime handler via `handlerRegistry.register(\"fetch\", …)`\n * — this interface is only the type-side declaration.\n */\nexport interface PermissionScopes {\n bash: string\n read: string\n tool: string\n write: string\n}\n\nexport type BuiltinScope = keyof typeof builtin\nexport type PermissionScope = keyof PermissionScopes\nexport type AnyScope = PermissionScope | (string & {})\n\nexport const handlerRegistry = createRegistry<HandlerLoader>(\"scope\").from(builtin)\n"],"x_google_ignoreList":[1],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import { AiError, defineTool } from "@zaly/ai";
2
+ import { Type } from "typebox";
3
+ //#region src/tools/search.ts
4
+ /**
5
+ * Web search via Brave's LLM Context API.
6
+ *
7
+ * Returns extracted snippets pre-chunked from each source page rather
8
+ * than just titles + URLs, so the model gets grounding content in one
9
+ * call without a follow-up `fetch`. Each result lands as one TextPart
10
+ * (snippets joined per-source) preceded by a `<source>` MetaPart with
11
+ * URL / title / age metadata.
12
+ *
13
+ * Authentication: reads `BRAVE_API_KEY` from the environment. Tools
14
+ * don't get config-injected today, so the env var is the simplest
15
+ * surface — same convention `fetch`-style tools use elsewhere.
16
+ *
17
+ * Endpoint: `https://api.search.brave.com/res/v1/llm/context`. Docs:
18
+ * https://api.search.brave.com/app/documentation/llm-context/get-started
19
+ */
20
+ const ENDPOINT = "https://api.search.brave.com/res/v1/llm/context";
21
+ const searchTool = defineTool({
22
+ name: "search",
23
+ desc: "Web search optimised for agents. Returns extracted snippets from each source page (not just titles + URLs), so you get grounding content in one call. Use for fact-finding, current events, documentation lookups, and anything beyond your knowledge cutoff.",
24
+ parallel: true,
25
+ params: Type.Object({
26
+ query: Type.String({
27
+ description: "The search query. 1–400 characters, max 50 words.",
28
+ maxLength: 400,
29
+ minLength: 1
30
+ }),
31
+ count: Type.Optional(Type.Integer({
32
+ default: 10,
33
+ description: "Maximum number of source URLs in the response.",
34
+ maximum: 50,
35
+ minimum: 1
36
+ })),
37
+ freshness: Type.Optional(Type.Union([
38
+ Type.Literal("pd"),
39
+ Type.Literal("pw"),
40
+ Type.Literal("pm"),
41
+ Type.Literal("py")
42
+ ], { description: "Restrict to recent pages. `pd` = past 24h, `pw` = past week, `pm` = past month, `py` = past year. Omit for no filter." })),
43
+ country: Type.Optional(Type.String({
44
+ default: "us",
45
+ description: "Two-letter country code for region-specific results."
46
+ }))
47
+ }),
48
+ async call(args) {
49
+ const apiKey = process.env.BRAVE_API_KEY;
50
+ if (!apiKey || apiKey === "") throw new AiError({
51
+ code: "MISSING_API_KEY",
52
+ message: "search requires BRAVE_API_KEY in the environment. Get a key at https://api.search.brave.com/."
53
+ });
54
+ const url = new URL(ENDPOINT);
55
+ url.searchParams.set("q", args.query);
56
+ url.searchParams.set("count", String(args.count ?? 10));
57
+ url.searchParams.set("country", args.country ?? "us");
58
+ if (args.freshness !== void 0) url.searchParams.set("freshness", args.freshness);
59
+ const t0 = Date.now();
60
+ const res = await fetch(url, { headers: {
61
+ accept: "application/json",
62
+ "x-subscription-token": apiKey
63
+ } });
64
+ if (!res.ok) {
65
+ const body = await res.text().catch(() => "");
66
+ throw new AiError({
67
+ code: "SEARCH_FAILED",
68
+ data: {
69
+ status: res.status,
70
+ statusText: res.statusText
71
+ },
72
+ message: `Brave search failed (${res.status} ${res.statusText}): ${body.slice(0, 200)}`,
73
+ retryable: res.status >= 500 || res.status === 429
74
+ });
75
+ }
76
+ const json = await res.json();
77
+ const results = json.grounding?.generic ?? [];
78
+ const sources = json.sources ?? {};
79
+ const durationMs = Date.now() - t0;
80
+ const parts = [{
81
+ data: {
82
+ count: results.length,
83
+ durationMs,
84
+ query: args.query
85
+ },
86
+ tag: "search",
87
+ type: "meta"
88
+ }];
89
+ if (results.length === 0) {
90
+ parts.push({
91
+ text: "No results found.",
92
+ type: "text"
93
+ });
94
+ return parts;
95
+ }
96
+ for (const r of results) {
97
+ const meta = sources[r.url] ?? {};
98
+ const header = { url: r.url };
99
+ if (meta.age && meta.age.length > 0) header.age = meta.age[1] ?? meta.age[0];
100
+ parts.push({
101
+ data: header,
102
+ tag: "source",
103
+ type: "meta"
104
+ });
105
+ const title = r.title ?? meta.title;
106
+ const body = [];
107
+ if (title) body.push(`# ${title}`);
108
+ const snippets = r.snippets ?? [];
109
+ if (snippets.length > 0) body.push(snippets.join("\n\n"));
110
+ if (body.length > 0) parts.push({
111
+ text: body.join("\n\n"),
112
+ type: "text"
113
+ });
114
+ }
115
+ return parts;
116
+ }
117
+ });
118
+ //#endregion
119
+ export { searchTool };
120
+
121
+ //# sourceMappingURL=search-CRw247ES.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-CRw247ES.mjs","names":[],"sources":["../src/tools/search.ts"],"sourcesContent":["import type { MetaPart, TextPart } from \"@zaly/ai\"\n\nimport { defineTool, AiError } from \"@zaly/ai\"\nimport { Type } from \"typebox\"\n\n/**\n * Web search via Brave's LLM Context API.\n *\n * Returns extracted snippets pre-chunked from each source page rather\n * than just titles + URLs, so the model gets grounding content in one\n * call without a follow-up `fetch`. Each result lands as one TextPart\n * (snippets joined per-source) preceded by a `<source>` MetaPart with\n * URL / title / age metadata.\n *\n * Authentication: reads `BRAVE_API_KEY` from the environment. Tools\n * don't get config-injected today, so the env var is the simplest\n * surface — same convention `fetch`-style tools use elsewhere.\n *\n * Endpoint: `https://api.search.brave.com/res/v1/llm/context`. Docs:\n * https://api.search.brave.com/app/documentation/llm-context/get-started\n */\n\nconst ENDPOINT = \"https://api.search.brave.com/res/v1/llm/context\"\n\ninterface BraveSourceMeta {\n title?: string\n hostname?: string\n age?: string[] | null\n}\n\ninterface BraveResult {\n url: string\n title?: string\n snippets?: string[]\n}\n\ninterface BraveResponse {\n grounding?: {\n generic?: BraveResult[]\n }\n sources?: Record<string, BraveSourceMeta>\n}\n\n// oxlint-disable-next-line sort-keys -- semantic field order: name, desc, params, call\nexport const searchTool = defineTool({\n name: \"search\",\n desc:\n \"Web search optimised for agents. Returns extracted snippets from each \" +\n \"source page (not just titles + URLs), so you get grounding content in \" +\n \"one call. Use for fact-finding, current events, documentation lookups, \" +\n \"and anything beyond your knowledge cutoff.\",\n parallel: true,\n // oxlint-disable-next-line sort-keys -- semantic param order\n params: Type.Object({\n query: Type.String({\n description: \"The search query. 1–400 characters, max 50 words.\",\n maxLength: 400,\n minLength: 1,\n }),\n count: Type.Optional(\n Type.Integer({\n default: 10,\n description: \"Maximum number of source URLs in the response.\",\n maximum: 50,\n minimum: 1,\n })\n ),\n freshness: Type.Optional(\n Type.Union([Type.Literal(\"pd\"), Type.Literal(\"pw\"), Type.Literal(\"pm\"), Type.Literal(\"py\")], {\n description:\n \"Restrict to recent pages. `pd` = past 24h, `pw` = past week, \" +\n \"`pm` = past month, `py` = past year. Omit for no filter.\",\n })\n ),\n country: Type.Optional(\n Type.String({\n default: \"us\",\n description: \"Two-letter country code for region-specific results.\",\n })\n ),\n }),\n\n async call(args): Promise<(MetaPart | TextPart)[]> {\n const apiKey = process.env.BRAVE_API_KEY\n if (!apiKey || apiKey === \"\") {\n throw new AiError({\n code: \"MISSING_API_KEY\",\n message:\n \"search requires BRAVE_API_KEY in the environment. Get a key at \" +\n \"https://api.search.brave.com/.\",\n })\n }\n\n const url = new URL(ENDPOINT)\n url.searchParams.set(\"q\", args.query)\n url.searchParams.set(\"count\", String(args.count ?? 10))\n url.searchParams.set(\"country\", args.country ?? \"us\")\n if (args.freshness !== undefined) url.searchParams.set(\"freshness\", args.freshness)\n\n const t0 = Date.now()\n const res = await fetch(url, {\n headers: {\n accept: \"application/json\",\n \"x-subscription-token\": apiKey,\n },\n })\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\")\n throw new AiError({\n code: \"SEARCH_FAILED\",\n data: { status: res.status, statusText: res.statusText },\n message: `Brave search failed (${res.status} ${res.statusText}): ${body.slice(0, 200)}`,\n retryable: res.status >= 500 || res.status === 429,\n })\n }\n\n const json = (await res.json()) as BraveResponse\n // console.log(json)\n const results = json.grounding?.generic ?? []\n const sources = json.sources ?? {}\n const durationMs = Date.now() - t0\n\n const parts: (MetaPart | TextPart)[] = [\n {\n data: { count: results.length, durationMs, query: args.query },\n tag: \"search\",\n type: \"meta\",\n },\n ]\n\n if (results.length === 0) {\n parts.push({ text: \"No results found.\", type: \"text\" })\n return parts\n }\n\n for (const r of results) {\n const meta = sources[r.url] ?? {}\n const header: Record<string, unknown> = { url: r.url }\n // `age` arrives as a 3-tuple [pretty, ISO, relative]; keep the\n // ISO form (index 1) when available — most useful for the model.\n if (meta.age && meta.age.length > 0) header.age = meta.age[1] ?? meta.age[0]\n\n parts.push({ data: header, tag: \"source\", type: \"meta\" })\n // Title as a markdown H1 right after the `<source>` tag — the\n // pair reads like a document section. Snippets flow underneath.\n const title = r.title ?? meta.title\n const body: string[] = []\n if (title) body.push(`# ${title}`)\n const snippets = r.snippets ?? []\n if (snippets.length > 0) body.push(snippets.join(\"\\n\\n\"))\n if (body.length > 0) parts.push({ text: body.join(\"\\n\\n\"), type: \"text\" })\n }\n\n return parts\n },\n})\n"],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { Message } from "@zaly/ai";
2
+ //#region src/session/claude.d.ts
3
+ /**
4
+ * Read a Claude Code session file (`.jsonl` from `~/.claude/projects/...`)
5
+ * and return its active conversation chain as zaly `Message[]` — pass
6
+ * the result to `Agent.load({ messages, ... })` to seed a fresh agent
7
+ * with the imported history.
8
+ *
9
+ * Claude Code stores its conversation as one JSON record per line. The
10
+ * active chain is reconstructed by walking `parentUuid` backward from the
11
+ * most recent on-chain user/assistant message. Non-message records
12
+ * (`permission-mode`, `attachment`, `system`, `summary`, `file-history-
13
+ * snapshot`, ...), sidechain branches (`isSidechain: true`), and orphan
14
+ * lines outside the chain are skipped.
15
+ *
16
+ * Format mapping:
17
+ *
18
+ * - **User message, string content** → zaly `role: "user"`, content
19
+ * passed through verbatim.
20
+ * - **User message, array content with `tool_result` blocks** → zaly
21
+ * `role: "tool"`. Anthropic's wire format puts tool results in a
22
+ * user message; zaly splits them into a dedicated `tool` role. The
23
+ * tool name (which Claude doesn't store on the result) is resolved
24
+ * from the matching `tool_use` block earlier in the chain.
25
+ * - **User message, array content with text/image blocks** → zaly
26
+ * `role: "user"` with the parts converted (text passes through,
27
+ * images become `ImagePart`).
28
+ * - **Assistant message** → zaly `role: "assistant"` with each block
29
+ * mapped: `text` → `TextPart`, `tool_use` → `ToolCallPart` (the
30
+ * block's `input` becomes `params`). `thinking` / `redacted_thinking`
31
+ * blocks are intentionally dropped on import — Anthropic requires
32
+ * them to round-trip with the exact original `signature` or the next
33
+ * request 400s, and any intermediate processing risks corrupting it.
34
+ * The visible conversation state survives without them.
35
+ *
36
+ * Lossy by design — tokens, finish reasons, model swaps, and timing
37
+ * info from Claude's records are dropped because zaly's `Session.add`
38
+ * doesn't expose those for arbitrary imports. The returned messages
39
+ * carry no `path` association; pass `session: { path: "..." }` to
40
+ * `Agent.load` alongside them if you want to start persisting the
41
+ * imported chain in zaly format.
42
+ */
43
+ interface ClaudeSessionOptions {
44
+ /** Which messages to import:
45
+ * - `"active"` (default) — walks `parentUuid` back from the most
46
+ * recent on-chain message. Returns the conversation as the model
47
+ * currently sees it: branches not on the active head are skipped,
48
+ * pre-compact history (parented to a summary record) is dropped.
49
+ * - `"all"` — every user/assistant message in the file, in
50
+ * chronological order, regardless of branch or compaction. Useful
51
+ * for analytics, fixtures, or recovering pre-compact context. */
52
+ walk?: "active" | "all";
53
+ }
54
+ declare function loadClaudeSession(path: string, opts?: ClaudeSessionOptions): Promise<{
55
+ messages: Message[];
56
+ }>;
57
+ //#endregion
58
+ export { ClaudeSessionOptions, loadClaudeSession };
59
+ //# sourceMappingURL=claude.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.mts","names":[],"sources":["../../src/session/claude.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAsDiB;;;;;;;;;EASf;;iBAaoB,kBACpB,cACA,OAAM,uBACL;EAAU,UAAU"}