arol-ai 0.1.0 → 0.1.1
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/README.md +73 -48
- package/dist/cli.js +1 -0
- package/dist/data.js +14 -2
- package/dist/report.js +17 -15
- package/dist/scanner.js +82 -11
- package/package.json +1 -1
- package/src/data/deprecations.json +6 -0
package/README.md
CHANGED
|
@@ -35,25 +35,26 @@ arol-ai scan
|
|
|
35
35
|
|
|
36
36
|
```
|
|
37
37
|
arol · local deprecation scan
|
|
38
|
-
Scanned 128 files ·
|
|
38
|
+
Scanned 128 files · 1 API detected
|
|
39
39
|
|
|
40
|
-
⚠
|
|
40
|
+
⚠ 1 deprecation found (1 high, 0 medium, 0 low)
|
|
41
41
|
|
|
42
|
-
●
|
|
43
|
-
sunsets
|
|
44
|
-
The
|
|
45
|
-
|
|
42
|
+
● OpenAI · Assistants API (beta) HIGH
|
|
43
|
+
sunsets 2026-08-26 (in 84 days)
|
|
44
|
+
The Assistants API beta is being removed on Aug 26, 2026; requests to
|
|
45
|
+
/v1/assistants and /v1/threads will fail. Migrate to the Responses API +
|
|
46
|
+
Conversations API.
|
|
46
47
|
found in:
|
|
47
|
-
|
|
48
|
-
src/
|
|
49
|
-
→ migrate: https://
|
|
50
|
-
|
|
51
|
-
...
|
|
48
|
+
src/agents/run.ts:42 → beta.assistants
|
|
49
|
+
src/agents/run.ts:88 → beta.threads
|
|
50
|
+
→ migrate: https://platform.openai.com/docs/assistants/migration
|
|
52
51
|
|
|
53
52
|
These are today's deprecations. New ones land constantly — get
|
|
54
53
|
alerted before the next one breaks you → arol.ai
|
|
55
54
|
```
|
|
56
55
|
|
|
56
|
+
Note the citations point at the **exact source lines that use the deprecated API**, not at the manifest. Having the `openai` package installed is not enough on its own — your code has to actually call the removed surface.
|
|
57
|
+
|
|
57
58
|
When nothing is found:
|
|
58
59
|
|
|
59
60
|
```
|
|
@@ -62,20 +63,29 @@ When nothing is found:
|
|
|
62
63
|
|
|
63
64
|
## How detection works
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
Detection keys on **actual usage, not mere SDK presence.** Each dataset entry declares a `match` mode that decides what triggers it.
|
|
67
|
+
|
|
68
|
+
### `match: "pattern"` — the default
|
|
69
|
+
|
|
70
|
+
Flags **only** when one of the entry's `detect.patterns` regexes matches inside a scanned **source file** — i.e. your code actually references the deprecated endpoint, method, or model string. `detect.sdk` is just a scope hint here and is **never** a trigger on its own. This is the default and covers almost everything.
|
|
71
|
+
|
|
72
|
+
- Extensions scanned: `.js .mjs .cjs .jsx .ts .mts .cts .tsx .py .go`
|
|
73
|
+
- Skipped directories: `node_modules`, `.git`, `dist`, `build`, `.next`, `out`, `coverage`, `.venv`, `venv`, `vendor`
|
|
74
|
+
- Each hit records the **file path, line number, and matched text**, and one deprecation aggregates **all** of its matched locations into a single finding.
|
|
75
|
+
|
|
76
|
+
> Having the `openai` package in `requirements.txt` does **not** flag the Assistants API deprecation. Your code has to actually use `beta.assistants` / `beta.threads` (etc.).
|
|
77
|
+
|
|
78
|
+
### `match: "sdk"`
|
|
66
79
|
|
|
67
|
-
|
|
68
|
-
- `package.json` (`dependencies`, `devDependencies`, `peerDependencies`, `optionalDependencies`, plus simple npm `workspaces`)
|
|
69
|
-
- `requirements.txt` (Python)
|
|
70
|
-
- `go.mod` (Go)
|
|
80
|
+
Flags when a `detect.sdk` package appears in a manifest, **regardless of code** — for the rare "this whole SDK / version line is end-of-life" case.
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
### `match: "version"`
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
- Extensions scanned: `.js .mjs .cjs .jsx .ts .mts .cts .tsx .py .go`
|
|
76
|
-
- Skipped directories: `node_modules`, `.git`, `dist`, `build`, `.next`, `out`, `coverage`, `.venv`, `venv`, `vendor`
|
|
84
|
+
Flags when a `detect.sdk` package appears in a manifest **and** its declared version satisfies the entry's `version_range` (e.g. `"<3.0.0"`). Semver-style compare for npm; best-effort numeric compare for pip/go. If `version_range` is omitted, it behaves like `"sdk"`. *(No version entries ship today.)*
|
|
77
85
|
|
|
78
|
-
|
|
86
|
+
**Manifests parsed** (used by `sdk`/`version` modes): `package.json` (`dependencies`, `devDependencies`, `peerDependencies`, `optionalDependencies`, plus simple npm `workspaces`), `requirements.txt` (Python), and `go.mod` (Go). A dependency matches a `detect.sdk` name case-insensitively, with PyPI-style `_ . -` normalization.
|
|
87
|
+
|
|
88
|
+
The report cites **source code locations** for `pattern` findings, and the **manifest line** (`package.json → name@version`) for `sdk`/`version` findings.
|
|
79
89
|
|
|
80
90
|
## CLI
|
|
81
91
|
|
|
@@ -110,32 +120,45 @@ All detections are **data-driven** — the bundled dataset lives at
|
|
|
110
120
|
|
|
111
121
|
### Schema
|
|
112
122
|
|
|
123
|
+
The dataset is either a bare array of entries, or a `{ "deprecations": [ ... ] }` object. A typical `pattern` entry:
|
|
124
|
+
|
|
113
125
|
```jsonc
|
|
114
126
|
{
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
"migration_url": "https://docs.aws.amazon.com/.../migrating-to-v3.html",
|
|
132
|
-
"summary": "One or two sentences explaining the change and what to do."
|
|
133
|
-
}
|
|
134
|
-
]
|
|
127
|
+
"id": "openai-assistants-api", // unique, stable identifier (required)
|
|
128
|
+
"vendor": "OpenAI", // who owns the API (required)
|
|
129
|
+
"title": "Assistants API (beta)", // short headline (required)
|
|
130
|
+
"severity": "high", // "high" | "medium" | "low" (required)
|
|
131
|
+
"match": "pattern", // "pattern" (default) | "sdk" | "version"
|
|
132
|
+
"sunset_date": "2026-08-26", // ISO YYYY-MM-DD, or "" if no fixed date
|
|
133
|
+
"detect": {
|
|
134
|
+
"sdk": ["openai"], // scope hint for "pattern"; the trigger for "sdk"/"version"
|
|
135
|
+
"patterns": [ // regex strings matched against source files
|
|
136
|
+
"beta\\.assistants",
|
|
137
|
+
"beta\\.threads",
|
|
138
|
+
"/v1/assistants"
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
"migration_url": "https://platform.openai.com/docs/assistants/migration",
|
|
142
|
+
"summary": "One or two sentences explaining the change and what to do."
|
|
135
143
|
}
|
|
136
144
|
```
|
|
137
145
|
|
|
138
|
-
A
|
|
146
|
+
A `version` entry instead flags on the installed SDK version (no patterns needed):
|
|
147
|
+
|
|
148
|
+
```jsonc
|
|
149
|
+
{
|
|
150
|
+
"id": "example-sdk-v2-eol",
|
|
151
|
+
"vendor": "Example",
|
|
152
|
+
"title": "example-sdk v2 line end-of-life",
|
|
153
|
+
"severity": "medium",
|
|
154
|
+
"match": "version",
|
|
155
|
+
"version_range": "<3.0.0", // flags only when the declared version is in range
|
|
156
|
+
"sunset_date": "",
|
|
157
|
+
"detect": { "sdk": ["example-sdk"], "patterns": [] },
|
|
158
|
+
"migration_url": "https://example.com/migrate",
|
|
159
|
+
"summary": "Upgrade example-sdk to v3+."
|
|
160
|
+
}
|
|
161
|
+
```
|
|
139
162
|
|
|
140
163
|
### Field reference
|
|
141
164
|
|
|
@@ -145,19 +168,21 @@ A bare top-level array (`[ { ...entry }, ... ]`) is also accepted.
|
|
|
145
168
|
| `vendor` | string | ✓ | Displayed before the title. |
|
|
146
169
|
| `title` | string | ✓ | Short headline for the finding. |
|
|
147
170
|
| `severity` | `"high"` \| `"medium"` \| `"low"` | ✓ | Drives color, sort order, and `--fail-on`. |
|
|
171
|
+
| `match` | `"pattern"` \| `"sdk"` \| `"version"` | – | How the entry is triggered. **Defaults to `"pattern"`** when omitted. See [How detection works](#how-detection-works). |
|
|
172
|
+
| `version_range` | string | – | For `match: "version"` only — e.g. `"<3.0.0"`, `">=1.2.0"`, `"=2.1.0"`. If omitted, a `version` entry behaves like `"sdk"`. |
|
|
148
173
|
| `sunset_date` | string | – | ISO `YYYY-MM-DD`. Use `""` for unmaintained/no-fixed-date items; the report shows a relative hint (e.g. *"in 42 days"* / *"passed 12 days ago"*). |
|
|
149
|
-
| `detect.sdk` | string[] | – | Manifest dependency/module names.
|
|
150
|
-
| `detect.patterns` | string[] | – | **JSON-escaped** regular-expression strings (so `\d` becomes `\\d`). Matched
|
|
174
|
+
| `detect.sdk` | string[] | – | Manifest dependency/module names. For `match: "pattern"` this is only a **scope hint and never triggers** a finding; for `sdk`/`version` it is the trigger. |
|
|
175
|
+
| `detect.patterns` | string[] | – | **JSON-escaped** regular-expression strings (so `\d` becomes `\\d`). Matched against source-file contents; invalid regexes are skipped safely. Required (non-empty) for `match: "pattern"`. |
|
|
151
176
|
| `migration_url` | string | – | Link shown in the report. |
|
|
152
177
|
| `summary` | string | – | One or two sentences of guidance. |
|
|
153
178
|
|
|
154
|
-
>
|
|
179
|
+
> A `pattern` entry with no `patterns`, or an `sdk`/`version` entry with no `sdk`, can never fire and is dropped at load time.
|
|
155
180
|
|
|
156
181
|
### Writing good patterns
|
|
157
182
|
|
|
158
|
-
- Patterns are matched **case-sensitively** with the global flag over each file's contents; line
|
|
159
|
-
-
|
|
160
|
-
-
|
|
183
|
+
- Patterns are matched **case-sensitively** with the global flag over each file's contents; the file path, line number, and matched text are reported.
|
|
184
|
+
- Match the **deprecated surface itself** — the method/property (`beta\.assistants`), endpoint path (`/v1/threads`), or model string (`claude-opus-4-20250514`) — not the import or the package name. Importing an SDK isn't usage; calling the removed API is.
|
|
185
|
+
- Escape backslashes (and literal dots) for JSON: a regex `beta\.assistants` is written `"beta\\.assistants"`.
|
|
161
186
|
- Avoid `^`/`$` line anchors — matching runs against the whole file, not line-by-line; use `\b` word boundaries instead.
|
|
162
187
|
|
|
163
188
|
## Development
|
package/dist/cli.js
CHANGED
|
@@ -103,6 +103,7 @@ function runScan(targetPath, opts) {
|
|
|
103
103
|
vendor: f.deprecation.vendor,
|
|
104
104
|
title: f.deprecation.title,
|
|
105
105
|
severity: f.deprecation.severity,
|
|
106
|
+
match: f.deprecation.match,
|
|
106
107
|
sunset_date: f.deprecation.sunset_date,
|
|
107
108
|
migration_url: f.deprecation.migration_url,
|
|
108
109
|
summary: f.deprecation.summary,
|
package/dist/data.js
CHANGED
|
@@ -37,6 +37,7 @@ exports.loadDeprecations = loadDeprecations;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const SEVERITIES = ["high", "medium", "low"];
|
|
40
|
+
const MATCH_MODES = ["pattern", "sdk", "version"];
|
|
40
41
|
/**
|
|
41
42
|
* Locate the bundled deprecations.json. Tries several candidate locations so the
|
|
42
43
|
* tool works both when running the compiled output (dist/) from a published
|
|
@@ -80,16 +81,27 @@ function coerceDeprecation(raw) {
|
|
|
80
81
|
const detect = r.detect;
|
|
81
82
|
const sdk = detect && isStringArray(detect.sdk) ? detect.sdk : [];
|
|
82
83
|
const patterns = detect && isStringArray(detect.patterns) ? detect.patterns : [];
|
|
83
|
-
//
|
|
84
|
-
|
|
84
|
+
// Default to "pattern" — detection keys on real usage, not SDK presence.
|
|
85
|
+
const match = MATCH_MODES.includes(r.match)
|
|
86
|
+
? r.match
|
|
87
|
+
: "pattern";
|
|
88
|
+
const version_range = isNonEmptyString(r.version_range)
|
|
89
|
+
? r.version_range
|
|
90
|
+
: undefined;
|
|
91
|
+
// Drop entries that can never fire under their match mode.
|
|
92
|
+
if (match === "pattern" && patterns.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
if ((match === "sdk" || match === "version") && sdk.length === 0)
|
|
85
95
|
return null;
|
|
86
96
|
return {
|
|
87
97
|
id: r.id,
|
|
88
98
|
vendor: r.vendor,
|
|
89
99
|
title: r.title,
|
|
90
100
|
severity: r.severity,
|
|
101
|
+
match,
|
|
91
102
|
sunset_date: typeof r.sunset_date === "string" ? r.sunset_date : "",
|
|
92
103
|
detect: { sdk, patterns },
|
|
104
|
+
version_range,
|
|
93
105
|
migration_url: typeof r.migration_url === "string" ? r.migration_url : "",
|
|
94
106
|
summary: typeof r.summary === "string" ? r.summary : "",
|
|
95
107
|
};
|
package/dist/report.js
CHANGED
|
@@ -67,22 +67,24 @@ function sunsetPhrase(s, sunsetDate, now) {
|
|
|
67
67
|
// Past or imminent sunsets are the urgent ones.
|
|
68
68
|
return days <= 30 ? s.red(base + hint) : s.yellow(base + hint);
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
70
|
+
/** One line per source location: "path:line → matched text". */
|
|
71
71
|
function formatPatternMatches(s, finding) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
// De-duplicate identical file:line:text triples and order by file then line.
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
const items = finding.patternMatches.filter((pm) => {
|
|
75
|
+
const key = `${pm.file}:${pm.line}:${pm.text}`;
|
|
76
|
+
if (seen.has(key))
|
|
77
|
+
return false;
|
|
78
|
+
seen.add(key);
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
items.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
|
|
82
|
+
const MAX = 12;
|
|
83
|
+
const shown = items.slice(0, MAX);
|
|
84
|
+
const lines = shown.map((pm) => `${s.cyan(pm.file)}${s.gray(":")}${pm.line} ${s.gray("→")} ${pm.text}`);
|
|
85
|
+
const extra = items.length - shown.length;
|
|
86
|
+
if (extra > 0) {
|
|
87
|
+
lines.push(s.gray(`+${extra} more location${extra === 1 ? "" : "s"}`));
|
|
86
88
|
}
|
|
87
89
|
return lines;
|
|
88
90
|
}
|
package/dist/scanner.js
CHANGED
|
@@ -133,9 +133,9 @@ function scanContent(content, relPath, compiled, sink) {
|
|
|
133
133
|
if (seenLines.has(line))
|
|
134
134
|
continue; // one record per line per pattern
|
|
135
135
|
seenLines.add(line);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const text =
|
|
136
|
+
// Cite the matched substring itself (e.g. "beta.assistants"), normalized
|
|
137
|
+
// and length-capped, so the report points at exactly what triggered.
|
|
138
|
+
const text = (m[0] ?? "").replace(/\s+/g, " ").trim().slice(0, 120);
|
|
139
139
|
if (!recorded) {
|
|
140
140
|
recorded = [];
|
|
141
141
|
sink.set(deprecation.id, recorded);
|
|
@@ -171,6 +171,57 @@ function matchManifests(deprecations, refs) {
|
|
|
171
171
|
}
|
|
172
172
|
return byId;
|
|
173
173
|
}
|
|
174
|
+
/** Best-effort parse of a dotted numeric version from a declared string. */
|
|
175
|
+
function parseVersionNumbers(raw) {
|
|
176
|
+
if (!raw)
|
|
177
|
+
return null;
|
|
178
|
+
// Pull the first dotted-number run, ignoring ^ ~ >= <= operators and a "v" prefix.
|
|
179
|
+
const m = /(\d+(?:\.\d+)*)/.exec(raw);
|
|
180
|
+
if (!m)
|
|
181
|
+
return null;
|
|
182
|
+
return m[1].split(".").map((n) => parseInt(n, 10));
|
|
183
|
+
}
|
|
184
|
+
function compareVersions(a, b) {
|
|
185
|
+
const len = Math.max(a.length, b.length);
|
|
186
|
+
for (let i = 0; i < len; i++) {
|
|
187
|
+
const x = a[i] ?? 0;
|
|
188
|
+
const y = b[i] ?? 0;
|
|
189
|
+
if (x !== y)
|
|
190
|
+
return x < y ? -1 : 1;
|
|
191
|
+
}
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Best-effort check that a declared version satisfies a simple range such as
|
|
196
|
+
* "<3.0.0", ">=1.2.0", or "=2.1.0" / "2.1.0". Semver-ish: compares dotted numbers.
|
|
197
|
+
* Returns true when no range is given; false when a range is required but the
|
|
198
|
+
* declared version can't be parsed (stay conservative — don't over-flag).
|
|
199
|
+
*/
|
|
200
|
+
function versionInRange(declared, range) {
|
|
201
|
+
if (!range)
|
|
202
|
+
return true; // no constraint → presence already established by caller
|
|
203
|
+
const rm = /^\s*(<=|>=|<|>|={1,3})?\s*v?(\d+(?:\.\d+)*)\s*$/.exec(range);
|
|
204
|
+
if (!rm)
|
|
205
|
+
return true; // unparseable range → don't invent a false constraint
|
|
206
|
+
const op = rm[1] || "=";
|
|
207
|
+
const target = rm[2].split(".").map((n) => parseInt(n, 10));
|
|
208
|
+
const have = parseVersionNumbers(declared);
|
|
209
|
+
if (!have)
|
|
210
|
+
return false;
|
|
211
|
+
const cmp = compareVersions(have, target);
|
|
212
|
+
switch (op) {
|
|
213
|
+
case "<":
|
|
214
|
+
return cmp < 0;
|
|
215
|
+
case "<=":
|
|
216
|
+
return cmp <= 0;
|
|
217
|
+
case ">":
|
|
218
|
+
return cmp > 0;
|
|
219
|
+
case ">=":
|
|
220
|
+
return cmp >= 0;
|
|
221
|
+
default:
|
|
222
|
+
return cmp === 0;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
174
225
|
/**
|
|
175
226
|
* Scan a repository for deprecation usage.
|
|
176
227
|
* @param root repo root to scan.
|
|
@@ -178,11 +229,15 @@ function matchManifests(deprecations, refs) {
|
|
|
178
229
|
*/
|
|
179
230
|
function scanRepo(root, deprecations) {
|
|
180
231
|
const absRoot = path.resolve(root);
|
|
181
|
-
//
|
|
232
|
+
// Partition by match mode: "pattern" entries key on real source usage, while
|
|
233
|
+
// "sdk"/"version" entries key on the manifest.
|
|
234
|
+
const patternDeps = deprecations.filter((d) => d.match === "pattern");
|
|
235
|
+
const manifestDeps = deprecations.filter((d) => d.match === "sdk" || d.match === "version");
|
|
236
|
+
// 1. Manifest scan (drives sdk/version entries; also lists the manifests read).
|
|
182
237
|
const { refs, manifests } = (0, manifests_1.collectManifestDeps)(absRoot);
|
|
183
|
-
const manifestMatches = matchManifests(
|
|
184
|
-
// 2. Inline scan.
|
|
185
|
-
const compiled = compileDeprecations(
|
|
238
|
+
const manifestMatches = matchManifests(manifestDeps, refs);
|
|
239
|
+
// 2. Inline source scan (drives pattern entries — usage, not mere presence).
|
|
240
|
+
const compiled = compileDeprecations(patternDeps);
|
|
186
241
|
const patternSink = new Map();
|
|
187
242
|
const files = fast_glob_1.default.sync([`**/*.{${SOURCE_EXTENSIONS.join(",")}}`], {
|
|
188
243
|
cwd: absRoot,
|
|
@@ -215,14 +270,30 @@ function scanRepo(root, deprecations) {
|
|
|
215
270
|
scannedFiles++;
|
|
216
271
|
scanContent(content, rel, compiled, patternSink);
|
|
217
272
|
}
|
|
218
|
-
// 3.
|
|
273
|
+
// 3. Build findings — one per deprecation, evaluated per its match mode.
|
|
219
274
|
const findings = [];
|
|
220
275
|
for (const deprecation of deprecations) {
|
|
276
|
+
if (deprecation.match === "pattern") {
|
|
277
|
+
// Flag ONLY on a real source hit; manifest/SDK presence is irrelevant here.
|
|
278
|
+
const pm = patternSink.get(deprecation.id) ?? [];
|
|
279
|
+
if (pm.length === 0)
|
|
280
|
+
continue;
|
|
281
|
+
findings.push({ deprecation, manifestMatches: [], patternMatches: pm });
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// "sdk" / "version": evaluate against the manifest.
|
|
221
285
|
const mm = manifestMatches.get(deprecation.id) ?? [];
|
|
222
|
-
|
|
223
|
-
if (mm.length === 0 && pm.length === 0)
|
|
286
|
+
if (mm.length === 0)
|
|
224
287
|
continue;
|
|
225
|
-
|
|
288
|
+
if (deprecation.match === "version") {
|
|
289
|
+
const inRange = mm.filter((m) => versionInRange(m.version, deprecation.version_range));
|
|
290
|
+
if (inRange.length === 0)
|
|
291
|
+
continue;
|
|
292
|
+
findings.push({ deprecation, manifestMatches: inRange, patternMatches: [] });
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
// "sdk": mere presence in a manifest is enough.
|
|
296
|
+
findings.push({ deprecation, manifestMatches: mm, patternMatches: [] });
|
|
226
297
|
}
|
|
227
298
|
return { scannedFiles, manifestsScanned: manifests, findings };
|
|
228
299
|
}
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"vendor": "OpenAI",
|
|
5
5
|
"title": "Assistants API (beta)",
|
|
6
6
|
"severity": "high",
|
|
7
|
+
"match": "pattern",
|
|
7
8
|
"sunset_date": "2026-08-26",
|
|
8
9
|
"detect": {
|
|
9
10
|
"sdk": ["openai"],
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
"vendor": "Anthropic",
|
|
24
25
|
"title": "Claude Sonnet 4 & Opus 4",
|
|
25
26
|
"severity": "high",
|
|
27
|
+
"match": "pattern",
|
|
26
28
|
"sunset_date": "2026-06-15",
|
|
27
29
|
"detect": {
|
|
28
30
|
"sdk": ["@anthropic-ai/sdk", "anthropic"],
|
|
@@ -42,6 +44,7 @@
|
|
|
42
44
|
"vendor": "Anthropic",
|
|
43
45
|
"title": "Retired Claude models (Haiku 3, 3.5/3.7 Sonnet, Claude 2.x)",
|
|
44
46
|
"severity": "high",
|
|
47
|
+
"match": "pattern",
|
|
45
48
|
"sunset_date": "2026-04-20",
|
|
46
49
|
"detect": {
|
|
47
50
|
"sdk": ["@anthropic-ai/sdk", "anthropic"],
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
"vendor": "Google (Gemini)",
|
|
64
67
|
"title": "Gemini 2.5 Pro / Flash / Flash-Lite",
|
|
65
68
|
"severity": "high",
|
|
69
|
+
"match": "pattern",
|
|
66
70
|
"sunset_date": "2026-10-16",
|
|
67
71
|
"detect": {
|
|
68
72
|
"sdk": ["@google/generative-ai", "@google/genai", "google-generativeai"],
|
|
@@ -81,6 +85,7 @@
|
|
|
81
85
|
"vendor": "Google (Gemini)",
|
|
82
86
|
"title": "Gemini 2.0 Flash family",
|
|
83
87
|
"severity": "high",
|
|
88
|
+
"match": "pattern",
|
|
84
89
|
"sunset_date": "2026-06-01",
|
|
85
90
|
"detect": {
|
|
86
91
|
"sdk": ["@google/generative-ai", "@google/genai", "google-generativeai"],
|
|
@@ -100,6 +105,7 @@
|
|
|
100
105
|
"vendor": "Google (Gemini)",
|
|
101
106
|
"title": "Gemini 1.0 / 1.5 models",
|
|
102
107
|
"severity": "high",
|
|
108
|
+
"match": "pattern",
|
|
103
109
|
"sunset_date": "2026-04-29",
|
|
104
110
|
"detect": {
|
|
105
111
|
"sdk": ["@google/generative-ai", "@google/genai", "google-generativeai"],
|