@cassiomc1/forgeloop 1.12.0 → 1.14.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 (249) hide show
  1. package/.github/copilot-instructions.md +1 -1
  2. package/AGENTS.md +1 -1
  3. package/AGENT_COMPATIBILITY.md +8 -0
  4. package/CLAUDE.md +1 -1
  5. package/CONTRIBUTING.md +90 -0
  6. package/DOCS_INDEX.md +46 -12
  7. package/ENG/c-development-eng.md +112 -0
  8. package/ENG/cpp-development-eng.md +109 -0
  9. package/ENG/dotnet-aspnetcore-development-eng.md +401 -0
  10. package/ENG/go-development-eng.md +103 -0
  11. package/ENG/java-development-eng.md +125 -0
  12. package/ENG/nodejs-backend-development-eng.md +605 -0
  13. package/ENG/php-development-eng.md +104 -0
  14. package/ENG/rust-development-eng.md +422 -0
  15. package/ENG/sec-code-eng.md +7 -7
  16. package/ENG/sql-development-eng.md +108 -0
  17. package/ENG/swift-development-eng.md +111 -0
  18. package/ENG/typescript-development-eng.md +108 -0
  19. package/EXECUTION_STATE.md +12 -0
  20. package/GUIDE_ROUTER.md +418 -9
  21. package/LOOP_ENGINEERING.md +28 -2
  22. package/ORCHESTRATOR_INTEGRATION.md +9 -5
  23. package/PROTOCOL_INTEGRATION.md +55 -2
  24. package/QUALITY_SCORECARD.md +1 -0
  25. package/README.md +78 -52
  26. package/TERMINOLOGY.md +2 -0
  27. package/THIRD_PARTY_NOTICES.md +19 -7
  28. package/THREAT_MODEL.md +140 -1
  29. package/completions/_forgeloop +22 -4
  30. package/completions/forgeloop.bash +40 -4
  31. package/completions/forgeloop.fish +130 -1
  32. package/docs/ADVISORY_CONTEXT.md +25 -0
  33. package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
  34. package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
  35. package/docs/AGENT_PROTOCOL_SUMMARY.md +81 -3
  36. package/docs/AGENT_SKILL.md +66 -0
  37. package/docs/ARTIFACT_REFERENCE.md +123 -0
  38. package/docs/AUDIT_UX.md +46 -0
  39. package/docs/BROWSER_VERIFICATION.md +136 -0
  40. package/docs/CLI_REFERENCE.md +392 -10
  41. package/docs/CODE_ATTESTATION.md +2 -2
  42. package/docs/DOCUMENTATION_GUIDE.md +34 -12
  43. package/docs/GETTING_STARTED.md +59 -0
  44. package/docs/JEV_BENCHMARKS.md +31 -0
  45. package/docs/MODEL_ROUTING.md +37 -0
  46. package/docs/OPENSRC_ADAPTER.md +241 -0
  47. package/docs/PACKAGE_CONTENTS.md +60 -19
  48. package/docs/PROVIDERS.md +126 -0
  49. package/docs/PROVIDER_ARCHITECTURE.md +199 -0
  50. package/docs/RECIPES.md +32 -0
  51. package/docs/RELEASE_CHECKLIST.md +66 -5
  52. package/docs/SECURITY_REVIEW.md +71 -0
  53. package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
  54. package/docs/TEST_INTELLIGENCE.md +29 -0
  55. package/docs/TEST_PRUNING.md +14 -0
  56. package/docs/TROUBLESHOOTING.md +298 -3
  57. package/docs/UNIVERSAL_INTEGRATION.md +31 -0
  58. package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
  59. package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
  60. package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
  61. package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
  62. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
  63. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
  64. package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
  65. package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
  66. package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
  67. package/docs/diagrams/README.md +13 -9
  68. package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
  69. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
  70. package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
  71. package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
  72. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
  73. package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
  74. package/docs/documentation-manifest.json +1397 -0
  75. package/docs/protocol-requirements.json +101 -0
  76. package/package.json +46 -4
  77. package/schemas/config.schema.json +14 -0
  78. package/schemas/context-plan.schema.json +18 -0
  79. package/schemas/routing-input.schema.json +1 -1
  80. package/schemas/semantic-decision.schema.json +46 -0
  81. package/schemas/test-utility.schema.json +44 -0
  82. package/scripts/CI_VALIDATORS.md +84 -11
  83. package/scripts/benchmark-jev.mjs +5 -0
  84. package/scripts/benchmark-test-intelligence.mjs +4 -0
  85. package/scripts/generate-agent-protocol-summary.mjs +40 -1
  86. package/scripts/generate-forgeloop-skill.mjs +133 -0
  87. package/scripts/jev-smoke.mjs +19 -0
  88. package/skills/forgeloop/README.md +9 -0
  89. package/skills/forgeloop/SKILL.md +77 -0
  90. package/skills/forgeloop/references/lifecycle.md +9 -0
  91. package/skills/forgeloop/references/recovery.md +7 -0
  92. package/skills/forgeloop/references/verification.md +7 -0
  93. package/src/adapters/agent-browser/assertions.js +47 -0
  94. package/src/adapters/agent-browser/commands.js +54 -0
  95. package/src/adapters/agent-browser/index.js +3 -0
  96. package/src/adapters/agent-browser/locator.js +40 -0
  97. package/src/adapters/agent-browser/process.js +215 -0
  98. package/src/adapters/agent-browser/provider.js +313 -0
  99. package/src/adapters/emulated-services/constants.js +24 -0
  100. package/src/adapters/emulated-services/index.js +7 -0
  101. package/src/adapters/emulated-services/process.js +162 -0
  102. package/src/adapters/emulated-services/provider.js +282 -0
  103. package/src/adapters/opensrc/normalize.js +90 -0
  104. package/src/adapters/opensrc/process.js +248 -0
  105. package/src/adapters/opensrc/provider.js +338 -0
  106. package/src/adapters/opensrc/search.js +264 -0
  107. package/src/adapters/typesafe/client.js +28 -0
  108. package/src/adapters/typesafe/engine.js +63 -0
  109. package/src/adapters/typesafe/normalize.js +41 -0
  110. package/src/cli.js +108 -0
  111. package/src/commands/checkpoint-revalidate.js +176 -0
  112. package/src/commands/context-plan.js +38 -0
  113. package/src/commands/contract-create.js +264 -0
  114. package/src/commands/contract-revise.js +236 -0
  115. package/src/commands/decision-show.js +14 -0
  116. package/src/commands/decision-status.js +22 -0
  117. package/src/commands/discover.js +41 -0
  118. package/src/commands/doctor.js +15 -0
  119. package/src/commands/gate-record.js +205 -0
  120. package/src/commands/gate-revalidate.js +137 -0
  121. package/src/commands/model-route.js +32 -0
  122. package/src/commands/next.js +19 -7
  123. package/src/commands/route.js +146 -18
  124. package/src/commands/semantic-plan.js +17 -0
  125. package/src/commands/task-abandon.js +224 -0
  126. package/src/commands/task-create.js +84 -25
  127. package/src/commands/task-list.js +22 -2
  128. package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
  129. package/src/commands/task-repair-contract-bootstrap.js +263 -0
  130. package/src/commands/test-inventory.js +5 -0
  131. package/src/commands/test-prune-plan.js +5 -0
  132. package/src/commands/test-prune-probe.js +5 -0
  133. package/src/commands/test-utility.js +5 -0
  134. package/src/commands/validate-protocol.js +10 -1
  135. package/src/config/guides.json +44 -0
  136. package/src/core/artifact-registry.js +24 -0
  137. package/src/core/audit-ux.js +514 -0
  138. package/src/core/browser-verification/constants.js +149 -0
  139. package/src/core/browser-verification/normalize.js +254 -0
  140. package/src/core/browser-verification/provider.js +519 -0
  141. package/src/core/browser-verification/service.js +115 -0
  142. package/src/core/build-script.js +151 -0
  143. package/src/core/c-cpp-project.js +143 -0
  144. package/src/core/checkpoint-revalidation.js +319 -0
  145. package/src/core/cli-command-definitions.js +249 -1
  146. package/src/core/command-executors.js +115 -3
  147. package/src/core/command-input.js +212 -102
  148. package/src/core/completion-artifacts.js +14 -5
  149. package/src/core/completion.js +4 -6
  150. package/src/core/config.js +3 -0
  151. package/src/core/context-compiler/budget.js +9 -0
  152. package/src/core/context-compiler/candidates.js +39 -0
  153. package/src/core/context-compiler/compiler.js +63 -0
  154. package/src/core/context-compiler/fingerprint.js +11 -0
  155. package/src/core/context-compiler/policy.js +13 -0
  156. package/src/core/context-compiler/result.js +23 -0
  157. package/src/core/contract-bootstrap-recovery.js +655 -0
  158. package/src/core/contract-presets.js +82 -0
  159. package/src/core/contract-revision.js +210 -0
  160. package/src/core/decision/artifact.js +69 -0
  161. package/src/core/decision/benchmarks.js +103 -0
  162. package/src/core/decision/cache.js +27 -0
  163. package/src/core/decision/constants.js +58 -0
  164. package/src/core/decision/cutover.js +34 -0
  165. package/src/core/decision/engine.js +22 -0
  166. package/src/core/decision/errors.js +68 -0
  167. package/src/core/decision/events.js +101 -0
  168. package/src/core/decision/freshness.js +19 -0
  169. package/src/core/decision/normalizers/index.js +115 -0
  170. package/src/core/decision/policy.js +18 -0
  171. package/src/core/decision/projection.js +16 -0
  172. package/src/core/decision/question-registry.js +201 -0
  173. package/src/core/decision/request.js +26 -0
  174. package/src/core/decision/resolver.js +130 -0
  175. package/src/core/decision/result.js +58 -0
  176. package/src/core/decision/service.js +156 -0
  177. package/src/core/decision/state-builder.js +65 -0
  178. package/src/core/decision/task-bindings.js +30 -0
  179. package/src/core/decision/test-provider.js +32 -0
  180. package/src/core/decision/thresholds.js +15 -0
  181. package/src/core/error-codes.js +281 -3
  182. package/src/core/events.js +226 -57
  183. package/src/core/evidence-readiness.js +9 -0
  184. package/src/core/execution-prerequisites.js +14 -0
  185. package/src/core/execution-profile.js +63 -38
  186. package/src/core/filesystem.js +1 -10
  187. package/src/core/gate-provenance.js +124 -0
  188. package/src/core/go-project.js +206 -0
  189. package/src/core/integration-invocation-policy.js +27 -4
  190. package/src/core/integration-resources.js +86 -61
  191. package/src/core/java-project.js +403 -0
  192. package/src/core/model-router/constants.js +10 -0
  193. package/src/core/model-router/policy.js +103 -0
  194. package/src/core/model-router/router.js +37 -0
  195. package/src/core/multi-language-project.js +117 -0
  196. package/src/core/next-action-model.js +58 -0
  197. package/src/core/next-action-phases.js +130 -42
  198. package/src/core/next-action-refresh.js +43 -9
  199. package/src/core/next-action-review-phase.js +7 -2
  200. package/src/core/next-action.js +35 -7
  201. package/src/core/next-explanation.js +63 -0
  202. package/src/core/phase.js +128 -10
  203. package/src/core/php-project.js +85 -0
  204. package/src/core/preflight-consistency.js +23 -9
  205. package/src/core/preflight-loaders.js +37 -5
  206. package/src/core/project-detection.js +1760 -52
  207. package/src/core/protocol-info.js +65 -0
  208. package/src/core/protocol.js +20 -0
  209. package/src/core/reconcile-closure.js +132 -53
  210. package/src/core/recovery-history.js +1 -0
  211. package/src/core/resumability.js +154 -44
  212. package/src/core/route-artifact.js +15 -1
  213. package/src/core/router.js +223 -4
  214. package/src/core/runtime-context.js +118 -61
  215. package/src/core/rust-project.js +400 -0
  216. package/src/core/schema-validation.js +3 -0
  217. package/src/core/security-review/constants.js +64 -0
  218. package/src/core/security-review/normalize.js +245 -0
  219. package/src/core/security-review/provider.js +204 -0
  220. package/src/core/security-review/service.js +134 -0
  221. package/src/core/semantic-planning/constants.js +19 -0
  222. package/src/core/semantic-planning/projection.js +94 -0
  223. package/src/core/semantic-planning/service.js +15 -0
  224. package/src/core/sources.js +37 -0
  225. package/src/core/sql-project.js +141 -0
  226. package/src/core/swift-project.js +200 -0
  227. package/src/core/task-claim-state.js +201 -1
  228. package/src/core/task-conflict-inspection.js +31 -5
  229. package/src/core/task-paths.js +13 -0
  230. package/src/core/task-recovery.js +1 -0
  231. package/src/core/templates.js +3 -0
  232. package/src/core/test-intelligence/benchmarks.js +68 -0
  233. package/src/core/test-intelligence/inventory.js +73 -0
  234. package/src/core/test-intelligence/prune.js +90 -0
  235. package/src/core/test-intelligence/semantic-state.js +15 -0
  236. package/src/core/test-intelligence/service.js +40 -0
  237. package/src/core/test-intelligence/utility.js +50 -0
  238. package/src/core/trace.js +11 -7
  239. package/src/core/transaction.js +1 -0
  240. package/src/core/typescript-project.js +349 -0
  241. package/src/core/xml-structure.js +123 -0
  242. package/src/integration.d.ts +492 -0
  243. package/src/integration.js +54 -0
  244. package/src/providers/README.md +47 -0
  245. package/src/providers/capabilities.js +46 -0
  246. package/src/providers/errors.js +15 -0
  247. package/src/providers/index.js +29 -0
  248. package/src/providers/json-snapshot.js +105 -0
  249. package/src/providers/registry.js +152 -0
