@marwansaab/obsidian-vault-bootstrap 0.1.0
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/CONTRIBUTING.md +87 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/package.json +38 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Commit-message convention
|
|
4
|
+
|
|
5
|
+
Every commit in this project follows the convention below. It is a superset
|
|
6
|
+
of [Conventional Commits](https://www.conventionalcommits.org/) — the
|
|
7
|
+
`type(scope): description` subject is the same; the body conventions
|
|
8
|
+
layered on top are project-specific.
|
|
9
|
+
|
|
10
|
+
### Subject line (≤72 chars, no trailing period)
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
<type>(<scope>): <description>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- **`type`** — one of: `feat`, `fix`, `chore`, `docs`, `ci`, `refactor`,
|
|
17
|
+
`test`, `perf`.
|
|
18
|
+
- **`scope`** — the spec/feature ID when one exists (e.g. `013`,
|
|
19
|
+
`specs/009`); otherwise a component name (e.g. `git-extension`,
|
|
20
|
+
`release`, `readme`, `ci`).
|
|
21
|
+
- **`description`** — lowercase, imperative present tense ("add",
|
|
22
|
+
"implement", "bump", "clarify", "remediate", "pivot to", "mark",
|
|
23
|
+
"scaffold", "revert", "enable"). Sentence fragment, no period. May end
|
|
24
|
+
with a parenthetical clarifier like `(round 4)`,
|
|
25
|
+
`(consistency + coverage)`, or a task-ID list like `(T001, T003, T006)`.
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
|
|
29
|
+
- `feat(013): implement find_and_replace MCP tool with three-layer composition`
|
|
30
|
+
- `docs(013): clarify enumeration and count semantics for find_and_replace (round 3)`
|
|
31
|
+
- `chore(release): bump to 0.5.0 — spec 008 list_tags`
|
|
32
|
+
|
|
33
|
+
### Body (blank line after subject, wrap ~72 cols)
|
|
34
|
+
|
|
35
|
+
Lead with the **WHY** and **WHAT**, not the HOW (the diff shows the how).
|
|
36
|
+
|
|
37
|
+
1. One-paragraph summary of what this commit does and why it exists
|
|
38
|
+
(link to the user clarification, spike outcome, analyzer finding, or
|
|
39
|
+
upstream dependency that prompted it).
|
|
40
|
+
2. Itemised detail using bullets. Group related items under a SHOUTY-CAPS
|
|
41
|
+
prefix when categorising — e.g. `LAYER 1 — …`,
|
|
42
|
+
`T002 spike outcome (YYYY-MM-DD): NEGATIVE.`, `MINOR bump:` /
|
|
43
|
+
`PATCH bump:`, `F1 (HIGH) — …` (analyzer finding ID + severity),
|
|
44
|
+
`I2 (MEDIUM) — …` (consistency-issue ID + severity).
|
|
45
|
+
3. Reference identifiers wherever they apply, in their native form, no
|
|
46
|
+
decoration: `FR-NNN` (functional requirement), `SC-NNN` (success
|
|
47
|
+
criterion), `TNNN` (task ID, e.g. `T009a`), `RNN` (research item, e.g.
|
|
48
|
+
`R12`), `Q1` (clarification question), `file/path.ts:LINE` (when
|
|
49
|
+
pointing at code), `PR #NN`, `commit shortsha`. Don't gloss IDs as
|
|
50
|
+
"the requirement" — name them.
|
|
51
|
+
4. Be honest about tradeoffs, deferrals, and negative outcomes. If a
|
|
52
|
+
spike failed, say "NEGATIVE" and explain. If something is gated on
|
|
53
|
+
another piece of work, name the gate. If a task is deferred, say so
|
|
54
|
+
explicitly.
|
|
55
|
+
5. Close with quality-gate results when the commit changes code:
|
|
56
|
+
`Quality gates: lint clean, typecheck clean, build clean, 572/572
|
|
57
|
+
tests pass (was 422 baseline, +150 new, 0 regressions).` Include
|
|
58
|
+
coverage % when the project tracks a coverage floor.
|
|
59
|
+
6. For semver bumps, state the bump category and the rationale in one
|
|
60
|
+
sentence: `MINOR bump: adds the X public tool. Backward compatible —
|
|
61
|
+
no existing tool surface changes.` `PATCH bump (0.5.0 → 0.5.1) is the
|
|
62
|
+
honest signal: this PR ships internal preparation but no user-visible
|
|
63
|
+
capability.`
|
|
64
|
+
|
|
65
|
+
Bodies are **mandatory** for `feat`, spec, and analyzer-remediation
|
|
66
|
+
commits. They are optional for tiny one-line `fix`/`chore` commits, but
|
|
67
|
+
even those keep the `type(scope): subject` form.
|
|
68
|
+
|
|
69
|
+
### Trailers (blank line before, one per line, no wrap)
|
|
70
|
+
|
|
71
|
+
For AI-assisted commits, append:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Substitute the actual model name + version of the assistant session
|
|
78
|
+
that drafted the message.
|
|
79
|
+
|
|
80
|
+
### Tone
|
|
81
|
+
|
|
82
|
+
Direct, technical, no marketing language, no emoji. Prefer concrete
|
|
83
|
+
nouns ("the dispatcher's `getRestService` throw path") over abstractions
|
|
84
|
+
("the error handling"). Be willing to write things like "the templated
|
|
85
|
+
commit messages are too generic to be useful" when reverting something.
|
|
86
|
+
Write so a maintainer reading `git log` six months later can reconstruct
|
|
87
|
+
the WHY without opening the PR.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marwan Saab
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @marwansaab/obsidian-vault-bootstrap
|
|
2
|
+
|
|
3
|
+
Initialise a complete Obsidian vault — folder structure, templates, MOCs,
|
|
4
|
+
frontmatter conventions — and generate matching agent-instruction files for
|
|
5
|
+
Claude, Cursor, Cline, or any AI coding assistant. Q&A-driven, npm-versioned,
|
|
6
|
+
single source across your portfolio.
|
|
7
|
+
|
|
8
|
+
> **Governance.** Every change in this repository is measured against the
|
|
9
|
+
> project constitution:
|
|
10
|
+
> [`.specify/memory/constitution.md`](.specify/memory/constitution.md) (v1.0.0,
|
|
11
|
+
> ratified 2026-05-18). Principles I–VII are non-negotiable; reviewers cite
|
|
12
|
+
> them by Roman numeral when accepting or rejecting changes.
|
|
13
|
+
|
|
14
|
+
## Quickstart
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git clone https://github.com/marwansaab/obsidian-vault-bootstrap.git
|
|
18
|
+
cd obsidian-vault-bootstrap
|
|
19
|
+
nvm use 22 # or fnm / volta — Node >= 22.13.0 is required
|
|
20
|
+
npm ci # honours the lockfile and .npmrc engine-strict
|
|
21
|
+
npm run build
|
|
22
|
+
npx . --help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
v0.1 ships a placeholder CLI only — `npx . --help` and `npx . --version` are
|
|
26
|
+
the entire end-user surface. See **Limitations (v0.1)** below for what does
|
|
27
|
+
not work yet.
|
|
28
|
+
|
|
29
|
+
## Quality gates
|
|
30
|
+
|
|
31
|
+
The same six gates run locally and in CI (single source of truth per FR-014).
|
|
32
|
+
Each gate exits non-zero on any failure and names the offending file in its
|
|
33
|
+
output (FR-006).
|
|
34
|
+
|
|
35
|
+
| Gate | Command | Strictness bar |
|
|
36
|
+
| ------------ | ----------------------- | ---------------------------------------------- |
|
|
37
|
+
| format-check | `npm run format:check` | `prettier --check .` — zero divergence |
|
|
38
|
+
| lint | `npm run lint` | `eslint . --max-warnings 0` |
|
|
39
|
+
| typecheck | `npm run typecheck` | `tsc --noEmit` — zero diagnostics, strict mode |
|
|
40
|
+
| build | `npm run build` | `tsc` — zero warning-severity emit |
|
|
41
|
+
| test | `npm test` | `vitest run` — non-zero on any failure |
|
|
42
|
+
| coverage | `npm run test:coverage` | statements ≥ 80% (vitest threshold) |
|
|
43
|
+
|
|
44
|
+
`npm run format` is the local fix-it command (writes prettier-formatted files
|
|
45
|
+
back); it is **not** a CI gate.
|
|
46
|
+
|
|
47
|
+
## Limitations (v0.1)
|
|
48
|
+
|
|
49
|
+
v0.1 is a scaffold. The following are deliberately deferred — each will land
|
|
50
|
+
with the spec that first consumes it. The full version history is in
|
|
51
|
+
[`CHANGELOG.md`](CHANGELOG.md).
|
|
52
|
+
|
|
53
|
+
- No content-rendering pipeline yet — `core/`, `families/`, `templates/`, and
|
|
54
|
+
`projects/` ship empty (with `.gitkeep` placeholders) and will be populated
|
|
55
|
+
by subsequent specs.
|
|
56
|
+
- No end-user subcommands beyond `--help` / `--version` — no `init`, no
|
|
57
|
+
`bootstrap`, no profile-driven render.
|
|
58
|
+
- No interactive Q&A flow.
|
|
59
|
+
- No content-bearing fixtures (instruction-content files, template files,
|
|
60
|
+
project-profile files arrive in later specs).
|
|
61
|
+
- Not published to the public npm registry.
|
|
62
|
+
- No Obsidian vault-folder initialisation pipeline.
|
|
63
|
+
- **Single supported OS in CI: `ubuntu-latest`.** The package itself is Node
|
|
64
|
+
and runs anywhere Node does; the gate-verified OS in CI is Linux only.
|
|
65
|
+
Windows and macOS contributors can use the package, but their environment
|
|
66
|
+
is not covered by the CI matrix.
|
|
67
|
+
- No code-graph integration.
|
|
68
|
+
|
|
69
|
+
## Attributions
|
|
70
|
+
|
|
71
|
+
v0.1 ships no upstream-derived code; every source file in this commit carries
|
|
72
|
+
an `// Original — no upstream. <intent>.` header per constitution Principle
|
|
73
|
+
VII. This section exists as a stable insertion point — future modules
|
|
74
|
+
adapted from external projects will be listed here with their SPDX
|
|
75
|
+
identifier and pinned commit hash.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAOA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAuBD,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAwBvD"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Original — no upstream. Placeholder CLI entry-point for the v1 scaffold.
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { dirname, resolve } from "node:path";
|
|
7
|
+
const HELP_TEXT = `obsidian-vault-bootstrap
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
npx . [--help|--version]
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
-h, --help Show this help text and exit.
|
|
14
|
+
-v, --version Print the package version and exit.
|
|
15
|
+
|
|
16
|
+
v0.1 ships a placeholder CLI only. See README.md for the v0.1 limitations
|
|
17
|
+
and .specify/memory/constitution.md for the governance constitution.
|
|
18
|
+
`;
|
|
19
|
+
function readPackageVersion() {
|
|
20
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const pkgPath = resolve(here, "..", "package.json");
|
|
22
|
+
const raw = readFileSync(pkgPath, "utf8");
|
|
23
|
+
const parsed = JSON.parse(raw);
|
|
24
|
+
return parsed.version;
|
|
25
|
+
}
|
|
26
|
+
export function main(argv) {
|
|
27
|
+
try {
|
|
28
|
+
const { values } = parseArgs({
|
|
29
|
+
args: [...argv],
|
|
30
|
+
options: {
|
|
31
|
+
help: { type: "boolean", short: "h" },
|
|
32
|
+
version: { type: "boolean", short: "v" },
|
|
33
|
+
},
|
|
34
|
+
strict: true,
|
|
35
|
+
allowPositionals: false,
|
|
36
|
+
});
|
|
37
|
+
if (values.version) {
|
|
38
|
+
return { exitCode: 0, stdout: `${readPackageVersion()}\n`, stderr: "" };
|
|
39
|
+
}
|
|
40
|
+
return { exitCode: 0, stdout: HELP_TEXT, stderr: "" };
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
44
|
+
return {
|
|
45
|
+
exitCode: 1,
|
|
46
|
+
stdout: "",
|
|
47
|
+
stderr: `${message}\nUse --help for usage information.\n`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function invokedDirectly() {
|
|
52
|
+
const entry = process.argv[1];
|
|
53
|
+
if (!entry)
|
|
54
|
+
return false;
|
|
55
|
+
try {
|
|
56
|
+
return fileURLToPath(import.meta.url) === resolve(entry);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (invokedDirectly()) {
|
|
63
|
+
const result = main(process.argv.slice(2));
|
|
64
|
+
if (result.stdout)
|
|
65
|
+
process.stdout.write(result.stdout);
|
|
66
|
+
if (result.stderr)
|
|
67
|
+
process.stderr.write(result.stderr);
|
|
68
|
+
process.exit(result.exitCode);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,2EAA2E;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQ7C,MAAM,SAAS,GAAG;;;;;;;;;;;CAWjB,CAAC;AAEF,SAAS,kBAAkB;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;IACtD,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAuB;IAC1C,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;YAC3B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;YACf,OAAO,EAAE;gBACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;gBACrC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;aACzC;YACD,MAAM,EAAE,IAAI;YACZ,gBAAgB,EAAE,KAAK;SACxB,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAC1E,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,GAAG,OAAO,uCAAuC;SAC1D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,eAAe,EAAE,EAAE,CAAC;IACtB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@marwansaab/obsidian-vault-bootstrap",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22.13.0"
|
|
7
|
+
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"obsidian-vault-bootstrap": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"CONTRIBUTING.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"format:check": "prettier --check .",
|
|
19
|
+
"format": "prettier --write .",
|
|
20
|
+
"lint": "eslint . --max-warnings 0",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"prepare": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@eslint/js": "^9.0.0",
|
|
29
|
+
"@types/node": "^22.0.0",
|
|
30
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
31
|
+
"eslint": "^9.0.0",
|
|
32
|
+
"eslint-config-prettier": "^9.0.0",
|
|
33
|
+
"prettier": "^3.0.0",
|
|
34
|
+
"typescript": "^5.6.0",
|
|
35
|
+
"typescript-eslint": "^8.0.0",
|
|
36
|
+
"vitest": "^3.2.4"
|
|
37
|
+
}
|
|
38
|
+
}
|