baselane 0.1.2 → 0.1.3
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/dist/audit.d.ts +3 -1
- package/dist/audit.js +2 -2
- package/dist/cli.js +15 -7
- package/dist/graph.d.ts +3 -1
- package/dist/graph.js +2 -2
- package/dist/map.d.ts +1 -0
- package/dist/map.js +43 -2
- package/package.json +5 -5
package/dist/audit.d.ts
CHANGED
|
@@ -4,5 +4,7 @@ export interface AuditResult {
|
|
|
4
4
|
packs: string[];
|
|
5
5
|
recommended: string;
|
|
6
6
|
}
|
|
7
|
-
export declare function auditRepo(dir: string
|
|
7
|
+
export declare function auditRepo(dir: string, opts?: {
|
|
8
|
+
excludes?: string[];
|
|
9
|
+
}): Promise<AuditResult>;
|
|
8
10
|
export declare function formatAuditReport(r: AuditResult): string;
|
package/dist/audit.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { analyze, LocalDirFileSource } from "@baselane/analyze";
|
|
2
2
|
import { listBuiltinPacks } from "@baselane/packs";
|
|
3
|
-
export async function auditRepo(dir) {
|
|
4
|
-
const profile = await analyze(new LocalDirFileSource(dir));
|
|
3
|
+
export async function auditRepo(dir, opts = {}) {
|
|
4
|
+
const profile = await analyze(new LocalDirFileSource(dir, { excludes: opts.excludes }));
|
|
5
5
|
const packs = await listBuiltinPacks();
|
|
6
6
|
// Flagship default; every pack remains selectable via `apply --pack`.
|
|
7
7
|
const recommended = "software-engineer-harness";
|
package/dist/cli.js
CHANGED
|
@@ -16,12 +16,12 @@ import { LocalDirFileSource, analyze, analyzeConventions, analyzeDesignTokens, n
|
|
|
16
16
|
// page can never drift into a syntax this CLI doesn't actually accept.
|
|
17
17
|
export const USAGE = [
|
|
18
18
|
"usage:",
|
|
19
|
-
" baselane audit <dir> [--json]",
|
|
19
|
+
" baselane audit <dir> [--json] [--exclude <patterns>]",
|
|
20
20
|
" baselane apply <dir> (--pack <id> | --pack-file <path>) [--force] [--dry-run]",
|
|
21
21
|
" baselane distribute <owner/repo> (--pack <id> | --pack-file <path>) [--portal <url>]",
|
|
22
22
|
" baselane draft-pack <dir> [--json]",
|
|
23
|
-
" baselane graph <dir> [--json]",
|
|
24
|
-
" baselane map <dir> [--json] [--llm] [--dry-run]",
|
|
23
|
+
" baselane graph <dir> [--json] [--exclude <patterns>]",
|
|
24
|
+
" baselane map <dir> [--json] [--llm] [--dry-run] [--exclude <patterns>]",
|
|
25
25
|
" baselane install [github:owner/repo@ref | @scope/name[@version] | owner/repo@skill] [-g] [--dir <d>] [--dry-run] [--json]",
|
|
26
26
|
" baselane update [github:owner/repo | @scope/name] [-g] [--dir <d>] [--dry-run]",
|
|
27
27
|
" baselane drift [-g] [--dir <d>] [--json]",
|
|
@@ -31,6 +31,14 @@ function argValue(argv, flag) {
|
|
|
31
31
|
const i = argv.indexOf(flag);
|
|
32
32
|
return i !== -1 ? argv[i + 1] : undefined;
|
|
33
33
|
}
|
|
34
|
+
/** `--exclude a,b` → ["a", "b"] (gitignore syntax, comma-separated), or undefined when absent. */
|
|
35
|
+
function excludesArg(argv) {
|
|
36
|
+
const raw = argValue(argv, "--exclude");
|
|
37
|
+
if (!raw)
|
|
38
|
+
return undefined;
|
|
39
|
+
const patterns = raw.split(",").map((p) => p.trim()).filter((p) => p !== "");
|
|
40
|
+
return patterns.length > 0 ? patterns : undefined;
|
|
41
|
+
}
|
|
34
42
|
// #6: --pack-file is the escape hatch for a custom pack the CLI doesn't ship (a portal-authored
|
|
35
43
|
// or AI-drafted one saved to disk) — loadBuiltinPack only ever knows built-in ids. Same rule as
|
|
36
44
|
// every other pack entry point in this repo: validatePack is the sole authority, so a hand-edited
|
|
@@ -53,7 +61,7 @@ export async function main(argv, deps = {}) {
|
|
|
53
61
|
}
|
|
54
62
|
try {
|
|
55
63
|
if (cmd === "audit" && dir) {
|
|
56
|
-
const result = await auditRepo(dir);
|
|
64
|
+
const result = await auditRepo(dir, { excludes: excludesArg(argv) });
|
|
57
65
|
console.log(argv.includes("--json") ? JSON.stringify(result, null, 2) : formatAuditReport(result));
|
|
58
66
|
return 0;
|
|
59
67
|
}
|
|
@@ -76,7 +84,7 @@ export async function main(argv, deps = {}) {
|
|
|
76
84
|
return 0;
|
|
77
85
|
}
|
|
78
86
|
if (cmd === "graph" && dir) {
|
|
79
|
-
const r = await runGraph(dir);
|
|
87
|
+
const r = await runGraph(dir, { excludes: excludesArg(argv) });
|
|
80
88
|
console.log(argv.includes("--json") ? JSON.stringify(r.graph, null, 2) : formatGraphSummary(r.graph, r.written));
|
|
81
89
|
return 0;
|
|
82
90
|
}
|
|
@@ -90,7 +98,7 @@ export async function main(argv, deps = {}) {
|
|
|
90
98
|
"Run without --llm for the deterministic map.");
|
|
91
99
|
return 1;
|
|
92
100
|
}
|
|
93
|
-
const source = new LocalDirFileSource(dir);
|
|
101
|
+
const source = new LocalDirFileSource(dir, { excludes: excludesArg(argv) });
|
|
94
102
|
const [profile, conventions, samples, tokens, designSamples] = await Promise.all([
|
|
95
103
|
analyze(source),
|
|
96
104
|
analyzeConventions(source),
|
|
@@ -109,7 +117,7 @@ export async function main(argv, deps = {}) {
|
|
|
109
117
|
return 1;
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
|
-
const r = await runMap(dir, { dryRun: argv.includes("--dry-run"), narration, designNarration });
|
|
120
|
+
const r = await runMap(dir, { dryRun: argv.includes("--dry-run"), narration, designNarration, excludes: excludesArg(argv) });
|
|
113
121
|
console.log(argv.includes("--json")
|
|
114
122
|
? JSON.stringify({ profile: r.profile, conventions: r.conventions, tokens: r.tokens }, null, 2)
|
|
115
123
|
: argv.includes("--dry-run")
|
package/dist/graph.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export interface GraphResult {
|
|
|
5
5
|
written: string[];
|
|
6
6
|
}
|
|
7
7
|
/** Scans `dir` and writes `.baselane/graph.json` + `.baselane/graph/GRAPH.md` through the containment guard. */
|
|
8
|
-
export declare function runGraph(dir: string
|
|
8
|
+
export declare function runGraph(dir: string, opts?: {
|
|
9
|
+
excludes?: string[];
|
|
10
|
+
}): Promise<GraphResult>;
|
|
9
11
|
/** One-screen human summary: totals + top fan-in + what was written. */
|
|
10
12
|
export declare function formatGraphSummary(graph: ImportGraph, written: string[]): string;
|
package/dist/graph.js
CHANGED
|
@@ -3,8 +3,8 @@ import { dirname } from "node:path";
|
|
|
3
3
|
import { LocalDirFileSource, buildImportGraph, renderGraphMd } from "@baselane/analyze";
|
|
4
4
|
import { assertInsideDir } from "./apply.js";
|
|
5
5
|
/** Scans `dir` and writes `.baselane/graph.json` + `.baselane/graph/GRAPH.md` through the containment guard. */
|
|
6
|
-
export async function runGraph(dir) {
|
|
7
|
-
const graph = await buildImportGraph(new LocalDirFileSource(dir));
|
|
6
|
+
export async function runGraph(dir, opts = {}) {
|
|
7
|
+
const graph = await buildImportGraph(new LocalDirFileSource(dir, { excludes: opts.excludes }));
|
|
8
8
|
const outputs = [
|
|
9
9
|
[".baselane/graph.json", JSON.stringify(graph, null, 2) + "\n"],
|
|
10
10
|
[".baselane/graph/GRAPH.md", renderGraphMd(graph)],
|
package/dist/map.d.ts
CHANGED
|
@@ -11,5 +11,6 @@ export declare function runMap(dir: string, opts?: {
|
|
|
11
11
|
dryRun?: boolean;
|
|
12
12
|
narration?: NarrationSections | null;
|
|
13
13
|
designNarration?: DesignNarration | null;
|
|
14
|
+
excludes?: string[];
|
|
14
15
|
}): Promise<MapResult>;
|
|
15
16
|
export declare function formatMapSummary(result: MapResult): string;
|
package/dist/map.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { LocalDirFileSource, analyze, analyzeConventions, analyzeDesignTokens, buildImportGraph, renderArchitectureMd, renderDesignMd, DESIGN_REGION_ID, DESIGN_REGION_VERSION, SYSTEM_MAP_REGION_ID, SYSTEM_MAP_REGION_VERSION, } from "@baselane/analyze";
|
|
4
|
-
import { mergeManagedRegion } from "@baselane/packs";
|
|
4
|
+
import { buildManifest, extractManagedRegions, mergeManagedRegion, sha256Hex } from "@baselane/packs";
|
|
5
|
+
import { readManifestWithFallback, targetLocation, writeManifestFile } from "@baselane/materialize";
|
|
5
6
|
import { assertInsideDir } from "./apply.js";
|
|
6
7
|
export async function runMap(dir, opts = {}) {
|
|
7
|
-
const source = new LocalDirFileSource(dir);
|
|
8
|
+
const source = new LocalDirFileSource(dir, { excludes: opts.excludes });
|
|
8
9
|
const [profile, graph, conventions, tokens] = await Promise.all([
|
|
9
10
|
analyze(source),
|
|
10
11
|
buildImportGraph(source),
|
|
@@ -32,9 +33,49 @@ export async function runMap(dir, opts = {}) {
|
|
|
32
33
|
await writeFile(abs, content, "utf8");
|
|
33
34
|
written.push(rel);
|
|
34
35
|
}
|
|
36
|
+
await recordMapRegionReceipts(dir, architectureMd, designMd);
|
|
35
37
|
}
|
|
36
38
|
return { profile, conventions, tokens, architectureMd, designMd, written };
|
|
37
39
|
}
|
|
40
|
+
/** Issue #1: capability outputs were invisible to drift — apply/map wrote ARCHITECTURE.md and
|
|
41
|
+
* DESIGN.md but recorded nothing, so hand-edits or deletions never surfaced. Record their managed
|
|
42
|
+
* regions into harness.json's managedRegions receipts (drift's regions loop already verifies any
|
|
43
|
+
* path listed there). Region receipts, not whole-file hashes: prose the developer writes OUTSIDE
|
|
44
|
+
* the region is theirs and must not flag. No-op when the target has no manifest yet — drift has
|
|
45
|
+
* nothing to run against until an apply/install creates one. */
|
|
46
|
+
async function recordMapRegionReceipts(dir, architectureMd, designMd) {
|
|
47
|
+
const loc = targetLocation({ global: false, dir });
|
|
48
|
+
const { manifest: existing } = await readManifestWithFallback(loc);
|
|
49
|
+
if (existing === null)
|
|
50
|
+
return;
|
|
51
|
+
const managed = new Map(existing.materialized.managedRegions.map((m) => [m.path, m]));
|
|
52
|
+
const outputs = [["ARCHITECTURE.md", architectureMd]];
|
|
53
|
+
if (designMd !== null)
|
|
54
|
+
outputs.push(["DESIGN.md", designMd]);
|
|
55
|
+
for (const [path, content] of outputs) {
|
|
56
|
+
const regions = extractManagedRegions(content).map((r) => ({
|
|
57
|
+
packId: r.packId,
|
|
58
|
+
version: r.version,
|
|
59
|
+
sha256: sha256Hex(r.body),
|
|
60
|
+
}));
|
|
61
|
+
if (regions.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
const regionIds = new Set(regions.map((r) => r.packId));
|
|
64
|
+
const others = (managed.get(path)?.regions ?? []).filter((r) => !regionIds.has(r.packId));
|
|
65
|
+
managed.set(path, { path, regions: [...others, ...regions] });
|
|
66
|
+
}
|
|
67
|
+
const manifest = buildManifest({
|
|
68
|
+
target: loc.target,
|
|
69
|
+
packs: existing.packs,
|
|
70
|
+
registry: existing.registry,
|
|
71
|
+
capabilities: existing.capabilities,
|
|
72
|
+
receipt: {
|
|
73
|
+
...existing.materialized,
|
|
74
|
+
managedRegions: [...managed.values()].sort((a, b) => a.path.localeCompare(b.path)),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
await writeManifestFile(loc.manifestPath, manifest);
|
|
78
|
+
}
|
|
38
79
|
/** Reads a file, returning null (not throwing) when it does not exist. */
|
|
39
80
|
async function readIfExists(path) {
|
|
40
81
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "baselane",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Git-native package manager for AI coding harnesses — audit a repo, apply workflow packs, and keep agent config in sync.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"README.md"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@baselane/
|
|
38
|
-
"@baselane/
|
|
39
|
-
"@baselane/
|
|
40
|
-
"@baselane/
|
|
37
|
+
"@baselane/distribute": "0.1.3",
|
|
38
|
+
"@baselane/analyze": "0.1.3",
|
|
39
|
+
"@baselane/materialize": "0.1.3",
|
|
40
|
+
"@baselane/packs": "0.1.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^24.0.0",
|