quotalens 1.0__tar.gz

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 (123) hide show
  1. quotalens-1.0/.github/ISSUE_TEMPLATE/bug_report.md +54 -0
  2. quotalens-1.0/.github/ISSUE_TEMPLATE/config.yml +7 -0
  3. quotalens-1.0/.github/ISSUE_TEMPLATE/endpoint_drift.md +38 -0
  4. quotalens-1.0/.github/workflows/ci.yml +136 -0
  5. quotalens-1.0/.github/workflows/release.yml +125 -0
  6. quotalens-1.0/.gitignore +46 -0
  7. quotalens-1.0/LICENSE +21 -0
  8. quotalens-1.0/PKG-INFO +582 -0
  9. quotalens-1.0/PLAN.md +181 -0
  10. quotalens-1.0/README.md +550 -0
  11. quotalens-1.0/SECURITY.md +52 -0
  12. quotalens-1.0/VISION.md +102 -0
  13. quotalens-1.0/design/DESIGN.md +482 -0
  14. quotalens-1.0/design/DIRECTIONS.html +574 -0
  15. quotalens-1.0/design/MARKS.html +367 -0
  16. quotalens-1.0/design/RING.html +310 -0
  17. quotalens-1.0/design/favicon.svg +4 -0
  18. quotalens-1.0/design/logo.svg +5 -0
  19. quotalens-1.0/design/mark.svg +4 -0
  20. quotalens-1.0/design/marks/01-ring.svg +4 -0
  21. quotalens-1.0/design/marks/02-tank.svg +4 -0
  22. quotalens-1.0/design/marks/03-bar.svg +4 -0
  23. quotalens-1.0/design/marks/04-break.svg +4 -0
  24. quotalens-1.0/design/marks/05-columns.svg +4 -0
  25. quotalens-1.0/design/marks/06-gauge.svg +4 -0
  26. quotalens-1.0/design/marks/07-dial.svg +4 -0
  27. quotalens-1.0/design/marks/08-glass.svg +4 -0
  28. quotalens-1.0/design/marks/09-brackets.svg +4 -0
  29. quotalens-1.0/design/marks/10-q.svg +4 -0
  30. quotalens-1.0/design/marks/11-pair.svg +4 -0
  31. quotalens-1.0/design/marks/12-battery.svg +4 -0
  32. quotalens-1.0/design/marks/boost-rocket.svg +19 -0
  33. quotalens-1.0/design/marks/ring/01-track-favicon-16.svg +5 -0
  34. quotalens-1.0/design/marks/ring/01-track.svg +4 -0
  35. quotalens-1.0/design/marks/ring/02-open.svg +4 -0
  36. quotalens-1.0/design/marks/ring/03-bead.svg +4 -0
  37. quotalens-1.0/design/marks/ring/04-dual.svg +4 -0
  38. quotalens-1.0/design/og-image.png +0 -0
  39. quotalens-1.0/design/preview.html +310 -0
  40. quotalens-1.0/design/render_gear.py +84 -0
  41. quotalens-1.0/design/render_mark_png.py +108 -0
  42. quotalens-1.0/design/tokens.css +136 -0
  43. quotalens-1.0/docs/FEATURE-REVIEW.md +856 -0
  44. quotalens-1.0/docs/MVP-SCOPE.md +158 -0
  45. quotalens-1.0/docs/QA.md +550 -0
  46. quotalens-1.0/docs/RELEASE-CHECKLIST.md +149 -0
  47. quotalens-1.0/docs/RELEASE-NOTES-v1.0.md +119 -0
  48. quotalens-1.0/docs/V0.1.0-PLAN.md +217 -0
  49. quotalens-1.0/pyproject.toml +67 -0
  50. quotalens-1.0/qa/fake_claude.py +136 -0
  51. quotalens-1.0/qa/smoke.py +266 -0
  52. quotalens-1.0/src/quotalens/__init__.py +3 -0
  53. quotalens-1.0/src/quotalens/__main__.py +7 -0
  54. quotalens-1.0/src/quotalens/alerts.py +122 -0
  55. quotalens-1.0/src/quotalens/api.py +616 -0
  56. quotalens-1.0/src/quotalens/boost.py +209 -0
  57. quotalens-1.0/src/quotalens/budget.py +277 -0
  58. quotalens-1.0/src/quotalens/burn.py +158 -0
  59. quotalens-1.0/src/quotalens/cli.py +846 -0
  60. quotalens-1.0/src/quotalens/client.py +352 -0
  61. quotalens-1.0/src/quotalens/config.py +505 -0
  62. quotalens-1.0/src/quotalens/credits.py +185 -0
  63. quotalens-1.0/src/quotalens/dashboard.py +1660 -0
  64. quotalens-1.0/src/quotalens/export.py +162 -0
  65. quotalens-1.0/src/quotalens/metrics.py +227 -0
  66. quotalens-1.0/src/quotalens/notify.py +411 -0
  67. quotalens-1.0/src/quotalens/origin_guard.py +112 -0
  68. quotalens-1.0/src/quotalens/parse.py +480 -0
  69. quotalens-1.0/src/quotalens/poller.py +735 -0
  70. quotalens-1.0/src/quotalens/render.py +1463 -0
  71. quotalens-1.0/src/quotalens/retention.py +219 -0
  72. quotalens-1.0/src/quotalens/runway.py +177 -0
  73. quotalens-1.0/src/quotalens/secrets.py +217 -0
  74. quotalens-1.0/src/quotalens/service.py +787 -0
  75. quotalens-1.0/src/quotalens/sessions.py +320 -0
  76. quotalens-1.0/src/quotalens/settings_view.py +223 -0
  77. quotalens-1.0/src/quotalens/state.py +162 -0
  78. quotalens-1.0/src/quotalens/status.py +290 -0
  79. quotalens-1.0/src/quotalens/store.py +677 -0
  80. quotalens-1.0/src/quotalens/views.py +170 -0
  81. quotalens-1.0/src/quotalens/web/app.css +397 -0
  82. quotalens-1.0/src/quotalens/web/app.js +278 -0
  83. quotalens-1.0/src/quotalens/web/boost-rocket.svg +19 -0
  84. quotalens-1.0/src/quotalens/web/chart.js +206 -0
  85. quotalens-1.0/src/quotalens/web/favicon.svg +4 -0
  86. quotalens-1.0/src/quotalens/web/mark.png +0 -0
  87. quotalens-1.0/src/quotalens/web/tokens.css +136 -0
  88. quotalens-1.0/src/quotalens/web/vendor/README.md +27 -0
  89. quotalens-1.0/src/quotalens/web/vendor/claude.svg +1 -0
  90. quotalens-1.0/src/quotalens/web/vendor/openai.svg +1 -0
  91. quotalens-1.0/tests/conftest.py +266 -0
  92. quotalens-1.0/tests/test_alerts.py +381 -0
  93. quotalens-1.0/tests/test_api.py +120 -0
  94. quotalens-1.0/tests/test_boost.py +343 -0
  95. quotalens-1.0/tests/test_boost_mark.py +391 -0
  96. quotalens-1.0/tests/test_budget.py +363 -0
  97. quotalens-1.0/tests/test_burn.py +137 -0
  98. quotalens-1.0/tests/test_cli.py +217 -0
  99. quotalens-1.0/tests/test_client.py +221 -0
  100. quotalens-1.0/tests/test_config_store.py +169 -0
  101. quotalens-1.0/tests/test_controls.py +251 -0
  102. quotalens-1.0/tests/test_credits.py +100 -0
  103. quotalens-1.0/tests/test_dashboard.py +698 -0
  104. quotalens-1.0/tests/test_export.py +154 -0
  105. quotalens-1.0/tests/test_favicon_render.py +158 -0
  106. quotalens-1.0/tests/test_lapsed_window.py +296 -0
  107. quotalens-1.0/tests/test_mark.py +227 -0
  108. quotalens-1.0/tests/test_metrics.py +374 -0
  109. quotalens-1.0/tests/test_notify.py +332 -0
  110. quotalens-1.0/tests/test_origin_guard.py +163 -0
  111. quotalens-1.0/tests/test_parse.py +334 -0
  112. quotalens-1.0/tests/test_poller.py +308 -0
  113. quotalens-1.0/tests/test_profiles.py +165 -0
  114. quotalens-1.0/tests/test_prompt5.py +337 -0
  115. quotalens-1.0/tests/test_readout_colour.py +178 -0
  116. quotalens-1.0/tests/test_redaction.py +139 -0
  117. quotalens-1.0/tests/test_rendered_type.py +154 -0
  118. quotalens-1.0/tests/test_retention.py +151 -0
  119. quotalens-1.0/tests/test_runway.py +102 -0
  120. quotalens-1.0/tests/test_service.py +422 -0
  121. quotalens-1.0/tests/test_sessions.py +450 -0
  122. quotalens-1.0/tests/test_status_and_settings.py +806 -0
  123. quotalens-1.0/tests/test_store.py +118 -0
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something QuotaLens did that it should not have
4
+ labels: bug
5
+ ---
6
+
7
+ ## Before you paste anything
8
+
9
+ **`quotalens probe` output is your account's data.** It never contains your
10
+ session cookie, and UUID-shaped values are masked by default — but only by
11
+ default. Do not paste output from `probe --no-redact` or from
12
+ `/api/export.json?table=samples&raw=1`; both are unmasked on purpose.
13
+
14
+ If you need to show a payload, `quotalens probe` (no flags) is the safe form.
15
+ If you are unsure whether something identifies you, leave it out and say so; a
16
+ missing field is easier to ask for than a leaked one is to take back.
17
+
18
+ Never paste your cookie. Nobody debugging this will ever need it. If you think
19
+ you have pasted one anywhere, sign out of claude.ai on all devices, which
20
+ invalidates it.
21
+
22
+ ## What happened
23
+
24
+ <!-- What you saw, and what you expected instead. -->
25
+
26
+ ## How to reproduce
27
+
28
+ <!-- The exact commands, and the URL if it was the dashboard. Every view is a
29
+ URL, so pasting the address bar captures the range, the lookback and which
30
+ series were hidden. -->
31
+
32
+ ## Environment
33
+
34
+ - QuotaLens version: <!-- quotalens --version -->
35
+ - OS and version:
36
+ - Installed with: <!-- pipx / uvx / from source -->
37
+ - Python: <!-- python3 --version -->
38
+
39
+ ## Collector state
40
+
41
+ <!-- `quotalens status` output. It contains your window percentages and reset
42
+ times but no identifiers. Trim it if you would rather not share those. -->
43
+
44
+ ```
45
+ ```
46
+
47
+ ## Anything in the log
48
+
49
+ <!-- `quotalens logs -n 50`. The cookie is redacted from logs by design; if you
50
+ ever find one in there, that is itself the bug and it is a serious one —
51
+ please report it privately rather than in a public issue. -->
52
+
53
+ ```
54
+ ```
@@ -0,0 +1,7 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Security issue
4
+ url: https://github.com/amitshcc/quotalens/security/advisories/new
5
+ about: >-
6
+ Anything involving the session cookie, credential storage or redaction.
7
+ Report it privately, not in a public issue. See SECURITY.md.
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: Endpoint drift
3
+ about: QuotaLens says the response shape changed, or a number looks wrong
4
+ labels: drift
5
+ ---
6
+
7
+ ## Before you paste anything
8
+
9
+ `quotalens probe` masks UUID-shaped values by default. Use it without
10
+ `--no-redact`, and do not paste raw sample exports. See the bug report template
11
+ for the longer version; the short version is that the payload is your account's
12
+ data and the safe form is `quotalens probe` with no flags.
13
+
14
+ ## What the dashboard said
15
+
16
+ <!-- "shape drifted", "could not be parsed", a window missing, a percentage that
17
+ disagrees with claude.ai's own Settings page, and so on. -->
18
+
19
+ ## The parsed section of `quotalens probe`
20
+
21
+ <!-- The `== parsed ==` block alone is often enough, and it contains no
22
+ identifiers at all. Start with that. -->
23
+
24
+ ```
25
+ ```
26
+
27
+ ## The raw payload, if the parsed section is not enough
28
+
29
+ <!-- `quotalens probe` (masked). Delete anything you would rather not share;
30
+ the top-level key names are the part that matters for drift. -->
31
+
32
+ ```
33
+ ```
34
+
35
+ ## What claude.ai's own Settings → Usage page showed at the same moment
36
+
37
+ <!-- A number to compare against. A screenshot with the account details cropped
38
+ out is fine. -->
@@ -0,0 +1,136 @@
1
+ name: CI
2
+
3
+ # Cross-platform is a headline claim in the README. Until this is green on all
4
+ # three runners it stays a claim, and the README says "Windows untested".
5
+
6
+ on:
7
+ push:
8
+ branches: [main, master]
9
+ pull_request:
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: ci-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ lint:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.11"
27
+ - run: python -m pip install "ruff==0.16.*"
28
+ - run: ruff check src tests qa
29
+ - run: ruff format --check src tests qa
30
+
31
+ # Whether the favicon draws, and what size a cell computes to, are questions
32
+ # about SVG and CSS rather than about the operating system, so they run once
33
+ # rather than on all six matrix jobs. A separate job because these are the only
34
+ # things here that need a browser.
35
+ render:
36
+ name: what a browser actually renders
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - uses: actions/setup-python@v5
41
+ with:
42
+ python-version: "3.13"
43
+ - run: python -m pip install --upgrade pip
44
+ - run: python -m pip install -e ".[test,browser]"
45
+ - run: python -m playwright install --with-deps chromium
46
+ - run: python -m pytest tests/test_favicon_render.py tests/test_rendered_type.py -q
47
+
48
+ test:
49
+ name: ${{ matrix.os }} / py${{ matrix.python }}
50
+ runs-on: ${{ matrix.os }}
51
+ strategy:
52
+ fail-fast: false # a Windows failure must not hide a Linux one
53
+ matrix:
54
+ os: [ubuntu-latest, macos-latest, windows-latest]
55
+ python: ["3.11", "3.13"]
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+
59
+ - uses: actions/setup-python@v5
60
+ with:
61
+ python-version: ${{ matrix.python }}
62
+
63
+ - name: Build the wheel
64
+ run: |
65
+ python -m pip install --upgrade pip build
66
+ python -m build --wheel
67
+
68
+ # Installing the wheel rather than the source tree is the point: it is what
69
+ # a user gets from pipx, and it catches anything missing from the package
70
+ # data (the stylesheet, the scripts, the favicon).
71
+ - name: Install from the wheel
72
+ shell: bash
73
+ run: |
74
+ WHEEL=$(ls dist/*.whl)
75
+ python -m pip install "${WHEEL}[test]"
76
+
77
+ - name: Unit tests
78
+ run: python -m pytest -q
79
+
80
+ # The tests mock every HTTP call, so nothing above proves the process can
81
+ # actually start, poll, write rows and serve them on this platform.
82
+ - name: Smoke (server against a fake upstream, then the CLI lifecycle)
83
+ run: python qa/smoke.py
84
+
85
+ # Registering a scheduled task is the one thing unit tests cannot prove: the
86
+ # XML either satisfies Task Scheduler's schema or it does not, and only
87
+ # Windows can say. Install for real, confirm the task exists, then remove it.
88
+ # pwsh, not bash: Git Bash rewrites a leading-slash argument into a path, so
89
+ # `schtasks /Query` would arrive as `schtasks C:/Program Files/Git/Query`.
90
+ - name: Auto-start at login registers and unregisters (Windows)
91
+ if: runner.os == 'Windows'
92
+ shell: pwsh
93
+ run: |
94
+ $data = Join-Path $env:RUNNER_TEMP "svc"
95
+ python -m quotalens --data-dir $data service install --interval 300
96
+ if ($LASTEXITCODE -ne 0) { throw "service install failed" }
97
+ schtasks /Query /TN QuotaLens
98
+ if ($LASTEXITCODE -ne 0) { throw "install reported success but no task was registered" }
99
+ python -m quotalens --data-dir $data service status
100
+ python -m quotalens --data-dir $data service uninstall
101
+ if ($LASTEXITCODE -ne 0) { throw "service uninstall failed" }
102
+ schtasks /Query /TN QuotaLens 2>$null
103
+ if ($LASTEXITCODE -eq 0) { throw "the task survived uninstall" }
104
+ Write-Host "registered, queried and removed"
105
+ exit 0 # the query above is meant to fail; without this the step inherits its code
106
+
107
+ - name: Package contents
108
+ shell: bash
109
+ run: |
110
+ python - <<'PY'
111
+ from importlib import resources
112
+ web = resources.files("quotalens.web")
113
+ # An asset that works from the source tree and is missing from the
114
+ # installed wheel is exactly what this step exists to catch.
115
+ for name in (
116
+ "tokens.css", "app.css", "app.js", "chart.js",
117
+ "favicon.svg", "boost-rocket.svg",
118
+ "mark.png", # the notification icon
119
+ ):
120
+ data = web.joinpath(name).read_bytes()
121
+ assert data, name
122
+ print(f"{name}: {len(data)} bytes")
123
+
124
+ # Vendor marks are optional by design -- a missing file renders the row
125
+ # with the name alone -- so this asserts the *directory* ships, and
126
+ # reports whichever marks are present.
127
+ from quotalens.status import VENDORS
128
+ vendor = web.joinpath("vendor")
129
+ assert vendor.is_dir(), "quotalens/web/vendor/ is missing from the wheel"
130
+ for v in VENDORS:
131
+ if not v.logo:
132
+ continue
133
+ path = vendor.joinpath(v.logo)
134
+ state = f"{len(path.read_bytes())} bytes" if path.is_file() else "absent (name only)"
135
+ print(f"vendor/{v.logo}: {state}")
136
+ PY
@@ -0,0 +1,125 @@
1
+ name: Release
2
+
3
+ # Publishing is the owner's action, so this workflow does nothing on its own:
4
+ # it fires on a tag you push, or on a manual dispatch aimed at TestPyPI.
5
+ #
6
+ # No API token anywhere. Both jobs mint a short-lived credential per run through
7
+ # OIDC (PyPI "trusted publishing"), which is why each has `id-token: write` and
8
+ # names an environment. A token in `secrets.*` would work and would be worse: it
9
+ # does not expire, and it is one leaked log line from being someone else's.
10
+ #
11
+ # A manual dispatch can only reach TestPyPI. Pushing a tag is the only route to
12
+ # PyPI, because that is the only condition under which the tag/__version__/wheel
13
+ # agreement check runs.
14
+ #
15
+ # Before the first real tag, publish once to TestPyPI via workflow_dispatch. The
16
+ # upload is irreversible and a filename can never be reused, even after a
17
+ # deletion — so a bad wheel on PyPI burns `quotalens-1.0-py3-none-any.whl`
18
+ # forever.
19
+
20
+ on:
21
+ push:
22
+ tags: ["v*"]
23
+ workflow_dispatch:
24
+ inputs:
25
+ target:
26
+ description: "Where to publish"
27
+ required: true
28
+ default: testpypi
29
+ type: choice
30
+ # TestPyPI only. A dispatch can run from any ref, and the step that
31
+ # checks the tag, pyproject.toml and __version__ against each other
32
+ # is gated on refs/tags/v* -- so a dispatch to PyPI would be an
33
+ # irreversible upload with no version check at all. The tag is the
34
+ # only route to PyPI.
35
+ options: [testpypi]
36
+
37
+ permissions:
38
+ contents: read
39
+
40
+ jobs:
41
+ # The tag is not evidence. Build from the tagged tree, then run the same
42
+ # checks CI runs, against the artifact that is about to be uploaded rather
43
+ # than against the source tree.
44
+ build:
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+
49
+ - uses: actions/setup-python@v5
50
+ with:
51
+ python-version: "3.11"
52
+
53
+ - run: python -m pip install --upgrade pip build twine
54
+
55
+ - name: Build sdist and wheel
56
+ run: python -m build
57
+
58
+ # `twine check` reads the metadata PyPI will read. It catches a README
59
+ # that does not render before the upload does, which is the one class of
60
+ # error you cannot take back.
61
+ - name: Check the metadata
62
+ run: python -m twine check dist/*
63
+
64
+ # The version in the tag, the version in pyproject.toml and the version
65
+ # the installed package reports must be one number. They have disagreed
66
+ # before, and a release that says 1.0 in two places and 0.1.0 in the
67
+ # third is worse than no release.
68
+ - name: The tag, the metadata and __version__ agree
69
+ if: startsWith(github.ref, 'refs/tags/v')
70
+ shell: bash
71
+ run: |
72
+ TAG="${GITHUB_REF_NAME#v}"
73
+ WHEEL=$(ls dist/*.whl)
74
+ python -m pip install "${WHEEL}"
75
+ PKG=$(python -c "import quotalens; print(quotalens.__version__)")
76
+ echo "tag=$TAG package=$PKG wheel=$WHEEL"
77
+ [ "$TAG" = "$PKG" ] || { echo "::error::tag v$TAG does not match __version__ $PKG"; exit 1; }
78
+ case "$WHEEL" in *"quotalens-$TAG-"*) ;; *) echo "::error::wheel filename does not carry $TAG"; exit 1;; esac
79
+
80
+ # A wheel that installs but cannot start is what CI's smoke test exists to
81
+ # catch. Run it here too: this is the artifact being published, not a
82
+ # rebuild of it.
83
+ - name: Smoke the built wheel
84
+ run: |
85
+ python -m pip install "$(ls dist/*.whl)[test]"
86
+ python -m pytest -q
87
+ python qa/smoke.py
88
+
89
+ - uses: actions/upload-artifact@v4
90
+ with:
91
+ name: dist
92
+ path: dist/
93
+
94
+ testpypi:
95
+ needs: build
96
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
97
+ runs-on: ubuntu-latest
98
+ environment: testpypi
99
+ permissions:
100
+ id-token: write
101
+ steps:
102
+ - uses: actions/download-artifact@v4
103
+ with:
104
+ name: dist
105
+ path: dist/
106
+ - uses: pypa/gh-action-pypi-publish@release/v1
107
+ with:
108
+ repository-url: https://test.pypi.org/legacy/
109
+
110
+ # Reachable only by pushing a tag, which is also the only condition under
111
+ # which the version-agreement step above runs. See the dispatch input.
112
+ pypi:
113
+ needs: build
114
+ if: startsWith(github.ref, 'refs/tags/v')
115
+ runs-on: ubuntu-latest
116
+ environment: pypi # add a required reviewer on this environment, so a
117
+ # tag alone cannot publish without you clicking
118
+ permissions:
119
+ id-token: write # OIDC: this is the whole credential story
120
+ steps:
121
+ - uses: actions/download-artifact@v4
122
+ with:
123
+ name: dist
124
+ path: dist/
125
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,46 @@
1
+ # secrets and local state — never commit
2
+ .env
3
+ .env.*
4
+ *.db
5
+ *.db-journal
6
+ *.db-wal
7
+ *.db-shm
8
+ *.sqlite
9
+ *.sqlite3
10
+ probe-output*.json
11
+ scratch/
12
+
13
+ # python
14
+ __pycache__/
15
+ *.py[cod]
16
+ *.egg-info/
17
+ build/
18
+ dist/
19
+ .venv/
20
+ venv/
21
+ .pytest_cache/
22
+ .ruff_cache/
23
+ .mypy_cache/
24
+ .coverage
25
+ htmlcov/
26
+
27
+ # editors / os
28
+ .DS_Store
29
+ .idea/
30
+ .vscode/
31
+
32
+ # local reference checkouts, never committed
33
+ TEMP/
34
+
35
+ # working prompts and the local agent definition — kept out of the public repo
36
+ # on purpose. The versioned copies live in the private quotalens-web repo under
37
+ # prompts/. Removed from history on 2026-09-06; see that repo for the record.
38
+ design/prompts/
39
+ docs/prompts/
40
+ .claude/
41
+ CLAUDE_CODE_PROMPT.md
42
+ docs/V0.1.0-PROMPT.md
43
+ docs/AUDIT-*.md
44
+ docs/SECURITY-AUDIT-*.md
45
+ docs/LAUNCH-READINESS-*.md
46
+ docs/LAUNCH-TODO.md
quotalens-1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amit Sharma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.