@@ -0,0 +1,94 @@
1
+ import { FAILURE_CLASSES, DIAGNOSIS_STRATEGIES, REVIEW_FOCUSES } from "./constants.js";
2
+
3
+ function strings(value) {
4
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim()).map((item) => item.trim()) : [];
5
+ }
6
+
7
+ function text(input) {
8
+ return [input?.message, input?.error, input?.failure, input?.objective, ...(input?.paths ?? []), ...(input?.risks ?? [])]
9
+ .filter((value) => typeof value === "string").join(" ").toLowerCase();
10
+ }
11
+
12
+ function unique(values) { return [...new Set(values)]; }
13
+
14
+ function validateRecommendation(recommendation, allowed, label) {
15
+ if (recommendation === undefined || recommendation === null) return null;
16
+ const values = typeof recommendation === "string" ? [recommendation]
17
+ : recommendation && typeof recommendation === "object" && !Array.isArray(recommendation)
18
+ ? Object.entries(recommendation).filter(([, value]) => value === true).map(([key]) => key)
19
+ : strings(recommendation);
20
+ const unknown = values.filter((value) => !allowed.includes(value));
21
+ if (unknown.length > 0) {
22
+ const error = new Error(`${label} contains unknown semantic values: ${unknown.join(", ")}`);
23
+ error.code = "E_DECISION_RESULT_INVALID";
24
+ throw error;
25
+ }
26
+ return unique(values);
27
+ }
28
+
29
+ export function projectFailureTriage({ input = {}, semanticRecommendation = null } = {}) {
30
+ const candidate = semanticRecommendation?.failureClass ?? semanticRecommendation;
31
+ const value = validateRecommendation(candidate, FAILURE_CLASSES, "failure recommendation");
32
+ const inferred = /timeout|timed out/.test(text(input)) ? "timeout"
33
+ : /network|dns|connection|environment/.test(text(input)) ? "network/environment"
34
+ : /ownership|protocol|ledger|phase/.test(text(input)) ? "ownership/protocol mismatch"
35
+ : "unknown";
36
+ return {
37
+ decisionKind: "FAILURE_TRIAGE",
38
+ questionSetId: "failure-v1",
39
+ candidates: [...FAILURE_CLASSES],
40
+ ranked: unique([...(value ?? []), inferred]),
41
+ semanticRequired: true,
42
+ unknownEscalates: !value,
43
+ authority: "SEMANTIC_DECISION",
44
+ evidenceAuthority: "NONE",
45
+ };
46
+ }
47
+
48
+ export function projectDiagnosisPriority({ input = {}, semanticRecommendation = null } = {}) {
49
+ const candidate = semanticRecommendation?.priority ?? semanticRecommendation;
50
+ const value = validateRecommendation(candidate, DIAGNOSIS_STRATEGIES, "diagnosis recommendation");
51
+ const inferred = /race|concurr|lock/.test(text(input)) ? "inspect concurrency path"
52
+ : /state|ledger|phase|fingerprint/.test(text(input)) ? "inspect state transition"
53
+ : /depend|package|module/.test(text(input)) ? "inspect dependency behavior"
54
+ : "run narrower experiment";
55
+ return {
56
+ decisionKind: "DIAGNOSIS_PRIORITY",
57
+ questionSetId: "diagnosis-v1",
58
+ candidates: [...DIAGNOSIS_STRATEGIES],
59
+ ranked: unique([...(value ?? []), inferred]),
60
+ previouslyFailed: strings(input.previouslyFailed),
61
+ semanticRequired: true,
62
+ unknownEscalates: !value,
63
+ authority: "SEMANTIC_DECISION",
64
+ evidenceAuthority: "NONE",
65
+ };
66
+ }
67
+
68
+ export function projectReviewPlan({ input = {}, semanticRecommendation = null } = {}) {
69
+ const candidate = semanticRecommendation?.reviewFocus ?? semanticRecommendation;
70
+ const value = validateRecommendation(candidate, REVIEW_FOCUSES, "review recommendation");
71
+ const body = text(input);
72
+ const mandatory = ["needs_full_diff_context"];
73
+ if (/security|secret|credential|auth|permission/.test(body)) mandatory.push("needs_security_review");
74
+ if (/api|public|compatib/.test(body)) mandatory.push("needs_api_compatibility_review");
75
+ if (/race|concurr|lock/.test(body)) mandatory.push("needs_concurrency_review");
76
+ if (/package|release|dependency/.test(body)) mandatory.push("needs_package_review", "needs_dependency_review");
77
+ if (/doc|readme|guide/.test(body)) mandatory.push("needs_docs_review");
78
+ if (/migration|schema|database/.test(body)) mandatory.push("needs_migration_review");
79
+ if (/performance|timeout|latency/.test(body)) mandatory.push("needs_performance_review");
80
+ if (input.fullDiff === true || body.includes("full diff")) mandatory.push("needs_full_diff_context");
81
+ const ranked = unique([...mandatory, ...(value ?? [])]);
82
+ if (ranked.length === 0) ranked.push("needs_full_diff_context");
83
+ if (input.primaryModel === true || input.ambiguity === true) ranked.push("needs_primary_model");
84
+ return {
85
+ decisionKind: "REVIEW_PLAN",
86
+ questionSetId: "review-v1",
87
+ mandatory: unique(mandatory),
88
+ ranked: unique(ranked),
89
+ semanticRequired: true,
90
+ unknownEscalates: !value,
91
+ authority: "SEMANTIC_DECISION",
92
+ evidenceAuthority: "NONE",
93
+ };
94
+ }
@@ -0,0 +1,15 @@
1
+ import { DECISION_ERROR_CODES, decisionError } from "../decision/errors.js";
2
+ import { projectDiagnosisPriority, projectFailureTriage, projectReviewPlan } from "./projection.js";
3
+
4
+ const PROJECTORS = Object.freeze({
5
+ failure: projectFailureTriage,
6
+ diagnosis: projectDiagnosisPriority,
7
+ review: projectReviewPlan,
8
+ });
9
+
10
+ export function runSemanticPlan({ kind, input = {}, semanticRecommendation = null } = {}) {
11
+ const projector = PROJECTORS[kind];
12
+ if (!projector) throw decisionError(DECISION_ERROR_CODES.QUESTION_SET_UNKNOWN, `Unknown semantic plan kind: ${kind}`);
13
+ return projector({ input, semanticRecommendation });
14
+ }
15
+
@@ -1,5 +1,19 @@
1
+ import { CONTRACT_PRESET_IDS } from "./contract-presets.js";
1
2
  import { PROTOCOL_VERSION } from "./protocol.js";
