@driftless-sh/cli 0.1.23 → 0.1.25
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 +11 -1
- package/dist/index.js +159 -5
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,6 +136,8 @@ driftless context get auth-boundaries --json
|
|
|
136
136
|
| `context search <query>` | Full-text search across topics |
|
|
137
137
|
| `context anchor <slug>` | Anchor a doc to a topic |
|
|
138
138
|
| `context push --files` | Match topics for given file paths |
|
|
139
|
+
| `context export` | Export all watchers to `.driftless/watchers/*.yaml` |
|
|
140
|
+
| `context import` | Import watchers from `.driftless/watchers/*.yaml` |
|
|
139
141
|
|
|
140
142
|
#### Dry run
|
|
141
143
|
|
|
@@ -205,6 +207,12 @@ driftless context update sdk --gotchas "Reset token on org switch"
|
|
|
205
207
|
# Anchor a doc
|
|
206
208
|
driftless context anchor auth --doc docs/auth.md --files "src/auth/**"
|
|
207
209
|
|
|
210
|
+
# Export all watchers to .driftless/watchers/*.yaml
|
|
211
|
+
driftless context export
|
|
212
|
+
|
|
213
|
+
# Import watchers from .driftless/watchers/*.yaml
|
|
214
|
+
driftless context import
|
|
215
|
+
|
|
208
216
|
# Delete a topic
|
|
209
217
|
driftless context delete old-feature
|
|
210
218
|
```
|
|
@@ -308,7 +316,9 @@ driftless scan
|
|
|
308
316
|
driftless context
|
|
309
317
|
├── CRUD topics via REST API
|
|
310
318
|
├── Full-text search (Postgres tsvector)
|
|
311
|
-
|
|
319
|
+
├── Pattern resolution (glob → resolved files)
|
|
320
|
+
├── export → .driftless/watchers/*.yaml (context as code)
|
|
321
|
+
└── import ← .driftless/watchers/*.yaml (bootstrap from repo)
|
|
312
322
|
```
|
|
313
323
|
|
|
314
324
|
## License
|
package/dist/index.js
CHANGED
|
@@ -445,7 +445,7 @@ var require_util = __commonJS({
|
|
|
445
445
|
return path;
|
|
446
446
|
}
|
|
447
447
|
exports2.normalize = normalize;
|
|
448
|
-
function
|
|
448
|
+
function join3(aRoot, aPath) {
|
|
449
449
|
if (aRoot === "") {
|
|
450
450
|
aRoot = ".";
|
|
451
451
|
}
|
|
@@ -477,7 +477,7 @@ var require_util = __commonJS({
|
|
|
477
477
|
}
|
|
478
478
|
return joined;
|
|
479
479
|
}
|
|
480
|
-
exports2.join =
|
|
480
|
+
exports2.join = join3;
|
|
481
481
|
exports2.isAbsolute = function(aPath) {
|
|
482
482
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
483
483
|
};
|
|
@@ -650,7 +650,7 @@ var require_util = __commonJS({
|
|
|
650
650
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
651
651
|
}
|
|
652
652
|
}
|
|
653
|
-
sourceURL =
|
|
653
|
+
sourceURL = join3(urlGenerate(parsed), sourceURL);
|
|
654
654
|
}
|
|
655
655
|
return normalize(sourceURL);
|
|
656
656
|
}
|
|
@@ -215072,6 +215072,7 @@ ${items.length} topic${items.length === 1 ? "" : "s"}.`);
|
|
|
215072
215072
|
function renderContextHuman(ctx) {
|
|
215073
215073
|
console.log(`\u258C ${ctx.topic}`);
|
|
215074
215074
|
console.log(` ${ctx.summary}`);
|
|
215075
|
+
if (ctx.version !== void 0) console.log(` version: ${ctx.version}`);
|
|
215075
215076
|
if (ctx.stale.is_stale) {
|
|
215076
215077
|
console.log(`
|
|
215077
215078
|
\u26A0 STALE: ${ctx.stale.reason || "Context may be outdated"}`);
|
|
@@ -215501,6 +215502,7 @@ async function contextCommand(args) {
|
|
|
215501
215502
|
}
|
|
215502
215503
|
const updates = { last_updated: /* @__PURE__ */ new Date() };
|
|
215503
215504
|
if (fileContent) updates.file_content = fileContent;
|
|
215505
|
+
if (docFlag) updates.anchored_doc_path = docFlag;
|
|
215504
215506
|
if (noteFlag) updates.decisions = noteFlag;
|
|
215505
215507
|
if (filesFlag) updates.where_files = filesFlag.split(",").map((f) => f.trim()).filter(Boolean);
|
|
215506
215508
|
if (patternFlag) updates.pattern = patternFlag;
|
|
@@ -215615,6 +215617,157 @@ Context delivered for ${files.length} file${files.length === 1 ? "" : "s"}.`);
|
|
|
215615
215617
|
}
|
|
215616
215618
|
return;
|
|
215617
215619
|
}
|
|
215620
|
+
if (subCommand === "export") {
|
|
215621
|
+
const dir = flags["dir"] ?? ".driftless/watchers";
|
|
215622
|
+
const absDir = (0, import_node_path4.resolve)(process.cwd(), dir);
|
|
215623
|
+
try {
|
|
215624
|
+
const summaries = await api.get(`/workspaces/${workspaceSlug}/watchers`);
|
|
215625
|
+
(0, import_node_fs4.mkdirSync)(absDir, { recursive: true });
|
|
215626
|
+
for (const summary of summaries) {
|
|
215627
|
+
const slug = summary.topic;
|
|
215628
|
+
let ctx;
|
|
215629
|
+
try {
|
|
215630
|
+
ctx = await api.get(`/workspaces/${workspaceSlug}/watchers/${slug}`);
|
|
215631
|
+
} catch {
|
|
215632
|
+
console.error(` skipped ${slug} (fetch failed)`);
|
|
215633
|
+
continue;
|
|
215634
|
+
}
|
|
215635
|
+
const lines = [];
|
|
215636
|
+
const needsQuotes = (s) => /[:#\[\]{}&*!|>'"%@`,]/.test(s) || s.trim() !== s;
|
|
215637
|
+
const safeStr = (s) => needsQuotes(s) ? `"${s.replace(/"/g, '\\"')}"` : s;
|
|
215638
|
+
lines.push(`slug: ${safeStr(slug)}`);
|
|
215639
|
+
if (ctx.version !== void 0) lines.push(`version: ${ctx.version}`);
|
|
215640
|
+
if (ctx.description.what) lines.push(`what: ${safeStr(ctx.description.what)}`);
|
|
215641
|
+
if (ctx.description.how) lines.push(`how: ${safeStr(ctx.description.how)}`);
|
|
215642
|
+
if (ctx.anchors.files.length > 0) {
|
|
215643
|
+
lines.push(`where_files:`);
|
|
215644
|
+
for (const f of ctx.anchors.files) lines.push(` - ${safeStr(f)}`);
|
|
215645
|
+
}
|
|
215646
|
+
if (ctx.anchors.docs.length > 0 && ctx.anchors.docs[0].path) {
|
|
215647
|
+
lines.push(`anchored_doc: ${safeStr(ctx.anchors.docs[0].path)}`);
|
|
215648
|
+
}
|
|
215649
|
+
if (ctx.description.decisions) lines.push(`decisions: ${safeStr(ctx.description.decisions)}`);
|
|
215650
|
+
if (ctx.description.gotchas.length > 0) {
|
|
215651
|
+
lines.push(`gotchas: ${safeStr(ctx.description.gotchas.join(". "))}`);
|
|
215652
|
+
}
|
|
215653
|
+
if (ctx.description.ownership) lines.push(`ownership: ${safeStr(ctx.description.ownership)}`);
|
|
215654
|
+
const yamlContent = lines.join("\n") + "\n";
|
|
215655
|
+
(0, import_node_fs4.writeFileSync)((0, import_node_path4.join)(absDir, `${slug}.yaml`), yamlContent, "utf-8");
|
|
215656
|
+
}
|
|
215657
|
+
if (!isJSON) {
|
|
215658
|
+
console.log(`Exported ${summaries.length} watcher${summaries.length === 1 ? "" : "s"} \u2192 ${dir}/`);
|
|
215659
|
+
} else {
|
|
215660
|
+
emitJSON2({ exported: summaries.length, dir });
|
|
215661
|
+
}
|
|
215662
|
+
} catch (e) {
|
|
215663
|
+
console.error(`Export failed: ${formatError(e)}`);
|
|
215664
|
+
process.exit(1);
|
|
215665
|
+
}
|
|
215666
|
+
return;
|
|
215667
|
+
}
|
|
215668
|
+
if (subCommand === "import") {
|
|
215669
|
+
const dir = flags["dir"] ?? ".driftless/watchers";
|
|
215670
|
+
const absDir = (0, import_node_path4.resolve)(process.cwd(), dir);
|
|
215671
|
+
if (!(0, import_node_fs4.existsSync)(absDir)) {
|
|
215672
|
+
console.error(`Directory not found: ${dir}`);
|
|
215673
|
+
process.exit(1);
|
|
215674
|
+
}
|
|
215675
|
+
let files;
|
|
215676
|
+
try {
|
|
215677
|
+
files = (0, import_node_fs4.readdirSync)(absDir).filter((f) => f.endsWith(".yaml"));
|
|
215678
|
+
} catch (e) {
|
|
215679
|
+
console.error(`Failed to read directory: ${formatError(e)}`);
|
|
215680
|
+
process.exit(1);
|
|
215681
|
+
}
|
|
215682
|
+
if (files.length === 0) {
|
|
215683
|
+
console.log(`No .yaml files found in ${dir}/`);
|
|
215684
|
+
return;
|
|
215685
|
+
}
|
|
215686
|
+
let created = 0;
|
|
215687
|
+
let updated = 0;
|
|
215688
|
+
for (const file of files) {
|
|
215689
|
+
const filePath = (0, import_node_path4.join)(absDir, file);
|
|
215690
|
+
let raw;
|
|
215691
|
+
try {
|
|
215692
|
+
raw = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
|
|
215693
|
+
} catch {
|
|
215694
|
+
console.error(` skipped ${file} (read error)`);
|
|
215695
|
+
continue;
|
|
215696
|
+
}
|
|
215697
|
+
const parsed = {};
|
|
215698
|
+
let lastArrayKey = null;
|
|
215699
|
+
for (const line of raw.split("\n")) {
|
|
215700
|
+
if (!line.trim() || line.trim().startsWith("#")) continue;
|
|
215701
|
+
if (/^\s{2,}-\s/.test(line)) {
|
|
215702
|
+
if (lastArrayKey) {
|
|
215703
|
+
const item = line.replace(/^\s{2,}-\s*/, "").trim();
|
|
215704
|
+
const existing = parsed[lastArrayKey];
|
|
215705
|
+
if (Array.isArray(existing)) {
|
|
215706
|
+
existing.push(item);
|
|
215707
|
+
} else {
|
|
215708
|
+
parsed[lastArrayKey] = [item];
|
|
215709
|
+
}
|
|
215710
|
+
}
|
|
215711
|
+
continue;
|
|
215712
|
+
}
|
|
215713
|
+
const colonIdx = line.indexOf(":");
|
|
215714
|
+
if (colonIdx === -1) continue;
|
|
215715
|
+
const key = line.slice(0, colonIdx).trim();
|
|
215716
|
+
let value = line.slice(colonIdx + 1).trim();
|
|
215717
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
215718
|
+
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
215719
|
+
}
|
|
215720
|
+
if (value === "") {
|
|
215721
|
+
lastArrayKey = key;
|
|
215722
|
+
parsed[key] = [];
|
|
215723
|
+
} else {
|
|
215724
|
+
lastArrayKey = null;
|
|
215725
|
+
parsed[key] = value;
|
|
215726
|
+
}
|
|
215727
|
+
}
|
|
215728
|
+
const slug = parsed["slug"];
|
|
215729
|
+
if (!slug) {
|
|
215730
|
+
console.error(` skipped ${file} (no slug field)`);
|
|
215731
|
+
continue;
|
|
215732
|
+
}
|
|
215733
|
+
const payload = {};
|
|
215734
|
+
if (parsed["what"]) payload.what = parsed["what"];
|
|
215735
|
+
if (parsed["how"]) payload.how = parsed["how"];
|
|
215736
|
+
if (parsed["where_files"]) payload.where_files = parsed["where_files"];
|
|
215737
|
+
if (parsed["anchored_doc"]) payload.anchored_doc_path = parsed["anchored_doc"];
|
|
215738
|
+
if (parsed["decisions"]) payload.decisions = parsed["decisions"];
|
|
215739
|
+
if (parsed["gotchas"]) payload.gotchas = parsed["gotchas"];
|
|
215740
|
+
if (parsed["ownership"]) payload.ownership = parsed["ownership"];
|
|
215741
|
+
let exists = false;
|
|
215742
|
+
try {
|
|
215743
|
+
await api.get(`/workspaces/${workspaceSlug}/watchers/${slug}`);
|
|
215744
|
+
exists = true;
|
|
215745
|
+
} catch {
|
|
215746
|
+
exists = false;
|
|
215747
|
+
}
|
|
215748
|
+
try {
|
|
215749
|
+
if (exists) {
|
|
215750
|
+
await api.patch(`/workspaces/${workspaceSlug}/watchers/${slug}`, payload);
|
|
215751
|
+
console.log(` \u2713 ${slug} (updated)`);
|
|
215752
|
+
updated++;
|
|
215753
|
+
} else {
|
|
215754
|
+
const name = slug.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
215755
|
+
await api.post(`/workspaces/${workspaceSlug}/watchers`, { name, ...payload });
|
|
215756
|
+
console.log(` \u2713 ${slug} (created)`);
|
|
215757
|
+
created++;
|
|
215758
|
+
}
|
|
215759
|
+
} catch (e) {
|
|
215760
|
+
console.error(` \u2717 ${slug}: ${formatError(e)}`);
|
|
215761
|
+
}
|
|
215762
|
+
}
|
|
215763
|
+
if (!isJSON) {
|
|
215764
|
+
console.log(`
|
|
215765
|
+
Done: ${created} created, ${updated} updated.`);
|
|
215766
|
+
} else {
|
|
215767
|
+
emitJSON2({ created, updated });
|
|
215768
|
+
}
|
|
215769
|
+
return;
|
|
215770
|
+
}
|
|
215618
215771
|
console.log(`Usage: driftless context <list|get|add|update|delete|search|push> [args]
|
|
215619
215772
|
|
|
215620
215773
|
Run 'driftless help context' for full reference.`);
|
|
@@ -216048,7 +216201,8 @@ var CONFIG_DIR = (0, import_node_path7.resolve)((0, import_node_os2.homedir)(),
|
|
|
216048
216201
|
var CONFIG_PATH2 = (0, import_node_path7.resolve)(CONFIG_DIR, "config.json");
|
|
216049
216202
|
function openBrowser(url) {
|
|
216050
216203
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
216051
|
-
(0, import_node_child_process2.
|
|
216204
|
+
const child = (0, import_node_child_process2.spawn)(cmd, [url], { stdio: "ignore", detached: true });
|
|
216205
|
+
child.unref();
|
|
216052
216206
|
}
|
|
216053
216207
|
async function loginCommand(args) {
|
|
216054
216208
|
const keyIndex = args.indexOf("--key");
|
|
@@ -216254,7 +216408,7 @@ function pad2(s, n) {
|
|
|
216254
216408
|
}
|
|
216255
216409
|
|
|
216256
216410
|
// src/index.ts
|
|
216257
|
-
var VERSION = "0.1.
|
|
216411
|
+
var VERSION = "0.1.25";
|
|
216258
216412
|
var HELP_TEXT = `Driftless CLI v${VERSION} \u2014 Living repo context for humans and coding agents
|
|
216259
216413
|
|
|
216260
216414
|
Install: npm install -g @driftless-sh/cli
|