crowbar-cli 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.
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/PKG-INFO +1 -1
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/__init__.py +1 -1
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/LAUNCH.md +1 -1
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/install.mjs +25 -12
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/.gitignore +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/AGENTS.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/LICENSE +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/Makefile +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/README.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/bin/crowbar +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/catalog.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/cli.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/datasets.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/db.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/indexer.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/intel.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/loaders.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/mcp.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/paths.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/crowbar/query.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/DATASETS.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/INTEL.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/INTEL_RESEARCH_PROMPT.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/MAP.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/NIX.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/assets/agent-session.gif +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/assets/demo.gif +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/docs/assets/flow.svg +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/mcp/server.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/pyproject.toml +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/age_index.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/check.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/fetch_intel.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/install.test.mjs +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/make_fixture.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/merge_p0.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/rollback_index.sh +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/selftest.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/scripts/smoke.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/skills/crowbar/SKILL.md +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/tests/__init__.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/tests/support.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/tests/test_corpus.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/tests/test_unit.py +0 -0
- {crowbar_cli-0.1.0 → crowbar_cli-0.1.1}/tests/test_v3.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: crowbar-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Retrieve CVEs and index them inside your codebase. One SQLite+FTS5 index, one CLI, one MCP server.
|
|
5
5
|
Project-URL: Homepage, https://github.com/kushvinth/crowbar
|
|
6
6
|
Project-URL: Repository, https://github.com/kushvinth/crowbar
|
|
@@ -27,7 +27,7 @@ to `main`, `release-please` opens/updates a release PR; merging it tags
|
|
|
27
27
|
|
|
28
28
|
So after the one-time setup, **publishing = merge the release PR**.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
v0.1.0 was cut with a temporary `release-as: 0.1.0` pin in `release-please-config.json`, removed once tagged; versions now follow the Conventional Commits since the last release.
|
|
31
31
|
|
|
32
32
|
Registries publish only once switched on: set the repo variables `PUBLISH_NPM` / `PUBLISH_PYPI` to `true` (Settings > Secrets and variables > Actions > Variables). npm needs `NPM_TOKEN` to be a granular token with "bypass 2FA" enabled; PyPI needs the trusted publisher (owner `kushvinth`, repo `crowbar`, workflow `release.yml`, environment `pypi`). To publish an existing release to a registry switched on later, run the `release` workflow by hand with that tag (e.g. `gh workflow run release -f tag=v0.1.0`); versions already on a registry are skipped.
|
|
33
33
|
|
|
@@ -81,10 +81,21 @@ export function describe(step, remove = false) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
// One read per file: the backup and the edit both start from this text, so
|
|
85
|
+
// nothing can change the file between a check and its use.
|
|
86
|
+
function readText(file) {
|
|
87
|
+
try {
|
|
88
|
+
return fs.readFileSync(file, "utf8");
|
|
89
|
+
} catch (e) {
|
|
90
|
+
if (e.code === "ENOENT") return null;
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function backup(file, text, stamp) {
|
|
96
|
+
if (text === null) return null;
|
|
86
97
|
const dst = `${file}.crowbar-backup-${stamp}`;
|
|
87
|
-
fs.
|
|
98
|
+
fs.writeFileSync(dst, text);
|
|
88
99
|
return dst;
|
|
89
100
|
}
|
|
90
101
|
|
|
@@ -104,11 +115,12 @@ export function apply(step, stamp = Date.now()) {
|
|
|
104
115
|
return "registered";
|
|
105
116
|
}
|
|
106
117
|
fs.mkdirSync(path.dirname(step.file), { recursive: true });
|
|
107
|
-
const
|
|
118
|
+
const original = readText(step.file);
|
|
119
|
+
const text = original ?? "";
|
|
108
120
|
if (step.kind === "toml") {
|
|
109
121
|
const header = `[${step.table}]`;
|
|
110
122
|
if (text.split(/\r?\n/).some((l) => l.trim() === header)) return "already registered";
|
|
111
|
-
const saved = backup(step.file, stamp);
|
|
123
|
+
const saved = backup(step.file, original, stamp);
|
|
112
124
|
const sep = text && !text.endsWith("\n") ? "\n\n" : text ? "\n" : "";
|
|
113
125
|
fs.writeFileSync(step.file, `${text}${sep}${header}\n${step.body}`);
|
|
114
126
|
return saved ? `updated (backup ${path.basename(saved)})` : "created";
|
|
@@ -120,7 +132,7 @@ export function apply(step, stamp = Date.now()) {
|
|
|
120
132
|
// JSONC with comments or a broken file: leave it alone rather than rewrite it
|
|
121
133
|
throw new Error(`${step.file} is not plain JSON - add crowbar by hand (npx crowbar-cli prints the block)`);
|
|
122
134
|
}
|
|
123
|
-
const saved = backup(step.file, stamp);
|
|
135
|
+
const saved = backup(step.file, original, stamp);
|
|
124
136
|
step.mutate(cfg);
|
|
125
137
|
fs.writeFileSync(step.file, JSON.stringify(cfg, null, 2) + "\n");
|
|
126
138
|
return saved ? `updated (backup ${path.basename(saved)})` : "created";
|
|
@@ -141,8 +153,8 @@ export function unapply(step, stamp = Date.now()) {
|
|
|
141
153
|
if (r.status !== 0) throw new Error((r.stderr || r.stdout || "failed").trim());
|
|
142
154
|
return "unregistered";
|
|
143
155
|
}
|
|
144
|
-
|
|
145
|
-
|
|
156
|
+
const text = readText(step.file);
|
|
157
|
+
if (text === null) return "not registered";
|
|
146
158
|
if (step.kind === "toml") {
|
|
147
159
|
const lines = text.split(/\r?\n/);
|
|
148
160
|
const start = lines.findIndex((l) => l.trim() === `[${step.table}]`);
|
|
@@ -151,7 +163,7 @@ export function unapply(step, stamp = Date.now()) {
|
|
|
151
163
|
while (end < lines.length && !(/^\s*\[/.test(lines[end]) && !lines[end].trim().startsWith(`[${step.table}.`))) end++;
|
|
152
164
|
let from = start; // and takes the blank lines setup put before it
|
|
153
165
|
while (from > 0 && !lines[from - 1].trim()) from--;
|
|
154
|
-
const saved = backup(step.file, stamp);
|
|
166
|
+
const saved = backup(step.file, text, stamp);
|
|
155
167
|
const rest = [...lines.slice(0, from), ...(from && end < lines.length ? [""] : []), ...lines.slice(end)];
|
|
156
168
|
fs.writeFileSync(step.file, rest.join("\n").replace(/\n*$/, rest.some((l) => l.trim()) ? "\n" : ""));
|
|
157
169
|
return `removed (backup ${path.basename(saved)})`;
|
|
@@ -162,9 +174,10 @@ export function unapply(step, stamp = Date.now()) {
|
|
|
162
174
|
} catch {
|
|
163
175
|
throw new Error(`${step.file} is not plain JSON - remove crowbar by hand`);
|
|
164
176
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
177
|
+
const servers = Object.hasOwn(cfg, step.key) ? cfg[step.key] : null;
|
|
178
|
+
if (!servers || typeof servers !== "object" || !Object.hasOwn(servers, "crowbar")) return "not registered";
|
|
179
|
+
const saved = backup(step.file, text, stamp);
|
|
180
|
+
delete servers.crowbar;
|
|
168
181
|
fs.writeFileSync(step.file, JSON.stringify(cfg, null, 2) + "\n");
|
|
169
182
|
return `removed (backup ${path.basename(saved)})`;
|
|
170
183
|
}
|
|
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
|