2
3
 
4
+ const CONTRACT_PRESET_PREFIX = "contract-preset:";
5
+ const BUILTIN_CONTRACT_PRESET_REFS = new Set(
6
+ CONTRACT_PRESET_IDS.map((presetId) => `${CONTRACT_PRESET_PREFIX}${presetId}`),
7
+ );
8
+
9
+ export function isBuiltinContractPresetRef(ref) {
10
+ return typeof ref === "string" && BUILTIN_CONTRACT_PRESET_REFS.has(ref);
11
+ }
12
+
13
+ export function externalContractSourceRefs(refs = []) {
14
+ return refs.filter((ref) => !isBuiltinContractPresetRef(ref));
15
+ }
16
+
3
17
  export const SOURCE_REGISTRY_SCHEMA_VERSION = 1;
4
18
  export const SOURCE_KINDS = Object.freeze([
5
19
  "user-request",
@@ -84,3 +98,26 @@ export function assertSourceProvenance(registry, refs = [], { expectedKind } = {
84
98
  }
85
99
  return true;
86
100
  }
101
+
102
+ export function assertContractPresetRefs(refs = []) {
103
+ for (const ref of refs) {
104
+ if (typeof ref === "string" && ref.startsWith(CONTRACT_PRESET_PREFIX) && !isBuiltinContractPresetRef(ref)) {
105
+ const error = new Error(`Unknown built-in contract preset source: ${ref}`);
106
+ error.code = "E_PROFILE_SOURCE_UNKNOWN";
107
+ throw error;
108
+ }
109
+ }
110
+ return true;
111
+ }
112
+
113
+ export function assertContractSourceProvenance(registry, refs = []) {
114
+ assertContractPresetRefs(refs);
115
+ const externalRefs = externalContractSourceRefs(refs);
116
+ if (externalRefs.length === 0) return true;
117
+ if (!registry) {
118
+ const error = new Error("External contract source references require a source registry");
119
+ error.code = "E_PROFILE_SOURCE_MISSING";
120
+ throw error;
121
+ }
122
+ return assertSourceProvenance(registry, externalRefs);
123
+ }
@@ -0,0 +1,141 @@
1
+ import { parseXmlStructure } from "./xml-structure.js";
2
+
3
+ const SQL_STATEMENT_PATTERNS = Object.freeze([
4
+ /(?:^|[;\n])\s*select\b[\s\S]{0,240}\bfrom\s+[A-Za-z_][A-Za-z0-9_$]*(?:\s*\.\s*[A-Za-z_][A-Za-z0-9_$]*)*(?:\s*(?:;|$)|\s+(?:where|group|order|having|limit|offset|union|join|left|right|inner|outer|on)\b)/imu,
5
+ /(?:^|[;\n])\s*select\s+(?:distinct\s+)?[-+]?\d+(?:\s*,\s*[-+]?\d+)*\s*;?\s*(?:$|[\n])/imu,
6
+ /(?:^|[;\n])\s*insert\s+into\b/imu,
7
+ /(?:^|[;\n])\s*update\b[\s\S]{0,160}\bset\b/imu,
8
+ /(?:^|[;\n])\s*delete\s+from\b/imu,
9
+ /(?:^|[;\n])\s*merge\s+into\b/imu,
10
+ /(?:^|[;\n])\s*with\b[\s\S]{0,1024}\bas\s*\([\s\S]*\)\s*(?:select|insert|update|delete|merge)\b/imu,
11
+ /(?:^|[;\n])\s*create\s+(?:table|view|index|schema|database|function|procedure|trigger|type|sequence)\s+(?:if\s+not\s+exists\s+)?[A-Za-z_][A-Za-z0-9_$]*(?:\s*\.\s*[A-Za-z_][A-Za-z0-9_$]*)*(?:\s*(?:\(|;|$)|\s+(?:as|like)\b)/imu,
12
+ /(?:^|[;\n])\s*alter\s+(?:table|view|index|schema|database|function|procedure|trigger|type|sequence)\s+(?:if\s+exists\s+)?[A-Za-z_][A-Za-z0-9_$]*(?:\s*\.\s*[A-Za-z_][A-Za-z0-9_$]*)*(?:\s*(?:;|$)|\s+(?:add|drop|alter|rename|set|owner|enable|disable)\b)/imu,
13
+ /(?:^|[;\n])\s*drop\s+(?:table|view|index|schema|database|function|procedure|trigger|type|sequence)\s+(?:if\s+exists\s+)?[A-Za-z_][A-Za-z0-9_$]*(?:\s*\.\s*[A-Za-z_][A-Za-z0-9_$]*)*(?:\s*(?:;|$)|\s+(?:cascade|restrict)\b)/imu,
14
+ /(?:^|[;\n])\s*(?:grant|revoke)\b[\s\S]{0,240}\bon\b/imu,
15
+ /(?:^|[;\n])\s*begin(?:\s+(?:transaction|work))?\s*;?\s*(?:$|[\n])/imu,
16
+ /(?:^|[;\n])\s*(?:commit|rollback)(?:\s+(?:transaction|work))?\s*;?\s*(?:$|[\n])/imu,
17
+ /(?:^|[;\n])\s*savepoint\s+[A-Za-z_][A-Za-z0-9_$]*\s*;?/imu,
18
+ /(?:^|[;\n])\s*release\s+savepoint\s+[A-Za-z_][A-Za-z0-9_$]*\s*;?/imu,
19
+ ]);
20
+
21
+ function maskSqlComment(text, start, block) {
22
+ const lineEnd = text.slice(start).search(/[\n\r]/u);
23
+ const end = block ? text.indexOf("*/", start + 2) : lineEnd < 0 ? -1 : start + lineEnd;
24
+ if (block && end < 0) return null;
25
+ const finish = block ? end + 2 : (end < 0 ? text.length : end);
26
+ const value = text.slice(start, finish);
27
+ return { text: value.replace(/[^\n\r]/gu, " "), next: finish };
28
+ }
29
+
30
+ function maskSqlQuoted(text, start, quote) {
31
+ let result = " ";
32
+ for (let index = start + 1; index < text.length; index += 1) {
33
+ const character = text[index];
34
+ const next = text[index + 1];
35
+ if (character === quote && next === quote) {
36
+ result += " ";
37
+ index += 1;
38
+ } else if (character === quote) {
39
+ return { text: result + " ", next: index + 1 };
40
+ } else {
41
+ result += character === "\n" || character === "\r" ? character : " ";
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+
47
+ function maskSqlQuotedIdentifier(text, start, quote) {
48
+ for (let index = start + 1; index < text.length; index += 1) {
49
+ const character = text[index];
50
+ const next = text[index + 1];
51
+ if (character === quote && next === quote) {
52
+ index += 1;
53
+ } else if (character === quote) {
54
+ return { text: "__identifier__", next: index + 1 };
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+
60
+ function maskSqlBracketIdentifier(text, start) {
61
+ for (let index = start + 1; index < text.length; index += 1) {
62
+ if (text[index] === "]") {
63
+ if (text[index + 1] === "]") {
64
+ index += 1;
65
+ } else {
66
+ return { text: "__identifier__", next: index + 1 };
67
+ }
68
+ }
69
+ }
70
+ return null;
71
+ }
72
+
73
+ function maskSqlDollarQuote(text, start) {
74
+ const marker = text.slice(start).match(/^\$[A-Za-z_][A-Za-z0-9_]*\$|^\$\$/u)?.[0];
75
+ if (!marker) return null;
76
+ const end = text.indexOf(marker, start + marker.length);
77
+ if (end < 0) return { invalid: true };
78
+ const finish = end + marker.length;
79
+ return { text: text.slice(start, finish).replace(/[^\n\r]/gu, " "), next: finish };
80
+ }
81
+
82
+ function maskSqlToken(text, index) {
83
+ const character = text[index];
84
+ const next = text[index + 1];
85
+ if (character === "-" && next === "-") {
86
+ return maskSqlComment(text, index, false);
87
+ }
88
+ if (character === "/" && next === "*") return maskSqlComment(text, index, true);
89
+ if (character === "'") return maskSqlQuoted(text, index, character);
90
+ if (character === '"' || character === "`") return maskSqlQuotedIdentifier(text, index, character);
91
+ if (character === "[") return maskSqlBracketIdentifier(text, index);
92
+ if (character === "$") {
93
+ const dollarQuote = maskSqlDollarQuote(text, index);
94
+ if (dollarQuote?.invalid) return null;
95
+ return dollarQuote ?? { text: character, next: index + 1 };
96
+ }
97
+ return { text: character, next: index + 1 };
98
+ }
99
+
100
+ function maskSql(text) {
101
+ let result = "";
102
+ for (let index = 0; index < text.length;) {
103
+ const segment = maskSqlToken(text, index);
104
+ if (!segment) return null;
105
+ result += segment.text;
106
+ index = segment.next;
107
+ }
108
+ return result;
109
+ }
110
+
111
+ export function looksLikeSql(text) {
112
+ if (typeof text !== "string" || text.length > 512 * 1024 || /\r(?!\n)/u.test(text)) return false;
113
+ const masked = maskSql(text);
114
+ return masked !== null && SQL_STATEMENT_PATTERNS.some((pattern) => pattern.test(masked));
115
+ }
116
+
117
+ export function sqlSignal(text) {
118
+ if (!looksLikeSql(text)) return null;
119
+ const masked = maskSql(text);
120
+ return masked === null ? null : SQL_STATEMENT_PATTERNS.find((pattern) => pattern.test(masked))?.source ?? "statement";
121
+ }
122
+
123
+ function childValues(node, name) {
124
+ return node.children
125
+ .filter((child) => child.name.toLowerCase() === name)
126
+ .map((child) => child.text.trim())
127
+ .filter(Boolean);
128
+ }
129
+
130
+ export function parseSqlProject(text) {
131
+ const document = parseXmlStructure(text);
132
+ if (!document || document.root.name.toLowerCase() !== "project") return { valid: false, database: false };
133
+ const sdk = document.root.attributes.Sdk ?? document.root.attributes.sdk ?? "";
134
+ const databaseMarkers = [
135
+ sdk.toLowerCase().startsWith("microsoft.build.sql/"),
136
+ childValues(document.root, "dsp").length > 0,
137
+ document.nodes.some((node) => ["databaseproject", "sqlscript"].includes(node.name.toLowerCase())),
138
+ ];
139
+ const database = databaseMarkers.some(Boolean);
140
+ return { valid: database, database };
141
+ }
@@ -0,0 +1,200 @@
1
+ import { createLanguageProject, C_SOURCE_EXTENSIONS, CPP_SOURCE_EXTENSIONS, SWIFT_SOURCE_EXTENSIONS, pathBelongsToRoot, portablePath } from "./multi-language-project.js";
2
+ import { extractBuildCalls, maskBuildScript, quotedBuildArguments } from "./build-script.js";
3
+
4
+ function invalidSwift() {
5
+ return { valid: false, swift: false, c: false, cpp: false };
6
+ }
7
+
8
+ function stripSwiftComments(text) {
9
+ let result = "";
10
+ let state = "code";
11
+ let escaped = false;
12
+ let blockDepth = 0;
13
+ for (let index = 0; index < text.length; index += 1) {
14
+ const character = text[index];
15
+ const next = text[index + 1];
16
+ if (state === "string") {
17
+ result += character;
18
+ if (escaped) escaped = false;
19
+ else if (character === "\\") escaped = true;
20
+ else if (character === '"') state = "code";
21
+ } else if (state === "line-comment") {
22
+ if (character === "\n") {
23
+ result += character;
24
+ state = "code";
25
+ } else result += " ";
26
+ } else if (state === "block-comment") {
27
+ if (character === "/" && next === "*") {
28
+ blockDepth += 1;
29
+ result += " ";
30
+ index += 1;
31
+ } else if (character === "*" && next === "/") {
32
+ blockDepth -= 1;
33
+ result += " ";
34
+ index += 1;
35
+ if (blockDepth === 0) state = "code";
36
+ } else result += character === "\n" ? "\n" : " ";
37
+ } else if (character === '"') {
38
+ result += character;
39
+ state = "string";
40
+ } else if (character === "/" && next === "/") {
41
+ result += " ";
42
+ index += 1;
43
+ state = "line-comment";
44
+ } else if (character === "/" && next === "*") {
45
+ result += " ";
46
+ index += 1;
47
+ blockDepth = 1;
48
+ state = "block-comment";
49
+ } else result += character;
50
+ }
51
+ return state === "block-comment" ? null : result;
52
+ }
53
+
54
+ function maskSwiftStrings(text) {
55
+ let result = "";
56
+ let state = "code";
57
+ let escaped = false;
58
+ let delimiter = null;
59
+ for (let index = 0; index < text.length; index += 1) {
60
+ const character = text[index];
61
+ const rawMatch = character === "#" ? text.slice(index).match(/^(#+)("{1,3})/u) : null;
62
+ if (state === "string") {
63
+ if (escaped) escaped = false;
64
+ else if (character === "\\") escaped = true;
65
+ else if (text.startsWith(delimiter, index)) {
66
+ result += " ".repeat(delimiter.length);
67
+ index += delimiter.length - 1;
68
+ state = "code";
69
+ delimiter = null;
70
+ continue;
71
+ }
72
+ result += character === "\n" ? "\n" : " ";
73
+ } else if (character === '"') {
74
+ delimiter = text.startsWith('"""', index) ? '"""' : '"';
75
+ state = "string";
76
+ result += " ".repeat(delimiter.length);
77
+ index += delimiter.length - 1;
78
+ } else if (rawMatch) {
79
+ delimiter = `${rawMatch[2]}${rawMatch[1]}`;
80
+ state = "string";
81
+ result += " ".repeat(rawMatch[0].length);
82
+ index += rawMatch[0].length - 1;
83
+ } else {
84
+ result += character;
85
+ }
86
+ }
87
+ return state === "string" ? null : result;
88
+ }
89
+
90
+ function maskSwiftLexicalNoise(text) {
91
+ const withoutComments = stripSwiftComments(text);
92
+ return withoutComments === null ? null : maskSwiftStrings(withoutComments);
93
+ }
94
+
95
+ function hasBalancedSwiftDelimiters(source) {
96
+ const expectedClosers = new Map([
97
+ ["(", ")"],
98
+ ["{", "}"],
99
+ ["[", "]"],
100
+ ]);
101
+ const stack = [];
102
+ for (const character of source) {
103
+ if (expectedClosers.has(character)) {
104
+ stack.push(expectedClosers.get(character));
105
+ } else if (")]}".includes(character) && stack.pop() !== character) {
106
+ return false;
107
+ }
108
+ }
109
+ return stack.length === 0;
110
+ }
111
+
112
+ export function parseSwiftPackage(text) {
113
+ if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidSwift();
114
+ const toolsVersion = /^\s*\/\/\s*swift-tools-version:\s*\d+(?:\.\d+){1,2}\s*$/mu.test(text);
115
+ const source = maskSwiftLexicalNoise(text);
116
+ const packageDescription = source !== null && /\bimport\s+PackageDescription\b/u.test(source);
117
+ const balanced = source !== null && hasBalancedSwiftDelimiters(source);
118
+ const packageDeclaration = source !== null && /\bPackage\s*\(/u.test(source);
119
+ return {
120
+ valid: toolsVersion && packageDescription && packageDeclaration && balanced,
121
+ swift: toolsVersion && packageDescription && packageDeclaration && balanced,
122
+ c: false,
123
+ cpp: false,
124
+ };
125
+ }
126
+
127
+ export function parseXcodeProject(text) {
128
+ if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidSwift();
129
+ const source = stripSwiftComments(text);
130
+ const swift = source !== null && /\bSWIFT_VERSION\s*=/u.test(source) && /\.swift\b/u.test(source);
131
+ return { valid: swift, swift, c: false, cpp: false };
132
+ }
133
+
134
+ export function parseSwiftCMake(text) {
135
+ if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidSwift();
136
+ const source = maskBuildScript(text);
137
+ const swift = source !== null && /\b(?:LANGUAGES[^\n)]*\bSwift\b|enable_language\s*\(\s*Swift\b)/iu.test(source);
138
+ return { valid: swift, swift, c: false, cpp: false };
139
+ }
140
+
141
+ export function parseSwiftMeson(text) {
142
+ if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidSwift();
143
+ const calls = extractBuildCalls(text, ["project", "add_languages"]);
144
+ const swift = Boolean(calls?.some((call) => {
145
+ const values = quotedBuildArguments(call.body) ?? [];
146
+ return (call.name === "project" ? values.slice(1) : values)
147
+ .some((value) => value.toLowerCase() === "swift");
148
+ }));
149
+ return { valid: swift, swift, c: false, cpp: false };
150
+ }
151
+
152
+ function sourceEvidence(sourceFiles, targetRoot, projectRoot, projectRoots) {
153
+ const owns = (file) => pathBelongsToRoot(portablePath(targetRoot, file.path), projectRoot, projectRoots);
154
+ return {
155
+ swift: sourceFiles.some((file) => SWIFT_SOURCE_EXTENSIONS.has(file.extension) && owns(file)),
156
+ c: sourceFiles.some((file) => C_SOURCE_EXTENSIONS.has(file.extension) && owns(file)),
157
+ cpp: sourceFiles.some((file) => CPP_SOURCE_EXTENSIONS.has(file.extension) && owns(file)),
158
+ };
159
+ }
160
+
161
+ export function swiftSourceLooksExecutable(text) {
162
+ const source = maskSwiftLexicalNoise(text);
163
+ return source !== null && /\b(?:import|class|struct|enum|protocol|func|let|var)\b/u.test(source);
164
+ }
165
+
166
+ export function inspectSwiftProject({ projectRoot, manifestRelative, manifestText, manifestName, targetRoot, sourceFiles, projectRoots, directClaim = false }) {
167
+ const normalizedManifestName = manifestName.toLowerCase();
168
+ const parsed = normalizedManifestName === "package.swift"
169
+ ? parseSwiftPackage(manifestText)
170
+ : normalizedManifestName === "project.pbxproj"
171
+ ? parseXcodeProject(manifestText)
172
+ : normalizedManifestName === "meson.build"
173
+ ? parseSwiftMeson(manifestText)
174
+ : parseSwiftCMake(manifestText);
175
+ const source = sourceEvidence(sourceFiles, targetRoot, projectRoot, projectRoots);
176
+ const swift = parsed.swift
177
+ && (normalizedManifestName !== "package.swift" || source.swift || directClaim);
178
+ const frameworks = [];
179
+ if (swift) frameworks.push("swift");
180
+ if (normalizedManifestName === "package.swift" && parsed.valid && source.c) frameworks.push("c");
181
+ if (normalizedManifestName === "package.swift" && parsed.valid && source.cpp) frameworks.push("cpp");
182
+ const primary = frameworks.length > 0;
183
+ const primarySignals = [];
184
+ const manifestSignal = normalizedManifestName === "package.swift"
185
+ ? "package"
186
+ : normalizedManifestName === "project.pbxproj" ? "xcode" : "build";
187
+ if (swift) primarySignals.push(`${manifestRelative}:${manifestSignal}`);
188
+ if (normalizedManifestName === "package.swift" && parsed.valid && source.c) primarySignals.push(`${projectRoot}/source:c`);
189
+ if (normalizedManifestName === "package.swift" && parsed.valid && source.cpp) primarySignals.push(`${projectRoot}/source:cpp`);
190
+ return createLanguageProject({
191
+ kind: "swift",
192
+ root: projectRoot,
193
+ manifest: manifestRelative,
194
+ frameworks,
195
+ primary,
196
+ primarySignals,
197
+ supportingSignals: [],
198
+ internal: { ...parsed, valid: parsed.valid, source },
199
+ });
200
+ }