@ossiq/cli-linux-x64 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/bin/ossiq/_internal/attrs-26.1.0.dist-info/INSTALLER +1 -0
  2. package/bin/ossiq/_internal/attrs-26.1.0.dist-info/METADATA +199 -0
  3. package/bin/ossiq/_internal/attrs-26.1.0.dist-info/RECORD +37 -0
  4. package/bin/ossiq/_internal/attrs-26.1.0.dist-info/REQUESTED +0 -0
  5. package/bin/ossiq/_internal/attrs-26.1.0.dist-info/WHEEL +4 -0
  6. package/bin/ossiq/_internal/attrs-26.1.0.dist-info/licenses/LICENSE +21 -0
  7. package/bin/ossiq/_internal/base_library.zip +0 -0
  8. package/bin/ossiq/_internal/cel/cel.cpython-313-x86_64-linux-gnu.so +0 -0
  9. package/bin/ossiq/_internal/certifi/cacert.pem +3959 -0
  10. package/bin/ossiq/_internal/certifi/py.typed +0 -0
  11. package/bin/ossiq/_internal/charset_normalizer/cd.cpython-313-x86_64-linux-gnu.so +0 -0
  12. package/bin/ossiq/_internal/charset_normalizer/md.cpython-313-x86_64-linux-gnu.so +0 -0
  13. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/INSTALLER +1 -0
  14. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/METADATA +261 -0
  15. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/RECORD +16 -0
  16. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/REQUESTED +0 -0
  17. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/WHEEL +5 -0
  18. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/entry_points.txt +2 -0
  19. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/licenses/LICENSE +201 -0
  20. package/bin/ossiq/_internal/common_expression_language-0.10.0.dist-info/sboms/cel.cyclonedx.json +2072 -0
  21. package/bin/ossiq/_internal/libgcc_s.so.1 +0 -0
  22. package/bin/ossiq/_internal/libpython3.13.so.1.0 +0 -0
  23. package/bin/ossiq/_internal/libstdc++.so.6 +0 -0
  24. package/bin/ossiq/_internal/ossiq/data/SKILL.md +313 -0
  25. package/bin/ossiq/_internal/ossiq/domain/README.md +373 -0
  26. package/bin/ossiq/_internal/ossiq/solver/README.md +155 -0
  27. package/bin/ossiq/_internal/ossiq/strategy/README.md +182 -0
  28. package/bin/ossiq/_internal/ossiq/ui/html_templates/filter_format_highlight_days.html +7 -0
  29. package/bin/ossiq/_internal/ossiq/ui/html_templates/spa_app.html +18125 -0
  30. package/bin/ossiq/_internal/ossiq/ui/html_templates/tag_versions_difference.html +33 -0
  31. package/bin/ossiq/_internal/ossiq/ui/renderers/export/README.md +207 -0
  32. package/bin/ossiq/_internal/ossiq/ui/renderers/export/schemas/export_schema_v1.5.json +1637 -0
  33. package/bin/ossiq/_internal/ossiq/ui/renderers/export/schemas/export_schema_v1.5_standard.json +1164 -0
  34. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/INSTALLER +1 -0
  35. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/METADATA +385 -0
  36. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/RECORD +13 -0
  37. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/REQUESTED +0 -0
  38. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/WHEEL +4 -0
  39. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/direct_url.json +1 -0
  40. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/entry_points.txt +2 -0
  41. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/licenses/AUTHORS +8 -0
  42. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/licenses/LICENSE +661 -0
  43. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/uv_build.json +1 -0
  44. package/bin/ossiq/_internal/ossiq-0.1.12.dist-info/uv_cache.json +1 -0
  45. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/INSTALLER +1 -0
  46. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/METADATA +171 -0
  47. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/RECORD +154 -0
  48. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/REQUESTED +0 -0
  49. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/WHEEL +5 -0
  50. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/licenses/AUTHORS.rst +11 -0
  51. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/licenses/LICENSE +27 -0
  52. package/bin/ossiq/_internal/prompt_toolkit-3.0.53.dist-info/top_level.txt +1 -0
  53. package/bin/ossiq/_internal/pycard.cpython-313-x86_64-linux-gnu.so +0 -0
  54. package/bin/ossiq/_internal/pydantic-2.13.5.dist-info/INSTALLER +1 -0
  55. package/bin/ossiq/_internal/pydantic-2.13.5.dist-info/METADATA +1307 -0
  56. package/bin/ossiq/_internal/pydantic-2.13.5.dist-info/RECORD +113 -0
  57. package/bin/ossiq/_internal/pydantic-2.13.5.dist-info/REQUESTED +0 -0
  58. package/bin/ossiq/_internal/pydantic-2.13.5.dist-info/WHEEL +4 -0
  59. package/bin/ossiq/_internal/pydantic-2.13.5.dist-info/licenses/LICENSE +21 -0
  60. package/bin/ossiq/_internal/pydantic_core/_pydantic_core.cpython-313-x86_64-linux-gnu.so +0 -0
  61. package/bin/ossiq/_internal/pyformula.cpython-313-x86_64-linux-gnu.so +0 -0
  62. package/bin/ossiq/_internal/pysolvers.cpython-313-x86_64-linux-gnu.so +0 -0
  63. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/INSTALLER +1 -0
  64. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/LICENSE +22 -0
  65. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/METADATA +324 -0
  66. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/RECORD +10 -0
  67. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/REQUESTED +0 -0
  68. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/WHEEL +6 -0
  69. package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/top_level.txt +1 -0
  70. package/bin/ossiq/_internal/setuptools/_vendor/jaraco/text/Lorem ipsum.txt +2 -0
  71. package/bin/ossiq/_internal/wcwidth/py.typed +0 -0
  72. package/bin/ossiq/_internal/wcwidth/textwrap.py,cover +664 -0
  73. package/bin/ossiq/_internal/yaml/_yaml.cpython-313-x86_64-linux-gnu.so +0 -0
  74. package/bin/ossiq/ossiq +0 -0
  75. package/package.json +24 -0
