avorelo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/bin/avorelo +9 -0
  4. package/package.json +135 -0
  5. package/scripts/README.md +40 -0
  6. package/scripts/cco-dashboard.js +252 -0
  7. package/scripts/cco-status.js +430 -0
  8. package/scripts/lib/activation/account-state.js +37 -0
  9. package/scripts/lib/activation/activation-runner.js +546 -0
  10. package/scripts/lib/activation/activation-self-healing.js +480 -0
  11. package/scripts/lib/activation/activation-state.js +83 -0
  12. package/scripts/lib/activation/activation-summary.js +191 -0
  13. package/scripts/lib/activation/adapters/claude-code.js +77 -0
  14. package/scripts/lib/activation/adapters/codex-cli.js +52 -0
  15. package/scripts/lib/activation/adapters/cursor.js +37 -0
  16. package/scripts/lib/activation/adapters/github-agent.js +39 -0
  17. package/scripts/lib/activation/adapters/terminal.js +42 -0
  18. package/scripts/lib/activation/adapters/vscode.js +39 -0
  19. package/scripts/lib/activation/adapters/windsurf.js +37 -0
  20. package/scripts/lib/activation/ai-surface-detector.js +151 -0
  21. package/scripts/lib/activation/connect-account.js +145 -0
  22. package/scripts/lib/activation/detect-environment.js +75 -0
  23. package/scripts/lib/activation/detect-hosts.js +62 -0
  24. package/scripts/lib/activation/format-activation-output.js +109 -0
  25. package/scripts/lib/activation/next-action.js +43 -0
  26. package/scripts/lib/activation/repair-engine.js +219 -0
  27. package/scripts/lib/activation-distribution-readiness.js +507 -0
  28. package/scripts/lib/adapter-conformance.js +176 -0
  29. package/scripts/lib/adapter-readiness.js +417 -0
  30. package/scripts/lib/adapter-safety-boundaries.js +335 -0
  31. package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
  32. package/scripts/lib/agent-access-governance.js +455 -0
  33. package/scripts/lib/agent-enforcement.js +765 -0
  34. package/scripts/lib/agent-policy-profile.js +210 -0
  35. package/scripts/lib/agent-security/action-evaluator.js +507 -0
  36. package/scripts/lib/agent-security/adapter-registry.js +98 -0
  37. package/scripts/lib/agent-security/auto-policy.js +139 -0
  38. package/scripts/lib/agent-security/bounded-scan.js +93 -0
  39. package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
  40. package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
  41. package/scripts/lib/agent-security/file-write-adapter.js +183 -0
  42. package/scripts/lib/agent-security/file-write-rules.js +178 -0
  43. package/scripts/lib/agent-security/index.js +3342 -0
  44. package/scripts/lib/agent-security/instruction-risk.js +181 -0
  45. package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
  46. package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
  47. package/scripts/lib/agent-security/package-action-adapter.js +175 -0
  48. package/scripts/lib/agent-security/package-action-rules.js +233 -0
  49. package/scripts/lib/agent-security/performance.js +148 -0
  50. package/scripts/lib/agent-security/permission-minimizer.js +403 -0
  51. package/scripts/lib/agent-security/scan-cache.js +74 -0
  52. package/scripts/lib/agent-security/source-trust.js +146 -0
  53. package/scripts/lib/ai-install-prompt.js +288 -0
  54. package/scripts/lib/ai-workspace-hygiene.js +1499 -0
  55. package/scripts/lib/alpha-activation.js +520 -0
  56. package/scripts/lib/alpha-feedback.js +263 -0
  57. package/scripts/lib/alpha-readiness-gate.js +332 -0
  58. package/scripts/lib/anti-gaming.js +169 -0
  59. package/scripts/lib/artifact-health.js +431 -0
  60. package/scripts/lib/attribution.js +180 -0
  61. package/scripts/lib/audit.js +289 -0
  62. package/scripts/lib/avorelo-skill-registry.js +810 -0
  63. package/scripts/lib/batch-jobs.js +71 -0
  64. package/scripts/lib/brain-pack.js +578 -0
  65. package/scripts/lib/brand-boundary.js +424 -0
  66. package/scripts/lib/brand.js +74 -0
  67. package/scripts/lib/browser-capability.js +1048 -0
  68. package/scripts/lib/browser-proof-preflight.js +321 -0
  69. package/scripts/lib/cache-readiness.js +187 -0
  70. package/scripts/lib/canonical-reentry.js +162 -0
  71. package/scripts/lib/capability-packs.js +314 -0
  72. package/scripts/lib/capability-recommender.js +512 -0
  73. package/scripts/lib/capability-registry.js +1059 -0
  74. package/scripts/lib/carry-forward-surfacing.js +194 -0
  75. package/scripts/lib/ccusage-adapter.js +188 -0
  76. package/scripts/lib/company-loop.js +1149 -0
  77. package/scripts/lib/config.js +637 -0
  78. package/scripts/lib/context-acquisition-plan.js +287 -0
  79. package/scripts/lib/context-budget-guard.js +170 -0
  80. package/scripts/lib/context-budget-scanner.js +257 -0
  81. package/scripts/lib/context-optimizer.js +715 -0
  82. package/scripts/lib/context-reduction-plan.js +178 -0
  83. package/scripts/lib/context-safety.js +88 -0
  84. package/scripts/lib/context-savings-engine.js +158 -0
  85. package/scripts/lib/cost-evidence.js +254 -0
  86. package/scripts/lib/cross-host-install-plan.js +308 -0
  87. package/scripts/lib/cross-host-install-readiness.js +237 -0
  88. package/scripts/lib/cross-host-value-flow.js +268 -0
  89. package/scripts/lib/dashboard.js +900 -0
  90. package/scripts/lib/design-partner-feedback.js +346 -0
  91. package/scripts/lib/entitlements.js +100 -0
  92. package/scripts/lib/execution-packet.js +559 -0
  93. package/scripts/lib/experimentation-events.js +547 -0
  94. package/scripts/lib/external-capability-compliance.js +107 -0
  95. package/scripts/lib/external-user-simulation.js +166 -0
  96. package/scripts/lib/failure-recovery-readiness.js +81 -0
  97. package/scripts/lib/failure-recovery.js +419 -0
  98. package/scripts/lib/feedback-intelligence.js +537 -0
  99. package/scripts/lib/feedback-signals.js +205 -0
  100. package/scripts/lib/file-integrity.js +68 -0
  101. package/scripts/lib/fsx.js +127 -0
  102. package/scripts/lib/full-readiness-gate.js +451 -0
  103. package/scripts/lib/guidance-builder.js +174 -0
  104. package/scripts/lib/hook-apply.js +1019 -0
  105. package/scripts/lib/hook-baseline.js +310 -0
  106. package/scripts/lib/hook-config-preview.js +275 -0
  107. package/scripts/lib/hook-contracts.js +290 -0
  108. package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
  109. package/scripts/lib/host-capability-matrix.js +351 -0
  110. package/scripts/lib/host-support-context.js +254 -0
  111. package/scripts/lib/http-hook-action.js +538 -0
  112. package/scripts/lib/install-ai-readiness.js +84 -0
  113. package/scripts/lib/install-intake-risk.js +1037 -0
  114. package/scripts/lib/install-journey-intelligence.js +329 -0
  115. package/scripts/lib/intervention-guidance.js +57 -0
  116. package/scripts/lib/known-limitations.js +115 -0
  117. package/scripts/lib/l8-path-truth.js +146 -0
  118. package/scripts/lib/launch-hardening-gate.js +436 -0
  119. package/scripts/lib/launch-readiness.js +628 -0
  120. package/scripts/lib/learning-memory.js +686 -0
  121. package/scripts/lib/lifecycle-hooks.js +802 -0
  122. package/scripts/lib/local-package-smoke.js +423 -0
  123. package/scripts/lib/local-pricing.js +299 -0
  124. package/scripts/lib/mcp-enforcement.js +311 -0
  125. package/scripts/lib/mcp-least-privilege-policy.js +303 -0
  126. package/scripts/lib/mcp-tool-inventory.js +388 -0
  127. package/scripts/lib/mcp-tool-risk.js +0 -0
  128. package/scripts/lib/memory.js +335 -0
  129. package/scripts/lib/metrics.js +699 -0
  130. package/scripts/lib/micro-proof.js +133 -0
  131. package/scripts/lib/next-run-context.js +436 -0
  132. package/scripts/lib/operating-value.js +1648 -0
  133. package/scripts/lib/optimization-v3.js +122 -0
  134. package/scripts/lib/orchestration/adapters/_shared.js +49 -0
  135. package/scripts/lib/orchestration/adapters/aider.js +18 -0
  136. package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
  137. package/scripts/lib/orchestration/adapters/codex.js +35 -0
  138. package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
  139. package/scripts/lib/orchestration/adapters/git.js +25 -0
  140. package/scripts/lib/orchestration/adapters/index.js +31 -0
  141. package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
  142. package/scripts/lib/orchestration/adapters/ollama.js +18 -0
  143. package/scripts/lib/orchestration/adapters/opencode.js +18 -0
  144. package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
  145. package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
  146. package/scripts/lib/orchestration/cli.js +438 -0
  147. package/scripts/lib/orchestration/execution-manager.js +279 -0
  148. package/scripts/lib/orchestration/handoff.js +314 -0
  149. package/scripts/lib/orchestration/index.js +456 -0
  150. package/scripts/lib/orchestration/inventory.js +47 -0
  151. package/scripts/lib/orchestration/model-discovery.js +498 -0
  152. package/scripts/lib/orchestration/model-profiler.js +170 -0
  153. package/scripts/lib/orchestration/model-profiles.js +252 -0
  154. package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
  155. package/scripts/lib/orchestration/proof-writer.js +349 -0
  156. package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
  157. package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
  158. package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
  159. package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
  160. package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
  161. package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
  162. package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
  163. package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
  164. package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
  165. package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
  166. package/scripts/lib/orchestration/risk-classifier.js +130 -0
  167. package/scripts/lib/orchestration/routing-policy.js +486 -0
  168. package/scripts/lib/orchestration/settings.js +112 -0
  169. package/scripts/lib/orchestration/state.js +165 -0
  170. package/scripts/lib/orchestration/verification-manager.js +138 -0
  171. package/scripts/lib/output-profiles.js +146 -0
  172. package/scripts/lib/package-content-audit.js +368 -0
  173. package/scripts/lib/package-runtime.js +278 -0
  174. package/scripts/lib/plan-surface.js +53 -0
  175. package/scripts/lib/plans.js +2318 -0
  176. package/scripts/lib/policy-provider.js +27 -0
  177. package/scripts/lib/prelaunch-activation-readiness.js +409 -0
  178. package/scripts/lib/prelaunch-evidence-store.js +816 -0
  179. package/scripts/lib/prelaunch-intelligence.js +869 -0
  180. package/scripts/lib/pricing-experiment.js +118 -0
  181. package/scripts/lib/pro-moment-events.js +77 -0
  182. package/scripts/lib/pro-moment-state.js +227 -0
  183. package/scripts/lib/pro-moments.js +1216 -0
  184. package/scripts/lib/product-learning-events.js +629 -0
  185. package/scripts/lib/project-profile.js +555 -0
  186. package/scripts/lib/prompt-compiler.js +280 -0
  187. package/scripts/lib/prompt-lint.js +32 -0
  188. package/scripts/lib/prompt-suggestions.js +52 -0
  189. package/scripts/lib/proof-canonical.js +398 -0
  190. package/scripts/lib/proof-drilldown.js +383 -0
  191. package/scripts/lib/proof-events.js +342 -0
  192. package/scripts/lib/proof-history.js +243 -0
  193. package/scripts/lib/proof-metrics.js +296 -0
  194. package/scripts/lib/proof-outcome-evidence.js +134 -0
  195. package/scripts/lib/proof-receipt.js +335 -0
  196. package/scripts/lib/proof-record.js +461 -0
  197. package/scripts/lib/public-activation-distribution-gate.js +258 -0
  198. package/scripts/lib/public-cli.js +3891 -0
  199. package/scripts/lib/public-distribution-truth.js +211 -0
  200. package/scripts/lib/public-install-claim-checker.js +294 -0
  201. package/scripts/lib/publish-provenance-readiness.js +283 -0
  202. package/scripts/lib/readiness-delta.js +218 -0
  203. package/scripts/lib/readiness-evidence-closure.js +196 -0
  204. package/scripts/lib/reentry-memory-capture.js +241 -0
  205. package/scripts/lib/reentry-memory-retrieval.js +302 -0
  206. package/scripts/lib/reentry-memory-status.js +146 -0
  207. package/scripts/lib/reentry-memory-store.js +178 -0
  208. package/scripts/lib/reentry-state.js +66 -0
  209. package/scripts/lib/release-candidate-bundle.js +166 -0
  210. package/scripts/lib/remediation.js +81 -0
  211. package/scripts/lib/repo-map.js +391 -0
  212. package/scripts/lib/run-improvements-lifecycle.js +330 -0
  213. package/scripts/lib/run-improvements.js +789 -0
  214. package/scripts/lib/runtime-decision-policy.js +387 -0
  215. package/scripts/lib/safe-path-engine.js +705 -0
  216. package/scripts/lib/safe-run-controller.js +887 -0
  217. package/scripts/lib/score.js +262 -0
  218. package/scripts/lib/seamless-enforcement.js +329 -0
  219. package/scripts/lib/seamless-outcome.js +689 -0
  220. package/scripts/lib/seamless-reality-gate.js +5043 -0
  221. package/scripts/lib/security-risk-classifier.js +511 -0
  222. package/scripts/lib/security-scan.js +384 -0
  223. package/scripts/lib/session-context-optimizer.js +1211 -0
  224. package/scripts/lib/session-timing.js +315 -0
  225. package/scripts/lib/skill-hygiene.js +805 -0
  226. package/scripts/lib/skill-packs.js +161 -0
  227. package/scripts/lib/skills-operating-layer.js +580 -0
  228. package/scripts/lib/smart-work-routing.js +768 -0
  229. package/scripts/lib/source-catalog.js +700 -0
  230. package/scripts/lib/status-value-summary.js +32 -0
  231. package/scripts/lib/support-bundle.js +578 -0
  232. package/scripts/lib/task-continuation.js +440 -0
  233. package/scripts/lib/test-helpers.js +15 -0
  234. package/scripts/lib/tier.js +38 -0
  235. package/scripts/lib/token-context-quality-gate.js +370 -0
  236. package/scripts/lib/token-cost-capture.js +187 -0
  237. package/scripts/lib/token-cost-intelligence.js +358 -0
  238. package/scripts/lib/token-efficiency-evidence.js +213 -0
  239. package/scripts/lib/token-evidence.js +699 -0
  240. package/scripts/lib/tokenish.js +17 -0
  241. package/scripts/lib/tool-output-sandbox.js +304 -0
  242. package/scripts/lib/trust-audit.js +136 -0
  243. package/scripts/lib/unified-events.js +396 -0
  244. package/scripts/lib/upgrade-interruption-recovery.js +407 -0
  245. package/scripts/lib/usage-ledger.js +201 -0
  246. package/scripts/lib/value-ledger.js +130 -0
  247. package/scripts/lib/value-proof-calibration.js +531 -0
  248. package/scripts/lib/visual-qa.js +231 -0
  249. package/scripts/lib/voice-alpha.js +29 -0
  250. package/scripts/lib/work-aware-orchestration.js +976 -0
  251. package/scripts/lib/work-control-receipts.js +577 -0
  252. package/scripts/lib/work-ledger.js +1123 -0
  253. package/scripts/lib/work-panel-preview.js +352 -0
  254. package/scripts/lib/workflow-discipline.js +280 -0
  255. package/scripts/lib/workflow-signals.js +419 -0
  256. package/scripts/lib/workspace-map.js +281 -0
  257. package/scripts/lib/workspace-registry.js +1367 -0
  258. package/scripts/lib/workspace-resolver.js +480 -0
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ const path = require("path");
4
+ const { inferModelRecord } = require("../model-profiler");
5
+ const { buildBaseToolRecord, envPresence, pathExists } = require("./common");
6
+
7
+ function discover(cwd, context = {}) {
8
+ const env = context.env || process.env;
9
+ const exists = context.commandExists;
10
+ const activeModel = env.AIDER_MODEL || null;
11
+ const installStatus = exists("aider", env)
12
+ || pathExists(path.join(cwd, ".aider.conf.yml"))
13
+ || pathExists(path.join(cwd, ".aider.model.settings.yml"))
14
+ || envPresence(env, "AIDER_MODEL")
15
+ ? "configured"
16
+ : "not_installed";
17
+ const availability = installStatus === "configured" ? "configured" : "unavailable";
18
+ const models = activeModel ? [
19
+ inferModelRecord({
20
+ toolId: "aider",
21
+ providerId: "aider",
22
+ modelId: activeModel,
23
+ availability: "configured",
24
+ source: env.AIDER_MODEL ? "env" : "inferred",
25
+ trustTier: "external",
26
+ privacyTier: "external_remote",
27
+ confidence: "low",
28
+ }),
29
+ ] : [];
30
+
31
+ return buildBaseToolRecord({
32
+ toolId: "aider",
33
+ label: "Aider",
34
+ providerId: "aider",
35
+ installStatus,
36
+ availability,
37
+ activeModel,
38
+ configuredModelSource: env.AIDER_MODEL ? "env:AIDER_MODEL" : null,
39
+ models,
40
+ supportedRoles: ["implementation", "refactor", "tests", "cli"],
41
+ costTier: "medium",
42
+ qualityTier: "high",
43
+ trustTier: "external",
44
+ privacyTier: "external_remote",
45
+ latencyTier: "medium",
46
+ });
47
+ }
48
+
49
+ module.exports = { discover };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ const path = require("path");
4
+ const { inferModelRecord } = require("../model-profiler");
5
+ const { buildBaseToolRecord, envPresence, safeReadJsonFile, findFirstModelValue, pathExists } = require("./common");
6
+
7
+ function discover(cwd, context = {}) {
8
+ const env = context.env || process.env;
9
+ const settings = safeReadJsonFile(path.join(cwd, ".claude", "settings.json"));
10
+ const localSettings = safeReadJsonFile(path.join(cwd, ".claude", "settings.local.json"));
11
+ const activeModel = env.ANTHROPIC_MODEL || findFirstModelValue(localSettings) || findFirstModelValue(settings) || null;
12
+ const baseUrl = env.ANTHROPIC_BASE_URL || null;
13
+ const gateway = Boolean(baseUrl && !/anthropic\.com/i.test(baseUrl));
14
+ const installStatus = pathExists(path.join(cwd, ".claude")) || pathExists(path.join(cwd, ".claude-plugin")) ? "configured" : "not_installed";
15
+ const availability = installStatus === "configured" || envPresence(env, "ANTHROPIC_AUTH_TOKEN") ? "configured" : "unavailable";
16
+ const models = activeModel ? [
17
+ inferModelRecord({
18
+ toolId: "claude_code",
19
+ providerId: gateway ? "gateway" : "anthropic",
20
+ modelId: activeModel,
21
+ displayName: activeModel,
22
+ availability: availability === "configured" ? "configured" : "unavailable",
23
+ source: env.ANTHROPIC_MODEL ? "env" : (localSettings ? "config" : "inferred"),
24
+ trustTier: gateway ? "unknown" : "trusted",
25
+ privacyTier: gateway ? "gateway_remote" : "trusted_remote",
26
+ confidence: "medium",
27
+ }),
28
+ ] : [];
29
+
30
+ return buildBaseToolRecord({
31
+ toolId: "claude_code",
32
+ label: "Claude Code",
33
+ providerId: gateway ? "gateway" : "anthropic",
34
+ installStatus,
35
+ availability,
36
+ activeModel,
37
+ configuredModelSource: env.ANTHROPIC_MODEL ? "env:ANTHROPIC_MODEL" : (localSettings ? ".claude/settings.local.json" : (settings ? ".claude/settings.json" : null)),
38
+ models,
39
+ supportedRoles: ["planning", "implementation", "review", "security", "tests", "docs", "ui", "cli"],
40
+ costTier: "high",
41
+ qualityTier: "high",
42
+ trustTier: gateway ? "unknown" : "trusted",
43
+ privacyTier: gateway ? "gateway_remote" : "trusted_remote",
44
+ latencyTier: "medium",
45
+ executionMode: context.surface === "claude_code" ? "in_session" : "handoff",
46
+ details: {
47
+ settingsPresent: Boolean(settings),
48
+ localSettingsPresent: Boolean(localSettings),
49
+ anthropicBaseUrlPresent: Boolean(baseUrl),
50
+ anthropicGatewayConfigured: gateway,
51
+ anthropicAuthTokenPresent: envPresence(env, "ANTHROPIC_AUTH_TOKEN"),
52
+ },
53
+ });
54
+ }
55
+
56
+ module.exports = { discover };
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ const { inferModelRecord } = require("../model-profiler");
4
+ const { buildBaseToolRecord, envPresence, pathExists } = require("./common");
5
+
6
+ function discover(cwd, context = {}) {
7
+ const env = context.env || process.env;
8
+ const exists = context.commandExists;
9
+ const activeModel = env.CODEX_MODEL || env.OPENAI_MODEL || null;
10
+ const installStatus = exists("codex", env) || pathExists(require("path").join(cwd, ".codex")) || envPresence(env, "CODEX_HOME") ? "configured" : "not_installed";
11
+ const availability = installStatus === "configured" || envPresence(env, "OPENAI_API_KEY") ? "confirmed" : "unavailable";
12
+ const models = activeModel ? [
13
+ inferModelRecord({
14
+ toolId: "codex",
15
+ providerId: "openai",
16
+ modelId: activeModel,
17
+ displayName: activeModel,
18
+ availability: availability === "confirmed" ? "confirmed" : "configured",
19
+ source: env.CODEX_MODEL || env.OPENAI_MODEL ? "env" : "inferred",
20
+ trustTier: "trusted",
21
+ privacyTier: "trusted_remote",
22
+ confidence: "high",
23
+ }),
24
+ ] : [];
25
+ return buildBaseToolRecord({
26
+ toolId: "codex",
27
+ label: "Codex / OpenAI CLI",
28
+ providerId: "openai",
29
+ installStatus,
30
+ availability,
31
+ activeModel,
32
+ configuredModelSource: env.CODEX_MODEL ? "env:CODEX_MODEL" : (env.OPENAI_MODEL ? "env:OPENAI_MODEL" : null),
33
+ models,
34
+ supportedRoles: ["planning", "implementation", "review", "tests", "refactor", "ui", "cli", "docs"],
35
+ costTier: "medium",
36
+ qualityTier: "high",
37
+ trustTier: "trusted",
38
+ privacyTier: "trusted_remote",
39
+ latencyTier: "medium",
40
+ executionMode: context.surface === "codex_cli" ? "in_session" : "handoff",
41
+ details: {
42
+ codexHomePresent: envPresence(env, "CODEX_HOME"),
43
+ openAiApiKeyPresent: envPresence(env, "OPENAI_API_KEY"),
44
+ },
45
+ safeForHighRisk: true,
46
+ });
47
+ }
48
+
49
+ module.exports = { discover };
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const os = require("os");
5
+ const path = require("path");
6
+ const { spawnSync } = require("child_process");
7
+
8
+ const LOCAL_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
9
+
10
+ function envPresence(env, name) {
11
+ return Boolean(env && Object.prototype.hasOwnProperty.call(env, name) && env[name]);
12
+ }
13
+
14
+ function pathExists(absPath) {
15
+ try {
16
+ return Boolean(absPath && fs.existsSync(absPath));
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ function safeReadJsonFile(absPath) {
23
+ try {
24
+ return JSON.parse(fs.readFileSync(absPath, "utf8").replace(/^\uFEFF/, ""));
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ function safeReadText(absPath) {
31
+ try {
32
+ return fs.readFileSync(absPath, "utf8");
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function safeHomeDir(options = {}) {
39
+ return options.homeDir || process.env.USERPROFILE || process.env.HOME || os.homedir() || "";
40
+ }
41
+
42
+ function parseCommandText(result) {
43
+ return `${String(result?.stdout || "")}\n${String(result?.stderr || "")}`.trim();
44
+ }
45
+
46
+ function runCommand(commandName, args, options = {}) {
47
+ const runner = options.commandRunner;
48
+ if (typeof runner === "function") return runner(commandName, args, options);
49
+ return spawnSync(commandName, args, {
50
+ cwd: options.cwd,
51
+ env: options.env,
52
+ encoding: "utf8",
53
+ timeout: options.timeoutMs || 1500,
54
+ });
55
+ }
56
+
57
+ function readLocalJson(url, options = {}) {
58
+ if (typeof options.httpGetJson === "function") {
59
+ return options.httpGetJson(url, options);
60
+ }
61
+
62
+ let parsed;
63
+ try {
64
+ parsed = new URL(url);
65
+ } catch {
66
+ return { ok: false, error: "invalid_url" };
67
+ }
68
+ if (!LOCAL_HOSTS.has(parsed.hostname)) return { ok: false, error: "non_local_url_blocked" };
69
+
70
+ const script = [
71
+ "const target = process.argv[1];",
72
+ "const { URL } = require('url');",
73
+ "const http = require('http');",
74
+ "const https = require('https');",
75
+ "let parsed;",
76
+ "try { parsed = new URL(target); } catch { process.stdout.write(JSON.stringify({ ok:false, error:'invalid_url' })); process.exit(0); }",
77
+ "const client = parsed.protocol === 'https:' ? https : http;",
78
+ "const req = client.request(parsed, { method: 'GET', timeout: 1200 }, (res) => {",
79
+ " let body = '';",
80
+ " res.on('data', (chunk) => { body += String(chunk || ''); });",
81
+ " res.on('end', () => {",
82
+ " try { process.stdout.write(JSON.stringify({ ok:true, statusCode:res.statusCode || 0, body: JSON.parse(body || '{}') })); }",
83
+ " catch { process.stdout.write(JSON.stringify({ ok:false, statusCode:res.statusCode || 0, error:'invalid_json' })); }",
84
+ " });",
85
+ "});",
86
+ "req.on('timeout', () => { req.destroy(new Error('timeout')); });",
87
+ "req.on('error', (error) => { process.stdout.write(JSON.stringify({ ok:false, error:String(error && error.message || error || 'request_failed') })); });",
88
+ "req.end();",
89
+ ].join("");
90
+
91
+ const result = spawnSync(process.execPath, ["-e", script, url], {
92
+ cwd: options.cwd,
93
+ env: options.env,
94
+ encoding: "utf8",
95
+ timeout: options.timeoutMs || 1800,
96
+ });
97
+ try {
98
+ return JSON.parse(String(result.stdout || "").trim() || "{}");
99
+ } catch {
100
+ return { ok: false, error: parseCommandText(result) || "request_failed" };
101
+ }
102
+ }
103
+
104
+ function findFirstModelValue(input) {
105
+ const seen = new Set();
106
+ const queue = [input];
107
+ while (queue.length > 0) {
108
+ const current = queue.shift();
109
+ if (!current || typeof current !== "object" || seen.has(current)) continue;
110
+ seen.add(current);
111
+ if (Array.isArray(current)) {
112
+ current.forEach((item) => queue.push(item));
113
+ continue;
114
+ }
115
+ for (const [key, value] of Object.entries(current)) {
116
+ if (/model/i.test(key) && typeof value === "string" && value.trim()) return value.trim();
117
+ if (value && typeof value === "object") queue.push(value);
118
+ }
119
+ }
120
+ return null;
121
+ }
122
+
123
+ function buildBaseToolRecord({
124
+ toolId,
125
+ label,
126
+ providerId,
127
+ installStatus = "not_installed",
128
+ availability = "unavailable",
129
+ activeModel = null,
130
+ configuredModelSource = null,
131
+ models = [],
132
+ supportedRoles = [],
133
+ costTier = "unknown",
134
+ qualityTier = "unknown",
135
+ trustTier = "unknown",
136
+ privacyTier = "unknown",
137
+ latencyTier = "unknown",
138
+ quotaSignal = "unknown",
139
+ quotaVisibility = "unknown",
140
+ executionMode = "handoff",
141
+ details = {},
142
+ safeForHighRisk = false,
143
+ }) {
144
+ return {
145
+ schemaVersion: 2,
146
+ toolId,
147
+ label,
148
+ providerId,
149
+ provider: providerId,
150
+ installStatus,
151
+ availability,
152
+ activeModel,
153
+ configuredModelSource,
154
+ models,
155
+ availableModels: models.map((model) => ({ id: model.modelId, availability: model.availability })),
156
+ candidateProfiles: [],
157
+ quotaVisibility,
158
+ quotaSignal,
159
+ costTier,
160
+ qualityTier,
161
+ trustTier,
162
+ privacyTier,
163
+ latencyTier,
164
+ supportedRoles,
165
+ recentHistory: { successes: 0, failures: 0, lastFailureReason: null, recentlyLimited: false, recentlyFailed: false },
166
+ lastFailureReason: null,
167
+ workerState: "unknown",
168
+ enabled: true,
169
+ safeForHighRisk,
170
+ executionMode,
171
+ details,
172
+ };
173
+ }
174
+
175
+ module.exports = {
176
+ envPresence,
177
+ pathExists,
178
+ safeReadJsonFile,
179
+ safeReadText,
180
+ safeHomeDir,
181
+ parseCommandText,
182
+ runCommand,
183
+ readLocalJson,
184
+ findFirstModelValue,
185
+ buildBaseToolRecord,
186
+ };
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+
3
+ const path = require("path");
4
+ const { inferModelRecord } = require("../model-profiler");
5
+ const { buildBaseToolRecord, envPresence, safeHomeDir, pathExists, runCommand, parseCommandText } = require("./common");
6
+
7
+ const LOGIN_PATTERNS = /(login|log in|sign in|authenticate|authentication required|not logged in|credentials required)/i;
8
+ const LIMIT_PATTERNS = /(quota|rate limit|credits exhausted|usage limit|too many requests)/i;
9
+
10
+ function installSignals(env, options = {}) {
11
+ const homeDir = safeHomeDir(options);
12
+ const npmRoot = path.join(homeDir, "AppData", "Roaming", "npm");
13
+ return {
14
+ homeConfigPresent: pathExists(path.join(homeDir, ".gemini")),
15
+ npmPackagePresent: pathExists(path.join(npmRoot, "node_modules", "@google", "gemini-cli")) || pathExists(path.join(npmRoot, "node_modules", "gemini-cli")),
16
+ envConfigured: envPresence(env, "GEMINI_API_KEY"),
17
+ };
18
+ }
19
+
20
+ function discover(cwd, context = {}) {
21
+ const env = context.env || process.env;
22
+ const exists = context.commandExists;
23
+ const signals = installSignals(env, context);
24
+ const commandPresent = exists("gemini", env) || exists("gemini-cli", env);
25
+ const activeModel = env.GEMINI_MODEL || null;
26
+ let installStatus = "not_installed";
27
+ let availability = "unavailable";
28
+ let loginProfile = signals.envConfigured ? "api" : "cli_login_or_unknown";
29
+ let probeReason = "command_missing";
30
+ let quotaSignal = "unknown";
31
+
32
+ if (commandPresent) {
33
+ const result = runCommand("gemini", ["--version"], {
34
+ cwd,
35
+ env,
36
+ timeoutMs: 1200,
37
+ commandRunner: context.commandRunner,
38
+ });
39
+ const output = parseCommandText(result);
40
+ if (Number(result?.status) === 0) {
41
+ installStatus = "configured";
42
+ availability = "confirmed";
43
+ probeReason = "version_ok";
44
+ } else if (LOGIN_PATTERNS.test(output)) {
45
+ installStatus = "configured";
46
+ availability = "needs_login";
47
+ loginProfile = "needs_login";
48
+ probeReason = "login_required";
49
+ } else if (LIMIT_PATTERNS.test(output)) {
50
+ installStatus = "configured";
51
+ availability = "recently_limited";
52
+ quotaSignal = "recently_limited";
53
+ probeReason = "quota_limited";
54
+ } else {
55
+ installStatus = "configured";
56
+ availability = "configured";
57
+ probeReason = "version_probe_failed";
58
+ }
59
+ } else if (signals.homeConfigPresent || signals.npmPackagePresent || signals.envConfigured) {
60
+ installStatus = "installed_not_on_path";
61
+ availability = "unavailable";
62
+ probeReason = "installed_not_on_path";
63
+ }
64
+
65
+ const models = activeModel ? [
66
+ inferModelRecord({
67
+ toolId: "gemini_cli",
68
+ providerId: "google",
69
+ modelId: activeModel,
70
+ availability: availability === "confirmed" ? "confirmed" : "candidate",
71
+ source: env.GEMINI_MODEL ? "env" : "inferred",
72
+ trustTier: "external",
73
+ privacyTier: "external_remote",
74
+ confidence: availability === "confirmed" ? "medium" : "low",
75
+ }),
76
+ ] : [];
77
+
78
+ return buildBaseToolRecord({
79
+ toolId: "gemini_cli",
80
+ label: "Gemini CLI",
81
+ providerId: "google",
82
+ installStatus,
83
+ availability,
84
+ activeModel,
85
+ configuredModelSource: env.GEMINI_MODEL ? "env:GEMINI_MODEL" : null,
86
+ models,
87
+ supportedRoles: ["planning", "docs", "tests", "ui"],
88
+ costTier: "low",
89
+ qualityTier: "medium",
90
+ trustTier: "external",
91
+ privacyTier: "external_remote",
92
+ latencyTier: "fast",
93
+ quotaSignal,
94
+ executionMode: "handoff",
95
+ details: {
96
+ geminiApiKeyPresent: signals.envConfigured,
97
+ homeConfigPresent: signals.homeConfigPresent,
98
+ npmPackagePresent: signals.npmPackagePresent,
99
+ loginProfile,
100
+ probeReason,
101
+ pathCommandPresent: commandPresent,
102
+ },
103
+ });
104
+ }
105
+
106
+ module.exports = { discover };
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+
3
+ const path = require("path");
4
+ const { inferModelRecord } = require("../model-profiler");
5
+ const { buildBaseToolRecord, envPresence, safeHomeDir, pathExists, readLocalJson } = require("./common");
6
+
7
+ const DEFAULT_BASE_URL = "http://127.0.0.1:1234";
8
+
9
+ function signals(env, options = {}) {
10
+ const homeDir = safeHomeDir(options);
11
+ return {
12
+ appPathPresent: pathExists(path.join(homeDir, "AppData", "Local", "Programs", "LM Studio", "LM Studio.exe"))
13
+ || pathExists(path.join("C:\\", "Program Files", "LM Studio", "LM Studio.exe")),
14
+ appDataPresent: pathExists(path.join(homeDir, "AppData", "Roaming", "LM Studio")),
15
+ baseUrl: env.LM_STUDIO_BASE_URL || env.LMSTUDIO_BASE_URL || DEFAULT_BASE_URL,
16
+ modelHint: env.LM_STUDIO_MODEL || env.LMSTUDIO_MODEL || null,
17
+ };
18
+ }
19
+
20
+ function discover(cwd, context = {}) {
21
+ const env = context.env || process.env;
22
+ const s = signals(env, context);
23
+ const baseUrl = String(s.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
24
+ const localServerUrl = `${baseUrl}/v1/models`;
25
+ const nativeModelsUrl = `${baseUrl}/api/v1/models`;
26
+ const signalPresent = s.appPathPresent || s.appDataPresent || Boolean(s.modelHint) || envPresence(env, "LM_STUDIO_BASE_URL") || envPresence(env, "LMSTUDIO_BASE_URL");
27
+
28
+ let response = { ok: false, error: "server_unreachable" };
29
+ if (context.refreshLevel === "full" || context.refreshLevel === "deep" || context.refreshLevel === "single_model") {
30
+ response = readLocalJson(localServerUrl, {
31
+ cwd,
32
+ env,
33
+ timeoutMs: 1800,
34
+ httpGetJson: context.httpGetJson,
35
+ });
36
+ if ((!response.ok || !Array.isArray(response.body?.data)) && context.tryNativeLmStudio === true) {
37
+ response = readLocalJson(nativeModelsUrl, {
38
+ cwd,
39
+ env,
40
+ timeoutMs: 1800,
41
+ httpGetJson: context.httpGetJson,
42
+ });
43
+ }
44
+ }
45
+
46
+ const payload = Array.isArray(response?.body?.data)
47
+ ? response.body.data
48
+ : Array.isArray(response?.body?.models)
49
+ ? response.body.models
50
+ : [];
51
+ const models = payload
52
+ .map((entry) => entry && typeof entry.id === "string" ? entry.id.trim() : "")
53
+ .filter(Boolean)
54
+ .map((modelId) => inferModelRecord({
55
+ toolId: "lm_studio",
56
+ providerId: "local",
57
+ modelId,
58
+ displayName: modelId,
59
+ availability: "confirmed",
60
+ source: response.ok ? "local_server" : "inferred",
61
+ trustTier: "local",
62
+ privacyTier: "local_only",
63
+ confidence: "medium",
64
+ metadata: {},
65
+ }));
66
+
67
+ const activeModel = s.modelHint || models[0]?.modelId || null;
68
+ let installStatus = "not_installed";
69
+ let availability = "unavailable";
70
+ let note = "not_running";
71
+ if (response?.ok && models.length > 0) {
72
+ installStatus = "available";
73
+ availability = "confirmed";
74
+ note = "models_found";
75
+ } else if (response?.ok && models.length === 0) {
76
+ installStatus = "configured_but_no_models";
77
+ availability = "configured";
78
+ note = "server_empty_models";
79
+ } else if (signalPresent) {
80
+ installStatus = "installed_or_configured_but_not_running";
81
+ availability = "unavailable";
82
+ note = "server_unreachable";
83
+ }
84
+
85
+ const supportedRoles = models.some((model) => model.profiles.includes("coding_candidate"))
86
+ ? ["planning", "summaries", "docs", "local_private", "repo_reading", "cheap_build", "implementation"]
87
+ : ["planning", "summaries", "docs", "local_private", "repo_reading"];
88
+
89
+ return buildBaseToolRecord({
90
+ toolId: "lm_studio",
91
+ label: "LM Studio",
92
+ providerId: "lm_studio",
93
+ installStatus,
94
+ availability,
95
+ activeModel,
96
+ configuredModelSource: s.modelHint ? (env.LM_STUDIO_MODEL ? "env:LM_STUDIO_MODEL" : "env:LMSTUDIO_MODEL") : null,
97
+ models,
98
+ supportedRoles,
99
+ costTier: "free_local",
100
+ qualityTier: models.some((model) => model.profiles.includes("coding_candidate")) ? "medium" : "unknown",
101
+ trustTier: "local",
102
+ privacyTier: "local_only",
103
+ latencyTier: "fast",
104
+ quotaSignal: "local",
105
+ executionMode: "handoff",
106
+ details: {
107
+ localServerUrl: baseUrl,
108
+ localServerReachable: Boolean(response?.ok),
109
+ appPathPresent: s.appPathPresent,
110
+ appDataPresent: s.appDataPresent,
111
+ modelCount: models.length,
112
+ probeReason: note,
113
+ nextAction: installStatus === "installed_or_configured_but_not_running" ? "Start LM Studio local server." : null,
114
+ },
115
+ });
116
+ }
117
+
118
+ module.exports = { discover };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ function enrichModels(models, options = {}) {
4
+ const enabled = options.enableMetadataEnrichment === true;
5
+ return {
6
+ enabled,
7
+ source: enabled ? "models_dev_stub" : "disabled",
8
+ models: Array.isArray(models) ? models.slice() : [],
9
+ };
10
+ }
11
+
12
+ module.exports = { enrichModels };
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+
3
+ const { inferModelRecord } = require("../model-profiler");
4
+ const { buildBaseToolRecord, envPresence, runCommand, readLocalJson } = require("./common");
5
+
6
+ function parseTags(payload) {
7
+ return Array.isArray(payload?.models) ? payload.models : [];
8
+ }
9
+
10
+ function discover(cwd, context = {}) {
11
+ const env = context.env || process.env;
12
+ const exists = context.commandExists;
13
+ const commandPresent = exists("ollama", env);
14
+ const host = env.OLLAMA_HOST || "http://localhost:11434";
15
+ let entries = [];
16
+ let localReachable = false;
17
+
18
+ if (context.refreshLevel === "full" || context.refreshLevel === "deep" || context.refreshLevel === "single_model") {
19
+ const response = readLocalJson(`${String(host).replace(/\/+$/, "")}/api/tags`, {
20
+ cwd,
21
+ env,
22
+ timeoutMs: 1800,
23
+ httpGetJson: context.httpGetJson,
24
+ });
25
+ if (response.ok) {
26
+ entries = parseTags(response.body);
27
+ localReachable = true;
28
+ } else if (commandPresent) {
29
+ const result = runCommand("ollama", ["list"], {
30
+ cwd,
31
+ env,
32
+ timeoutMs: 1200,
33
+ commandRunner: context.commandRunner,
34
+ });
35
+ if (Number(result?.status) === 0) {
36
+ entries = String(result.stdout || "")
37
+ .split(/\r?\n/)
38
+ .slice(1)
39
+ .map((line) => line.trim().split(/\s+/)[0])
40
+ .filter(Boolean)
41
+ .map((name) => ({ name }));
42
+ }
43
+ }
44
+ }
45
+
46
+ const models = entries.map((entry) => {
47
+ const modelId = entry.model || entry.name;
48
+ return inferModelRecord({
49
+ toolId: "ollama",
50
+ providerId: "local",
51
+ modelId,
52
+ displayName: modelId,
53
+ availability: "confirmed",
54
+ source: localReachable ? "local_server" : "cli",
55
+ trustTier: "local",
56
+ privacyTier: "local_only",
57
+ confidence: "medium",
58
+ metadata: {
59
+ family: entry.details?.family,
60
+ families: entry.details?.families || [],
61
+ notes: [
62
+ entry.details?.parameter_size ? `parameter_size=${entry.details.parameter_size}` : null,
63
+ entry.details?.quantization_level ? `quantization=${entry.details.quantization_level}` : null,
64
+ ].filter(Boolean),
65
+ },
66
+ });
67
+ });
68
+
69
+ const activeModel = env.OLLAMA_MODEL || models[0]?.modelId || null;
70
+ const installStatus = commandPresent || envPresence(env, "OLLAMA_HOST") ? "configured" : "not_installed";
71
+ const availability = models.length > 0 ? "confirmed" : (installStatus === "configured" ? "configured" : "unavailable");
72
+ const supportedRoles = models.some((model) => model.profiles.includes("coding_candidate"))
73
+ ? ["planning", "summaries", "docs", "repo_reading", "cheap_build", "local_private", "implementation"]
74
+ : ["planning", "summaries", "docs", "repo_reading", "local_private"];
75
+
76
+ return buildBaseToolRecord({
77
+ toolId: "ollama",
78
+ label: "Ollama",
79
+ providerId: "ollama",
80
+ installStatus,
81
+ availability,
82
+ activeModel,
83
+ configuredModelSource: env.OLLAMA_MODEL ? "env:OLLAMA_MODEL" : null,
84
+ models,
85
+ supportedRoles,
86
+ costTier: "free_local",
87
+ qualityTier: models.some((model) => model.profiles.includes("coding_candidate")) ? "medium" : "unknown",
88
+ trustTier: "local",
89
+ privacyTier: "local_only",
90
+ latencyTier: "fast",
91
+ quotaSignal: "local",
92
+ details: {
93
+ ollamaHostPresent: envPresence(env, "OLLAMA_HOST"),
94
+ localServerReachable: localReachable,
95
+ modelCount: models.length,
96
+ },
97
+ });
98
+ }
99
+
100
+ module.exports = { discover };