@inkeep/agents-cli 0.58.9 → 0.58.12
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.
- package/dist/agents-cli/package.js +3 -2
- package/dist/agents-cli/package.js.map +1 -0
- package/dist/api.js +7 -11
- package/dist/api.js.map +1 -0
- package/dist/commands/add-ui.js +2 -1
- package/dist/commands/add-ui.js.map +1 -0
- package/dist/commands/add.js +2 -1
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/config.js +2 -1
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/dev.js +2 -1
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.js +2 -1
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list-agents.js +2 -1
- package/dist/commands/list-agents.js.map +1 -0
- package/dist/commands/login.js +2 -1
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +2 -1
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/profile.js +2 -1
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/pull-v4/component-parser.js +2 -1
- package/dist/commands/pull-v4/component-parser.js.map +1 -0
- package/dist/commands/pull-v4/component-registry.js +2 -1
- package/dist/commands/pull-v4/component-registry.js.map +1 -0
- package/dist/commands/pull-v4/generators/agent-generator.helpers.js +186 -0
- package/dist/commands/pull-v4/generators/agent-generator.helpers.js.map +1 -0
- package/dist/commands/pull-v4/generators/agent-generator.js +70 -209
- package/dist/commands/pull-v4/generators/agent-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/artifact-component-generator.js +13 -16
- package/dist/commands/pull-v4/generators/artifact-component-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/context-config-generator.js +38 -24
- package/dist/commands/pull-v4/generators/context-config-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/credential-generator.js +14 -10
- package/dist/commands/pull-v4/generators/credential-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/data-component-generator.js +10 -12
- package/dist/commands/pull-v4/generators/data-component-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/environment-generator.js +11 -91
- package/dist/commands/pull-v4/generators/environment-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/external-agent-generator.js +22 -39
- package/dist/commands/pull-v4/generators/external-agent-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/function-tool-generator.js +19 -31
- package/dist/commands/pull-v4/generators/function-tool-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/mcp-tool-generator.js +30 -71
- package/dist/commands/pull-v4/generators/mcp-tool-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/project-generator.js +64 -31
- package/dist/commands/pull-v4/generators/project-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/skill-generator.js +4 -1
- package/dist/commands/pull-v4/generators/skill-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/status-component-generator.js +19 -19
- package/dist/commands/pull-v4/generators/status-component-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/sub-agent-generator.helpers.js +84 -0
- package/dist/commands/pull-v4/generators/sub-agent-generator.helpers.js.map +1 -0
- package/dist/commands/pull-v4/generators/sub-agent-generator.js +82 -113
- package/dist/commands/pull-v4/generators/sub-agent-generator.js.map +1 -0
- package/dist/commands/pull-v4/generators/trigger-generator.js +21 -30
- package/dist/commands/pull-v4/generators/trigger-generator.js.map +1 -0
- package/dist/commands/pull-v4/introspect/demo-project.js +1616 -0
- package/dist/commands/pull-v4/introspect/demo-project.js.map +1 -0
- package/dist/commands/pull-v4/introspect/index.js +17 -16
- package/dist/commands/pull-v4/introspect/index.js.map +1 -0
- package/dist/commands/pull-v4/introspect/test-helpers.js +5 -3
- package/dist/commands/pull-v4/introspect/test-helpers.js.map +1 -0
- package/dist/commands/pull-v4/introspect-generator.js +606 -93
- package/dist/commands/pull-v4/introspect-generator.js.map +1 -0
- package/dist/commands/pull-v4/module-merge.js +2 -1
- package/dist/commands/pull-v4/module-merge.js.map +1 -0
- package/dist/commands/pull-v4/scheduled-trigger-generator.js +16 -17
- package/dist/commands/pull-v4/scheduled-trigger-generator.js.map +1 -0
- package/dist/commands/pull-v4/utils.js +90 -28
- package/dist/commands/pull-v4/utils.js.map +1 -0
- package/dist/commands/push.js +2 -1
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/status.js +2 -1
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.js +2 -1
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/whoami.js +2 -1
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -0
- package/dist/env.js +2 -1
- package/dist/env.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.js +2 -1
- package/dist/instrumentation.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js.map +1 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +2 -1
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js.map +1 -0
- package/dist/utils/background-version-check.js +2 -1
- package/dist/utils/background-version-check.js.map +1 -0
- package/dist/utils/ci-environment.js +2 -1
- package/dist/utils/ci-environment.js.map +1 -0
- package/dist/utils/cli-pipeline.js +2 -1
- package/dist/utils/cli-pipeline.js.map +1 -0
- package/dist/utils/config.js +2 -1
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/credentials.js +2 -1
- package/dist/utils/credentials.js.map +1 -0
- package/dist/utils/environment-loader.js +2 -1
- package/dist/utils/environment-loader.js.map +1 -0
- package/dist/utils/file-finder.js +2 -1
- package/dist/utils/file-finder.js.map +1 -0
- package/dist/utils/json-comparator.js +2 -1
- package/dist/utils/json-comparator.js.map +1 -0
- package/dist/utils/json-comparison.js +2 -1
- package/dist/utils/json-comparison.js.map +1 -0
- package/dist/utils/mcp-runner.js +2 -1
- package/dist/utils/mcp-runner.js.map +1 -0
- package/dist/utils/model-config.js +2 -1
- package/dist/utils/model-config.js.map +1 -0
- package/dist/utils/package-manager.js +2 -1
- package/dist/utils/package-manager.js.map +1 -0
- package/dist/utils/profile-config.js +2 -1
- package/dist/utils/profile-config.js.map +1 -0
- package/dist/utils/profiles/profile-manager.js +2 -1
- package/dist/utils/profiles/profile-manager.js.map +1 -0
- package/dist/utils/profiles/types.js +2 -1
- package/dist/utils/profiles/types.js.map +1 -0
- package/dist/utils/project-directory.js +2 -1
- package/dist/utils/project-directory.js.map +1 -0
- package/dist/utils/project-loader.js +2 -1
- package/dist/utils/project-loader.js.map +1 -0
- package/dist/utils/schema-introspection.js +2 -1
- package/dist/utils/schema-introspection.js.map +1 -0
- package/dist/utils/templates.js +2 -1
- package/dist/utils/templates.js.map +1 -0
- package/dist/utils/tsx-loader.js +2 -1
- package/dist/utils/tsx-loader.js.map +1 -0
- package/dist/utils/version-check.js +2 -1
- package/dist/utils/version-check.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentence.js","names":[],"sources":["../../../../../../../../../node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js"],"sourcesContent":["import Diff from './base.js';\nfunction isSentenceEndPunct(char) {\n return char == '.' || char == '!' || char == '?';\n}\nclass SentenceDiff extends Diff {\n tokenize(value) {\n var _a;\n // If in future we drop support for environments that don't support lookbehinds, we can replace\n // this entire function with:\n // return value.split(/(?<=[.!?])(\\s+|$)/);\n // but until then, for similar reasons to the trailingWs function in string.ts, we are forced\n // to do this verbosely \"by hand\" instead of using a regex.\n const result = [];\n let tokenStartI = 0;\n for (let i = 0; i < value.length; i++) {\n if (i == value.length - 1) {\n result.push(value.slice(tokenStartI));\n break;\n }\n if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\\s/)) {\n // We've hit a sentence break - i.e. a punctuation mark followed by whitespace.\n // We now want to push TWO tokens to the result:\n // 1. the sentence\n result.push(value.slice(tokenStartI, i + 1));\n // 2. the whitespace\n i = tokenStartI = i + 1;\n while ((_a = value[i + 1]) === null || _a === void 0 ? void 0 : _a.match(/\\s/)) {\n i++;\n }\n result.push(value.slice(tokenStartI, i + 1));\n // Then the next token (a sentence) starts on the character after the whitespace.\n // (It's okay if this is off the end of the string - then the outer loop will terminate\n // here anyway.)\n tokenStartI = i + 1;\n }\n }\n return result;\n }\n}\nexport const sentenceDiff = new SentenceDiff();\nexport function diffSentences(oldStr, newStr, options) {\n return sentenceDiff.diff(oldStr, newStr, options);\n}\n"],"x_google_ignoreList":[0],"mappings":";;;AACA,SAAS,mBAAmB,MAAM;AAC9B,QAAO,QAAQ,OAAO,QAAQ,OAAO,QAAQ;;AAEjD,IAAM,eAAN,cAA2B,KAAK;CAC5B,SAAS,OAAO;EACZ,IAAI;EAMJ,MAAM,SAAS,EAAE;EACjB,IAAI,cAAc;AAClB,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACnC,OAAI,KAAK,MAAM,SAAS,GAAG;AACvB,WAAO,KAAK,MAAM,MAAM,YAAY,CAAC;AACrC;;AAEJ,OAAI,mBAAmB,MAAM,GAAG,IAAI,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE;AAI1D,WAAO,KAAK,MAAM,MAAM,aAAa,IAAI,EAAE,CAAC;AAE5C,QAAI,cAAc,IAAI;AACtB,YAAQ,KAAK,MAAM,IAAI,QAAQ,QAAQ,OAAO,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,KAAK,CAC1E;AAEJ,WAAO,KAAK,MAAM,MAAM,aAAa,IAAI,EAAE,CAAC;AAI5C,kBAAc,IAAI;;;AAG1B,SAAO;;;AAGf,MAAa,eAAe,IAAI,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"word.js","names":[],"sources":["../../../../../../../../../node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js"],"sourcesContent":["import Diff from './base.js';\nimport { longestCommonPrefix, longestCommonSuffix, replacePrefix, replaceSuffix, removePrefix, removeSuffix, maximumOverlap, leadingWs, trailingWs } from '../util/string.js';\n// Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode\n//\n// Chars/ranges counted as \"word\" characters by this regex are as follows:\n//\n// + U+00AD Soft hyphen\n// + 00C0–00FF (letters with diacritics from the Latin-1 Supplement), except:\n// - U+00D7 × Multiplication sign\n// - U+00F7 ÷ Division sign\n// + Latin Extended-A, 0100–017F\n// + Latin Extended-B, 0180–024F\n// + IPA Extensions, 0250–02AF\n// + Spacing Modifier Letters, 02B0–02FF, except:\n// - U+02C7 ˇ ˇ Caron\n// - U+02D8 ˘ ˘ Breve\n// - U+02D9 ˙ ˙ Dot Above\n// - U+02DA ˚ ˚ Ring Above\n// - U+02DB ˛ ˛ Ogonek\n// - U+02DC ˜ ˜ Small Tilde\n// - U+02DD ˝ ˝ Double Acute Accent\n// + Latin Extended Additional, 1E00–1EFF\nconst extendedWordChars = 'a-zA-Z0-9_\\\\u{AD}\\\\u{C0}-\\\\u{D6}\\\\u{D8}-\\\\u{F6}\\\\u{F8}-\\\\u{2C6}\\\\u{2C8}-\\\\u{2D7}\\\\u{2DE}-\\\\u{2FF}\\\\u{1E00}-\\\\u{1EFF}';\n// Each token is one of the following:\n// - A punctuation mark plus the surrounding whitespace\n// - A word plus the surrounding whitespace\n// - Pure whitespace (but only in the special case where the entire text\n// is just whitespace)\n//\n// We have to include surrounding whitespace in the tokens because the two\n// alternative approaches produce horribly broken results:\n// * If we just discard the whitespace, we can't fully reproduce the original\n// text from the sequence of tokens and any attempt to render the diff will\n// get the whitespace wrong.\n// * If we have separate tokens for whitespace, then in a typical text every\n// second token will be a single space character. But this often results in\n// the optimal diff between two texts being a perverse one that preserves\n// the spaces between words but deletes and reinserts actual common words.\n// See https://github.com/kpdecker/jsdiff/issues/160#issuecomment-1866099640\n// for an example.\n//\n// Keeping the surrounding whitespace of course has implications for .equals\n// and .join, not just .tokenize.\n// This regex does NOT fully implement the tokenization rules described above.\n// Instead, it gives runs of whitespace their own \"token\". The tokenize method\n// then handles stitching whitespace tokens onto adjacent word or punctuation\n// tokens.\nconst tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\\\s+|[^${extendedWordChars}]`, 'ug');\nclass WordDiff extends Diff {\n equals(left, right, options) {\n if (options.ignoreCase) {\n left = left.toLowerCase();\n right = right.toLowerCase();\n }\n return left.trim() === right.trim();\n }\n tokenize(value, options = {}) {\n let parts;\n if (options.intlSegmenter) {\n const segmenter = options.intlSegmenter;\n if (segmenter.resolvedOptions().granularity != 'word') {\n throw new Error('The segmenter passed must have a granularity of \"word\"');\n }\n // We want `parts` to be an array whose elements alternate between being\n // pure whitespace and being pure non-whitespace. This is ALMOST what the\n // segments returned by a word-based Intl.Segmenter already look like,\n // and therefore we can ALMOST get what we want by simply doing...\n // parts = Array.from(segmenter.segment(value), segment => segment.segment);\n // ... but not QUITE, because there's of one annoying special case: every\n // newline character gets its own segment, instead of sharing a segment\n // with other surrounding whitespace. We therefore need to manually merge\n // consecutive segments of whitespace into a single part:\n parts = [];\n for (const segmentObj of Array.from(segmenter.segment(value))) {\n const segment = segmentObj.segment;\n if (parts.length && (/\\s/).test(parts[parts.length - 1]) && (/\\s/).test(segment)) {\n parts[parts.length - 1] += segment;\n }\n else {\n parts.push(segment);\n }\n }\n }\n else {\n parts = value.match(tokenizeIncludingWhitespace) || [];\n }\n const tokens = [];\n let prevPart = null;\n parts.forEach(part => {\n if ((/\\s/).test(part)) {\n if (prevPart == null) {\n tokens.push(part);\n }\n else {\n tokens.push(tokens.pop() + part);\n }\n }\n else if (prevPart != null && (/\\s/).test(prevPart)) {\n if (tokens[tokens.length - 1] == prevPart) {\n tokens.push(tokens.pop() + part);\n }\n else {\n tokens.push(prevPart + part);\n }\n }\n else {\n tokens.push(part);\n }\n prevPart = part;\n });\n return tokens;\n }\n join(tokens) {\n // Tokens being joined here will always have appeared consecutively in the\n // same text, so we can simply strip off the leading whitespace from all the\n // tokens except the first (and except any whitespace-only tokens - but such\n // a token will always be the first and only token anyway) and then join them\n // and the whitespace around words and punctuation will end up correct.\n return tokens.map((token, i) => {\n if (i == 0) {\n return token;\n }\n else {\n return token.replace((/^\\s+/), '');\n }\n }).join('');\n }\n postProcess(changes, options) {\n if (!changes || options.oneChangePerToken) {\n return changes;\n }\n let lastKeep = null;\n // Change objects representing any insertion or deletion since the last\n // \"keep\" change object. There can be at most one of each.\n let insertion = null;\n let deletion = null;\n changes.forEach(change => {\n if (change.added) {\n insertion = change;\n }\n else if (change.removed) {\n deletion = change;\n }\n else {\n if (insertion || deletion) { // May be false at start of text\n dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);\n }\n lastKeep = change;\n insertion = null;\n deletion = null;\n }\n });\n if (insertion || deletion) {\n dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);\n }\n return changes;\n }\n}\nexport const wordDiff = new WordDiff();\nexport function diffWords(oldStr, newStr, options) {\n // This option has never been documented and never will be (it's clearer to\n // just call `diffWordsWithSpace` directly if you need that behavior), but\n // has existed in jsdiff for a long time, so we retain support for it here\n // for the sake of backwards compatibility.\n if ((options === null || options === void 0 ? void 0 : options.ignoreWhitespace) != null && !options.ignoreWhitespace) {\n return diffWordsWithSpace(oldStr, newStr, options);\n }\n return wordDiff.diff(oldStr, newStr, options);\n}\nfunction dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {\n // Before returning, we tidy up the leading and trailing whitespace of the\n // change objects to eliminate cases where trailing whitespace in one object\n // is repeated as leading whitespace in the next.\n // Below are examples of the outcomes we want here to explain the code.\n // I=insert, K=keep, D=delete\n // 1. diffing 'foo bar baz' vs 'foo baz'\n // Prior to cleanup, we have K:'foo ' D:' bar ' K:' baz'\n // After cleanup, we want: K:'foo ' D:'bar ' K:'baz'\n //\n // 2. Diffing 'foo bar baz' vs 'foo qux baz'\n // Prior to cleanup, we have K:'foo ' D:' bar ' I:' qux ' K:' baz'\n // After cleanup, we want K:'foo ' D:'bar' I:'qux' K:' baz'\n //\n // 3. Diffing 'foo\\nbar baz' vs 'foo baz'\n // Prior to cleanup, we have K:'foo ' D:'\\nbar ' K:' baz'\n // After cleanup, we want K'foo' D:'\\nbar' K:' baz'\n //\n // 4. Diffing 'foo baz' vs 'foo\\nbar baz'\n // Prior to cleanup, we have K:'foo\\n' I:'\\nbar ' K:' baz'\n // After cleanup, we ideally want K'foo' I:'\\nbar' K:' baz'\n // but don't actually manage this currently (the pre-cleanup change\n // objects don't contain enough information to make it possible).\n //\n // 5. Diffing 'foo bar baz' vs 'foo baz'\n // Prior to cleanup, we have K:'foo ' D:' bar ' K:' baz'\n // After cleanup, we want K:'foo ' D:' bar ' K:'baz'\n //\n // Our handling is unavoidably imperfect in the case where there's a single\n // indel between keeps and the whitespace has changed. For instance, consider\n // diffing 'foo\\tbar\\nbaz' vs 'foo baz'. Unless we create an extra change\n // object to represent the insertion of the space character (which isn't even\n // a token), we have no way to avoid losing information about the texts'\n // original whitespace in the result we return. Still, we do our best to\n // output something that will look sensible if we e.g. print it with\n // insertions in green and deletions in red.\n // Between two \"keep\" change objects (or before the first or after the last\n // change object), we can have either:\n // * A \"delete\" followed by an \"insert\"\n // * Just an \"insert\"\n // * Just a \"delete\"\n // We handle the three cases separately.\n if (deletion && insertion) {\n const oldWsPrefix = leadingWs(deletion.value);\n const oldWsSuffix = trailingWs(deletion.value);\n const newWsPrefix = leadingWs(insertion.value);\n const newWsSuffix = trailingWs(insertion.value);\n if (startKeep) {\n const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);\n startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);\n deletion.value = removePrefix(deletion.value, commonWsPrefix);\n insertion.value = removePrefix(insertion.value, commonWsPrefix);\n }\n if (endKeep) {\n const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);\n endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);\n deletion.value = removeSuffix(deletion.value, commonWsSuffix);\n insertion.value = removeSuffix(insertion.value, commonWsSuffix);\n }\n }\n else if (insertion) {\n // The whitespaces all reflect what was in the new text rather than\n // the old, so we essentially have no information about whitespace\n // insertion or deletion. We just want to dedupe the whitespace.\n // We do that by having each change object keep its trailing\n // whitespace and deleting duplicate leading whitespace where\n // present.\n if (startKeep) {\n const ws = leadingWs(insertion.value);\n insertion.value = insertion.value.substring(ws.length);\n }\n if (endKeep) {\n const ws = leadingWs(endKeep.value);\n endKeep.value = endKeep.value.substring(ws.length);\n }\n // otherwise we've got a deletion and no insertion\n }\n else if (startKeep && endKeep) {\n const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value);\n // Any whitespace that comes straight after startKeep in both the old and\n // new texts, assign to startKeep and remove from the deletion.\n const newWsStart = longestCommonPrefix(newWsFull, delWsStart);\n deletion.value = removePrefix(deletion.value, newWsStart);\n // Any whitespace that comes straight before endKeep in both the old and\n // new texts, and hasn't already been assigned to startKeep, assign to\n // endKeep and remove from the deletion.\n const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);\n deletion.value = removeSuffix(deletion.value, newWsEnd);\n endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);\n // If there's any whitespace from the new text that HASN'T already been\n // assigned, assign it to the start:\n startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));\n }\n else if (endKeep) {\n // We are at the start of the text. Preserve all the whitespace on\n // endKeep, and just remove whitespace from the end of deletion to the\n // extent that it overlaps with the start of endKeep.\n const endKeepWsPrefix = leadingWs(endKeep.value);\n const deletionWsSuffix = trailingWs(deletion.value);\n const overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);\n deletion.value = removeSuffix(deletion.value, overlap);\n }\n else if (startKeep) {\n // We are at the END of the text. Preserve all the whitespace on\n // startKeep, and just remove whitespace from the start of deletion to\n // the extent that it overlaps with the end of startKeep.\n const startKeepWsSuffix = trailingWs(startKeep.value);\n const deletionWsPrefix = leadingWs(deletion.value);\n const overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);\n deletion.value = removePrefix(deletion.value, overlap);\n }\n}\nclass WordsWithSpaceDiff extends Diff {\n tokenize(value) {\n // Slightly different to the tokenizeIncludingWhitespace regex used above in\n // that this one treats each individual newline as a distinct token, rather\n // than merging them into other surrounding whitespace. This was requested\n // in https://github.com/kpdecker/jsdiff/issues/180 &\n // https://github.com/kpdecker/jsdiff/issues/211\n const regex = new RegExp(`(\\\\r?\\\\n)|[${extendedWordChars}]+|[^\\\\S\\\\n\\\\r]+|[^${extendedWordChars}]`, 'ug');\n return value.match(regex) || [];\n }\n}\nexport const wordsWithSpaceDiff = new WordsWithSpaceDiff();\nexport function diffWordsWithSpace(oldStr, newStr, options) {\n return wordsWithSpaceDiff.diff(oldStr, newStr, options);\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","names":[],"sources":["../../../../../../../../../node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js"],"sourcesContent":["import { diffLines } from '../diff/line.js';\nexport const INCLUDE_HEADERS = {\n includeIndex: true,\n includeUnderline: true,\n includeFileHeaders: true\n};\nexport const FILE_HEADERS_ONLY = {\n includeIndex: false,\n includeUnderline: false,\n includeFileHeaders: true\n};\nexport const OMIT_HEADERS = {\n includeIndex: false,\n includeUnderline: false,\n includeFileHeaders: false\n};\nexport function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {\n let optionsObj;\n if (!options) {\n optionsObj = {};\n }\n else if (typeof options === 'function') {\n optionsObj = { callback: options };\n }\n else {\n optionsObj = options;\n }\n if (typeof optionsObj.context === 'undefined') {\n optionsObj.context = 4;\n }\n // We copy this into its own variable to placate TypeScript, which thinks\n // optionsObj.context might be undefined in the callbacks below.\n const context = optionsObj.context;\n // @ts-expect-error (runtime check for something that is correctly a static type error)\n if (optionsObj.newlineIsToken) {\n throw new Error('newlineIsToken may not be used with patch-generation functions, only with diffing functions');\n }\n if (!optionsObj.callback) {\n return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));\n }\n else {\n const { callback } = optionsObj;\n diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {\n const patch = diffLinesResultToPatch(diff);\n // TypeScript is unhappy without the cast because it does not understand that `patch` may\n // be undefined here only if `callback` is StructuredPatchCallbackAbortable:\n callback(patch);\n } }));\n }\n function diffLinesResultToPatch(diff) {\n // STEP 1: Build up the patch with no \"\\" lines and with the arrays\n // of lines containing trailing newline characters. We'll tidy up later...\n if (!diff) {\n return;\n }\n diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier\n function contextLines(lines) {\n return lines.map(function (entry) { return ' ' + entry; });\n }\n const hunks = [];\n let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;\n for (let i = 0; i < diff.length; i++) {\n const current = diff[i], lines = current.lines || splitLines(current.value);\n current.lines = lines;\n if (current.added || current.removed) {\n // If we have previous context, start with that\n if (!oldRangeStart) {\n const prev = diff[i - 1];\n oldRangeStart = oldLine;\n newRangeStart = newLine;\n if (prev) {\n curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];\n oldRangeStart -= curRange.length;\n newRangeStart -= curRange.length;\n }\n }\n // Output our changes\n for (const line of lines) {\n curRange.push((current.added ? '+' : '-') + line);\n }\n // Track the updated file position\n if (current.added) {\n newLine += lines.length;\n }\n else {\n oldLine += lines.length;\n }\n }\n else {\n // Identical context lines. Track line changes\n if (oldRangeStart) {\n // Close out any changes that have been output (or join overlapping)\n if (lines.length <= context * 2 && i < diff.length - 2) {\n // Overlapping\n for (const line of contextLines(lines)) {\n curRange.push(line);\n }\n }\n else {\n // end the range and output\n const contextSize = Math.min(lines.length, context);\n for (const line of contextLines(lines.slice(0, contextSize))) {\n curRange.push(line);\n }\n const hunk = {\n oldStart: oldRangeStart,\n oldLines: (oldLine - oldRangeStart + contextSize),\n newStart: newRangeStart,\n newLines: (newLine - newRangeStart + contextSize),\n lines: curRange\n };\n hunks.push(hunk);\n oldRangeStart = 0;\n newRangeStart = 0;\n curRange = [];\n }\n }\n oldLine += lines.length;\n newLine += lines.length;\n }\n }\n // Step 2: eliminate the trailing `\\n` from each line of each hunk, and, where needed, add\n // \"\\".\n for (const hunk of hunks) {\n for (let i = 0; i < hunk.lines.length; i++) {\n if (hunk.lines[i].endsWith('\\n')) {\n hunk.lines[i] = hunk.lines[i].slice(0, -1);\n }\n else {\n hunk.lines.splice(i + 1, 0, '\\\');\n i++; // Skip the line we just added, then continue iterating\n }\n }\n }\n return {\n oldFileName: oldFileName, newFileName: newFileName,\n oldHeader: oldHeader, newHeader: newHeader,\n hunks: hunks\n };\n }\n}\n/**\n * creates a unified diff patch.\n * @param patch either a single structured patch object (as returned by `structuredPatch`) or an array of them (as returned by `parsePatch`)\n */\nexport function formatPatch(patch, headerOptions) {\n if (!headerOptions) {\n headerOptions = INCLUDE_HEADERS;\n }\n if (Array.isArray(patch)) {\n if (patch.length > 1 && !headerOptions.includeFileHeaders) {\n throw new Error('Cannot omit file headers on a multi-file patch. '\n + '(The result would be unparseable; how would a tool trying to apply '\n + 'the patch know which changes are to which file?)');\n }\n return patch.map(p => formatPatch(p, headerOptions)).join('\\n');\n }\n const ret = [];\n if (headerOptions.includeIndex && patch.oldFileName == patch.newFileName) {\n ret.push('Index: ' + patch.oldFileName);\n }\n if (headerOptions.includeUnderline) {\n ret.push('===================================================================');\n }\n if (headerOptions.includeFileHeaders) {\n ret.push('--- ' + patch.oldFileName + (typeof patch.oldHeader === 'undefined' ? '' : '\\t' + patch.oldHeader));\n ret.push('+++ ' + patch.newFileName + (typeof patch.newHeader === 'undefined' ? '' : '\\t' + patch.newHeader));\n }\n for (let i = 0; i < patch.hunks.length; i++) {\n const hunk = patch.hunks[i];\n // Unified Diff Format quirk: If the chunk size is 0,\n // the first number is one lower than one would expect.\n // https://www.artima.com/weblogs/viewpost.jsp?thread=164293\n if (hunk.oldLines === 0) {\n hunk.oldStart -= 1;\n }\n if (hunk.newLines === 0) {\n hunk.newStart -= 1;\n }\n ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines\n + ' +' + hunk.newStart + ',' + hunk.newLines\n + ' @@');\n for (const line of hunk.lines) {\n ret.push(line);\n }\n }\n return ret.join('\\n') + '\\n';\n}\nexport function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {\n if (typeof options === 'function') {\n options = { callback: options };\n }\n if (!(options === null || options === void 0 ? void 0 : options.callback)) {\n const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);\n if (!patchObj) {\n return;\n }\n return formatPatch(patchObj, options === null || options === void 0 ? void 0 : options.headerOptions);\n }\n else {\n const { callback } = options;\n structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: patchObj => {\n if (!patchObj) {\n callback(undefined);\n }\n else {\n callback(formatPatch(patchObj, options.headerOptions));\n }\n } }));\n }\n}\nexport function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) {\n return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options);\n}\n/**\n * Split `text` into an array of lines, including the trailing newline character (where present)\n */\nfunction splitLines(text) {\n const hasTrailingNl = text.endsWith('\\n');\n const result = text.split('\\n').map(line => line + '\\n');\n if (hasTrailingNl) {\n result.pop();\n }\n else {\n result.push(result.pop().slice(0, -1));\n }\n return result;\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
@@ -60,4 +60,5 @@ function leadingWs(string) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
//#endregion
|
|
63
|
-
export { leadingWs, longestCommonPrefix, longestCommonSuffix, maximumOverlap, removePrefix, removeSuffix, replacePrefix, replaceSuffix, trailingWs };
|
|
63
|
+
export { leadingWs, longestCommonPrefix, longestCommonSuffix, maximumOverlap, removePrefix, removeSuffix, replacePrefix, replaceSuffix, trailingWs };
|
|
64
|
+
//# sourceMappingURL=string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string.js","names":[],"sources":["../../../../../../../../../node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js"],"sourcesContent":["export function longestCommonPrefix(str1, str2) {\n let i;\n for (i = 0; i < str1.length && i < str2.length; i++) {\n if (str1[i] != str2[i]) {\n return str1.slice(0, i);\n }\n }\n return str1.slice(0, i);\n}\nexport function longestCommonSuffix(str1, str2) {\n let i;\n // Unlike longestCommonPrefix, we need a special case to handle all scenarios\n // where we return the empty string since str1.slice(-0) will return the\n // entire string.\n if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) {\n return '';\n }\n for (i = 0; i < str1.length && i < str2.length; i++) {\n if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) {\n return str1.slice(-i);\n }\n }\n return str1.slice(-i);\n}\nexport function replacePrefix(string, oldPrefix, newPrefix) {\n if (string.slice(0, oldPrefix.length) != oldPrefix) {\n throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);\n }\n return newPrefix + string.slice(oldPrefix.length);\n}\nexport function replaceSuffix(string, oldSuffix, newSuffix) {\n if (!oldSuffix) {\n return string + newSuffix;\n }\n if (string.slice(-oldSuffix.length) != oldSuffix) {\n throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);\n }\n return string.slice(0, -oldSuffix.length) + newSuffix;\n}\nexport function removePrefix(string, oldPrefix) {\n return replacePrefix(string, oldPrefix, '');\n}\nexport function removeSuffix(string, oldSuffix) {\n return replaceSuffix(string, oldSuffix, '');\n}\nexport function maximumOverlap(string1, string2) {\n return string2.slice(0, overlapCount(string1, string2));\n}\n// Nicked from https://stackoverflow.com/a/60422853/1709587\nfunction overlapCount(a, b) {\n // Deal with cases where the strings differ in length\n let startA = 0;\n if (a.length > b.length) {\n startA = a.length - b.length;\n }\n let endB = b.length;\n if (a.length < b.length) {\n endB = a.length;\n }\n // Create a back-reference for each index\n // that should be followed in case of a mismatch.\n // We only need B to make these references:\n const map = Array(endB);\n let k = 0; // Index that lags behind j\n map[0] = 0;\n for (let j = 1; j < endB; j++) {\n if (b[j] == b[k]) {\n map[j] = map[k]; // skip over the same character (optional optimisation)\n }\n else {\n map[j] = k;\n }\n while (k > 0 && b[j] != b[k]) {\n k = map[k];\n }\n if (b[j] == b[k]) {\n k++;\n }\n }\n // Phase 2: use these references while iterating over A\n k = 0;\n for (let i = startA; i < a.length; i++) {\n while (k > 0 && a[i] != b[k]) {\n k = map[k];\n }\n if (a[i] == b[k]) {\n k++;\n }\n }\n return k;\n}\n/**\n * Returns true if the string consistently uses Windows line endings.\n */\nexport function hasOnlyWinLineEndings(string) {\n return string.includes('\\r\\n') && !string.startsWith('\\n') && !string.match(/[^\\r]\\n/);\n}\n/**\n * Returns true if the string consistently uses Unix line endings.\n */\nexport function hasOnlyUnixLineEndings(string) {\n return !string.includes('\\r\\n') && string.includes('\\n');\n}\nexport function trailingWs(string) {\n // Yes, this looks overcomplicated and dumb - why not replace the whole function with\n // return string.match(/\\s*$/)[0]\n // you ask? Because:\n // 1. the trap described at https://markamery.com/blog/quadratic-time-regexes/ would mean doing\n // this would cause this function to take O(n²) time in the worst case (specifically when\n // there is a massive run of NON-TRAILING whitespace in `string`), and\n // 2. the fix proposed in the same blog post, of using a negative lookbehind, is incompatible\n // with old Safari versions that we'd like to not break if possible (see\n // https://github.com/kpdecker/jsdiff/pull/550)\n // It feels absurd to do this with an explicit loop instead of a regex, but I really can't see a\n // better way that doesn't result in broken behaviour.\n let i;\n for (i = string.length - 1; i >= 0; i--) {\n if (!string[i].match(/\\s/)) {\n break;\n }\n }\n return string.substring(i + 1);\n}\nexport function leadingWs(string) {\n // Thankfully the annoying considerations described in trailingWs don't apply here:\n const match = string.match(/^\\s*/);\n return match ? match[0] : '';\n}\n"],"x_google_ignoreList":[0],"mappings":";AAAA,SAAgB,oBAAoB,MAAM,MAAM;CAC5C,IAAI;AACJ,MAAK,IAAI,GAAG,IAAI,KAAK,UAAU,IAAI,KAAK,QAAQ,IAC5C,KAAI,KAAK,MAAM,KAAK,GAChB,QAAO,KAAK,MAAM,GAAG,EAAE;AAG/B,QAAO,KAAK,MAAM,GAAG,EAAE;;AAE3B,SAAgB,oBAAoB,MAAM,MAAM;CAC5C,IAAI;AAIJ,KAAI,CAAC,QAAQ,CAAC,QAAQ,KAAK,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,GAC9D,QAAO;AAEX,MAAK,IAAI,GAAG,IAAI,KAAK,UAAU,IAAI,KAAK,QAAQ,IAC5C,KAAI,KAAK,KAAK,UAAU,IAAI,OAAO,KAAK,KAAK,UAAU,IAAI,IACvD,QAAO,KAAK,MAAM,CAAC,EAAE;AAG7B,QAAO,KAAK,MAAM,CAAC,EAAE;;AAEzB,SAAgB,cAAc,QAAQ,WAAW,WAAW;AACxD,KAAI,OAAO,MAAM,GAAG,UAAU,OAAO,IAAI,UACrC,OAAM,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,6BAA6B,KAAK,UAAU,UAAU,CAAC,iBAAiB;AAEzH,QAAO,YAAY,OAAO,MAAM,UAAU,OAAO;;AAErD,SAAgB,cAAc,QAAQ,WAAW,WAAW;AACxD,KAAI,CAAC,UACD,QAAO,SAAS;AAEpB,KAAI,OAAO,MAAM,CAAC,UAAU,OAAO,IAAI,UACnC,OAAM,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,2BAA2B,KAAK,UAAU,UAAU,CAAC,iBAAiB;AAEvH,QAAO,OAAO,MAAM,GAAG,CAAC,UAAU,OAAO,GAAG;;AAEhD,SAAgB,aAAa,QAAQ,WAAW;AAC5C,QAAO,cAAc,QAAQ,WAAW,GAAG;;AAE/C,SAAgB,aAAa,QAAQ,WAAW;AAC5C,QAAO,cAAc,QAAQ,WAAW,GAAG;;AAE/C,SAAgB,eAAe,SAAS,SAAS;AAC7C,QAAO,QAAQ,MAAM,GAAG,aAAa,SAAS,QAAQ,CAAC;;AAG3D,SAAS,aAAa,GAAG,GAAG;CAExB,IAAI,SAAS;AACb,KAAI,EAAE,SAAS,EAAE,OACb,UAAS,EAAE,SAAS,EAAE;CAE1B,IAAI,OAAO,EAAE;AACb,KAAI,EAAE,SAAS,EAAE,OACb,QAAO,EAAE;CAKb,MAAM,MAAM,MAAM,KAAK;CACvB,IAAI,IAAI;AACR,KAAI,KAAK;AACT,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK;AAC3B,MAAI,EAAE,MAAM,EAAE,GACV,KAAI,KAAK,IAAI;MAGb,KAAI,KAAK;AAEb,SAAO,IAAI,KAAK,EAAE,MAAM,EAAE,GACtB,KAAI,IAAI;AAEZ,MAAI,EAAE,MAAM,EAAE,GACV;;AAIR,KAAI;AACJ,MAAK,IAAI,IAAI,QAAQ,IAAI,EAAE,QAAQ,KAAK;AACpC,SAAO,IAAI,KAAK,EAAE,MAAM,EAAE,GACtB,KAAI,IAAI;AAEZ,MAAI,EAAE,MAAM,EAAE,GACV;;AAGR,QAAO;;AAcX,SAAgB,WAAW,QAAQ;CAY/B,IAAI;AACJ,MAAK,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,IAChC,KAAI,CAAC,OAAO,GAAG,MAAM,KAAK,CACtB;AAGR,QAAO,OAAO,UAAU,IAAI,EAAE;;AAElC,SAAgB,UAAU,QAAQ;CAE9B,MAAM,QAAQ,OAAO,MAAM,OAAO;AAClC,QAAO,QAAQ,MAAM,KAAK"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background-version-check.js","names":[],"sources":["../../src/utils/background-version-check.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { checkForUpdate } from './version-check';\n\n/**\n * Perform a non-blocking version check and display a warning if an update is available\n * This function runs in the background and will not block command execution\n */\nexport function performBackgroundVersionCheck(): void {\n // Run version check asynchronously without blocking\n checkForUpdate()\n .then((versionInfo) => {\n if (versionInfo.needsUpdate) {\n // Display warning message\n console.log(\n chalk.yellow(\n `\\n⚠️ A new version of @inkeep/agents-cli is available: ${versionInfo.latest} (current: ${versionInfo.current})`\n )\n );\n console.log(chalk.gray(' Run `inkeep update` to upgrade to the latest version\\n'));\n }\n })\n .catch(() => {\n // Silently fail if version check fails - we don't want to interrupt the user's workflow\n // No error message is displayed to avoid confusion\n });\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,gCAAsC;AAEpD,iBAAgB,CACb,MAAM,gBAAgB;AACrB,MAAI,YAAY,aAAa;AAE3B,WAAQ,IACN,MAAM,OACJ,2DAA2D,YAAY,OAAO,aAAa,YAAY,QAAQ,GAChH,CACF;AACD,WAAQ,IAAI,MAAM,KAAK,4DAA4D,CAAC;;GAEtF,CACD,YAAY,GAGX"}
|
|
@@ -82,4 +82,5 @@ function validateCIConfig(config) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
//#endregion
|
|
85
|
-
export { detectCIEnvironment, getAuthHeaders, loadCIEnvironmentConfig, logCIConfig, validateCIConfig };
|
|
85
|
+
export { detectCIEnvironment, getAuthHeaders, loadCIEnvironmentConfig, logCIConfig, validateCIConfig };
|
|
86
|
+
//# sourceMappingURL=ci-environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-environment.js","names":[],"sources":["../../src/utils/ci-environment.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport chalk from 'chalk';\nimport { checkKeychainAvailability } from './credentials';\n\nexport interface CIEnvironmentConfig {\n isCI: boolean;\n reason?: string;\n apiKey?: string;\n agentsApiUrl?: string;\n environment?: string;\n tenantId?: string;\n}\n\nexport interface CIDetectionResult {\n isCI: boolean;\n reason: string;\n}\n\nexport async function detectCIEnvironment(): Promise<CIDetectionResult> {\n // Check explicit CI flag\n if (process.env.INKEEP_CI === 'true') {\n return { isCI: true, reason: 'INKEEP_CI=true' };\n }\n\n // Check common CI environment variables\n if (process.env.CI === 'true' || process.env.CI === '1') {\n return { isCI: true, reason: 'CI environment detected' };\n }\n\n // Check GitHub Actions\n if (process.env.GITHUB_ACTIONS === 'true') {\n return { isCI: true, reason: 'GitHub Actions detected' };\n }\n\n // Check GitLab CI\n if (process.env.GITLAB_CI === 'true') {\n return { isCI: true, reason: 'GitLab CI detected' };\n }\n\n // Check Jenkins\n if (process.env.JENKINS_URL) {\n return { isCI: true, reason: 'Jenkins detected' };\n }\n\n // Check CircleCI\n if (process.env.CIRCLECI === 'true') {\n return { isCI: true, reason: 'CircleCI detected' };\n }\n\n // Check no profiles.yaml exists\n const profilesPath = join(homedir(), '.inkeep', 'profiles.yaml');\n const profilesExist = existsSync(profilesPath);\n\n // Check keychain availability\n const { available: keychainAvailable } = await checkKeychainAvailability();\n\n // If no profiles and no keychain, treat as CI\n if (!profilesExist && !keychainAvailable) {\n return { isCI: true, reason: 'no keychain available' };\n }\n\n // If keychain unavailable and INKEEP_API_KEY is set, treat as CI\n if (!keychainAvailable && process.env.INKEEP_API_KEY) {\n return { isCI: true, reason: 'no keychain available, using API key' };\n }\n\n return { isCI: false, reason: '' };\n}\n\nexport function loadCIEnvironmentConfig(): CIEnvironmentConfig | null {\n const apiKey = process.env.INKEEP_API_KEY;\n const agentsApiUrl = process.env.INKEEP_AGENTS_API_URL;\n const environment = process.env.INKEEP_ENVIRONMENT || 'production';\n const tenantId = process.env.INKEEP_TENANT_ID;\n\n // If no API key, CI mode isn't properly configured\n if (!apiKey) {\n return null;\n }\n\n return {\n isCI: true,\n apiKey,\n agentsApiUrl: agentsApiUrl || 'https://agents-api.inkeep.com',\n environment,\n tenantId,\n };\n}\n\nexport function logCIConfig(config: CIEnvironmentConfig, reason: string): void {\n console.log(chalk.yellow(`CI mode detected (${reason})`));\n console.log(chalk.gray(` Remote: ${config.agentsApiUrl}`));\n console.log(chalk.gray(` Environment: ${config.environment}`));\n console.log(chalk.gray(` Auth: API key (INKEEP_API_KEY)`));\n if (config.tenantId) {\n console.log(chalk.gray(` Tenant: ${config.tenantId}`));\n }\n}\n\nexport function getAuthHeaders(\n config: { accessToken?: string; apiKey?: string },\n isCI: boolean = false\n): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (isCI && config.apiKey) {\n headers['X-API-Key'] = config.apiKey;\n } else if (config.accessToken) {\n headers.Authorization = `Bearer ${config.accessToken}`;\n }\n\n return headers;\n}\n\nexport function validateCIConfig(config: CIEnvironmentConfig): {\n valid: boolean;\n errors: string[];\n} {\n const errors: string[] = [];\n\n if (!config.apiKey) {\n errors.push('INKEEP_API_KEY environment variable is required in CI mode');\n }\n\n return { valid: errors.length === 0, errors };\n}\n"],"mappings":";;;;;;;AAoBA,eAAsB,sBAAkD;AAEtE,KAAI,QAAQ,IAAI,cAAc,OAC5B,QAAO;EAAE,MAAM;EAAM,QAAQ;EAAkB;AAIjD,KAAI,QAAQ,IAAI,OAAO,UAAU,QAAQ,IAAI,OAAO,IAClD,QAAO;EAAE,MAAM;EAAM,QAAQ;EAA2B;AAI1D,KAAI,QAAQ,IAAI,mBAAmB,OACjC,QAAO;EAAE,MAAM;EAAM,QAAQ;EAA2B;AAI1D,KAAI,QAAQ,IAAI,cAAc,OAC5B,QAAO;EAAE,MAAM;EAAM,QAAQ;EAAsB;AAIrD,KAAI,QAAQ,IAAI,YACd,QAAO;EAAE,MAAM;EAAM,QAAQ;EAAoB;AAInD,KAAI,QAAQ,IAAI,aAAa,OAC3B,QAAO;EAAE,MAAM;EAAM,QAAQ;EAAqB;CAKpD,MAAM,gBAAgB,WADD,KAAK,SAAS,EAAE,WAAW,gBAAgB,CAClB;CAG9C,MAAM,EAAE,WAAW,sBAAsB,MAAM,2BAA2B;AAG1E,KAAI,CAAC,iBAAiB,CAAC,kBACrB,QAAO;EAAE,MAAM;EAAM,QAAQ;EAAyB;AAIxD,KAAI,CAAC,qBAAqB,QAAQ,IAAI,eACpC,QAAO;EAAE,MAAM;EAAM,QAAQ;EAAwC;AAGvE,QAAO;EAAE,MAAM;EAAO,QAAQ;EAAI;;AAGpC,SAAgB,0BAAsD;CACpE,MAAM,SAAS,QAAQ,IAAI;CAC3B,MAAM,eAAe,QAAQ,IAAI;CACjC,MAAM,cAAc,QAAQ,IAAI,sBAAsB;CACtD,MAAM,WAAW,QAAQ,IAAI;AAG7B,KAAI,CAAC,OACH,QAAO;AAGT,QAAO;EACL,MAAM;EACN;EACA,cAAc,gBAAgB;EAC9B;EACA;EACD;;AAGH,SAAgB,YAAY,QAA6B,QAAsB;AAC7E,SAAQ,IAAI,MAAM,OAAO,qBAAqB,OAAO,GAAG,CAAC;AACzD,SAAQ,IAAI,MAAM,KAAK,aAAa,OAAO,eAAe,CAAC;AAC3D,SAAQ,IAAI,MAAM,KAAK,kBAAkB,OAAO,cAAc,CAAC;AAC/D,SAAQ,IAAI,MAAM,KAAK,mCAAmC,CAAC;AAC3D,KAAI,OAAO,SACT,SAAQ,IAAI,MAAM,KAAK,aAAa,OAAO,WAAW,CAAC;;AAI3D,SAAgB,eACd,QACA,OAAgB,OACQ;CACxB,MAAM,UAAkC,EAAE;AAE1C,KAAI,QAAQ,OAAO,OACjB,SAAQ,eAAe,OAAO;UACrB,OAAO,YAChB,SAAQ,gBAAgB,UAAU,OAAO;AAG3C,QAAO;;AAGT,SAAgB,iBAAiB,QAG/B;CACA,MAAM,SAAmB,EAAE;AAE3B,KAAI,CAAC,OAAO,OACV,QAAO,KAAK,6DAA6D;AAG3E,QAAO;EAAE,OAAO,OAAO,WAAW;EAAG;EAAQ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-pipeline.js","names":["config"],"sources":["../../src/utils/cli-pipeline.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport {\n type CIEnvironmentConfig,\n detectCIEnvironment,\n loadCIEnvironmentConfig,\n logCIConfig,\n} from './ci-environment';\nimport type { ValidatedConfiguration } from './config';\nimport { validateConfiguration } from './config';\nimport { getCredentialExpiryInfo, loadCredentials } from './credentials';\nimport { ProfileManager, type ResolvedProfile } from './profiles';\n\n/**\n * Options for initializing a CLI command\n */\nexport interface CommandInitOptions {\n /** Path to config file (from --config flag) */\n configPath?: string;\n /** Tag for environment-specific config (e.g., 'prod', 'staging') */\n tag?: string;\n /** Profile name to use (--profile flag) */\n profileName?: string;\n /** Whether to show a spinner during initialization */\n showSpinner?: boolean;\n /** Custom spinner text */\n spinnerText?: string;\n /** Whether to log configuration sources */\n logConfig?: boolean;\n /** Suppress profile logging (--quiet) */\n quiet?: boolean;\n}\n\n/**\n * Result from CLI command initialization\n */\nexport interface CommandInitResult {\n /** Validated configuration */\n config: ValidatedConfiguration;\n /** Resolved profile (if profiles are configured) */\n profile?: ResolvedProfile;\n /** Whether the user is authenticated via profile or CI API key */\n isAuthenticated?: boolean;\n /** Auth token expiry info */\n authExpiry?: string;\n /** Whether running in CI mode */\n isCI?: boolean;\n /** CI configuration (if in CI mode) */\n ciConfig?: CIEnvironmentConfig;\n}\n\n/**\n * Standard pipeline for initializing CLI commands\n *\n * This function provides a consistent way to:\n * 1. Load profile configuration (if available)\n * 2. Load and validate configuration from inkeep.config.ts\n * 3. Merge profile config with file config (profile takes precedence)\n * 4. Handle errors with user-friendly messages\n * 5. Optionally display progress with spinners\n * 6. Log configuration sources for debugging\n *\n * Configuration precedence: CLI flag > profile > config.ts defaults\n *\n * @example\n * ```ts\n * export async function myCommand(options: MyOptions) {\n * const { config, profile, isAuthenticated } = await initializeCommand({\n * configPath: options.config,\n * profileName: options.profile,\n * showSpinner: true,\n * spinnerText: 'Loading configuration...',\n * logConfig: true\n * });\n *\n * // Your command logic here...\n * }\n * ```\n */\nexport async function initializeCommand(\n options: CommandInitOptions = {}\n): Promise<CommandInitResult> {\n const {\n configPath,\n tag,\n profileName,\n showSpinner = false,\n spinnerText = 'Loading configuration...',\n logConfig = true,\n quiet = false,\n } = options;\n\n // Start spinner if requested\n const s = showSpinner ? p.spinner() : undefined;\n if (s) {\n s.start(spinnerText);\n }\n\n try {\n // Check for CI environment first\n const ciDetection = await detectCIEnvironment();\n const ciConfig = ciDetection.isCI ? loadCIEnvironmentConfig() : null;\n\n // In CI mode, use config file + CI env vars, skip profile loading entirely\n // This prevents ProfileManager from auto-creating a \"cloud\" profile that would\n // override config file URLs\n if (ciDetection.isCI) {\n // Load file config as base\n const config = await validateConfiguration(configPath, tag);\n\n // CI env vars take precedence over file config (if ciConfig is available)\n if (ciConfig) {\n if (ciConfig.agentsApiUrl) {\n config.agentsApiUrl = ciConfig.agentsApiUrl;\n }\n if (ciConfig.apiKey) {\n config.agentsApiKey = ciConfig.apiKey;\n }\n if (ciConfig.tenantId) {\n config.tenantId = ciConfig.tenantId;\n }\n }\n\n if (s) {\n s.stop('Configuration loaded');\n }\n\n if (logConfig && !quiet) {\n if (ciConfig) {\n logCIConfig(ciConfig, ciDetection.reason);\n } else {\n console.log(chalk.yellow(`CI mode detected (${ciDetection.reason})`));\n console.log(chalk.gray(` Using config file settings (no INKEEP_API_KEY set)`));\n console.log(chalk.gray(` Remote: ${config.agentsApiUrl}`));\n }\n }\n\n return {\n config,\n isAuthenticated: !!ciConfig?.apiKey,\n isCI: true,\n ciConfig: ciConfig ?? undefined,\n };\n }\n\n // Non-CI mode: Try to load profile configuration\n let profile: ResolvedProfile | undefined;\n let isAuthenticated = false;\n let authExpiry: string | undefined;\n let profileAccessToken: string | undefined;\n let profileOrganizationId: string | undefined;\n\n try {\n const profileManager = new ProfileManager();\n if (profileName) {\n const foundProfile = profileManager.getProfile(profileName);\n if (!foundProfile) {\n throw new Error(`Profile '${profileName}' not found.`);\n }\n profile = foundProfile;\n } else {\n profile = profileManager.getActiveProfile();\n }\n\n // Load credentials for this profile\n if (profile) {\n const credentials = await loadCredentials(profile.credential);\n if (credentials) {\n const expiryInfo = getCredentialExpiryInfo(credentials);\n if (!expiryInfo.isExpired) {\n profileAccessToken = credentials.accessToken;\n profileOrganizationId = credentials.organizationId;\n isAuthenticated = true;\n authExpiry = expiryInfo.expiresIn;\n }\n }\n }\n } catch {\n // No profile configured - continue with file config only\n }\n\n // Load and validate configuration from file\n const config = await validateConfiguration(configPath, tag);\n\n // Override config with profile values (profile takes precedence over config file)\n // Precedence: CLI flag > Profile credentials > Config file > Defaults\n if (profile) {\n config.agentsApiUrl = profile.remote.api;\n config.manageUiUrl = profile.remote.manageUi;\n\n // Profile credentials ALWAYS override config file values when using a profile\n // Config file values are intended for CI/CD scenarios without profiles\n if (profileAccessToken) {\n config.agentsApiKey = profileAccessToken;\n }\n\n // Use organization ID from authenticated session as tenantId\n if (profileOrganizationId) {\n config.tenantId = profileOrganizationId;\n }\n }\n\n if (s) {\n s.stop('Configuration loaded');\n }\n\n // Log configuration sources for debugging\n if (logConfig && !quiet) {\n if (profile) {\n const expiryText = authExpiry ? ` (expires in ${authExpiry})` : '';\n const authStatus = isAuthenticated\n ? chalk.green('authenticated') + expiryText\n : chalk.yellow('not authenticated');\n\n console.log(chalk.gray(`Using profile: ${chalk.cyan(profile.name)}`));\n console.log(chalk.gray(` Remote: ${config.agentsApiUrl}`));\n console.log(chalk.gray(` Environment: ${profile.environment}`));\n console.log(chalk.gray(` Auth: ${authStatus}`));\n } else {\n console.log(chalk.gray('Configuration:'));\n console.log(chalk.gray(` • Tenant ID: ${config.tenantId}`));\n console.log(chalk.gray(` • Agents API URL: ${config.agentsApiUrl}`));\n if (config.sources.configFile) {\n console.log(chalk.gray(` • Config file: ${config.sources.configFile}`));\n }\n }\n }\n\n return { config, profile, isAuthenticated, authExpiry, isCI: false };\n } catch (error: any) {\n if (s) {\n s.stop('Configuration failed');\n }\n console.error(chalk.red('Error:'), error.message);\n\n // Provide helpful hints for common errors\n if (error.message.includes('Profile') && error.message.includes('not found')) {\n console.log(chalk.yellow('\\nHint: Run \"inkeep profile list\" to see available profiles.'));\n } else if (error.message.includes('No configuration found')) {\n console.log(chalk.yellow('\\nHint: Create a configuration file by running:'));\n console.log(chalk.gray(' inkeep init'));\n } else if (error.message.includes('Config file not found')) {\n console.log(chalk.yellow('\\nHint: Check that your config file path is correct'));\n } else if (error.message.includes('tenantId') || error.message.includes('API URL')) {\n console.log(chalk.yellow('\\nHint: Ensure your inkeep.config.ts has all required fields:'));\n console.log(chalk.gray(' - tenantId'));\n console.log(chalk.gray(' - agentsApiUrl (or agentsApi.url)'));\n }\n\n process.exit(1);\n }\n}\n\n/**\n * Lightweight config loader without spinners or logging\n * Useful for commands that need config but handle their own UI\n */\nexport async function loadCommandConfig(\n configPath?: string,\n profileName?: string\n): Promise<CommandInitResult> {\n try {\n return await initializeCommand({\n configPath,\n profileName,\n showSpinner: false,\n logConfig: false,\n });\n } catch (error: any) {\n console.error(chalk.red('Configuration error:'), error.message);\n process.exit(1);\n }\n}\n"],"mappings":"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"}
|
package/dist/utils/config.js
CHANGED
|
@@ -298,4 +298,5 @@ or run "inkeep login" to authenticate with Inkeep Cloud.`);
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
//#endregion
|
|
301
|
-
export { extractProjectIdFromConfig, findAllConfigFiles, findConfigFile, findProjectConfig, getConfigFileNames, loadConfig, loadConfigFromFile, maskSensitiveConfig, validateConfiguration };
|
|
301
|
+
export { extractProjectIdFromConfig, findAllConfigFiles, findConfigFile, findProjectConfig, getConfigFileNames, loadConfig, loadConfigFromFile, maskSensitiveConfig, validateConfiguration };
|
|
302
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","names":[],"sources":["../../src/utils/config.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { getLogger } from '@inkeep/agents-core';\nimport { loadCredentials } from './credentials';\nimport { LOCAL_REMOTE } from './profiles';\nimport { importWithTypeScriptSupport } from './tsx-loader';\n\nconst logger = getLogger('config');\n\n/**\n * Masks sensitive values in config for safe logging\n * @internal Exported for testing purposes\n */\nexport function maskSensitiveConfig(config: any): any {\n if (!config) return config;\n\n const masked = { ...config };\n\n // Mask API keys - show last 4 characters only\n if (masked.agentsApiKey) {\n masked.agentsApiKey = `***${masked.agentsApiKey.slice(-4)}`;\n }\n\n return masked;\n}\n\n// Internal normalized configuration (supports both formats)\nexport interface InkeepConfig {\n tenantId?: string;\n agentsApiUrl?: string;\n agentsApiKey?: string;\n manageUiUrl?: string;\n outputDirectory?: string;\n}\n\nexport interface ValidatedConfiguration {\n tenantId: string;\n agentsApiUrl: string;\n agentsApiKey?: string;\n manageUiUrl?: string;\n outputDirectory?: string;\n sources: {\n tenantId: string;\n agentsApiUrl: string;\n configFile?: string;\n };\n}\n\n/**\n * Type guard to check if config uses nested format\n */\nfunction isNestedConfig(config: any): config is {\n tenantId?: string;\n agentsApi?: { url?: string; apiKey?: string };\n manageUiUrl?: string;\n outputDirectory?: string;\n} {\n return config && config.agentsApi !== undefined;\n}\n\n/**\n * Ensure URL has a scheme so fetch() works. Bare host:port gets http://.\n */\nfunction ensureUrlScheme(url: string | undefined): string | undefined {\n if (!url?.trim()) return url;\n const u = url.trim();\n if (/^https?:\\/\\//i.test(u)) return u;\n return `http://${u}`;\n}\n\n/**\n * Normalize config from either flat or nested format to internal format\n */\nfunction normalizeConfig(config: any): InkeepConfig {\n if (isNestedConfig(config)) {\n // New nested format\n return {\n tenantId: config.tenantId,\n agentsApiUrl: ensureUrlScheme(config.agentsApi?.url),\n agentsApiKey: config.agentsApi?.apiKey,\n manageUiUrl: config.manageUiUrl,\n outputDirectory: config.outputDirectory,\n };\n }\n // Legacy flat format\n return {\n tenantId: config.tenantId,\n agentsApiUrl: ensureUrlScheme(config.agentsApiUrl),\n manageUiUrl: config.manageUiUrl,\n outputDirectory: config.outputDirectory,\n };\n}\n\n/**\n * Get config file names for a given tag\n * @param tag - Optional tag for environment-specific config (e.g., 'prod', 'staging')\n * @returns Array of config file names to search for\n */\nexport function getConfigFileNames(tag?: string): string[] {\n if (tag) {\n // Tag-based config files: <tag>.__inkeep.config.ts__\n return [`${tag}.__inkeep.config.ts__`, `${tag}.__inkeep.config.js__`];\n }\n // Default config file names\n return ['inkeep.config.ts', 'inkeep.config.js', '.inkeeprc.ts', '.inkeeprc.js'];\n}\n\n/**\n * Search for config file in current directory and parent directories\n * @param startPath - Directory to start searching from (defaults to current working directory)\n * @param tag - Optional tag for environment-specific config (e.g., 'prod', 'staging')\n * @returns Path to config file or null if not found\n */\nexport function findConfigFile(startPath: string = process.cwd(), tag?: string): string | null {\n let currentPath = resolve(startPath);\n const root = '/';\n\n const configNames = getConfigFileNames(tag);\n\n while (currentPath !== root) {\n // Check for config files at this level\n for (const configName of configNames) {\n const configPath = join(currentPath, configName);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break; // Reached filesystem root\n }\n currentPath = parentPath;\n }\n\n return null;\n}\n\n/**\n * Result of finding a project config file\n */\nexport interface ProjectConfigResult {\n /** Absolute path to the config file */\n configPath: string;\n /** Directory containing the config file (project root) */\n projectDir: string;\n /** Project ID extracted from the config */\n projectId: string | null;\n}\n\n/**\n * Find all project config files recursively in a directory\n * @param rootDir - Root directory to search\n * @param tag - Optional tag for environment-specific config\n * @param excludeDirs - Directories to exclude from search\n * @returns Array of found config file paths\n */\nexport function findAllConfigFiles(\n rootDir: string,\n tag?: string,\n excludeDirs: string[] = ['node_modules', '.git', 'dist', 'build', '.temp-validation']\n): string[] {\n const configFiles: string[] = [];\n const configNames = getConfigFileNames(tag);\n\n function scanDirectory(dir: string): void {\n if (!existsSync(dir)) {\n return;\n }\n\n let items: string[];\n try {\n items = readdirSync(dir);\n } catch {\n return; // Skip directories we can't read\n }\n\n for (const item of items) {\n const fullPath = join(dir, item);\n const relativePath = relative(rootDir, fullPath);\n\n // Skip excluded directories\n if (excludeDirs.some((excl) => item === excl || relativePath.startsWith(`${excl}/`))) {\n continue;\n }\n\n try {\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n scanDirectory(fullPath);\n } else if (stat.isFile() && configNames.includes(item)) {\n configFiles.push(fullPath);\n }\n } catch {\n // Skip files/directories we can't stat\n }\n }\n }\n\n scanDirectory(rootDir);\n return configFiles.sort();\n}\n\n/**\n * Extract project ID from a loaded config\n * The project ID can be specified directly or needs to be loaded from the project\n * @param configPath - Path to the config file\n * @returns Project ID or null if not found\n */\nexport async function extractProjectIdFromConfig(configPath: string): Promise<string | null> {\n try {\n const module = await importWithTypeScriptSupport(configPath);\n const rawConfig = module.default || module.config;\n\n if (!rawConfig) {\n return null;\n }\n\n // Check if projectId is directly in config\n if (rawConfig.projectId) {\n return rawConfig.projectId;\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Find project config and extract project information\n * This walks up directories to find the nearest config file\n * @param startPath - Directory to start searching from\n * @param tag - Optional tag for environment-specific config\n * @returns Project config result or null if not found\n */\nexport async function findProjectConfig(\n startPath: string = process.cwd(),\n tag?: string\n): Promise<ProjectConfigResult | null> {\n const configPath = findConfigFile(startPath, tag);\n\n if (!configPath) {\n return null;\n }\n\n const projectDir = dirname(configPath);\n const projectId = await extractProjectIdFromConfig(configPath);\n\n return {\n configPath,\n projectDir,\n projectId,\n };\n}\n\n/**\n * Load config file from disk and normalize it\n * This is the core config loading logic used by all CLI commands\n *\n * @param configPath - Optional explicit path to config file\n * @param tag - Optional tag for environment-specific config (e.g., 'prod', 'staging')\n * @returns Normalized config or null if not found\n */\nexport async function loadConfigFromFile(\n configPath?: string,\n tag?: string\n): Promise<InkeepConfig | null> {\n logger.info({ fromPath: configPath, tag }, `Loading config file`);\n\n let resolvedPath: string | null;\n\n if (configPath) {\n // User specified a config path\n resolvedPath = resolve(process.cwd(), configPath);\n if (!existsSync(resolvedPath)) {\n throw new Error(`Config file not found: ${resolvedPath}`);\n }\n } else {\n // Search for config file (with optional tag)\n resolvedPath = findConfigFile(process.cwd(), tag);\n if (!resolvedPath) {\n // No config file found\n if (tag) {\n // Provide helpful error for missing tagged config\n const taggedFileName = getConfigFileNames(tag)[0];\n throw new Error(\n `Tagged config file not found: ${taggedFileName}\\n` +\n `Create this file or use a different --tag value.`\n );\n }\n return null;\n }\n }\n\n try {\n const module = await importWithTypeScriptSupport(resolvedPath);\n\n // Support both default export and named export (matching pull.ts pattern)\n const rawConfig = module.default || module.config;\n\n if (!rawConfig) {\n throw new Error(`No config exported from ${resolvedPath}`);\n }\n\n // Normalize config to internal format (handles both flat and nested)\n const config = normalizeConfig(rawConfig);\n\n logger.info({ config: maskSensitiveConfig(config) }, `Loaded config values`);\n\n return config;\n } catch (error) {\n if (error instanceof Error && error.message.includes('Tagged config file not found')) {\n throw error;\n }\n console.warn(`Warning: Failed to load config file ${resolvedPath}:`, error);\n return null;\n }\n}\n\n/**\n * Main config loader - single source of truth for loading inkeep.config.ts\n * This is the ONLY function that should be used to load configuration across all CLI commands.\n *\n * Configuration priority (highest to lowest):\n * 1. CLI flags (handled by caller)\n * 2. Config file (inkeep.config.ts)\n * 3. Default values\n *\n * @param configPath - Optional explicit path to config file\n * @param tag - Optional tag for environment-specific config (e.g., 'prod', 'staging')\n * @returns Normalized configuration with defaults applied\n */\nexport async function loadConfig(configPath?: string, tag?: string): Promise<InkeepConfig> {\n // IMPORTANT: URL configuration (agentsApiUrl) is loaded ONLY from\n // the config file or CLI flags, NOT from environment variables or .env files.\n //\n // Note: .env files ARE loaded by env.ts for secrets (API keys, bypass tokens), but those\n // environment variables are NOT used for URL configuration to ensure explicit control.\n\n // 1. Start with default config (lowest priority)\n const config: InkeepConfig = {\n agentsApiUrl: LOCAL_REMOTE.api,\n manageUiUrl: LOCAL_REMOTE.manageUi,\n };\n\n // 2. Override with file config (higher priority)\n // Only override defined values, keep defaults for undefined values\n const fileConfig = await loadConfigFromFile(configPath, tag);\n if (fileConfig) {\n // Filter out undefined values from fileConfig so they don't override defaults\n Object.keys(fileConfig).forEach((key) => {\n const value = fileConfig[key as keyof InkeepConfig];\n if (value !== undefined) {\n (config as any)[key] = value;\n }\n });\n logger.info({ mergedConfig: maskSensitiveConfig(config) }, `Config loaded from file`);\n } else {\n logger.info(\n { config: maskSensitiveConfig(config) },\n `Using default config (no config file found)`\n );\n }\n\n return config;\n}\n\n/**\n * Validates configuration loaded from inkeep.config.ts file\n * This is the ONLY way to configure the CLI - no CLI flags for URLs/keys\n *\n * Configuration priority:\n * 1. Config file (inkeep.config.ts or --config path/to/config.ts)\n * 2. CLI credentials (from `inkeep login`) - for API key and tenant ID fallback\n * 3. Default values (http://localhost:3002)\n *\n * Note: API URLs and keys are loaded ONLY from the config file, NOT from environment\n * variables or CLI flags. This ensures explicit control over where the CLI connects.\n *\n * Secrets (API keys, bypass tokens) CAN be loaded from .env files in the working directory\n * and parent directories via the config file's environment variable references.\n *\n * @param configPath - explicit path to config file (from --config parameter)\n * @param tag - optional tag for environment-specific config (e.g., 'prod', 'staging')\n * @returns configuration with tenantId, agentsApiUrl, and source info\n */\nexport async function validateConfiguration(\n configPath?: string,\n tag?: string\n): Promise<ValidatedConfiguration> {\n // Load config from file with defaults\n const config = await loadConfig(configPath, tag);\n\n // Determine the config file that was actually used\n const actualConfigFile = configPath || findConfigFile(process.cwd(), tag);\n\n // Load CLI credentials as fallback for API key and tenant ID\n // Skip keychain access in CI to avoid hanging on unavailable keychain services\n let cliCredentials: { accessToken: string; organizationId: string } | null = null;\n const isCI = process.env.CI === 'true' || process.env.CI === '1' || !!process.env.GITHUB_ACTIONS;\n if (!isCI) {\n try {\n const credentials = await loadCredentials();\n if (credentials?.accessToken && credentials.organizationId) {\n cliCredentials = {\n accessToken: credentials.accessToken,\n organizationId: credentials.organizationId,\n };\n logger.info({}, 'CLI credentials available for fallback');\n }\n } catch {\n // Ignore errors loading credentials - keychain might not be available\n logger.debug({}, 'Could not load CLI credentials');\n }\n } else {\n logger.debug({}, 'Skipping keychain credential loading in CI environment');\n }\n\n // Use CLI credentials as fallback for API key if not specified in config\n if (!config.agentsApiKey && cliCredentials) {\n config.agentsApiKey = cliCredentials.accessToken;\n logger.info({}, 'Using CLI session token as API key');\n }\n // Login stores under 'inkeep-cloud'; default loadCredentials() uses 'auth-credentials'\n if (!config.agentsApiKey && !cliCredentials) {\n const cloudCreds = await loadCredentials('inkeep-cloud');\n if (cloudCreds?.accessToken) {\n config.agentsApiKey = cloudCreds.accessToken;\n if (!config.tenantId) config.tenantId = cloudCreds.organizationId;\n logger.info({}, 'Using CLI login credentials (inkeep-cloud)');\n }\n }\n\n // Use CLI credentials as fallback for tenant ID if not specified in config\n if (!config.tenantId && cliCredentials) {\n config.tenantId = cliCredentials.organizationId;\n logger.info({}, 'Using CLI organization ID as tenant ID');\n }\n\n // Validate required fields\n if (!config.tenantId) {\n if (actualConfigFile) {\n throw new Error(\n `Tenant ID is missing from configuration file: ${actualConfigFile}\\n` +\n 'Please ensure your config file exports a valid configuration with tenantId,\\n' +\n 'or run \"inkeep login\" to authenticate with Inkeep Cloud.'\n );\n }\n throw new Error(\n 'No configuration found. Please:\\n' +\n ' 1. Run \"inkeep login\" to authenticate with Inkeep Cloud\\n' +\n ' 2. Or create \"inkeep.config.ts\" by running \"inkeep init\"\\n' +\n ' 3. Or provide --config to specify a config file path'\n );\n }\n\n if (!config.agentsApiUrl) {\n throw new Error(\n `Agents API URL is missing from config file${actualConfigFile ? `: ${actualConfigFile}` : ''}\\n` +\n 'Please add agentsApiUrl to your configuration file'\n );\n }\n\n // Build sources for debugging\n const sources: any = {\n tenantId:\n cliCredentials && !actualConfigFile\n ? 'CLI login (organization ID)'\n : actualConfigFile\n ? `config file (${actualConfigFile})`\n : 'default',\n agentsApiUrl: actualConfigFile ? `config file (${actualConfigFile})` : 'default value',\n };\n\n if (actualConfigFile) {\n sources.configFile = actualConfigFile;\n }\n\n return {\n tenantId: config.tenantId,\n agentsApiUrl: config.agentsApiUrl,\n agentsApiKey: config.agentsApiKey,\n manageUiUrl: config.manageUiUrl,\n sources,\n };\n}\n"],"mappings":"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"}
|
|
@@ -129,4 +129,5 @@ function getKeychainUnavailableMessage(reason) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
//#endregion
|
|
132
|
-
export { checkKeychainAvailability, clearCredentials, getCredentialExpiryInfo, getKeychainUnavailableMessage, hasValidCredentials, isCredentialExpired, loadCredentials, saveCredentials };
|
|
132
|
+
export { checkKeychainAvailability, clearCredentials, getCredentialExpiryInfo, getKeychainUnavailableMessage, hasValidCredentials, isCredentialExpired, loadCredentials, saveCredentials };
|
|
133
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","names":[],"sources":["../../src/utils/credentials.ts"],"sourcesContent":["import { KeyChainStore } from '@inkeep/agents-core/credential-stores';\n\nconst CLI_SERVICE_PREFIX = 'inkeep-cli';\nconst DEFAULT_CREDENTIALS_KEY = 'auth-credentials';\n\n/**\n * CLI credentials stored in the system keychain\n */\nexport interface CLICredentials {\n accessToken: string;\n refreshToken?: string;\n userId: string;\n userEmail: string;\n organizationId: string;\n organizationName?: string;\n expiresAt?: string;\n createdAt: string;\n}\n\n// Singleton keychain store instance\nlet keychainStore: KeyChainStore | null = null;\n\nfunction getKeychainStore(): KeyChainStore {\n if (!keychainStore) {\n keychainStore = new KeyChainStore('auth', CLI_SERVICE_PREFIX);\n }\n return keychainStore;\n}\n\n/**\n * Save CLI credentials to the system keychain\n * @param credentials - The credentials to store\n * @param credentialKey - Optional key to store under (from profile's credential field). Defaults to 'auth-credentials'\n */\nexport async function saveCredentials(\n credentials: CLICredentials,\n credentialKey?: string\n): Promise<void> {\n const store = getKeychainStore();\n\n // Check availability first\n const { available, reason } = await store.checkAvailability();\n if (!available) {\n throw new Error(getKeychainUnavailableMessage(reason));\n }\n\n const key = credentialKey || DEFAULT_CREDENTIALS_KEY;\n const credentialsJson = JSON.stringify(credentials);\n await store.set(key, credentialsJson);\n}\n\n/**\n * Load CLI credentials from the system keychain\n * @param credentialKey - Optional key to load from (from profile's credential field). Defaults to 'auth-credentials'\n */\nexport async function loadCredentials(credentialKey?: string): Promise<CLICredentials | null> {\n const store = getKeychainStore();\n const key = credentialKey || DEFAULT_CREDENTIALS_KEY;\n\n const credentialsJson = await store.get(key);\n if (!credentialsJson) {\n return null;\n }\n\n try {\n const credentials = JSON.parse(credentialsJson) as CLICredentials;\n\n // Validate required fields\n if (!credentials.accessToken || !credentials.userId || !credentials.userEmail) {\n return null;\n }\n\n return credentials;\n } catch {\n // Invalid JSON, clear and return null\n await store.delete(key);\n return null;\n }\n}\n\n/**\n * Clear CLI credentials from the system keychain\n * @param credentialKey - Optional key to clear (from profile's credential field). Defaults to 'auth-credentials'\n */\nexport async function clearCredentials(credentialKey?: string): Promise<boolean> {\n const store = getKeychainStore();\n const key = credentialKey || DEFAULT_CREDENTIALS_KEY;\n return store.delete(key);\n}\n\n/**\n * Check if valid credentials exist in the keychain\n * @param credentialKey - Optional key to check (from profile's credential field). Defaults to 'auth-credentials'\n */\nexport async function hasValidCredentials(credentialKey?: string): Promise<boolean> {\n const credentials = await loadCredentials(credentialKey);\n if (!credentials) {\n return false;\n }\n\n // Check if credentials have expired\n if (credentials.expiresAt) {\n const expiresAt = new Date(credentials.expiresAt);\n if (expiresAt < new Date()) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if credentials are expired\n */\nexport function isCredentialExpired(credentials: CLICredentials): boolean {\n if (!credentials.expiresAt) {\n return false;\n }\n const expiresAt = new Date(credentials.expiresAt);\n return expiresAt < new Date();\n}\n\n/**\n * Get time until credentials expire\n */\nexport function getCredentialExpiryInfo(credentials: CLICredentials): {\n isExpired: boolean;\n expiresIn?: string;\n expiresAt?: Date;\n} {\n if (!credentials.expiresAt) {\n return { isExpired: false };\n }\n\n const expiresAt = new Date(credentials.expiresAt);\n const now = new Date();\n const isExpired = expiresAt < now;\n\n if (isExpired) {\n return { isExpired: true, expiresAt };\n }\n\n const diffMs = expiresAt.getTime() - now.getTime();\n const hours = Math.floor(diffMs / (1000 * 60 * 60));\n const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));\n\n let expiresIn: string;\n if (hours > 24) {\n const days = Math.floor(hours / 24);\n expiresIn = `${days}d`;\n } else if (hours > 0) {\n expiresIn = `${hours}h`;\n } else {\n expiresIn = `${minutes}m`;\n }\n\n return { isExpired: false, expiresIn, expiresAt };\n}\n\n/**\n * Check if the keychain is available for storing credentials\n */\nexport async function checkKeychainAvailability(): Promise<{\n available: boolean;\n reason?: string;\n}> {\n const store = getKeychainStore();\n return store.checkAvailability();\n}\n\n/**\n * Get a helpful error message when keychain is unavailable\n */\nfunction getKeychainUnavailableMessage(reason?: string): string {\n const platform = process.platform;\n let message = 'Unable to store credentials securely.\\n\\n';\n\n if (reason) {\n message += `Reason: ${reason}\\n\\n`;\n }\n\n message +=\n 'The Inkeep CLI requires access to the system keychain to store your login credentials securely.\\n\\n';\n\n switch (platform) {\n case 'darwin':\n message += 'On macOS:\\n';\n message += ' 1. Ensure you have Keychain Access available\\n';\n message += ' 2. If prompted, click \"Allow\" or \"Always Allow\" to grant access\\n';\n message += ' 3. Check System Preferences > Security & Privacy if access was denied\\n';\n break;\n case 'win32':\n message += 'On Windows:\\n';\n message += ' 1. Ensure Windows Credential Manager is available\\n';\n message += ' 2. Try running the CLI as administrator if access is denied\\n';\n break;\n case 'linux':\n message += 'On Linux:\\n';\n message += ' 1. Ensure libsecret is installed (e.g., `sudo apt install libsecret-1-dev`)\\n';\n message += ' 2. Ensure a keyring service is running (GNOME Keyring, KWallet, etc.)\\n';\n message += ' 3. For headless servers, consider using an API key instead of `inkeep login`\\n';\n break;\n default:\n message +=\n 'Please ensure your system has a supported keychain/credential manager available.\\n';\n }\n\n return message;\n}\n\nexport { getKeychainUnavailableMessage };\n"],"mappings":";;;AAEA,MAAM,qBAAqB;AAC3B,MAAM,0BAA0B;AAiBhC,IAAI,gBAAsC;AAE1C,SAAS,mBAAkC;AACzC,KAAI,CAAC,cACH,iBAAgB,IAAI,cAAc,QAAQ,mBAAmB;AAE/D,QAAO;;;;;;;AAQT,eAAsB,gBACpB,aACA,eACe;CACf,MAAM,QAAQ,kBAAkB;CAGhC,MAAM,EAAE,WAAW,WAAW,MAAM,MAAM,mBAAmB;AAC7D,KAAI,CAAC,UACH,OAAM,IAAI,MAAM,8BAA8B,OAAO,CAAC;CAGxD,MAAM,MAAM,iBAAiB;CAC7B,MAAM,kBAAkB,KAAK,UAAU,YAAY;AACnD,OAAM,MAAM,IAAI,KAAK,gBAAgB;;;;;;AAOvC,eAAsB,gBAAgB,eAAwD;CAC5F,MAAM,QAAQ,kBAAkB;CAChC,MAAM,MAAM,iBAAiB;CAE7B,MAAM,kBAAkB,MAAM,MAAM,IAAI,IAAI;AAC5C,KAAI,CAAC,gBACH,QAAO;AAGT,KAAI;EACF,MAAM,cAAc,KAAK,MAAM,gBAAgB;AAG/C,MAAI,CAAC,YAAY,eAAe,CAAC,YAAY,UAAU,CAAC,YAAY,UAClE,QAAO;AAGT,SAAO;SACD;AAEN,QAAM,MAAM,OAAO,IAAI;AACvB,SAAO;;;;;;;AAQX,eAAsB,iBAAiB,eAA0C;CAC/E,MAAM,QAAQ,kBAAkB;CAChC,MAAM,MAAM,iBAAiB;AAC7B,QAAO,MAAM,OAAO,IAAI;;;;;;AAO1B,eAAsB,oBAAoB,eAA0C;CAClF,MAAM,cAAc,MAAM,gBAAgB,cAAc;AACxD,KAAI,CAAC,YACH,QAAO;AAIT,KAAI,YAAY,WAEd;MADkB,IAAI,KAAK,YAAY,UAAU,mBACjC,IAAI,MAAM,CACxB,QAAO;;AAIX,QAAO;;;;;AAMT,SAAgB,oBAAoB,aAAsC;AACxE,KAAI,CAAC,YAAY,UACf,QAAO;AAGT,QADkB,IAAI,KAAK,YAAY,UAAU,mBAC9B,IAAI,MAAM;;;;;AAM/B,SAAgB,wBAAwB,aAItC;AACA,KAAI,CAAC,YAAY,UACf,QAAO,EAAE,WAAW,OAAO;CAG7B,MAAM,YAAY,IAAI,KAAK,YAAY,UAAU;CACjD,MAAM,sBAAM,IAAI,MAAM;AAGtB,KAFkB,YAAY,IAG5B,QAAO;EAAE,WAAW;EAAM;EAAW;CAGvC,MAAM,SAAS,UAAU,SAAS,GAAG,IAAI,SAAS;CAClD,MAAM,QAAQ,KAAK,MAAM,UAAU,MAAO,KAAK,IAAI;CACnD,MAAM,UAAU,KAAK,MAAO,UAAU,MAAO,KAAK,OAAQ,MAAO,IAAI;CAErE,IAAI;AACJ,KAAI,QAAQ,GAEV,aAAY,GADC,KAAK,MAAM,QAAQ,GAAG,CACf;UACX,QAAQ,EACjB,aAAY,GAAG,MAAM;KAErB,aAAY,GAAG,QAAQ;AAGzB,QAAO;EAAE,WAAW;EAAO;EAAW;EAAW;;;;;AAMnD,eAAsB,4BAGnB;AAED,QADc,kBAAkB,CACnB,mBAAmB;;;;;AAMlC,SAAS,8BAA8B,QAAyB;CAC9D,MAAM,WAAW,QAAQ;CACzB,IAAI,UAAU;AAEd,KAAI,OACF,YAAW,WAAW,OAAO;AAG/B,YACE;AAEF,SAAQ,UAAR;EACE,KAAK;AACH,cAAW;AACX,cAAW;AACX,cAAW;AACX,cAAW;AACX;EACF,KAAK;AACH,cAAW;AACX,cAAW;AACX,cAAW;AACX;EACF,KAAK;AACH,cAAW;AACX,cAAW;AACX,cAAW;AACX,cAAW;AACX;EACF,QACE,YACE;;AAGN,QAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-loader.js","names":[],"sources":["../../src/utils/environment-loader.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { importWithTypeScriptSupport } from './tsx-loader';\n\n/**\n * Load environment credentials from the environments directory\n * @param projectDir - Path to the project directory\n * @param env - Environment name (e.g., 'development', 'production')\n * @returns Object containing credentials or null if not found\n */\nexport async function loadEnvironmentCredentials(\n projectDir: string,\n env: string\n): Promise<any | null> {\n const environmentsDir = join(projectDir, 'environments');\n const envFilePath = join(environmentsDir, `${env}.env.ts`);\n\n if (!existsSync(envFilePath)) {\n throw new Error(\n `Environment file not found: ${envFilePath}\\n` +\n `Make sure you have a ${env}.env.ts file in the environments directory.`\n );\n }\n\n try {\n const envModule = await importWithTypeScriptSupport(envFilePath);\n\n // Get the first export (should be the environment settings)\n const exports = Object.keys(envModule);\n if (exports.length === 0) {\n throw new Error(`No exports found in environment file: ${envFilePath}`);\n }\n\n // Get the first export\n const firstExportKey = exports[0];\n const envSettings = envModule[firstExportKey];\n\n if (!envSettings || typeof envSettings !== 'object') {\n throw new Error(\n `Invalid environment settings in ${envFilePath}. Expected an object with credentials.`\n );\n }\n\n // Return the credentials from the environment settings\n return envSettings.credentials || {};\n } catch (error: any) {\n throw new Error(`Failed to load environment file ${envFilePath}: ${error.message}`);\n }\n}\n"],"mappings":";;;;;;;;;;;AAUA,eAAsB,2BACpB,YACA,KACqB;CAErB,MAAM,cAAc,KADI,KAAK,YAAY,eAAe,EACd,GAAG,IAAI,SAAS;AAE1D,KAAI,CAAC,WAAW,YAAY,CAC1B,OAAM,IAAI,MACR,+BAA+B,YAAY,yBACjB,IAAI,6CAC/B;AAGH,KAAI;EACF,MAAM,YAAY,MAAM,4BAA4B,YAAY;EAGhE,MAAM,UAAU,OAAO,KAAK,UAAU;AACtC,MAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,yCAAyC,cAAc;EAKzE,MAAM,cAAc,UADG,QAAQ;AAG/B,MAAI,CAAC,eAAe,OAAO,gBAAgB,SACzC,OAAM,IAAI,MACR,mCAAmC,YAAY,wCAChD;AAIH,SAAO,YAAY,eAAe,EAAE;UAC7B,OAAY;AACnB,QAAM,IAAI,MAAM,mCAAmC,YAAY,IAAI,MAAM,UAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-finder.js","names":[],"sources":["../../src/utils/file-finder.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join, relative } from 'node:path';\n\n/**\n * Recursively find all TypeScript files in a directory, excluding specified directories\n * @param rootDir - Root directory to search\n * @param excludeDirs - Array of directory names to exclude (relative to root)\n * @returns Array of file paths\n */\nexport function findAllTypeScriptFiles(rootDir: string, excludeDirs: string[] = []): string[] {\n const tsFiles: string[] = [];\n\n function scanDirectory(dir: string): void {\n if (!existsSync(dir)) {\n return;\n }\n\n const items = readdirSync(dir);\n\n for (const item of items) {\n const fullPath = join(dir, item);\n const relativePath = relative(rootDir, fullPath);\n\n // Skip excluded directories\n const isExcludedDir = excludeDirs.some(\n (excludeDir) => relativePath === excludeDir || relativePath.startsWith(`${excludeDir}/`)\n );\n\n if (isExcludedDir) {\n continue;\n }\n\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n // Recursively scan subdirectories\n scanDirectory(fullPath);\n } else if (stat.isFile() && item.endsWith('.ts')) {\n // Add TypeScript files\n tsFiles.push(fullPath);\n }\n }\n }\n\n scanDirectory(rootDir);\n return tsFiles.sort(); // Sort for consistent ordering\n}\n\n/**\n * Categorize TypeScript files by their likely purpose based on filename and location\n * @param files - Array of file paths\n * @param rootDir - Root directory for relative path calculation\n * @returns Object with categorized files\n */\nexport function categorizeTypeScriptFiles(\n files: string[],\n rootDir: string\n): {\n indexFile: string | null;\n configFiles: string[];\n agentFiles: string[];\n subAgentFiles: string[];\n toolFiles: string[];\n otherFiles: string[];\n} {\n const indexFile =\n files.find((file) => file.endsWith('/index.ts') || file === join(rootDir, 'index.ts')) || null;\n const configFiles: string[] = [];\n const agentFiles: string[] = [];\n const subAgentFiles: string[] = [];\n const toolFiles: string[] = [];\n const otherFiles: string[] = [];\n\n for (const file of files) {\n const fileName = file.split('/').pop() || '';\n const relativePath = relative(rootDir, file);\n\n if (file === indexFile) {\n continue; // Already handled\n }\n\n if (\n fileName.includes('.config.') ||\n fileName.includes('.env.') ||\n fileName === 'inkeep.config.ts'\n ) {\n configFiles.push(file);\n } else if (fileName.includes('.agent.') || relativePath.includes('agent/')) {\n agentFiles.push(file);\n } else if (\n fileName.includes('agent') ||\n fileName.includes('Agent') ||\n relativePath.includes('agents/')\n ) {\n agentFiles.push(file);\n } else if (\n fileName.includes('tool') ||\n fileName.includes('Tool') ||\n relativePath.includes('tools/')\n ) {\n toolFiles.push(file);\n } else {\n otherFiles.push(file);\n }\n }\n\n return {\n indexFile,\n configFiles,\n agentFiles,\n subAgentFiles,\n toolFiles,\n otherFiles,\n };\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,uBAAuB,SAAiB,cAAwB,EAAE,EAAY;CAC5F,MAAM,UAAoB,EAAE;CAE5B,SAAS,cAAc,KAAmB;AACxC,MAAI,CAAC,WAAW,IAAI,CAClB;EAGF,MAAM,QAAQ,YAAY,IAAI;AAE9B,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,WAAW,KAAK,KAAK,KAAK;GAChC,MAAM,eAAe,SAAS,SAAS,SAAS;AAOhD,OAJsB,YAAY,MAC/B,eAAe,iBAAiB,cAAc,aAAa,WAAW,GAAG,WAAW,GAAG,CACzF,CAGC;GAGF,MAAM,OAAO,SAAS,SAAS;AAE/B,OAAI,KAAK,aAAa,CAEpB,eAAc,SAAS;YACd,KAAK,QAAQ,IAAI,KAAK,SAAS,MAAM,CAE9C,SAAQ,KAAK,SAAS;;;AAK5B,eAAc,QAAQ;AACtB,QAAO,QAAQ,MAAM;;;;;;;;AASvB,SAAgB,0BACd,OACA,SAQA;CACA,MAAM,YACJ,MAAM,MAAM,SAAS,KAAK,SAAS,YAAY,IAAI,SAAS,KAAK,SAAS,WAAW,CAAC,IAAI;CAC5F,MAAM,cAAwB,EAAE;CAChC,MAAM,aAAuB,EAAE;CAC/B,MAAM,gBAA0B,EAAE;CAClC,MAAM,YAAsB,EAAE;CAC9B,MAAM,aAAuB,EAAE;AAE/B,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI;EAC1C,MAAM,eAAe,SAAS,SAAS,KAAK;AAE5C,MAAI,SAAS,UACX;AAGF,MACE,SAAS,SAAS,WAAW,IAC7B,SAAS,SAAS,QAAQ,IAC1B,aAAa,mBAEb,aAAY,KAAK,KAAK;WACb,SAAS,SAAS,UAAU,IAAI,aAAa,SAAS,SAAS,CACxE,YAAW,KAAK,KAAK;WAErB,SAAS,SAAS,QAAQ,IAC1B,SAAS,SAAS,QAAQ,IAC1B,aAAa,SAAS,UAAU,CAEhC,YAAW,KAAK,KAAK;WAErB,SAAS,SAAS,OAAO,IACzB,SAAS,SAAS,OAAO,IACzB,aAAa,SAAS,SAAS,CAE/B,WAAU,KAAK,KAAK;MAEpB,YAAW,KAAK,KAAK;;AAIzB,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -182,4 +182,5 @@ function getDifferenceSummary(result) {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
//#endregion
|
|
185
|
-
export { compareJsonObjects, getDifferenceSummary, normalizeJsonObject };
|
|
185
|
+
export { compareJsonObjects, getDifferenceSummary, normalizeJsonObject };
|
|
186
|
+
//# sourceMappingURL=json-comparator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-comparator.js","names":[],"sources":["../../src/utils/json-comparator.ts"],"sourcesContent":["/**\n * Options for JSON comparison\n */\nexport interface ComparisonOptions {\n /** Whether to ignore order in arrays (default: true) */\n ignoreArrayOrder?: boolean;\n /** Whether to ignore case in string comparisons (default: false) */\n ignoreCase?: boolean;\n /** Whether to ignore whitespace differences (default: false) */\n ignoreWhitespace?: boolean;\n /** Custom key paths to ignore during comparison */\n ignorePaths?: string[];\n /** Whether to show detailed differences (default: false) */\n showDetails?: boolean;\n}\n\n/**\n * Result of JSON comparison\n */\nexport interface ComparisonResult {\n /** Whether the objects are equivalent */\n isEqual: boolean;\n /** List of differences found */\n differences: Difference[];\n /** Summary statistics */\n stats: {\n totalKeys: number;\n differentKeys: number;\n missingKeys: number;\n extraKeys: number;\n };\n}\n\n/**\n * Represents a difference between two objects\n */\nexport interface Difference {\n /** Path to the differing value */\n path: string;\n /** Type of difference */\n type: 'different' | 'missing' | 'extra' | 'type_mismatch';\n /** Value in the first object */\n value1?: any;\n /** Value in the second object */\n value2?: any;\n /** Description of the difference */\n description: string;\n}\n\n/**\n * Compare two JSON objects for structural equivalence\n * Handles arrays with different ordering and nested objects\n */\nexport function compareJsonObjects(\n obj1: any,\n obj2: any,\n options: ComparisonOptions = {}\n): ComparisonResult {\n const {\n ignoreArrayOrder = true,\n ignoreCase = false,\n ignoreWhitespace = false,\n ignorePaths = [],\n } = options;\n\n const differences: Difference[] = [];\n const stats = {\n totalKeys: 0,\n differentKeys: 0,\n missingKeys: 0,\n extraKeys: 0,\n };\n\n function normalizeValue(value: any): any {\n if (typeof value === 'string') {\n let normalized = value;\n if (ignoreCase) {\n normalized = normalized.toLowerCase();\n }\n if (ignoreWhitespace) {\n normalized = normalized.trim().replace(/\\s+/g, ' ');\n }\n return normalized;\n }\n return value;\n }\n\n function shouldIgnorePath(path: string): boolean {\n return ignorePaths.some((ignorePath) => {\n if (ignorePath.endsWith('*')) {\n return path.startsWith(ignorePath.slice(0, -1));\n }\n return path === ignorePath;\n });\n }\n\n function compareValues(value1: any, value2: any, path: string = ''): boolean {\n if (shouldIgnorePath(path)) {\n return true;\n }\n\n // Handle null/undefined\n if (value1 === null || value1 === undefined) {\n if (value2 === null || value2 === undefined) {\n return true;\n }\n differences.push({\n path,\n type: 'different',\n value1,\n value2,\n description: `Null/undefined mismatch: ${value1} vs ${value2}`,\n });\n return false;\n }\n\n if (value2 === null || value2 === undefined) {\n differences.push({\n path,\n type: 'different',\n value1,\n value2,\n description: `Null/undefined mismatch: ${value1} vs ${value2}`,\n });\n return false;\n }\n\n // Handle different types\n if (typeof value1 !== typeof value2) {\n differences.push({\n path,\n type: 'type_mismatch',\n value1,\n value2,\n description: `Type mismatch: ${typeof value1} vs ${typeof value2}`,\n });\n return false;\n }\n\n // Handle primitives\n if (typeof value1 !== 'object') {\n const normalized1 = normalizeValue(value1);\n const normalized2 = normalizeValue(value2);\n\n if (normalized1 !== normalized2) {\n differences.push({\n path,\n type: 'different',\n value1,\n value2,\n description: `Value mismatch: ${value1} vs ${value2}`,\n });\n return false;\n }\n return true;\n }\n\n // Handle arrays\n if (Array.isArray(value1) && Array.isArray(value2)) {\n if (value1.length !== value2.length) {\n differences.push({\n path,\n type: 'different',\n value1: value1.length,\n value2: value2.length,\n description: `Array length mismatch: ${value1.length} vs ${value2.length}`,\n });\n return false; // Array length mismatch is a fundamental difference\n }\n\n if (ignoreArrayOrder) {\n // Compare arrays ignoring order\n const sorted1 = [...value1].sort((a, b) =>\n JSON.stringify(a).localeCompare(JSON.stringify(b))\n );\n const sorted2 = [...value2].sort((a, b) =>\n JSON.stringify(a).localeCompare(JSON.stringify(b))\n );\n\n for (let i = 0; i < sorted1.length; i++) {\n compareValues(sorted1[i], sorted2[i], `${path}[${i}]`); // Don't return false, just collect differences\n }\n } else {\n // Compare arrays in order\n for (let i = 0; i < value1.length; i++) {\n compareValues(value1[i], value2[i], `${path}[${i}]`); // Don't return false, just collect differences\n }\n }\n return true;\n }\n\n // Handle objects\n if (typeof value1 === 'object' && typeof value2 === 'object') {\n const keys1 = Object.keys(value1);\n const keys2 = Object.keys(value2);\n const allKeys = new Set([...keys1, ...keys2]);\n\n stats.totalKeys += allKeys.size;\n\n for (const key of allKeys) {\n const currentPath = path ? `${path}.${key}` : key;\n\n if (!keys1.includes(key)) {\n differences.push({\n path: currentPath,\n type: 'missing',\n value2: value2[key],\n description: `Missing key in first object: ${key}`,\n });\n stats.missingKeys++;\n continue; // Continue checking other keys instead of returning false\n }\n\n if (!keys2.includes(key)) {\n differences.push({\n path: currentPath,\n type: 'extra',\n value1: value1[key],\n description: `Extra key in first object: ${key}`,\n });\n stats.extraKeys++;\n continue; // Continue checking other keys instead of returning false\n }\n\n if (!compareValues(value1[key], value2[key], currentPath)) {\n stats.differentKeys++;\n // Don't return false here, continue checking other keys\n }\n }\n return true;\n }\n\n return true;\n }\n\n compareValues(obj1, obj2);\n\n return {\n isEqual: differences.length === 0,\n differences,\n stats,\n };\n}\n\n/**\n * Create a normalized version of a JSON object for comparison\n * This can be useful for creating a canonical representation\n */\nexport function normalizeJsonObject(obj: any, options: ComparisonOptions = {}): any {\n const { ignoreArrayOrder = true, ignoreCase = false, ignoreWhitespace = false } = options;\n\n function normalizeValue(value: any): any {\n if (typeof value === 'string') {\n let normalized = value;\n if (ignoreCase) {\n normalized = normalized.toLowerCase();\n }\n if (ignoreWhitespace) {\n normalized = normalized.trim().replace(/\\s+/g, ' ');\n }\n return normalized;\n }\n\n if (Array.isArray(value)) {\n const normalizedArray = value.map(normalizeValue);\n if (ignoreArrayOrder) {\n return normalizedArray.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));\n }\n return normalizedArray;\n }\n\n if (typeof value === 'object' && value !== null) {\n const normalizedObj: any = {};\n const sortedKeys = Object.keys(value).sort();\n for (const key of sortedKeys) {\n normalizedObj[key] = normalizeValue(value[key]);\n }\n return normalizedObj;\n }\n\n return value;\n }\n\n return normalizeValue(obj);\n}\n\n/**\n * Get a summary of differences in a human-readable format\n */\nexport function getDifferenceSummary(result: ComparisonResult): string {\n if (result.isEqual) {\n return '✅ Objects are equivalent';\n }\n\n const { differences, stats } = result;\n const summary = [`❌ Objects differ (${differences.length} differences found)`];\n\n summary.push(`📊 Statistics:`);\n summary.push(` • Total keys: ${stats.totalKeys}`);\n summary.push(` • Different values: ${stats.differentKeys}`);\n summary.push(` • Missing keys: ${stats.missingKeys}`);\n summary.push(` • Extra keys: ${stats.extraKeys}`);\n\n if (differences.length > 0) {\n summary.push(`\\n🔍 Differences:`);\n differences.slice(0, 10).forEach((diff, index) => {\n summary.push(` ${index + 1}. ${diff.path}: ${diff.description}`);\n });\n\n if (differences.length > 10) {\n summary.push(` ... and ${differences.length - 10} more differences`);\n }\n }\n\n return summary.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-comparison.js","names":["allIgnoredFields"],"sources":["../../src/utils/json-comparison.ts"],"sourcesContent":["import type { FullProjectDefinition } from '@inkeep/agents-core';\n\nexport interface ComparisonResult {\n matches: boolean;\n differences: string[];\n warnings: string[];\n}\n\n/**\n * Deep compare two FullProjectDefinition objects\n *\n * Ignores timestamp fields (createdAt, updatedAt) and provides detailed\n * error messages about specific differences.\n *\n * @param original - The original project definition from the backend\n * @param generated - The generated project definition from loaded TypeScript\n * @returns Comparison result with matches boolean and list of differences\n */\nexport function compareProjectDefinitions(\n original: FullProjectDefinition,\n generated: FullProjectDefinition\n): ComparisonResult {\n const differences: string[] = [];\n const warnings: string[] = [];\n\n // Define ignored fields at the top level so all helper functions can access them\n const dbGeneratedFields = ['agentToolRelationId']; // Database-generated IDs that should be ignored entirely\n const sdkGeneratedFields = ['type']; // SDK-generated metadata fields that should be ignored\n const contextFields = ['tenantId', 'projectId', 'agentId']; // Runtime context fields added by SDK\n const cosmenticFields = ['imageUrl']; // Cosmetic UI fields that don't affect functionality\n const allIgnoredFields = [\n ...dbGeneratedFields,\n ...sdkGeneratedFields,\n ...contextFields,\n ...cosmenticFields,\n ];\n\n // Helper to check if a value is \"empty\" (undefined, empty object, or empty array)\n const isEmpty = (value: any): boolean => {\n if (value === undefined || value === null) return true;\n if (Array.isArray(value) && value.length === 0) return true;\n if (typeof value === 'object' && Object.keys(value).length === 0) return true;\n return false;\n };\n\n // Helper to check if this is a schema-related field that should have stricter comparison\n const isSchemaField = (path: string): boolean => {\n return (\n path.endsWith('.props') ||\n path.endsWith('.schema') ||\n path.endsWith('Schema') ||\n path.includes('.props.') ||\n path.includes('.schema.')\n );\n };\n\n // Helper to check if an object has actual content (not just empty)\n const hasContent = (value: any): boolean => {\n if (!value || typeof value !== 'object') return false;\n if (Array.isArray(value)) return value.length > 0;\n return Object.keys(value).length > 0;\n };\n\n // Helper to compare primitive values\n const comparePrimitive = (path: string, a: any, b: any): boolean => {\n if (a === b) return true;\n\n // For schema fields, be stricter about empty vs populated\n if (isSchemaField(path)) {\n const aHasContent = hasContent(a);\n const bHasContent = hasContent(b);\n\n // If one has content and the other doesn't, they're not equivalent\n if (aHasContent !== bHasContent) {\n return false;\n }\n\n // Both empty or both have content - continue with normal comparison\n if (!aHasContent && !bHasContent) {\n // Both are empty - treat as equivalent\n return true;\n }\n } else {\n // For non-schema fields, treat empty values as equivalent (undefined, {}, [])\n if (isEmpty(a) && isEmpty(b)) {\n return true;\n }\n }\n\n // Special handling for credential fields - SDK may return object while API returns string ID\n if (path.includes('credential') || path.endsWith('ReferenceId')) {\n // If one is a string (ID) and the other is an object with an id field, compare IDs\n if (typeof a === 'string' && typeof b === 'object' && b !== null && 'id' in b) {\n return a === b.id;\n }\n if (typeof b === 'string' && typeof a === 'object' && a !== null && 'id' in a) {\n return b === a.id;\n }\n }\n\n if (typeof a !== typeof b) {\n differences.push(`Type mismatch at ${path}: ${typeof a} vs ${typeof b}`);\n return false;\n }\n if (a !== b) {\n differences.push(`Value mismatch at ${path}: \"${a}\" vs \"${b}\"`);\n return false;\n }\n return true;\n };\n\n // Helper to compare arrays\n const compareArrays = (path: string, a: any[], b: any[]): boolean => {\n if (a.length !== b.length) {\n differences.push(`Array length mismatch at ${path}: ${a.length} vs ${b.length}`);\n return false;\n }\n\n // For certain paths, treat arrays as sets (order doesn't matter)\n const orderIndependentPaths = [\n 'canDelegateTo',\n 'canTransferTo',\n 'canUse',\n 'tools',\n 'functionTools',\n 'dataComponents',\n 'artifactComponents',\n ];\n const isOrderIndependent = orderIndependentPaths.some((pattern) => path.includes(pattern));\n\n if (isOrderIndependent) {\n // Compare as sets - all elements in a must exist in b\n // Filter out ignored fields before comparison\n const allIgnoredFields = [...dbGeneratedFields, ...sdkGeneratedFields, ...contextFields];\n\n const filterIgnoredFields = (item: any) => {\n if (typeof item === 'object' && item !== null) {\n const filtered = { ...item };\n allIgnoredFields.forEach((field) => {\n delete filtered[field];\n });\n return JSON.stringify(filtered);\n }\n return item;\n };\n\n const aSet = new Set(a.map(filterIgnoredFields));\n const bSet = new Set(b.map(filterIgnoredFields));\n\n if (aSet.size !== bSet.size) {\n differences.push(`Array content mismatch at ${path}: different unique elements`);\n return false;\n }\n\n for (const item of aSet) {\n if (!bSet.has(item)) {\n differences.push(`Array content mismatch at ${path}: missing element ${item}`);\n return false;\n }\n }\n\n return true;\n }\n // Compare as ordered arrays (original behavior)\n let allMatch = true;\n for (let i = 0; i < a.length; i++) {\n if (!compareValues(`${path}[${i}]`, a[i], b[i])) {\n allMatch = false;\n }\n }\n return allMatch;\n };\n\n // Helper to compare objects\n const compareObjects = (path: string, a: any, b: any): boolean => {\n // Ignore timestamp fields (contextConfig IDs are now deterministic)\n const ignoredFields = ['createdAt', 'updatedAt'];\n\n const aKeys = Object.keys(a || {}).filter((k) => !ignoredFields.includes(k));\n const bKeys = Object.keys(b || {}).filter((k) => !ignoredFields.includes(k));\n\n // Check for missing keys, but ignore fields that are null/empty in API but omitted in SDK\n\n const missingInB = aKeys.filter(\n (k) =>\n !bKeys.includes(k) &&\n a[k] !== null && // Ignore if API has null (SDK omits null fields)\n !(Array.isArray(a[k]) && a[k].length === 0) && // Ignore if API has empty array\n !(typeof a[k] === 'object' && a[k] !== null && Object.keys(a[k]).length === 0) && // Ignore if API has empty object\n !allIgnoredFields.includes(k) &&\n // Ignore $schema fields which are typically added automatically by JSON schema serialization\n k !== '$schema' &&\n // Ignore common JSON Schema metadata fields that generators don't include but API adds\n !(k === 'properties' && path.includes('.schema')) &&\n !(k === 'required' && path.includes('.schema')) &&\n !(k === 'additionalProperties' && path.includes('.schema'))\n );\n const extraInB = bKeys.filter(\n (k) =>\n !aKeys.includes(k) &&\n b[k] !== null && // Ignore if SDK has null (API might omit null fields)\n !(Array.isArray(b[k]) && b[k].length === 0) && // Ignore if SDK has empty array\n !(typeof b[k] === 'object' && b[k] !== null && Object.keys(b[k]).length === 0) && // Ignore if SDK has empty object\n !allIgnoredFields.includes(k) &&\n // Ignore $schema fields which are typically added automatically by JSON schema serialization\n k !== '$schema' &&\n // Ignore extra JSON Schema metadata fields that generators might add but API doesn't expect\n !(k === 'additionalProperties' && path.includes('.props'))\n );\n\n if (missingInB.length > 0) {\n differences.push(`Missing keys in generated at ${path}: ${missingInB.join(', ')}`);\n }\n if (extraInB.length > 0) {\n // Split extra keys into meaningful content vs empty content\n const meaningfulExtraKeys = [];\n const emptyExtraKeys = [];\n\n for (const key of extraInB) {\n const value = b[key];\n const isEmpty =\n value === null ||\n value === undefined ||\n value === '' ||\n (Array.isArray(value) && value.length === 0) ||\n (typeof value === 'object' && value !== null && Object.keys(value).length === 0);\n\n if (isEmpty) {\n emptyExtraKeys.push(key);\n } else {\n meaningfulExtraKeys.push(key);\n }\n }\n\n // Meaningful extra content = real difference (generated files out of sync)\n if (meaningfulExtraKeys.length > 0) {\n differences.push(`Extra keys in generated at ${path}: ${meaningfulExtraKeys.join(', ')}`);\n }\n // Empty extra content = just warning (probably harmless metadata)\n if (emptyExtraKeys.length > 0) {\n warnings.push(`Extra keys in generated at ${path}: ${emptyExtraKeys.join(', ')}`);\n }\n }\n\n let allMatch = true;\n for (const key of aKeys) {\n if (bKeys.includes(key)) {\n if (!compareValues(`${path}.${key}`, a[key], b[key])) {\n allMatch = false;\n }\n }\n }\n\n return allMatch && missingInB.length === 0;\n };\n\n // Main comparison function\n const compareValues = (path: string, a: any, b: any): boolean => {\n // Prevent infinite recursion with depth check\n const depth = (path.match(/\\./g) || []).length;\n if (depth > 50) {\n warnings.push(`Max comparison depth reached at ${path}`);\n return true; // Consider deeply nested paths as equivalent to avoid hangs\n }\n\n // Handle null/undefined equivalence - API returns null, SDK returns undefined\n if (a === null && b === null) return true;\n if (a === undefined && b === undefined) return true;\n if ((a === null && b === undefined) || (a === undefined && b === null)) return true;\n\n // Handle empty array vs undefined equivalence - API returns [], SDK returns undefined\n if (Array.isArray(a) && a.length === 0 && b === undefined) return true;\n if (a === undefined && Array.isArray(b) && b.length === 0) return true;\n\n // Handle empty object vs undefined equivalence - API returns {}, SDK returns undefined\n if (typeof a === 'object' && a !== null && Object.keys(a).length === 0 && b === undefined)\n return true;\n if (a === undefined && typeof b === 'object' && b !== null && Object.keys(b).length === 0)\n return true;\n\n // Handle model inheritance - when generators inherit models from parent configs,\n // they may omit model fields that match inherited values, resulting in undefined\n // while API always returns explicit model objects. This is expected behavior.\n if (path.includes('.models') && typeof a === 'object' && a !== null && b === undefined) {\n // Check if the model object represents a \"default\" or inherited configuration\n // by looking for minimal required fields like 'model' property or typical model structure\n const hasMinimalModelStructure =\n a.model || a.provider || (typeof a === 'object' && (a.base || a.fast || a.smart));\n if (hasMinimalModelStructure) {\n warnings.push(\n `Model inheritance at ${path}: API has explicit model config, generator uses inheritance (this is expected)`\n );\n return true; // Treat as equivalent - inheritance is working as designed\n }\n }\n\n // Reverse case - generator has model but API doesn't (less common)\n if (path.includes('.models') && a === undefined && typeof b === 'object' && b !== null) {\n const hasMinimalModelStructure =\n b.model || b.provider || (typeof b === 'object' && (b.base || b.fast || b.smart));\n if (hasMinimalModelStructure) {\n warnings.push(\n `Model inheritance at ${path}: generator has explicit model config, API uses inheritance (this is expected)`\n );\n return true;\n }\n }\n\n // Handle arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n return compareArrays(path, a, b);\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n differences.push(`Array type mismatch at ${path}`);\n return false;\n }\n\n // Handle objects\n if (typeof a === 'object' && typeof b === 'object') {\n return compareObjects(path, a, b);\n }\n\n // Handle primitives\n return comparePrimitive(path, a, b);\n };\n\n // Compare top-level fields\n comparePrimitive('id', original.id, generated.id);\n comparePrimitive('name', original.name, generated.name);\n\n // Description can be empty string vs undefined\n if (original.description || generated.description) {\n const origDesc = original.description || '';\n const genDesc = generated.description || '';\n if (origDesc !== genDesc) {\n comparePrimitive('description', origDesc, genDesc);\n }\n }\n\n // Compare models configuration\n if (original.models || generated.models) {\n compareValues('models', original.models, generated.models);\n }\n\n // Compare stopWhen configuration\n if (original.stopWhen || generated.stopWhen) {\n compareValues('stopWhen', original.stopWhen, generated.stopWhen);\n }\n\n // Compare agents\n const originalAgentIds = Object.keys(original.agents || {});\n const generatedAgentIds = Object.keys(generated.agents || {});\n\n if (originalAgentIds.length !== generatedAgentIds.length) {\n differences.push(\n `Agent count mismatch: ${originalAgentIds.length} vs ${generatedAgentIds.length}`\n );\n }\n\n for (const agentId of originalAgentIds) {\n if (!generatedAgentIds.includes(agentId)) {\n differences.push(`Missing agent in generated: ${agentId}`);\n } else {\n compareValues(`agents.${agentId}`, original.agents?.[agentId], generated.agents?.[agentId]);\n }\n }\n\n for (const agentId of generatedAgentIds) {\n if (!originalAgentIds.includes(agentId)) {\n warnings.push(`Extra agent in generated: ${agentId}`);\n }\n }\n\n // Compare tools\n const originalToolIds = Object.keys(original.tools || {});\n const generatedToolIds = Object.keys(generated.tools || {});\n\n if (originalToolIds.length !== generatedToolIds.length) {\n differences.push(\n `Tool count mismatch: ${originalToolIds.length} vs ${generatedToolIds.length}`\n );\n }\n\n for (const toolId of originalToolIds) {\n if (!generatedToolIds.includes(toolId)) {\n differences.push(`Missing tool in generated: ${toolId}`);\n } else {\n compareValues(`tools.${toolId}`, original.tools?.[toolId], generated.tools?.[toolId]);\n }\n }\n\n // Compare functions (if present)\n if (original.functions || generated.functions) {\n const originalFunctionIds = Object.keys(original.functions || {});\n const generatedFunctionIds = Object.keys(generated.functions || {});\n\n for (const functionId of originalFunctionIds) {\n if (!generatedFunctionIds.includes(functionId)) {\n differences.push(`Missing function in generated: ${functionId}`);\n } else {\n compareValues(\n `functions.${functionId}`,\n original.functions?.[functionId],\n generated.functions?.[functionId]\n );\n }\n }\n }\n\n // Compare project-level function tools (if present)\n if (original.functionTools || generated.functionTools) {\n const originalFunctionToolIds = Object.keys(original.functionTools || {});\n const generatedFunctionToolIds = Object.keys(generated.functionTools || {});\n\n if (originalFunctionToolIds.length !== generatedFunctionToolIds.length) {\n differences.push(\n `Function tool count mismatch: ${originalFunctionToolIds.length} vs ${generatedFunctionToolIds.length}`\n );\n }\n\n for (const functionToolId of originalFunctionToolIds) {\n if (!generatedFunctionToolIds.includes(functionToolId)) {\n differences.push(`Missing function tool in generated: ${functionToolId}`);\n } else {\n compareValues(\n `functionTools.${functionToolId}`,\n original.functionTools?.[functionToolId],\n generated.functionTools?.[functionToolId]\n );\n }\n }\n\n for (const functionToolId of generatedFunctionToolIds) {\n if (!originalFunctionToolIds.includes(functionToolId)) {\n warnings.push(`Extra function tool in generated: ${functionToolId}`);\n }\n }\n }\n\n // Compare data components\n if (original.dataComponents || generated.dataComponents) {\n const originalComponentIds = Object.keys(original.dataComponents || {});\n const generatedComponentIds = Object.keys(generated.dataComponents || {});\n\n for (const componentId of originalComponentIds) {\n if (!generatedComponentIds.includes(componentId)) {\n differences.push(`Missing data component in generated: ${componentId}`);\n } else {\n compareValues(\n `dataComponents.${componentId}`,\n original.dataComponents?.[componentId],\n generated.dataComponents?.[componentId]\n );\n }\n }\n }\n\n // Compare artifact components\n if (original.artifactComponents || generated.artifactComponents) {\n const originalArtifactIds = Object.keys(original.artifactComponents || {});\n const generatedArtifactIds = Object.keys(generated.artifactComponents || {});\n\n for (const artifactId of originalArtifactIds) {\n if (!generatedArtifactIds.includes(artifactId)) {\n differences.push(`Missing artifact component in generated: ${artifactId}`);\n } else {\n compareValues(\n `artifactComponents.${artifactId}`,\n original.artifactComponents?.[artifactId],\n generated.artifactComponents?.[artifactId]\n );\n }\n }\n }\n\n // Compare credential references (if present)\n if (original.credentialReferences || generated.credentialReferences) {\n const originalCredIds = Object.keys(original.credentialReferences || {});\n const generatedCredIds = Object.keys(generated.credentialReferences || {});\n\n for (const credId of originalCredIds) {\n if (!generatedCredIds.includes(credId)) {\n differences.push(`Missing credential reference in generated: ${credId}`);\n } else {\n // Ignore usedBy field in credentials as it's computed\n const origCred = { ...((original.credentialReferences?.[credId] as any) || {}) };\n const genCred = { ...((generated.credentialReferences?.[credId] as any) || {}) };\n delete origCred.usedBy;\n delete genCred.usedBy;\n compareValues(`credentialReferences.${credId}`, origCred, genCred);\n }\n }\n }\n\n return {\n matches: differences.length === 0,\n differences,\n warnings,\n };\n}\n"],"mappings":"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"}
|
package/dist/utils/mcp-runner.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-runner.js","names":["agentPath"],"sources":["../../src/utils/mcp-runner.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Runner - Loads and starts MCP servers from an agent file\n * This is executed as a subprocess by the CLI\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport http from 'node:http';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst MCP_DIR = join(homedir(), '.inkeep', 'mcp');\nconst REGISTRY_FILE = join(MCP_DIR, 'servers.json');\n\n// Ensure MCP directory exists\nif (!existsSync(MCP_DIR)) {\n mkdirSync(MCP_DIR, { recursive: true });\n}\n\ninterface McpServer {\n pid: number;\n agentId: string;\n toolId: string;\n name: string;\n port?: number;\n serverUrl?: string;\n deployment: 'local' | 'remote';\n transport?: string;\n command: string;\n startedAt: string;\n description?: string;\n}\n\nasync function startServers(agentPath: string) {\n try {\n // Import the agent module\n const module = await import(agentPath);\n\n // Get servers\n const servers = module.servers || module.tools || [];\n\n // Get agent ID\n let agentId = 'unknown';\n if (module.agent && typeof module.agent.getId === 'function') {\n agentId = module.agent.getId();\n }\n\n const registeredServers: McpServer[] = [];\n let nextPort = 3100;\n\n // Start each server\n for (const server of servers) {\n if (!server) continue;\n\n // Get server metadata\n const name = server.name || 'unnamed';\n const id = server.id || name;\n const description = server.description || '';\n\n // Check deployment type\n const isLocal =\n typeof server.execute === 'function' ||\n typeof server.init === 'function' ||\n !server.serverUrl;\n\n if (isLocal) {\n // Start local server\n const port = server.port || nextPort++;\n\n // Initialize if needed\n if (typeof server.init === 'function') {\n await server.init();\n }\n\n // Create HTTP server for local MCP\n if (typeof server.execute === 'function') {\n const httpServer = http.createServer(async (req, res) => {\n if (req.method === 'POST' && req.url === '/mcp') {\n let body = '';\n req.on('data', (chunk) => (body += chunk));\n req.on('end', async () => {\n try {\n const params = JSON.parse(body);\n const result = await server.execute(params);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ result }));\n } catch (error: any) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: error.message }));\n }\n });\n } else {\n res.writeHead(404);\n res.end('Not Found');\n }\n });\n\n httpServer.listen(port, () => {\n console.log(\n JSON.stringify({\n type: 'server_started',\n name,\n port,\n deployment: 'local',\n })\n );\n });\n }\n\n registeredServers.push({\n pid: process.pid,\n agentId,\n toolId: id,\n name,\n port,\n deployment: 'local',\n transport: 'http',\n command: agentPath,\n startedAt: new Date().toISOString(),\n description,\n });\n } else {\n // Register remote server\n registeredServers.push({\n pid: process.pid,\n agentId,\n toolId: id,\n name,\n serverUrl: server.serverUrl || server.getServerUrl?.(),\n deployment: 'remote',\n transport: server.transport || 'http',\n command: agentPath,\n startedAt: new Date().toISOString(),\n description,\n });\n\n console.log(\n JSON.stringify({\n type: 'server_registered',\n name,\n serverUrl: server.serverUrl,\n deployment: 'remote',\n })\n );\n }\n }\n\n // Save to registry\n writeFileSync(REGISTRY_FILE, JSON.stringify({ servers: registeredServers }, null, 2));\n\n console.log(\n JSON.stringify({\n type: 'all_started',\n count: registeredServers.length,\n })\n );\n\n // Keep process alive\n process.stdin.resume();\n\n // Handle shutdown\n process.on('SIGINT', () => {\n console.log(JSON.stringify({ type: 'shutting_down' }));\n process.exit(0);\n });\n } catch (error: any) {\n console.error(\n JSON.stringify({\n type: 'error',\n message: error.message,\n })\n );\n process.exit(1);\n }\n}\n\n// Get agent path from command line\nconst agentPath = process.argv[2];\nif (!agentPath) {\n console.error(\n JSON.stringify({\n type: 'error',\n message: 'Agent path is required',\n })\n );\n process.exit(1);\n}\n\nstartServers(agentPath);\n"],"mappings":"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"}
|
|
@@ -304,4 +304,5 @@ async function promptForModelConfiguration() {
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
//#endregion
|
|
307
|
-
export { defaultAnthropicModelConfigurations, defaultGeminiModelConfigurations, defaultOpenaiModelConfigurations, promptForModelConfiguration };
|
|
307
|
+
export { defaultAnthropicModelConfigurations, defaultGeminiModelConfigurations, defaultOpenaiModelConfigurations, promptForModelConfiguration };
|
|
308
|
+
//# sourceMappingURL=model-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-config.js","names":[],"sources":["../../src/utils/model-config.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport { ANTHROPIC_MODELS, GOOGLE_MODELS, OPENAI_MODELS } from '@inkeep/agents-core';\n\nexport interface ModelConfigurationResult {\n modelSettings: {\n base: {\n model: string;\n providerOptions?: Record<string, any>;\n };\n structuredOutput?: {\n model: string;\n providerOptions?: Record<string, any>;\n };\n summarizer?: {\n model: string;\n providerOptions?: Record<string, any>;\n };\n };\n}\n\nexport type ModelSettings = ModelConfigurationResult['modelSettings'];\n\nexport const defaultGeminiModelConfigurations: ModelSettings = {\n base: {\n model: GOOGLE_MODELS.GEMINI_2_5_FLASH,\n },\n structuredOutput: {\n model: GOOGLE_MODELS.GEMINI_2_5_FLASH_LITE,\n },\n summarizer: {\n model: GOOGLE_MODELS.GEMINI_2_5_FLASH_LITE,\n },\n};\n\nexport const defaultOpenaiModelConfigurations: ModelSettings = {\n base: {\n model: OPENAI_MODELS.GPT_5_2,\n },\n structuredOutput: {\n model: OPENAI_MODELS.GPT_4_1_MINI,\n },\n summarizer: {\n model: OPENAI_MODELS.GPT_4_1_NANO,\n },\n};\n\nexport const defaultAnthropicModelConfigurations: ModelSettings = {\n base: {\n model: ANTHROPIC_MODELS.CLAUDE_SONNET_4_5,\n },\n structuredOutput: {\n model: ANTHROPIC_MODELS.CLAUDE_SONNET_4_5,\n },\n summarizer: {\n model: ANTHROPIC_MODELS.CLAUDE_SONNET_4_5,\n },\n};\n\n/**\n * Prompt user for model configuration (providers and model selection)\n * This is shared between init and push commands\n */\nexport async function promptForModelConfiguration(): Promise<ModelConfigurationResult> {\n // Provider selection\n const providers = (await p.multiselect({\n message: 'Which AI providers would you like to configure?',\n options: [\n { value: 'anthropic', label: 'Anthropic (Claude)' },\n { value: 'openai', label: 'OpenAI (GPT)' },\n { value: 'google', label: 'Google (Gemini)' },\n { value: 'azure', label: 'Azure OpenAI' },\n ],\n required: true,\n })) as string[];\n\n if (p.isCancel(providers)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n // Available models for each provider (matching frontend options)\n const anthropicModels = [\n { label: 'Claude Opus 4.6', value: ANTHROPIC_MODELS.CLAUDE_OPUS_4_6 },\n { label: 'Claude Opus 4.5', value: ANTHROPIC_MODELS.CLAUDE_OPUS_4_5 },\n { label: 'Claude Opus 4.1', value: ANTHROPIC_MODELS.CLAUDE_OPUS_4_1 },\n { label: 'Claude Opus 4', value: ANTHROPIC_MODELS.CLAUDE_OPUS_4 },\n { label: 'Claude Sonnet 4.6', value: ANTHROPIC_MODELS.CLAUDE_SONNET_4_6 },\n { label: 'Claude Sonnet 4.5', value: ANTHROPIC_MODELS.CLAUDE_SONNET_4_5 },\n { label: 'Claude Sonnet 4', value: ANTHROPIC_MODELS.CLAUDE_SONNET_4 },\n { label: 'Claude Haiku 4.5', value: ANTHROPIC_MODELS.CLAUDE_HAIKU_4_5 },\n ];\n\n const openaiModels = [\n { label: 'GPT-5.4 Pro', value: OPENAI_MODELS.GPT_5_4_PRO },\n { label: 'GPT-5.4', value: OPENAI_MODELS.GPT_5_4 },\n { label: 'GPT-5.3 Codex', value: OPENAI_MODELS.GPT_5_3_CODEX },\n { label: 'GPT-5.2 Pro', value: OPENAI_MODELS.GPT_5_2_PRO },\n { label: 'GPT-5.2', value: OPENAI_MODELS.GPT_5_2 },\n { label: 'GPT-5.1', value: OPENAI_MODELS.GPT_5_1 },\n { label: 'o3 Pro', value: OPENAI_MODELS.O3_PRO },\n { label: 'o3', value: OPENAI_MODELS.O3 },\n { label: 'GPT-4.1', value: OPENAI_MODELS.GPT_4_1 },\n { label: 'GPT-4.1 Mini', value: OPENAI_MODELS.GPT_4_1_MINI },\n { label: 'GPT-4.1 Nano', value: OPENAI_MODELS.GPT_4_1_NANO },\n { label: 'GPT-5', value: OPENAI_MODELS.GPT_5 },\n { label: 'GPT-5 Mini', value: OPENAI_MODELS.GPT_5_MINI },\n { label: 'GPT-5 Nano', value: OPENAI_MODELS.GPT_5_NANO },\n ];\n\n const googleModels = [\n { label: 'Gemini 3.1 Pro Preview', value: GOOGLE_MODELS.GEMINI_3_1_PRO_PREVIEW },\n { label: 'Gemini 3.1 Flash Lite Preview', value: GOOGLE_MODELS.GEMINI_3_1_FLASH_LITE_PREVIEW },\n { label: 'Gemini 3 Flash', value: GOOGLE_MODELS.GEMINI_3_FLASH },\n { label: 'Gemini 3 Pro Preview', value: GOOGLE_MODELS.GEMINI_3_PRO_PREVIEW },\n { label: 'Gemini 2.5 Pro', value: GOOGLE_MODELS.GEMINI_2_5_PRO },\n { label: 'Gemini 2.5 Flash', value: GOOGLE_MODELS.GEMINI_2_5_FLASH },\n { label: 'Gemini 2.5 Flash Lite', value: GOOGLE_MODELS.GEMINI_2_5_FLASH_LITE },\n ];\n\n // Handle Azure configuration if selected\n const azureConfigs: any = {};\n if (providers.includes('azure')) {\n p.note('Azure OpenAI requires custom deployment configuration.');\n\n const deploymentName = await p.text({\n message: 'Enter your Azure deployment name:',\n placeholder: 'my-gpt-4o-deployment',\n validate: (value) => {\n if (!value?.trim()) return 'Deployment name is required';\n },\n });\n\n if (p.isCancel(deploymentName)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n const connectionMethod = await p.select({\n message: 'How would you like to connect to Azure?',\n options: [\n { value: 'resource', label: 'Azure Resource Name (recommended)' },\n { value: 'url', label: 'Custom Base URL' },\n ],\n });\n\n if (p.isCancel(connectionMethod)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n if (connectionMethod === 'resource') {\n const resourceName = await p.text({\n message: 'Enter your Azure resource name:',\n placeholder: 'your-azure-resource',\n validate: (value) => {\n if (!value?.trim()) return 'Resource name is required';\n },\n });\n\n if (p.isCancel(resourceName)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n azureConfigs.resourceName = resourceName;\n } else {\n const baseURL = await p.text({\n message: 'Enter your Azure base URL:',\n placeholder: 'https://your-endpoint.openai.azure.com/openai',\n validate: (value) => {\n if (!value?.trim()) return 'Base URL is required';\n if (!value.startsWith('https://')) return 'Base URL must start with https://';\n },\n });\n\n if (p.isCancel(baseURL)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n azureConfigs.baseURL = baseURL;\n }\n\n azureConfigs.deploymentName = deploymentName;\n azureConfigs.model = `azure/${deploymentName}`;\n }\n\n // Collect all available models based on selected providers\n const availableModels = [];\n if (providers.includes('anthropic')) {\n availableModels.push(...anthropicModels);\n }\n if (providers.includes('openai')) {\n availableModels.push(...openaiModels);\n }\n if (providers.includes('google')) {\n availableModels.push(...googleModels);\n }\n if (providers.includes('azure') && azureConfigs.model) {\n availableModels.push({\n label: `${azureConfigs.deploymentName} (Azure)`,\n value: azureConfigs.model,\n });\n }\n\n // Model selection for different use cases\n const baseModel = (await p.select({\n message: 'Select your default model for general tasks (required):',\n options: availableModels,\n })) as string;\n\n if (p.isCancel(baseModel)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n const configureOptionalModels = await p.confirm({\n message: 'Would you like to configure optional models for structured output and summaries?',\n initialValue: false,\n });\n\n if (p.isCancel(configureOptionalModels)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n\n let structuredOutputModel: string | null = null;\n let summarizerModel: string | null = null;\n\n if (configureOptionalModels) {\n const optionalChoices = [...availableModels, { label: 'Use base model', value: null }];\n\n const structuredOutputResponse = await p.select({\n message: 'Select your model for structured output tasks (or use base model):',\n options: optionalChoices,\n });\n\n if (p.isCancel(structuredOutputResponse)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n structuredOutputModel = structuredOutputResponse as string | null;\n\n const summarizerResponse = await p.select({\n message: 'Select your model for summaries and quick tasks (or use base model):',\n options: optionalChoices,\n });\n\n if (p.isCancel(summarizerResponse)) {\n p.cancel('Operation cancelled');\n process.exit(0);\n }\n summarizerModel = summarizerResponse as string | null;\n }\n\n // Helper function to add Azure provider options if needed\n const addProviderOptions = (model: string) => {\n if (model.startsWith('azure/') && (azureConfigs.resourceName || azureConfigs.baseURL)) {\n const providerOptions: any = {};\n if (azureConfigs.resourceName) {\n providerOptions.resourceName = azureConfigs.resourceName;\n }\n if (azureConfigs.baseURL) {\n providerOptions.baseURL = azureConfigs.baseURL;\n }\n return providerOptions;\n }\n return undefined;\n };\n\n // Build model settings object\n const modelSettings: any = {\n base: {\n model: baseModel,\n },\n };\n\n // Add Azure provider options to base model if needed\n const baseProviderOptions = addProviderOptions(baseModel);\n if (baseProviderOptions) {\n modelSettings.base.providerOptions = baseProviderOptions;\n }\n\n // Add optional models only if they were configured\n if (structuredOutputModel) {\n modelSettings.structuredOutput = {\n model: structuredOutputModel,\n };\n\n const structuredProviderOptions = addProviderOptions(structuredOutputModel);\n if (structuredProviderOptions) {\n modelSettings.structuredOutput.providerOptions = structuredProviderOptions;\n }\n }\n\n if (summarizerModel) {\n modelSettings.summarizer = {\n model: summarizerModel,\n };\n\n const summarizerProviderOptions = addProviderOptions(summarizerModel);\n if (summarizerProviderOptions) {\n modelSettings.summarizer.providerOptions = summarizerProviderOptions;\n }\n }\n\n return { modelSettings };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manager.js","names":[],"sources":["../../src/utils/package-manager.ts"],"sourcesContent":["import { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { DEFAULT_PACKAGE_NAME } from './version-check';\n\nconst execAsync = promisify(exec);\n\nexport type PackageManager = 'npm' | 'pnpm' | 'bun' | 'yarn';\n\n/**\n * Detect which package manager was used to install the CLI globally\n */\nexport async function detectPackageManager(): Promise<PackageManager | null> {\n const managers: PackageManager[] = ['pnpm', 'bun', 'npm', 'yarn'];\n\n for (const manager of managers) {\n try {\n if (manager === 'npm') {\n const { stdout } = await execAsync(`npm list -g ${DEFAULT_PACKAGE_NAME} --depth=0`);\n if (stdout.includes(DEFAULT_PACKAGE_NAME)) {\n return 'npm';\n }\n } else if (manager === 'pnpm') {\n const { stdout } = await execAsync(`pnpm list -g ${DEFAULT_PACKAGE_NAME} --depth=0`);\n if (stdout.includes(DEFAULT_PACKAGE_NAME)) {\n return 'pnpm';\n }\n } else if (manager === 'bun') {\n const { stdout } = await execAsync('bun pm ls -g');\n if (stdout.includes(DEFAULT_PACKAGE_NAME)) {\n return 'bun';\n }\n } else if (manager === 'yarn') {\n const { stdout } = await execAsync('yarn global list');\n if (stdout.includes(DEFAULT_PACKAGE_NAME)) {\n return 'yarn';\n }\n }\n } catch {}\n }\n\n return null;\n}\n\n/**\n * Get the update command for a specific package manager\n */\nexport function getUpdateCommand(\n manager: PackageManager,\n packageName: string = DEFAULT_PACKAGE_NAME\n): string {\n switch (manager) {\n case 'npm':\n return `npm install -g ${packageName}@latest`;\n case 'pnpm':\n return `pnpm add -g ${packageName}@latest`;\n case 'bun':\n return `bun add -g ${packageName}@latest`;\n case 'yarn':\n return `yarn global add ${packageName}@latest`;\n }\n}\n\n/**\n * Execute update command\n */\nexport async function executeUpdate(manager: PackageManager): Promise<void> {\n // Validate that the manager is one of the allowed values\n const allowedManagers: readonly PackageManager[] = ['npm', 'pnpm', 'bun', 'yarn'] as const;\n if (!allowedManagers.includes(manager)) {\n throw new Error(`Unsupported package manager: ${manager}`);\n }\n\n const command = getUpdateCommand(manager);\n await execAsync(command);\n}\n"],"mappings":";;;;;AAIA,MAAM,YAAY,UAAU,KAAK;;;;AAOjC,eAAsB,uBAAuD;AAG3E,MAAK,MAAM,WAFwB;EAAC;EAAQ;EAAO;EAAO;EAAO,CAG/D,KAAI;AACF,MAAI,YAAY,OAAO;GACrB,MAAM,EAAE,WAAW,MAAM,UAAU,eAAe,qBAAqB,YAAY;AACnF,OAAI,OAAO,SAAS,qBAAqB,CACvC,QAAO;aAEA,YAAY,QAAQ;GAC7B,MAAM,EAAE,WAAW,MAAM,UAAU,gBAAgB,qBAAqB,YAAY;AACpF,OAAI,OAAO,SAAS,qBAAqB,CACvC,QAAO;aAEA,YAAY,OAAO;GAC5B,MAAM,EAAE,WAAW,MAAM,UAAU,eAAe;AAClD,OAAI,OAAO,SAAS,qBAAqB,CACvC,QAAO;aAEA,YAAY,QAAQ;GAC7B,MAAM,EAAE,WAAW,MAAM,UAAU,mBAAmB;AACtD,OAAI,OAAO,SAAS,qBAAqB,CACvC,QAAO;;SAGL;AAGV,QAAO;;;;;AAMT,SAAgB,iBACd,SACA,cAAsB,sBACd;AACR,SAAQ,SAAR;EACE,KAAK,MACH,QAAO,kBAAkB,YAAY;EACvC,KAAK,OACH,QAAO,eAAe,YAAY;EACpC,KAAK,MACH,QAAO,cAAc,YAAY;EACnC,KAAK,OACH,QAAO,mBAAmB,YAAY;;;;;;AAO5C,eAAsB,cAAc,SAAwC;AAG1E,KAAI,CAD+C;EAAC;EAAO;EAAQ;EAAO;EAAO,CAC5D,SAAS,QAAQ,CACpC,OAAM,IAAI,MAAM,gCAAgC,UAAU;AAI5D,OAAM,UADU,iBAAiB,QAAQ,CACjB"}
|