@@ -0,0 +1,182 @@
1
+ # Update Strategy — the dependency update pyramid
2
+
3
+ Pure decision module that answers one question per package: *given the evidence OSS IQ has
4
+ gathered, which version should be recommended, and why?* It sits where `risk/` sits — it computes
5
+ a verdict from facts, and never touches the registry, the solver, or a `ScanRecord` directly.
6
+
7
+ ```
8
+ ┌──────────────┐
9
+ │ cutting-edge │ + prereleases
10
+ ┌─┴──────────────┴─┐
11
+ │ latest │ + widen the constraint to reach newest
12
+ ┌─┴──────────────────┴─┐
13
+ │ standard │ + any drift, inside the declared range
14
+ ┌─┴──────────────────────┴─┐
15
+ │ deprecation │ + end-of-life packages
16
+ ┌─┴──────────────────────────┴─┐
17
+ │ security │ exploitable CVEs only, minimal diff
18
+ └──────────────────────────────┘
19
+ ```
20
+
21
+ Each tier is a strict superset of the one below it: every motive the lower tier admits, the higher
22
+ tier admits too, and it can reach at least as far up the version ladder. `security` proposes the
23
+ smallest possible diff that clears exploitable CVEs; `cutting-edge` proposes whatever is newest,
24
+ prereleases included.
25
+
26
+ ---
27
+
28
+ ## Module map
29
+
30
+ ```
31
+ strategy/
32
+ ├── pyramid.py UpdateStrategy + the two tables (ADMITTED_MOTIVES, MAX_REACH) that define the pyramid,
33
+ │ plus the tier sets (MINIMAL_DIFF_TIERS, PRERELEASE_TIERS, MODULE_BREAK_TIERS)
34
+ ├── motive.py UpdateMotive + PackageFacts + classify_motives() — why a package may move
35
+ ├── targeting.py Candidate, StrategySelection, select_target() — the selector itself
36
+ ├── compare.py compare_target() — judges a caller's chosen target against the recommendation
37
+ └── overrides.py StrategyPlan + parse_strategy / parse_overrides — per-run, per-package tiers
38
+ ```
39
+
40
+ ---
41
+
42
+ ## The two axes
43
+
44
+ A strategy is not one dial, it is two, kept separate on purpose:
45
+
46
+ - **Motive** — *why* a package is allowed to move: an exploitable CVE, an end-of-life marker, or
47
+ plain drift.
48
+ - **Reach** — *how far up the ladder* it may go on that motive: inside the declared range, inside
49
+ the installed major line, or anywhere.
50
+
51
+ ### `ADMITTED_MOTIVES`
52
+
53
+ | Tier | exploitable_cve | end_of_life | drift |
54
+ |---|:---:|:---:|:---:|
55
+ | `security` | ✓ | | |
56
+ | `deprecation` | ✓ | ✓ | |
57
+ | `standard` | ✓ | ✓ | ✓ |
58
+ | `latest` | ✓ | ✓ | ✓ |
59
+ | `cutting-edge` | ✓ | ✓ | ✓ |
60
+
61
+ ### `MAX_REACH`
62
+
63
+ | Tier | Base reach | Escalates to `LATEST` when... |
64
+ |---|---|---|
65
+ | `security` | in-range | an admitted motive is `exploitable_cve` (no in-range version clears the CVE) |
66
+ | `deprecation` | in-range | an admitted motive is `exploitable_cve` or `end_of_life` |
67
+ | `standard` | in-range | same as above |
68
+ | `latest` | latest | already maximal |
69
+ | `cutting-edge` | latest | already maximal, plus prereleases admitted |
70
+
71
+ ### Worked example
72
+
73
+ `pydantic==1.10.13` pinned exactly, no CVE, no maintenance signal; `requests==2.28.1`, CVEs affect
74
+ `2.28.1…2.31.0`, releases run through `2.34.2`:
75
+
76
+ | Tier | `pydantic` | `requests` |
77
+ |---|---|---|
78
+ | `security` | no target (no CVE) | `2.32.0` — nearest CVE-clear version |
79
+ | `deprecation` | no target | `2.32.0` |
80
+ | `standard` | `1.10.13` — pin admits no in-range move | `2.34.2` — newest, already CVE-clear |
81
+ | `latest` | `2.13.5` — widens the pin, `requires_widening=True` | `2.34.2` |
82
+ | `cutting-edge` | `2.13.5` (or newer, if a prerelease exists) | `2.34.2` |
83
+
84
+ ---
85
+
86
+ ## Interacting with OSS IQ
87
+
88
+ | Flag / field | Meaning |
89
+ |---|---|
90
+ | `--update-strategy <tier>` | The default tier for the run. Default: `standard` — preserves pre-fix behaviour. |
91
+ | `--strategy-override pkg=tier` | Run one package at a different tier than the run default. Repeatable. |
92
+ | `--override pkg==version` | Force an exact version, bypassing the strategy and the solver entirely. Wins over a `--strategy-override` on the same package. |
93
+ | `--allow-prerelease` / `cutting-edge` | Prereleases are not a sixth rung — `cutting-edge` is `latest` plus `allow_prerelease=True`, applied at prefetch so prereleases flow into the ladder through the existing path. |
94
+ | `--security` (retired) | Removed, not aliased — this is pre-release software; use `--update-strategy security`. |
95
+ | MCP `update_strategy` / `strategy_overrides` arguments | Same semantics, over the wire, on both MCP tools. |
96
+ | Export `metadata.update_strategy`, `PackageMetrics.strategy_*` | The tier used for the run and the per-package verdict, in `ossiq export` / `ossiq html`. |
97
+ | Agent JSON `update_strategy`, per-entry `motives` / `withheld_reason` | Same verdict, in `--format agent` and both MCP tools. |
98
+
99
+ ---
100
+
101
+ ## Reading the output
102
+
103
+ - **`withheld_reason`** — set only when *no* motive was admitted at the chosen tier (e.g. a package
104
+ with no CVE, under `security`). Names the lowest tier that would have moved it, so a project can
105
+ report "N more updates available under `--update-strategy standard`".
106
+ - **`requires_widening`** — the target sits outside the declared constraint (`IN_MAJOR` / `LATEST`
107
+ rung). `apply` confirms these in a separate prompt before writing them; `--yes` skips both
108
+ prompts.
109
+ - **`escalation`** — set when reach was pushed past the tier's base `MAX_REACH` (a CVE or
110
+ end-of-life motive escalated it), or when every reachable candidate still carries a qualifying
111
+ CVE and the newest was picked anyway. Never silently "stay put".
112
+
113
+ ---
114
+
115
+ ## Key Implementation Decisions
116
+
117
+ **Why two tables rather than one dial?** Collapsing motive and reach into a single ordered list of
118
+ five tiers would make "why did this move" and "how far could it move" the same question, and they
119
+ aren't: an end-of-life package can need to leave its declared range even under the otherwise
120
+ minimal-diff `deprecation` tier. Keeping them as two tables makes each tier's behaviour a lookup,
121
+ not a special case.
122
+
123
+ **Why do unscored CVEs count as exploitable, when `risk.triage` drops them?** `triage` is advisory
124
+ — an operator reads its verdict and decides. This module gates *writes*: recommending a version
125
+ that still carries an unscored CVE is a decision made on behalf of the user, and absent evidence
126
+ must not silently read as absent risk.
127
+
128
+ **Why is `WINDING_DOWN` not end-of-life?** It already surfaces as "Consider alternative" in
129
+ `next_action`, which is the right severity — a maintainer who is slowing down has not stopped.
130
+ Escalating it to `end_of_life` would make `deprecation`/`security` tiers move packages whose
131
+ maintainers are still shipping fixes, defeating the "minimal diff" promise of the bottom two tiers.
132
+
133
+ **Why minimal-diff for the bottom two tiers, freshness for the top three?** `security` and
134
+ `deprecation` exist to answer "what must I patch today" — the smallest change that resolves the
135
+ motive. `standard` and above answer "what would I install today" — freshness is the point.
136
+ Conflating them would make a security patch also carry unrelated drift, which is exactly the kind
137
+ of unreviewable diff this module exists to prevent.
138
+
139
+ **Why no fourth `PRERELEASE` rung?** `RecommendationRung` and the version ladder are about *where*
140
+ on the ladder a version sits (in-range / in-major / latest), which is orthogonal to whether
141
+ prereleases are visible on that ladder at all. Modelling prerelease admission as `allow_prerelease`
142
+ at prefetch time — exactly like `--allow-prerelease` already works — means `cutting-edge` needs no
143
+ changes to `VersionLadder`, `RecommendationRung`, or the export schema.
144
+
145
+ **Why is `Candidate` pre-tagged rather than parsed here?** Keeping version parsing, constraint
146
+ matching and registry lookups entirely in `service.project.strategy.build_candidates` means this
147
+ module has zero registry coupling and is trivially property-testable: a `Candidate` list is just
148
+ data, and `select_target` is a pure function over it. A release's age rides along the same way, as
149
+ `Candidate.age_days`: the tag is a registry fact, the threshold (`cooldown_period`) is a parameter,
150
+ and the decision stays here.
151
+
152
+ **Why does the cooldown live in the selector rather than in `plan`/`apply`?** It used to live only
153
+ there, as `service.update.is_held_for_cooldown`. But `apply_update_strategy` runs last and rewrites
154
+ `recommended_version`, so `status` would recommend a two-day-old release with "Update Immediately"
155
+ while `apply` refused it — with a settled release sitting between the two, recommended by nobody.
156
+ Filtering fresh candidates out of the ladder here makes one decision serve every surface, which is
157
+ the whole point of rule 5 in the root `CLAUDE.md`. The downstream hold survives as a backstop for
158
+ transitive recommendations, which come from the solver's *soft* freshness penalty.
159
+
160
+ **Why may only `latest`/`cutting-edge` cross to ESM-only, and only on a `require(esm)` Node?**
161
+ For a CommonJS project an ESM-only release is a break whatever its version number:
162
+ `require()` of it fails outright below Node 20.19/22.12, and above that it returns the module
163
+ namespace, so a default-export-only package (chalk) still breaks. `MODULE_BREAK_TIERS` makes
164
+ crossing a freshness decision the top of the pyramid may take, flagged with `breaking_change` so
165
+ `apply` asks for it separately. Everything below stays on the installed module system. The
166
+ permission only grows with the tier, so rule 6 ("a higher tier's target is never lower") still
167
+ holds by construction. The gate itself (`service.project.strategy.module_system_gate`) is a
168
+ *strict* gate: `build_candidates` never waives it just because it empties the ladder, because a
169
+ drift-only package should stay put rather than cross. `apply_update_strategy` waives it in one
170
+ case, when an `exploitable_cve` or `end_of_life` motive has no clean candidate left without it.
171
+ It re-runs `select_target` over the full ladder and keeps that answer only if it resolves the
172
+ motive. The selector stays pure; the re-run is wiring.
173
+
174
+ **Why does `compare_target` never pick a version?** `recommended_version` has one writer. A
175
+ second target-picker for `update_context` would be a second answer to the same question, and the
176
+ two would drift. `compare_target` only turns facts about a proposed target into a verdict relative
177
+ to that one answer.
178
+
179
+ **Why `--strategy-override` and not `--override-strategy`?** `--override pkg==version` already
180
+ exists and means "force this exact version". `--override-strategy` reads as a variant of the same
181
+ flag and invites the wrong mental model; `--strategy-override` parses unambiguously as "an override
182
+ of the strategy" for one package.
@@ -0,0 +1,7 @@
1
+ {% if duration_days == 0 %}
2
+ <strong class="text-green text-semibold">{{ formatted_string }}</strong>
3
+ {% elif threshold_days and duration_days and duration_days > threshold_days %}
4
+ <strong class="text-red-700 dark:text-red-500 text-semibold">{{ formatted_string }}</strong>
5
+ {% else %}
6
+ <strong class="text-semibold">{{ formatted_string }}</strong>
7
+ {% endif %}