devtime-ei 0.1.0__tar.gz → 0.1.1__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.
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/PKG-INFO +60 -24
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/README.md +58 -22
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/pyproject.toml +10 -3
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/__init__.py +1 -1
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/cli.py +35 -0
- devtime_ei-0.1.1/src/devtime/demo.py +75 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/.devtimeignore +23 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/README.md +5 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/docs/decisions/0001-use-jwt.md +15 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/package.json +15 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/admin/permissions.ts +9 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/auth/login.ts +21 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/auth/middleware.ts +16 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/auth/tokens.ts +11 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/billing/stripe-webhook.ts +25 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/billing/subscription-service.ts +11 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/export/export-csv.ts +14 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/jobs/email-worker.ts +16 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/src/jobs/queues.ts +6 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/tests/auth-login.test.ts +10 -0
- devtime_ei-0.1.1/src/devtime/resources/demo-saas/tests/stripe-signature.test.ts +8 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime_ei.egg-info/PKG-INFO +60 -24
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime_ei.egg-info/SOURCES.txt +16 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/LICENSE +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/setup.cfg +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/ai/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/ai/local.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/ai/prompts.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/ai/providers.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/assets/devtimeignore.starter +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/config.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/db/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/db/connection.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/db/migrations.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/db/repository.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/db/schema.sql +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/fixtures/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/fixtures/assertions.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/fixtures/loader.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/fixtures/runner.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/claims.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/concepts.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/context_pack.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/evidence.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/lineage.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/risk.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/intelligence/scoring.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/mcp/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/mcp/schemas.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/mcp/server.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/mcp/tools.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/output/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/output/json_export.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/output/markdown.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/output/terminal.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/paths.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/privacy.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/base.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/config_files.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/docs.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/nextjs.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/python.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/tests.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/extractors/typescript.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/file_walker.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/ignore.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/language.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime/scanner/signals.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime_ei.egg-info/dependency_links.txt +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime_ei.egg-info/entry_points.txt +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime_ei.egg-info/requires.txt +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.1}/src/devtime_ei.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devtime-ei
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Local-first Engineering Intelligence for software repositories
|
|
5
5
|
Author-email: Aviad Shakargi <aviad94@gmail.com>
|
|
6
6
|
Maintainer-email: Aviad Shakargi <aviad94@gmail.com>
|
|
@@ -8,7 +8,7 @@ License: Apache-2.0
|
|
|
8
8
|
Project-URL: Homepage, https://github.com/Shakargy/devtime
|
|
9
9
|
Project-URL: Repository, https://github.com/Shakargy/devtime
|
|
10
10
|
Project-URL: Issues, https://github.com/Shakargy/devtime/issues
|
|
11
|
-
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.1.
|
|
11
|
+
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.1.1
|
|
12
12
|
Project-URL: Demo, https://youtu.be/1Hiu3Y9J_SI
|
|
13
13
|
Keywords: devtools,cli,static-analysis,repository-analysis,engineering-intelligence,local-first
|
|
14
14
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -56,6 +56,22 @@ decision improves understanding.
|
|
|
56
56
|
|
|
57
57
|
## Try DevTime in 60 seconds
|
|
58
58
|
|
|
59
|
+
```bash
|
|
60
|
+
pipx install devtime-ei
|
|
61
|
+
dtc demo init
|
|
62
|
+
cd devtime-demo-saas
|
|
63
|
+
dtc init
|
|
64
|
+
dtc scan
|
|
65
|
+
dtc concepts
|
|
66
|
+
dtc explain "Billing Webhooks"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
70
|
+
CLI command remains `dtc`. `dtc demo init` copies a small static example repo into
|
|
71
|
+
`./devtime-demo-saas` so you can try DevTime without cloning this repository.
|
|
72
|
+
|
|
73
|
+
### From source
|
|
74
|
+
|
|
59
75
|
```bash
|
|
60
76
|
git clone https://github.com/Shakargy/devtime.git
|
|
61
77
|
cd devtime
|
|
@@ -98,27 +114,36 @@ steps) is in **[DEMO_SCRIPT.md](DEMO_SCRIPT.md)**.
|
|
|
98
114
|
|
|
99
115
|
## Why this exists
|
|
100
116
|
|
|
101
|
-
Git
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
117
|
+
Git records what changed, but it does not preserve the reasoning behind those
|
|
118
|
+
changes. When you return to a repository - or review one you did not write - you often
|
|
119
|
+
have to reconstruct why a behavior exists, what evidence supports it, and what is
|
|
120
|
+
still uncertain.
|
|
105
121
|
|
|
106
|
-
DevTime builds evidence-backed repository memory: a local layer that
|
|
107
|
-
|
|
122
|
+
DevTime builds evidence-backed repository memory: a local layer that helps a
|
|
123
|
+
codebase explain itself from code, tests, configs, routes, and recorded decisions.
|
|
124
|
+
It shows what the repository can support with evidence - and, just as importantly,
|
|
125
|
+
what it cannot support yet.
|
|
108
126
|
|
|
109
127
|
## Who it is for
|
|
110
128
|
|
|
111
|
-
DevTime is for
|
|
112
|
-
|
|
113
|
-
generated summaries.
|
|
129
|
+
DevTime is for people who need to understand a repository from evidence rather than
|
|
130
|
+
memory.
|
|
114
131
|
|
|
115
|
-
It is useful
|
|
132
|
+
It is especially useful if you:
|
|
116
133
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
134
|
+
- are onboarding to an unfamiliar codebase and need to understand how a feature is implemented;
|
|
135
|
+
- are reviewing a pull request and want to see what evidence supports a behavior;
|
|
136
|
+
- are returning to a project after weeks or months and cannot remember why something exists;
|
|
137
|
+
- maintain a long-lived project where design decisions are easily lost;
|
|
138
|
+
- want repository understanding to be backed by code and recorded decisions instead of generated summaries.
|
|
139
|
+
|
|
140
|
+
Questions DevTime helps answer include:
|
|
141
|
+
|
|
142
|
+
- Where is authentication actually implemented?
|
|
143
|
+
- What files prove that Billing Webhooks exist?
|
|
144
|
+
- What is still uncertain?
|
|
145
|
+
- Did this diff touch a risky concept?
|
|
146
|
+
- Is there a decision explaining this behavior?
|
|
122
147
|
|
|
123
148
|
## What DevTime does
|
|
124
149
|
|
|
@@ -185,7 +210,24 @@ step-by-step first run and troubleshooting.
|
|
|
185
210
|
|
|
186
211
|
## Installation
|
|
187
212
|
|
|
188
|
-
Recommended
|
|
213
|
+
Recommended: install from PyPI with [pipx](https://pipx.pypa.io/) so the `dtc`
|
|
214
|
+
command is available on your PATH in an isolated environment:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pipx install devtime-ei
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Or with pip:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pip install devtime-ei
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
227
|
+
CLI command remains `dtc`. After installing, run `dtc demo init` to create a local
|
|
228
|
+
example repo to try it on.
|
|
229
|
+
|
|
230
|
+
### From source
|
|
189
231
|
|
|
190
232
|
```bash
|
|
191
233
|
git clone https://github.com/Shakargy/devtime.git
|
|
@@ -205,12 +247,6 @@ python -m venv .venv
|
|
|
205
247
|
pip install -e ".[dev]"
|
|
206
248
|
```
|
|
207
249
|
|
|
208
|
-
Planned PyPI install (after the package is published and verified):
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
pipx install devtime
|
|
212
|
-
```
|
|
213
|
-
|
|
214
250
|
## Example output
|
|
215
251
|
|
|
216
252
|
```
|
|
@@ -20,6 +20,22 @@ decision improves understanding.
|
|
|
20
20
|
|
|
21
21
|
## Try DevTime in 60 seconds
|
|
22
22
|
|
|
23
|
+
```bash
|
|
24
|
+
pipx install devtime-ei
|
|
25
|
+
dtc demo init
|
|
26
|
+
cd devtime-demo-saas
|
|
27
|
+
dtc init
|
|
28
|
+
dtc scan
|
|
29
|
+
dtc concepts
|
|
30
|
+
dtc explain "Billing Webhooks"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
34
|
+
CLI command remains `dtc`. `dtc demo init` copies a small static example repo into
|
|
35
|
+
`./devtime-demo-saas` so you can try DevTime without cloning this repository.
|
|
36
|
+
|
|
37
|
+
### From source
|
|
38
|
+
|
|
23
39
|
```bash
|
|
24
40
|
git clone https://github.com/Shakargy/devtime.git
|
|
25
41
|
cd devtime
|
|
@@ -62,27 +78,36 @@ steps) is in **[DEMO_SCRIPT.md](DEMO_SCRIPT.md)**.
|
|
|
62
78
|
|
|
63
79
|
## Why this exists
|
|
64
80
|
|
|
65
|
-
Git
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
Git records what changed, but it does not preserve the reasoning behind those
|
|
82
|
+
changes. When you return to a repository - or review one you did not write - you often
|
|
83
|
+
have to reconstruct why a behavior exists, what evidence supports it, and what is
|
|
84
|
+
still uncertain.
|
|
69
85
|
|
|
70
|
-
DevTime builds evidence-backed repository memory: a local layer that
|
|
71
|
-
|
|
86
|
+
DevTime builds evidence-backed repository memory: a local layer that helps a
|
|
87
|
+
codebase explain itself from code, tests, configs, routes, and recorded decisions.
|
|
88
|
+
It shows what the repository can support with evidence - and, just as importantly,
|
|
89
|
+
what it cannot support yet.
|
|
72
90
|
|
|
73
91
|
## Who it is for
|
|
74
92
|
|
|
75
|
-
DevTime is for
|
|
76
|
-
|
|
77
|
-
generated summaries.
|
|
93
|
+
DevTime is for people who need to understand a repository from evidence rather than
|
|
94
|
+
memory.
|
|
78
95
|
|
|
79
|
-
It is useful
|
|
96
|
+
It is especially useful if you:
|
|
80
97
|
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
98
|
+
- are onboarding to an unfamiliar codebase and need to understand how a feature is implemented;
|
|
99
|
+
- are reviewing a pull request and want to see what evidence supports a behavior;
|
|
100
|
+
- are returning to a project after weeks or months and cannot remember why something exists;
|
|
101
|
+
- maintain a long-lived project where design decisions are easily lost;
|
|
102
|
+
- want repository understanding to be backed by code and recorded decisions instead of generated summaries.
|
|
103
|
+
|
|
104
|
+
Questions DevTime helps answer include:
|
|
105
|
+
|
|
106
|
+
- Where is authentication actually implemented?
|
|
107
|
+
- What files prove that Billing Webhooks exist?
|
|
108
|
+
- What is still uncertain?
|
|
109
|
+
- Did this diff touch a risky concept?
|
|
110
|
+
- Is there a decision explaining this behavior?
|
|
86
111
|
|
|
87
112
|
## What DevTime does
|
|
88
113
|
|
|
@@ -149,7 +174,24 @@ step-by-step first run and troubleshooting.
|
|
|
149
174
|
|
|
150
175
|
## Installation
|
|
151
176
|
|
|
152
|
-
Recommended
|
|
177
|
+
Recommended: install from PyPI with [pipx](https://pipx.pypa.io/) so the `dtc`
|
|
178
|
+
command is available on your PATH in an isolated environment:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
pipx install devtime-ei
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Or with pip:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install devtime-ei
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
191
|
+
CLI command remains `dtc`. After installing, run `dtc demo init` to create a local
|
|
192
|
+
example repo to try it on.
|
|
193
|
+
|
|
194
|
+
### From source
|
|
153
195
|
|
|
154
196
|
```bash
|
|
155
197
|
git clone https://github.com/Shakargy/devtime.git
|
|
@@ -169,12 +211,6 @@ python -m venv .venv
|
|
|
169
211
|
pip install -e ".[dev]"
|
|
170
212
|
```
|
|
171
213
|
|
|
172
|
-
Planned PyPI install (after the package is published and verified):
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
pipx install devtime
|
|
176
|
-
```
|
|
177
|
-
|
|
178
214
|
## Example output
|
|
179
215
|
|
|
180
216
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "devtime-ei"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.1"
|
|
4
4
|
description = "Local-first Engineering Intelligence for software repositories"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -45,7 +45,7 @@ dev = [
|
|
|
45
45
|
Homepage = "https://github.com/Shakargy/devtime"
|
|
46
46
|
Repository = "https://github.com/Shakargy/devtime"
|
|
47
47
|
Issues = "https://github.com/Shakargy/devtime/issues"
|
|
48
|
-
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.1.
|
|
48
|
+
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.1.1"
|
|
49
49
|
Demo = "https://youtu.be/1Hiu3Y9J_SI"
|
|
50
50
|
|
|
51
51
|
[project.scripts]
|
|
@@ -59,8 +59,15 @@ build-backend = "setuptools.build_meta"
|
|
|
59
59
|
where = ["src"]
|
|
60
60
|
|
|
61
61
|
# Non-Python runtime files that ship inside the package (read at runtime).
|
|
62
|
+
# The demo-saas resource is copied out by `dtc demo init`; the leading-dot
|
|
63
|
+
# .devtimeignore is listed explicitly because glob `*` does not match dotfiles.
|
|
62
64
|
[tool.setuptools.package-data]
|
|
63
|
-
devtime = [
|
|
65
|
+
devtime = [
|
|
66
|
+
"db/*.sql",
|
|
67
|
+
"assets/*",
|
|
68
|
+
"resources/demo-saas/**/*",
|
|
69
|
+
"resources/demo-saas/.devtimeignore",
|
|
70
|
+
]
|
|
64
71
|
|
|
65
72
|
[tool.pytest.ini_options]
|
|
66
73
|
testpaths = ["tests"]
|
|
@@ -24,9 +24,13 @@ console = Console()
|
|
|
24
24
|
claim_app = typer.Typer(help="Inspect and govern claims.")
|
|
25
25
|
decision_app = typer.Typer(help="Record human decisions.")
|
|
26
26
|
mcp_app = typer.Typer(help="Local read-only MCP server.")
|
|
27
|
+
demo_app = typer.Typer(
|
|
28
|
+
help="Create a local copy of the bundled demo repository.", no_args_is_help=True
|
|
29
|
+
)
|
|
27
30
|
app.add_typer(claim_app, name="claim")
|
|
28
31
|
app.add_typer(decision_app, name="decision")
|
|
29
32
|
app.add_typer(mcp_app, name="mcp")
|
|
33
|
+
app.add_typer(demo_app, name="demo")
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
# --------------------------------------------------------------------------- #
|
|
@@ -43,6 +47,37 @@ def init() -> None:
|
|
|
43
47
|
console.print("AI disabled. Cloud disabled. Telemetry off. MCP read-only.")
|
|
44
48
|
|
|
45
49
|
|
|
50
|
+
@demo_app.command("init")
|
|
51
|
+
def demo_init(
|
|
52
|
+
force: bool = typer.Option(
|
|
53
|
+
False, "--force", help="Replace devtime-demo-saas if it already exists."
|
|
54
|
+
),
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Copy the bundled demo repository into ./devtime-demo-saas (static files only)."""
|
|
57
|
+
from devtime.demo import DEMO_DIR_NAME, DemoExistsError, create_demo
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
create_demo(Path.cwd(), force=force)
|
|
61
|
+
except DemoExistsError as exc:
|
|
62
|
+
console.print(
|
|
63
|
+
f"[yellow]{DEMO_DIR_NAME}/ already exists[/yellow] at {exc.path}."
|
|
64
|
+
)
|
|
65
|
+
console.print(
|
|
66
|
+
"Use [bold]dtc demo init --force[/bold] to replace it, "
|
|
67
|
+
"or remove the directory first."
|
|
68
|
+
)
|
|
69
|
+
raise typer.Exit(code=1)
|
|
70
|
+
|
|
71
|
+
console.print(f"[green]Demo repository created[/green] at ./{DEMO_DIR_NAME}")
|
|
72
|
+
console.print("")
|
|
73
|
+
console.print("Next:")
|
|
74
|
+
console.print(f" cd {DEMO_DIR_NAME}")
|
|
75
|
+
console.print(" dtc init")
|
|
76
|
+
console.print(" dtc scan")
|
|
77
|
+
console.print(" dtc concepts")
|
|
78
|
+
console.print(' dtc explain "Billing Webhooks"')
|
|
79
|
+
|
|
80
|
+
|
|
46
81
|
@app.command()
|
|
47
82
|
def status() -> None:
|
|
48
83
|
"""Show local storage, AI, cloud, telemetry, MCP, and scan status."""
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Bundled demo repository support for `dtc demo init`.
|
|
2
|
+
|
|
3
|
+
This lets people who installed DevTime from PyPI (`pipx install devtime-ei`) try it
|
|
4
|
+
without cloning the source repository. It copies a small, static example repo that
|
|
5
|
+
ships inside the installed package into the current working directory.
|
|
6
|
+
|
|
7
|
+
It only copies static files. It never executes code, never installs anything, never
|
|
8
|
+
runs tests or migrations, and never touches the network. Nothing leaves the machine.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import shutil
|
|
14
|
+
from importlib import resources
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
# Directory name created in the current working directory.
|
|
18
|
+
DEMO_DIR_NAME = "devtime-demo-saas"
|
|
19
|
+
|
|
20
|
+
# The packaged demo lives at src/devtime/resources/demo-saas/ and ships in the wheel
|
|
21
|
+
# via [tool.setuptools.package-data].
|
|
22
|
+
_RESOURCE_SUBPATH = ("resources", "demo-saas")
|
|
23
|
+
|
|
24
|
+
# Artifacts that must never end up in a copied demo, stripped defensively after copy.
|
|
25
|
+
_FORBIDDEN_DIRS = {".devtime", ".git", "node_modules", "__pycache__", ".cache"}
|
|
26
|
+
_FORBIDDEN_FILE_SUFFIXES = (".sqlite", ".sqlite3", ".db")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DemoExistsError(Exception):
|
|
30
|
+
"""Raised when the demo directory already exists and force was not requested."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, path: Path) -> None:
|
|
33
|
+
self.path = path
|
|
34
|
+
super().__init__(str(path))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def packaged_demo_source() -> Path:
|
|
38
|
+
"""Return a filesystem path to the demo directory bundled in the package."""
|
|
39
|
+
root = resources.files("devtime")
|
|
40
|
+
source = root.joinpath(*_RESOURCE_SUBPATH)
|
|
41
|
+
# In a normal wheel/editable install this is already a real path on disk.
|
|
42
|
+
return Path(str(source))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _strip_forbidden(dest: Path) -> None:
|
|
46
|
+
"""Remove any artifacts that must never be part of a shared demo."""
|
|
47
|
+
for path in sorted(dest.rglob("*"), reverse=True):
|
|
48
|
+
if path.is_dir() and path.name in _FORBIDDEN_DIRS:
|
|
49
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
50
|
+
elif path.is_file() and path.suffix.lower() in _FORBIDDEN_FILE_SUFFIXES:
|
|
51
|
+
path.unlink(missing_ok=True)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def create_demo(dest_parent: Path, *, force: bool = False) -> Path:
|
|
55
|
+
"""Copy the bundled demo into ``dest_parent/devtime-demo-saas``.
|
|
56
|
+
|
|
57
|
+
Writes only inside ``dest_parent``. Returns the created directory path.
|
|
58
|
+
Raises :class:`DemoExistsError` if the destination exists and ``force`` is False.
|
|
59
|
+
"""
|
|
60
|
+
dest = dest_parent / DEMO_DIR_NAME
|
|
61
|
+
if dest.exists():
|
|
62
|
+
if not force:
|
|
63
|
+
raise DemoExistsError(dest)
|
|
64
|
+
shutil.rmtree(dest)
|
|
65
|
+
|
|
66
|
+
source = packaged_demo_source()
|
|
67
|
+
if not source.is_dir():
|
|
68
|
+
raise FileNotFoundError(f"Bundled demo not found at {source}")
|
|
69
|
+
|
|
70
|
+
# as_file guarantees a real filesystem path even if the package were zipped.
|
|
71
|
+
with resources.as_file(resources.files("devtime").joinpath(*_RESOURCE_SUBPATH)) as src_path:
|
|
72
|
+
shutil.copytree(src_path, dest)
|
|
73
|
+
|
|
74
|
+
_strip_forbidden(dest)
|
|
75
|
+
return dest
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Secrets
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
*.pem
|
|
5
|
+
*.key
|
|
6
|
+
*.p12
|
|
7
|
+
*.pfx
|
|
8
|
+
id_rsa
|
|
9
|
+
id_ed25519
|
|
10
|
+
secrets.*
|
|
11
|
+
credentials.*
|
|
12
|
+
service-account*.json
|
|
13
|
+
|
|
14
|
+
# Generated
|
|
15
|
+
node_modules/
|
|
16
|
+
dist/
|
|
17
|
+
build/
|
|
18
|
+
coverage/
|
|
19
|
+
.next/
|
|
20
|
+
.cache/
|
|
21
|
+
|
|
22
|
+
# VCS
|
|
23
|
+
.git/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 0001 - Use JWT for authentication
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
Accepted
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
We needed stateless authentication that works across multiple API instances
|
|
8
|
+
without shared session storage.
|
|
9
|
+
|
|
10
|
+
## Decision
|
|
11
|
+
Use JWT access tokens signed with a server secret, with a 1 hour expiry.
|
|
12
|
+
|
|
13
|
+
## Consequences
|
|
14
|
+
- No server-side session store required.
|
|
15
|
+
- Token revocation before expiry is not yet solved.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "demo-saas",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Demo SaaS app for DevTime (Builder Edition, Appendix E).",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"express": "^4.19.0",
|
|
7
|
+
"stripe": "^15.0.0",
|
|
8
|
+
"jsonwebtoken": "^9.0.0",
|
|
9
|
+
"bullmq": "^5.0.0",
|
|
10
|
+
"ioredis": "^5.4.0"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"jest": "^29.7.0"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
|
|
3
|
+
export function requireAdmin(req: Request, res: Response, next: NextFunction) {
|
|
4
|
+
const role = (req as any).role;
|
|
5
|
+
if (role !== "admin") {
|
|
6
|
+
return res.status(403).json({ error: "forbidden" });
|
|
7
|
+
}
|
|
8
|
+
return next();
|
|
9
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
|
|
4
|
+
export const authRouter = Router();
|
|
5
|
+
|
|
6
|
+
authRouter.post("/auth/login", async (req, res) => {
|
|
7
|
+
const { email, password } = req.body;
|
|
8
|
+
const user = await findUser(email, password);
|
|
9
|
+
if (!user) {
|
|
10
|
+
return res.status(401).json({ error: "invalid_credentials" });
|
|
11
|
+
}
|
|
12
|
+
const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET as string, {
|
|
13
|
+
expiresIn: "1h",
|
|
14
|
+
});
|
|
15
|
+
return res.json({ token });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
async function findUser(email: string, password: string) {
|
|
19
|
+
// Lookup omitted for the demo.
|
|
20
|
+
return { id: "u_1", email };
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { verifyAccessToken } from "./tokens";
|
|
3
|
+
|
|
4
|
+
export function requireAuth(req: Request, res: Response, next: NextFunction) {
|
|
5
|
+
const header = req.headers.authorization;
|
|
6
|
+
if (!header) {
|
|
7
|
+
return res.status(401).json({ error: "missing_token" });
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const payload = verifyAccessToken(header.replace("Bearer ", ""));
|
|
11
|
+
(req as any).userId = payload.sub;
|
|
12
|
+
return next();
|
|
13
|
+
} catch {
|
|
14
|
+
return res.status(401).json({ error: "invalid_token" });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import jwt from "jsonwebtoken";
|
|
2
|
+
|
|
3
|
+
export function issueAccessToken(userId: string): string {
|
|
4
|
+
return jwt.sign({ sub: userId }, process.env.JWT_SECRET as string, {
|
|
5
|
+
expiresIn: "1h",
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function verifyAccessToken(token: string): { sub: string } {
|
|
10
|
+
return jwt.verify(token, process.env.JWT_SECRET as string) as { sub: string };
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import Stripe from "stripe";
|
|
3
|
+
import { updateSubscriptionState } from "./subscription-service";
|
|
4
|
+
|
|
5
|
+
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string);
|
|
6
|
+
export const billingRouter = Router();
|
|
7
|
+
|
|
8
|
+
billingRouter.post("/api/stripe/webhook", async (req, res) => {
|
|
9
|
+
const sig = req.headers["stripe-signature"] as string;
|
|
10
|
+
let event;
|
|
11
|
+
try {
|
|
12
|
+
event = stripe.webhooks.constructEvent(
|
|
13
|
+
(req as any).rawBody,
|
|
14
|
+
sig,
|
|
15
|
+
process.env.STRIPE_WEBHOOK_SECRET as string
|
|
16
|
+
);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
return res.status(400).send("invalid_signature");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (event.type === "customer.subscription.updated") {
|
|
22
|
+
await updateSubscriptionState(event.data.object);
|
|
23
|
+
}
|
|
24
|
+
return res.json({ received: true });
|
|
25
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function updateSubscriptionState(subscription: any): Promise<void> {
|
|
2
|
+
// Maps a Stripe subscription onto local subscription state.
|
|
3
|
+
const status = subscription.status;
|
|
4
|
+
const customerId = subscription.customer;
|
|
5
|
+
await saveSubscription(customerId, status);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async function saveSubscription(customerId: string, status: string) {
|
|
9
|
+
// Persistence omitted for the demo.
|
|
10
|
+
return { customerId, status };
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
|
|
3
|
+
export const exportRouter = Router();
|
|
4
|
+
|
|
5
|
+
exportRouter.get("/api/export/users.csv", async (req, res) => {
|
|
6
|
+
const rows = await loadUsers();
|
|
7
|
+
const csv = rows.map((r) => `${r.id},${r.email}`).join("\n");
|
|
8
|
+
res.setHeader("Content-Type", "text/csv");
|
|
9
|
+
return res.send(csv);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
async function loadUsers() {
|
|
13
|
+
return [{ id: "u_1", email: "demo@example.com" }];
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Worker } from "bullmq";
|
|
2
|
+
import IORedis from "ioredis";
|
|
3
|
+
|
|
4
|
+
const connection = new IORedis(process.env.REDIS_URL as string);
|
|
5
|
+
|
|
6
|
+
export const emailWorker = new Worker(
|
|
7
|
+
"emails",
|
|
8
|
+
async (job) => {
|
|
9
|
+
await sendEmail(job.data.to, job.data.template);
|
|
10
|
+
},
|
|
11
|
+
{ connection }
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
async function sendEmail(to: string, template: string) {
|
|
15
|
+
return { to, template };
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { issueAccessToken, verifyAccessToken } from "../src/auth/tokens";
|
|
2
|
+
|
|
3
|
+
describe("auth login", () => {
|
|
4
|
+
it("issues and verifies a jwt access token", () => {
|
|
5
|
+
process.env.JWT_SECRET = "test-secret";
|
|
6
|
+
const token = issueAccessToken("u_1");
|
|
7
|
+
const payload = verifyAccessToken(token);
|
|
8
|
+
expect(payload.sub).toBe("u_1");
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
describe("stripe webhook signature", () => {
|
|
2
|
+
it("rejects an invalid stripe signature", async () => {
|
|
3
|
+
// Verifies the signature-check branch returns 400 on bad signatures.
|
|
4
|
+
expect(true).toBe(true);
|
|
5
|
+
});
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// NOTE: intentionally missing a duplicate-delivery / retry test.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devtime-ei
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Local-first Engineering Intelligence for software repositories
|
|
5
5
|
Author-email: Aviad Shakargi <aviad94@gmail.com>
|
|
6
6
|
Maintainer-email: Aviad Shakargi <aviad94@gmail.com>
|
|
@@ -8,7 +8,7 @@ License: Apache-2.0
|
|
|
8
8
|
Project-URL: Homepage, https://github.com/Shakargy/devtime
|
|
9
9
|
Project-URL: Repository, https://github.com/Shakargy/devtime
|
|
10
10
|
Project-URL: Issues, https://github.com/Shakargy/devtime/issues
|
|
11
|
-
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.1.
|
|
11
|
+
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.1.1
|
|
12
12
|
Project-URL: Demo, https://youtu.be/1Hiu3Y9J_SI
|
|
13
13
|
Keywords: devtools,cli,static-analysis,repository-analysis,engineering-intelligence,local-first
|
|
14
14
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -56,6 +56,22 @@ decision improves understanding.
|
|
|
56
56
|
|
|
57
57
|
## Try DevTime in 60 seconds
|
|
58
58
|
|
|
59
|
+
```bash
|
|
60
|
+
pipx install devtime-ei
|
|
61
|
+
dtc demo init
|
|
62
|
+
cd devtime-demo-saas
|
|
63
|
+
dtc init
|
|
64
|
+
dtc scan
|
|
65
|
+
dtc concepts
|
|
66
|
+
dtc explain "Billing Webhooks"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
70
|
+
CLI command remains `dtc`. `dtc demo init` copies a small static example repo into
|
|
71
|
+
`./devtime-demo-saas` so you can try DevTime without cloning this repository.
|
|
72
|
+
|
|
73
|
+
### From source
|
|
74
|
+
|
|
59
75
|
```bash
|
|
60
76
|
git clone https://github.com/Shakargy/devtime.git
|
|
61
77
|
cd devtime
|
|
@@ -98,27 +114,36 @@ steps) is in **[DEMO_SCRIPT.md](DEMO_SCRIPT.md)**.
|
|
|
98
114
|
|
|
99
115
|
## Why this exists
|
|
100
116
|
|
|
101
|
-
Git
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
117
|
+
Git records what changed, but it does not preserve the reasoning behind those
|
|
118
|
+
changes. When you return to a repository - or review one you did not write - you often
|
|
119
|
+
have to reconstruct why a behavior exists, what evidence supports it, and what is
|
|
120
|
+
still uncertain.
|
|
105
121
|
|
|
106
|
-
DevTime builds evidence-backed repository memory: a local layer that
|
|
107
|
-
|
|
122
|
+
DevTime builds evidence-backed repository memory: a local layer that helps a
|
|
123
|
+
codebase explain itself from code, tests, configs, routes, and recorded decisions.
|
|
124
|
+
It shows what the repository can support with evidence - and, just as importantly,
|
|
125
|
+
what it cannot support yet.
|
|
108
126
|
|
|
109
127
|
## Who it is for
|
|
110
128
|
|
|
111
|
-
DevTime is for
|
|
112
|
-
|
|
113
|
-
generated summaries.
|
|
129
|
+
DevTime is for people who need to understand a repository from evidence rather than
|
|
130
|
+
memory.
|
|
114
131
|
|
|
115
|
-
It is useful
|
|
132
|
+
It is especially useful if you:
|
|
116
133
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
134
|
+
- are onboarding to an unfamiliar codebase and need to understand how a feature is implemented;
|
|
135
|
+
- are reviewing a pull request and want to see what evidence supports a behavior;
|
|
136
|
+
- are returning to a project after weeks or months and cannot remember why something exists;
|
|
137
|
+
- maintain a long-lived project where design decisions are easily lost;
|
|
138
|
+
- want repository understanding to be backed by code and recorded decisions instead of generated summaries.
|
|
139
|
+
|
|
140
|
+
Questions DevTime helps answer include:
|
|
141
|
+
|
|
142
|
+
- Where is authentication actually implemented?
|
|
143
|
+
- What files prove that Billing Webhooks exist?
|
|
144
|
+
- What is still uncertain?
|
|
145
|
+
- Did this diff touch a risky concept?
|
|
146
|
+
- Is there a decision explaining this behavior?
|
|
122
147
|
|
|
123
148
|
## What DevTime does
|
|
124
149
|
|
|
@@ -185,7 +210,24 @@ step-by-step first run and troubleshooting.
|
|
|
185
210
|
|
|
186
211
|
## Installation
|
|
187
212
|
|
|
188
|
-
Recommended
|
|
213
|
+
Recommended: install from PyPI with [pipx](https://pipx.pypa.io/) so the `dtc`
|
|
214
|
+
command is available on your PATH in an isolated environment:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pipx install devtime-ei
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Or with pip:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pip install devtime-ei
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
227
|
+
CLI command remains `dtc`. After installing, run `dtc demo init` to create a local
|
|
228
|
+
example repo to try it on.
|
|
229
|
+
|
|
230
|
+
### From source
|
|
189
231
|
|
|
190
232
|
```bash
|
|
191
233
|
git clone https://github.com/Shakargy/devtime.git
|
|
@@ -205,12 +247,6 @@ python -m venv .venv
|
|
|
205
247
|
pip install -e ".[dev]"
|
|
206
248
|
```
|
|
207
249
|
|
|
208
|
-
Planned PyPI install (after the package is published and verified):
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
pipx install devtime
|
|
212
|
-
```
|
|
213
|
-
|
|
214
250
|
## Example output
|
|
215
251
|
|
|
216
252
|
```
|
|
@@ -4,6 +4,7 @@ pyproject.toml
|
|
|
4
4
|
src/devtime/__init__.py
|
|
5
5
|
src/devtime/cli.py
|
|
6
6
|
src/devtime/config.py
|
|
7
|
+
src/devtime/demo.py
|
|
7
8
|
src/devtime/paths.py
|
|
8
9
|
src/devtime/privacy.py
|
|
9
10
|
src/devtime/ai/__init__.py
|
|
@@ -36,6 +37,21 @@ src/devtime/output/__init__.py
|
|
|
36
37
|
src/devtime/output/json_export.py
|
|
37
38
|
src/devtime/output/markdown.py
|
|
38
39
|
src/devtime/output/terminal.py
|
|
40
|
+
src/devtime/resources/demo-saas/.devtimeignore
|
|
41
|
+
src/devtime/resources/demo-saas/README.md
|
|
42
|
+
src/devtime/resources/demo-saas/package.json
|
|
43
|
+
src/devtime/resources/demo-saas/docs/decisions/0001-use-jwt.md
|
|
44
|
+
src/devtime/resources/demo-saas/src/admin/permissions.ts
|
|
45
|
+
src/devtime/resources/demo-saas/src/auth/login.ts
|
|
46
|
+
src/devtime/resources/demo-saas/src/auth/middleware.ts
|
|
47
|
+
src/devtime/resources/demo-saas/src/auth/tokens.ts
|
|
48
|
+
src/devtime/resources/demo-saas/src/billing/stripe-webhook.ts
|
|
49
|
+
src/devtime/resources/demo-saas/src/billing/subscription-service.ts
|
|
50
|
+
src/devtime/resources/demo-saas/src/export/export-csv.ts
|
|
51
|
+
src/devtime/resources/demo-saas/src/jobs/email-worker.ts
|
|
52
|
+
src/devtime/resources/demo-saas/src/jobs/queues.ts
|
|
53
|
+
src/devtime/resources/demo-saas/tests/auth-login.test.ts
|
|
54
|
+
src/devtime/resources/demo-saas/tests/stripe-signature.test.ts
|
|
39
55
|
src/devtime/scanner/__init__.py
|
|
40
56
|
src/devtime/scanner/file_walker.py
|
|
41
57
|
src/devtime/scanner/ignore.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|