daftari 1.16.0 → 1.17.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/CHANGELOG.md +52 -0
- package/dist/backfill/apply.d.ts +14 -0
- package/dist/backfill/apply.d.ts.map +1 -0
- package/dist/backfill/apply.js +111 -0
- package/dist/backfill/apply.js.map +1 -0
- package/dist/backfill/derive.d.ts +25 -0
- package/dist/backfill/derive.d.ts.map +1 -0
- package/dist/backfill/derive.js +142 -0
- package/dist/backfill/derive.js.map +1 -0
- package/dist/backfill/index.d.ts +2 -0
- package/dist/backfill/index.d.ts.map +1 -0
- package/dist/backfill/index.js +232 -0
- package/dist/backfill/index.js.map +1 -0
- package/dist/backfill/plan.d.ts +19 -0
- package/dist/backfill/plan.d.ts.map +1 -0
- package/dist/backfill/plan.js +157 -0
- package/dist/backfill/plan.js.map +1 -0
- package/dist/backfill/types.d.ts +19 -0
- package/dist/backfill/types.d.ts.map +1 -0
- package/dist/backfill/types.js +10 -0
- package/dist/backfill/types.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -1
- package/dist/curation/lint.d.ts +3 -0
- package/dist/curation/lint.d.ts.map +1 -1
- package/dist/curation/lint.js +5 -0
- package/dist/curation/lint.js.map +1 -1
- package/dist/curation/staged-actions.d.ts +68 -0
- package/dist/curation/staged-actions.d.ts.map +1 -0
- package/dist/curation/staged-actions.js +394 -0
- package/dist/curation/staged-actions.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/search/reindex.d.ts.map +1 -1
- package/dist/search/reindex.js +6 -0
- package/dist/search/reindex.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/storage/index-db.d.ts +19 -0
- package/dist/storage/index-db.d.ts.map +1 -1
- package/dist/storage/index-db.js +56 -0
- package/dist/storage/index-db.js.map +1 -1
- package/dist/tools/curation.d.ts +2 -1
- package/dist/tools/curation.d.ts.map +1 -1
- package/dist/tools/curation.js +18 -4
- package/dist/tools/curation.js.map +1 -1
- package/dist/tools/staged-actions.d.ts +18 -0
- package/dist/tools/staged-actions.d.ts.map +1 -0
- package/dist/tools/staged-actions.js +275 -0
- package/dist/tools/staged-actions.js.map +1 -0
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +32 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/git.d.ts +6 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +34 -0
- package/dist/utils/git.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.17.0] - 2026-06-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`daftari backfill` git-driven frontmatter migration** (cortex consolidation
|
|
15
|
+
loop §11.1). A CLI command that adopts an existing wiki into Daftari without a
|
|
16
|
+
manual migration sprint: it walks the vault, derives frontmatter defaults
|
|
17
|
+
deterministically (no LLM calls) from git history and body conventions, and
|
|
18
|
+
writes them per-folder on human ratification. Two-step plan/apply:
|
|
19
|
+
`daftari backfill --plan [--scope <folder>]` derives proposals and stages them
|
|
20
|
+
to `.daftari/backfill-plan.jsonl` (modifying no markdown), and
|
|
21
|
+
`daftari backfill --apply --scope <folder> [--yes]` writes the proposals for
|
|
22
|
+
one folder and commits them in a single commit (honoring the vault's
|
|
23
|
+
`auto_commit` setting — with `auto_commit: false` the files are written but
|
|
24
|
+
the caller owns git, matching the other write tools). `--scope` is required on
|
|
25
|
+
apply so a whole-vault write can never happen by accident. Derivation: `title`
|
|
26
|
+
from the first H1 (else the filename), `created`/`updated`/`updated_by` from
|
|
27
|
+
git (`--diff-filter=A` first-add, last-commit, author through an optional
|
|
28
|
+
`backfill.identity_map` in `.daftari/config.yaml`), `collection` from the
|
|
29
|
+
parent folder, and `status: canonical` / `confidence: medium` /
|
|
30
|
+
`provenance: direct` / `domain: accumulation` defaults — explicitly suggested,
|
|
31
|
+
ratified by a human, never asserted. Existing frontmatter is preserved
|
|
32
|
+
field-by-field; a doc whose frontmatter already validates is reported
|
|
33
|
+
conformant and skipped. The plan is transient: backfill never stages or
|
|
34
|
+
commits it (apply stages only the doc paths), the apply commit is the durable
|
|
35
|
+
audit trail, and `.daftari/backfill-plan.jsonl` is added to the `daftari
|
|
36
|
+
--init` .gitignore template (a `--plan` run also prints a reminder to gitignore
|
|
37
|
+
it on wikis not scaffolded by Daftari). CLI-only for v1 — no MCP tool. See
|
|
38
|
+
[docs/superpowers/specs/2026-06-06-cortex-consolidation-loop-design-direction.md](docs/superpowers/specs/2026-06-06-cortex-consolidation-loop-design-direction.md)
|
|
39
|
+
§11.1.
|
|
40
|
+
- **Staged-action queue + `vault_ratify`** (cortex loop §11.2). A persistent
|
|
41
|
+
queue of proposed vault changes awaiting human ratification — the foundation
|
|
42
|
+
for the consolidation loop's "always-stage" tier. Two new MCP tools:
|
|
43
|
+
`vault_stage_action` (producer; normally the curation loop, exposed for
|
|
44
|
+
testing and future callers) records a proposed `promote` / `deprecate` /
|
|
45
|
+
`supersede` / `merge` / `confidence-up` action with a rationale, a proposed
|
|
46
|
+
diff, and a TTL (default 14 days); `vault_ratify` (consumer) lets a human
|
|
47
|
+
`approve` or `reject` one pending action. On approve, it dispatches to the
|
|
48
|
+
existing write path — `promote` → `vault_promote`, `deprecate` →
|
|
49
|
+
`vault_deprecate` (both auto-commit). `supersede` / `merge` / `confidence-up`
|
|
50
|
+
are staged only in v1 (their write tools are deferred to §11.4); approving
|
|
51
|
+
one returns `applied: false` with `deferred_to: "§11.4"` and a
|
|
52
|
+
`ratified-pending-tool` status. Storage mirrors the rest of Daftari: an
|
|
53
|
+
append-only canonical log at `.daftari/staged-actions.jsonl` (the source of
|
|
54
|
+
truth) plus a derived `staged_actions` table in the ephemeral
|
|
55
|
+
`.daftari/index.db`, rebuilt from the jsonl on reindex and startup.
|
|
56
|
+
`vault_lint` gains a "Staged actions" section listing pending actions
|
|
57
|
+
soonest-to-expire first, and expires actions past their TTL as a housekeeping
|
|
58
|
+
sweep on each invocation. See
|
|
59
|
+
[docs/superpowers/specs/2026-06-06-cortex-consolidation-loop-design-direction.md](docs/superpowers/specs/2026-06-06-cortex-consolidation-loop-design-direction.md)
|
|
60
|
+
§11.2.
|
|
61
|
+
|
|
10
62
|
## [1.16.0] - 2026-06-02
|
|
11
63
|
|
|
12
64
|
### Added
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Result } from "../frontmatter/types.js";
|
|
2
|
+
export interface SkippedDoc {
|
|
3
|
+
path: string;
|
|
4
|
+
reason: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ApplyResult {
|
|
7
|
+
scope: string;
|
|
8
|
+
applied: string[];
|
|
9
|
+
unchanged: string[];
|
|
10
|
+
skipped: SkippedDoc[];
|
|
11
|
+
commit: string | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function applyPlan(vaultRoot: string, scope: string, agent: string): Promise<Result<ApplyResult, Error>>;
|
|
14
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/backfill/apply.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAU1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,SAAS,EAAE,MAAM,EAAE,CAAC;IAEpB,OAAO,EAAE,UAAU,EAAE,CAAC;IAEtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAkCD,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAwErC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Plan application for `daftari backfill` (§11.1).
|
|
2
|
+
//
|
|
3
|
+
// `applyPlan` reads the plan, takes only the entries under the given scope
|
|
4
|
+
// (per-folder ratification), and writes each doc's proposed frontmatter through
|
|
5
|
+
// the same primitives the write tools use: validate, serialize, then one git
|
|
6
|
+
// commit for the whole scope. The body is taken from the file on disk at apply
|
|
7
|
+
// time, so a body edited between plan and apply is preserved; only frontmatter
|
|
8
|
+
// is filled.
|
|
9
|
+
//
|
|
10
|
+
// --scope is required (the CLI enforces it) so a whole-vault write can never
|
|
11
|
+
// happen by accident. The run is idempotent: a doc whose on-disk content
|
|
12
|
+
// already equals the proposed serialization is left untouched, so re-applying
|
|
13
|
+
// an already-applied folder is a no-op (and never produces an empty commit).
|
|
14
|
+
import { writeFile } from "node:fs/promises";
|
|
15
|
+
import { recordProvenance } from "../curation/provenance.js";
|
|
16
|
+
import { parseDocument } from "../frontmatter/parser.js";
|
|
17
|
+
import { validateFrontmatter } from "../frontmatter/schema.js";
|
|
18
|
+
import { ok } from "../frontmatter/types.js";
|
|
19
|
+
import { readFile, resolveVaultPath } from "../storage/local.js";
|
|
20
|
+
import { serializeDocument } from "../tools/write.js";
|
|
21
|
+
import { loadConfig } from "../utils/config.js";
|
|
22
|
+
import { commit } from "../utils/git.js";
|
|
23
|
+
import { planPath, readPlan } from "./plan.js";
|
|
24
|
+
// Serializes one plan entry against the file's current body. Returns the new
|
|
25
|
+
// file text, or a reason it cannot be written.
|
|
26
|
+
function renderEntry(entry, currentText, extensions) {
|
|
27
|
+
const parsed = parseDocument(currentText);
|
|
28
|
+
if (!parsed.ok)
|
|
29
|
+
return parsed;
|
|
30
|
+
// Guard: never write frontmatter the validator would reject. A non-conformant
|
|
31
|
+
// doc whose *present* field is itself malformed (so preservation carries the
|
|
32
|
+
// bad value through) is reported, not written.
|
|
33
|
+
const { report } = validateFrontmatter(entry.proposed);
|
|
34
|
+
if (!report.valid) {
|
|
35
|
+
const summary = report.issues.map((i) => `${i.field}: ${i.message}`).join("; ");
|
|
36
|
+
return { ok: false, error: new Error(`proposed frontmatter is invalid: ${summary}`) };
|
|
37
|
+
}
|
|
38
|
+
// Preserve any config-extension fields present on disk by passing the current
|
|
39
|
+
// raw frontmatter through to the serializer.
|
|
40
|
+
const text = serializeDocument(entry.proposed, parsed.value.content, extensions, parsed.value.raw);
|
|
41
|
+
return ok(text);
|
|
42
|
+
}
|
|
43
|
+
// Applies all plan entries under `scope`. Writes only changed docs and commits
|
|
44
|
+
// them in a single commit authored by `agent`.
|
|
45
|
+
export async function applyPlan(vaultRoot, scope, agent) {
|
|
46
|
+
const plan = await readPlan(planPath(vaultRoot));
|
|
47
|
+
if (!plan.ok)
|
|
48
|
+
return plan;
|
|
49
|
+
const config = loadConfig(vaultRoot);
|
|
50
|
+
if (!config.ok)
|
|
51
|
+
return config;
|
|
52
|
+
const extensions = config.value.schemaExtensions;
|
|
53
|
+
const inScope = plan.value.filter((e) => e.scope === scope);
|
|
54
|
+
const applied = [];
|
|
55
|
+
const unchanged = [];
|
|
56
|
+
const skipped = [];
|
|
57
|
+
for (const entry of inScope) {
|
|
58
|
+
const resolved = resolveVaultPath(vaultRoot, entry.path);
|
|
59
|
+
if (!resolved.ok) {
|
|
60
|
+
skipped.push({ path: entry.path, reason: resolved.error.message });
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const existing = await readFile(resolved.value);
|
|
64
|
+
if (!existing.ok) {
|
|
65
|
+
skipped.push({ path: entry.path, reason: existing.error.message });
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const rendered = renderEntry(entry, existing.value, extensions);
|
|
69
|
+
if (!rendered.ok) {
|
|
70
|
+
skipped.push({ path: entry.path, reason: rendered.error.message });
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Idempotence: identical bytes → no write, no stage, no commit churn.
|
|
74
|
+
if (rendered.value === existing.value) {
|
|
75
|
+
unchanged.push(entry.path);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await writeFile(resolved.value, rendered.value, "utf-8");
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
83
|
+
skipped.push({ path: entry.path, reason: `write failed: ${reason}` });
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
applied.push(entry.path);
|
|
87
|
+
}
|
|
88
|
+
// One commit for the whole scope. Skipped entirely when nothing changed (no
|
|
89
|
+
// empty commits) or when the vault is configured with auto_commit: false.
|
|
90
|
+
let commitHash = null;
|
|
91
|
+
if (applied.length > 0 && config.value.autoCommit) {
|
|
92
|
+
const message = `vault_backfill: ${scope} — ${applied.length} ` +
|
|
93
|
+
`${applied.length === 1 ? "doc" : "docs"} frontmatter backfilled by ${agent}`;
|
|
94
|
+
const committed = await commit(vaultRoot, applied, message, agent);
|
|
95
|
+
if (!committed.ok)
|
|
96
|
+
return committed;
|
|
97
|
+
commitHash = committed.value.hash;
|
|
98
|
+
}
|
|
99
|
+
// Advisory provenance, per applied doc. Best-effort: a log failure does not
|
|
100
|
+
// fail the backfill (the commit is the durable record).
|
|
101
|
+
for (const path of applied) {
|
|
102
|
+
await recordProvenance(vaultRoot, {
|
|
103
|
+
tool: "vault_backfill",
|
|
104
|
+
file: path,
|
|
105
|
+
agent,
|
|
106
|
+
action: "backfill",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return ok({ scope, applied, unchanged, skipped, commit: commitHash });
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/backfill/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Frontmatter } from "../frontmatter/types.js";
|
|
2
|
+
import type { FileGitMeta } from "../utils/git.js";
|
|
3
|
+
import type { DerivationMap, DocClassification } from "./types.js";
|
|
4
|
+
export declare function slugify(value: string): string;
|
|
5
|
+
export declare function firstH1(body: string): string | null;
|
|
6
|
+
export declare function titleFromFilename(relPath: string): string;
|
|
7
|
+
export declare function parseQuestionSection(body: string, heading: string): string[];
|
|
8
|
+
export declare function mapIdentity(author: string, identityMap: Record<string, string>): string;
|
|
9
|
+
export declare function classifyDoc(raw: Record<string, unknown>): DocClassification;
|
|
10
|
+
export interface DeriveInputs {
|
|
11
|
+
relPath: string;
|
|
12
|
+
body: string;
|
|
13
|
+
raw: Record<string, unknown>;
|
|
14
|
+
coerced: Frontmatter;
|
|
15
|
+
git: FileGitMeta;
|
|
16
|
+
mtimeDate: string;
|
|
17
|
+
identityMap: Record<string, string>;
|
|
18
|
+
invoker: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DerivedFrontmatter {
|
|
21
|
+
proposed: Frontmatter;
|
|
22
|
+
derivation: DerivationMap;
|
|
23
|
+
}
|
|
24
|
+
export declare function deriveProposed(input: DeriveInputs): DerivedFrontmatter;
|
|
25
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/backfill/derive.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAInE,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7C;AAID,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnD;AAID,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKzD;AAKD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqB5E;AAID,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAIvF;AAeD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,CAG3E;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAG7B,OAAO,EAAE,WAAW,CAAC;IACrB,GAAG,EAAE,WAAW,CAAC;IAEjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAGpC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,aAAa,CAAC;CAC3B;AAKD,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,kBAAkB,CA6EtE"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Deterministic frontmatter derivation for `daftari backfill` (§11.1).
|
|
2
|
+
//
|
|
3
|
+
// No LLM calls: every value comes from git metadata, body conventions, the
|
|
4
|
+
// path, or a fixed default. The contract is "suggest, don't assert" — adopted
|
|
5
|
+
// docs are proposed as canonical/medium/direct, but a human ratifies per folder
|
|
6
|
+
// before anything is written. Existing frontmatter is never overwritten: a
|
|
7
|
+
// present field is preserved verbatim, only missing fields are filled.
|
|
8
|
+
import { validateFrontmatter } from "../frontmatter/schema.js";
|
|
9
|
+
// kebab-case a free-form string: lowercase, non-alphanumerics → single hyphen,
|
|
10
|
+
// trimmed. Used for collection names and the identity fallback slug.
|
|
11
|
+
export function slugify(value) {
|
|
12
|
+
return value
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
15
|
+
.replace(/-+/g, "-")
|
|
16
|
+
.replace(/^-+|-+$/g, "");
|
|
17
|
+
}
|
|
18
|
+
// The first ATX H1 (`# Title`) in the body, or null. Only a single leading `#`
|
|
19
|
+
// counts — `##` and deeper are sub-headings, not the document title.
|
|
20
|
+
export function firstH1(body) {
|
|
21
|
+
for (const line of body.split(/\r?\n/)) {
|
|
22
|
+
const m = line.match(/^#\s+(.+?)\s*#*\s*$/);
|
|
23
|
+
if (m)
|
|
24
|
+
return m[1].trim();
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
// Title-cased title derived from a filename when the body has no H1. Strips the
|
|
29
|
+
// `.md`, splits the basename on `-`/`_`, and capitalizes each word.
|
|
30
|
+
export function titleFromFilename(relPath) {
|
|
31
|
+
const base = (relPath.split("/").pop() ?? relPath).replace(/\.md$/i, "");
|
|
32
|
+
const words = base.split(/[-_]+/).filter((w) => w.length > 0);
|
|
33
|
+
if (words.length === 0)
|
|
34
|
+
return base;
|
|
35
|
+
return words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
36
|
+
}
|
|
37
|
+
// Bullet items under a `## <heading>` section, in order. Collection stops at the
|
|
38
|
+
// next heading of any level. Placeholder bullets (empty, or fully parenthical
|
|
39
|
+
// like "(none yet)") are dropped — they are scaffolding, not real questions.
|
|
40
|
+
export function parseQuestionSection(body, heading) {
|
|
41
|
+
const lines = body.split(/\r?\n/);
|
|
42
|
+
const target = heading.toLowerCase();
|
|
43
|
+
const out = [];
|
|
44
|
+
let inSection = false;
|
|
45
|
+
for (const line of lines) {
|
|
46
|
+
const headingMatch = line.match(/^#{1,6}\s+(.+?)\s*#*\s*$/);
|
|
47
|
+
if (headingMatch) {
|
|
48
|
+
const text = headingMatch[1].trim().toLowerCase();
|
|
49
|
+
inSection = text === target;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!inSection)
|
|
53
|
+
continue;
|
|
54
|
+
const bullet = line.match(/^\s*[-*]\s+(.*\S)\s*$/);
|
|
55
|
+
if (!bullet)
|
|
56
|
+
continue;
|
|
57
|
+
const item = bullet[1].trim();
|
|
58
|
+
if (item.length === 0)
|
|
59
|
+
continue;
|
|
60
|
+
if (item.startsWith("(") && item.endsWith(")"))
|
|
61
|
+
continue;
|
|
62
|
+
out.push(item);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
// Maps a git author name to a Daftari identity: an explicit identity_map entry
|
|
67
|
+
// wins; otherwise the default `human:<slug>` fallback.
|
|
68
|
+
export function mapIdentity(author, identityMap) {
|
|
69
|
+
const mapped = identityMap[author];
|
|
70
|
+
if (mapped)
|
|
71
|
+
return mapped;
|
|
72
|
+
return `human:${slugify(author) || "unknown"}`;
|
|
73
|
+
}
|
|
74
|
+
// A frontmatter field is "present" — and therefore preserved — when the raw
|
|
75
|
+
// YAML carries a non-null, non-empty-string value for it. Empty arrays count as
|
|
76
|
+
// present (the author wrote `[]` deliberately).
|
|
77
|
+
function isPresent(raw, field) {
|
|
78
|
+
const v = raw[field];
|
|
79
|
+
if (v === undefined || v === null)
|
|
80
|
+
return false;
|
|
81
|
+
if (typeof v === "string" && v.length === 0)
|
|
82
|
+
return false;
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
// Whether a document needs backfilling. A doc whose existing frontmatter
|
|
86
|
+
// already validates against the built-in schema is conformant and skipped;
|
|
87
|
+
// otherwise it is `missing` (no frontmatter at all) or `partial`.
|
|
88
|
+
export function classifyDoc(raw) {
|
|
89
|
+
if (validateFrontmatter(raw).report.valid)
|
|
90
|
+
return "conformant";
|
|
91
|
+
return Object.keys(raw).length === 0 ? "missing" : "partial";
|
|
92
|
+
}
|
|
93
|
+
// Builds the full proposed frontmatter for a non-conformant doc plus a per-field
|
|
94
|
+
// derivation map. Present fields are preserved (coerced value, label
|
|
95
|
+
// "preserved"); missing fields are derived from git / body / path / defaults.
|
|
96
|
+
export function deriveProposed(input) {
|
|
97
|
+
const { relPath, body, raw, coerced, git, mtimeDate, identityMap, invoker } = input;
|
|
98
|
+
const derivation = {};
|
|
99
|
+
// Resolves one field: if present in raw, preserve the coerced value; else use
|
|
100
|
+
// the derived value. Records the chosen source label either way.
|
|
101
|
+
function resolve(field, derivedValue, derivedLabel) {
|
|
102
|
+
if (isPresent(raw, field)) {
|
|
103
|
+
derivation[field] = "preserved";
|
|
104
|
+
return coerced[field];
|
|
105
|
+
}
|
|
106
|
+
derivation[field] = derivedLabel;
|
|
107
|
+
return derivedValue;
|
|
108
|
+
}
|
|
109
|
+
// title ← H1, else filename.
|
|
110
|
+
const h1 = firstH1(body);
|
|
111
|
+
const title = resolve("title", h1 ?? titleFromFilename(relPath), h1 ? "body-h1" : "filename");
|
|
112
|
+
// collection ← first path component, kebab-cased.
|
|
113
|
+
const folder = relPath.split("/")[0] ?? "";
|
|
114
|
+
const collection = resolve("collection", slugify(folder), "parent-folder");
|
|
115
|
+
// created/updated ← git, else file mtime.
|
|
116
|
+
const created = resolve("created", git.created ?? mtimeDate, git.created ? "git-first-commit" : "file-mtime");
|
|
117
|
+
const updated = resolve("updated", git.updated ?? mtimeDate, git.updated ? "git-last-commit" : "file-mtime");
|
|
118
|
+
// updated_by ← git author mapped through identity config, else invoker.
|
|
119
|
+
const updatedBy = resolve("updated_by", git.author ? mapIdentity(git.author, identityMap) : invoker, git.author ? "git-author + identity-map" : "invoker-fallback");
|
|
120
|
+
// questions ← body sections, else empty.
|
|
121
|
+
const qAnswered = parseQuestionSection(body, "Questions Answered");
|
|
122
|
+
const qRaised = parseQuestionSection(body, "Questions Raised");
|
|
123
|
+
const proposed = {
|
|
124
|
+
title,
|
|
125
|
+
domain: resolve("domain", "accumulation", "default"),
|
|
126
|
+
collection,
|
|
127
|
+
status: resolve("status", "canonical", "default"),
|
|
128
|
+
confidence: resolve("confidence", "medium", "default"),
|
|
129
|
+
created,
|
|
130
|
+
updated,
|
|
131
|
+
updated_by: updatedBy,
|
|
132
|
+
provenance: resolve("provenance", "direct", "default"),
|
|
133
|
+
sources: resolve("sources", [], "empty"),
|
|
134
|
+
superseded_by: resolve("superseded_by", null, "null"),
|
|
135
|
+
ttl_days: resolve("ttl_days", null, "null"),
|
|
136
|
+
tags: resolve("tags", [], "empty"),
|
|
137
|
+
questions_answered: resolve("questions_answered", qAnswered, qAnswered.length > 0 ? "body-section" : "empty"),
|
|
138
|
+
questions_raised: resolve("questions_raised", qRaised, qRaised.length > 0 ? "body-section" : "empty"),
|
|
139
|
+
};
|
|
140
|
+
return { proposed, derivation };
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/backfill/derive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backfill/index.ts"],"names":[],"mappings":"AA+IA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA8GjE"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// Top-level entry for `daftari backfill` (§11.1) — git-driven frontmatter
|
|
2
|
+
// migration for adopting an existing wiki into Daftari.
|
|
3
|
+
//
|
|
4
|
+
// Two-step, plan/apply:
|
|
5
|
+
// daftari backfill --plan [--scope <folder>] derive + stage to a plan file
|
|
6
|
+
// daftari backfill --apply --scope <folder> write the plan under one folder
|
|
7
|
+
//
|
|
8
|
+
// --scope is REQUIRED on --apply so a whole-vault write can never happen by
|
|
9
|
+
// accident. The plan does not modify any markdown; the apply commits one folder
|
|
10
|
+
// at a time (per-folder human ratification).
|
|
11
|
+
//
|
|
12
|
+
// Exit codes:
|
|
13
|
+
// 0 — success
|
|
14
|
+
// 1 — usage error (bad flags, missing --scope on apply, no mode)
|
|
15
|
+
// 2 — runtime / config error
|
|
16
|
+
import { userInfo } from "node:os";
|
|
17
|
+
import { resolve } from "node:path";
|
|
18
|
+
import { createInterface } from "node:readline/promises";
|
|
19
|
+
import { loadConfig } from "../utils/config.js";
|
|
20
|
+
import { applyPlan } from "./apply.js";
|
|
21
|
+
import { slugify } from "./derive.js";
|
|
22
|
+
import { generatePlan } from "./plan.js";
|
|
23
|
+
const HELP = `daftari backfill — derive frontmatter for an existing wiki from git history.
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
daftari backfill --plan [--scope <folder>] [--vault <path>]
|
|
27
|
+
daftari backfill --apply --scope <folder> [--yes] [--vault <path>]
|
|
28
|
+
|
|
29
|
+
Modes:
|
|
30
|
+
--plan Walk the vault (or one folder), derive proposed
|
|
31
|
+
frontmatter, and write .daftari/backfill-plan.jsonl.
|
|
32
|
+
Modifies no markdown file. Idempotent — overwrites the
|
|
33
|
+
plan on each run.
|
|
34
|
+
--apply Write the plan's proposals for docs under --scope only,
|
|
35
|
+
then auto-commit them in one commit. --scope is
|
|
36
|
+
REQUIRED. Prompts for confirmation unless --yes.
|
|
37
|
+
|
|
38
|
+
Flags:
|
|
39
|
+
--scope <folder> First path component to act on (e.g. specs). Optional
|
|
40
|
+
on --plan (filters the walk), required on --apply.
|
|
41
|
+
--vault <path> Vault root (default: current directory).
|
|
42
|
+
--agent <identity> Acting identity for the apply COMMIT and provenance —
|
|
43
|
+
the migrator running the adoption (default:
|
|
44
|
+
human:<your-username>). Distinct from each doc's
|
|
45
|
+
'updated_by' FIELD, which is derived from the doc's git
|
|
46
|
+
author through backfill.identity_map (original
|
|
47
|
+
authorship, not the migrator).
|
|
48
|
+
--yes Skip the apply confirmation prompt.
|
|
49
|
+
--help, -h Show this help.
|
|
50
|
+
|
|
51
|
+
The frontmatter 'updated_by' field records who originally authored a doc (its
|
|
52
|
+
git author, mapped via .daftari/config.yaml backfill.identity_map). The --agent
|
|
53
|
+
identity records who ran the migration — it authors the commit, not the field.
|
|
54
|
+
`;
|
|
55
|
+
function readArg(argv, flag) {
|
|
56
|
+
for (let i = 0; i < argv.length; i++) {
|
|
57
|
+
if (argv[i] === flag)
|
|
58
|
+
return argv[i + 1];
|
|
59
|
+
const prefix = `${flag}=`;
|
|
60
|
+
const a = argv[i];
|
|
61
|
+
if (a?.startsWith(prefix))
|
|
62
|
+
return a.slice(prefix.length);
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
// Default acting identity: human:<os-username>, slugified. Falls back to
|
|
67
|
+
// human:cli when the username is unavailable.
|
|
68
|
+
function defaultAgent() {
|
|
69
|
+
try {
|
|
70
|
+
const name = userInfo().username;
|
|
71
|
+
const slug = slugify(name);
|
|
72
|
+
return `human:${slug || "cli"}`;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return "human:cli";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function renderSummary(summary, planFile) {
|
|
79
|
+
const lines = [];
|
|
80
|
+
lines.push(`Backfill plan written to ${planFile}`);
|
|
81
|
+
lines.push("");
|
|
82
|
+
lines.push(` missing frontmatter: ${summary.missing}`);
|
|
83
|
+
lines.push(` partial frontmatter: ${summary.partial}`);
|
|
84
|
+
lines.push(` already conformant: ${summary.conformant}`);
|
|
85
|
+
if (summary.rootSkipped > 0) {
|
|
86
|
+
lines.push(` root-level (no folder): ${summary.rootSkipped} (skipped — backfill is per-folder)`);
|
|
87
|
+
}
|
|
88
|
+
lines.push("");
|
|
89
|
+
lines.push(` ${summary.planned} doc(s) planned across ${Object.keys(summary.byScope).length} folder(s):`);
|
|
90
|
+
for (const scope of Object.keys(summary.byScope).sort()) {
|
|
91
|
+
lines.push(` ${scope}: ${summary.byScope[scope]}`);
|
|
92
|
+
}
|
|
93
|
+
lines.push("");
|
|
94
|
+
if (summary.planned > 0) {
|
|
95
|
+
lines.push("Ratify a folder with:");
|
|
96
|
+
for (const scope of Object.keys(summary.byScope).sort()) {
|
|
97
|
+
lines.push(` daftari backfill --apply --scope ${scope}`);
|
|
98
|
+
}
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push("The plan is transient — backfill never commits it (the apply commit is the");
|
|
101
|
+
lines.push("audit trail). If this vault wasn't scaffolded by `daftari --init`, add");
|
|
102
|
+
lines.push("`.daftari/backfill-plan.jsonl` to .gitignore so it can't be committed by hand.");
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
lines.push("Nothing to backfill.");
|
|
106
|
+
}
|
|
107
|
+
return `${lines.join("\n")}\n`;
|
|
108
|
+
}
|
|
109
|
+
// Throttled stderr progress for the plan walk: a heartbeat every 50 docs (and a
|
|
110
|
+
// final newline) when the vault is large enough to matter. Returns the
|
|
111
|
+
// onProgress callback, or undefined to stay silent on small vaults.
|
|
112
|
+
function planProgress() {
|
|
113
|
+
let lastShown = 0;
|
|
114
|
+
return (done, total) => {
|
|
115
|
+
if (total < 50)
|
|
116
|
+
return;
|
|
117
|
+
if (done === total) {
|
|
118
|
+
process.stderr.write(`\rbackfill: scanned ${total}/${total} docs\n`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (done - lastShown >= 50) {
|
|
122
|
+
lastShown = done;
|
|
123
|
+
process.stderr.write(`\rbackfill: scanned ${done}/${total} docs`);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function confirm(prompt) {
|
|
128
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
129
|
+
try {
|
|
130
|
+
const answer = await rl.question(prompt);
|
|
131
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
rl.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
export async function runBackfill(argv) {
|
|
138
|
+
if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
|
|
139
|
+
process.stdout.write(HELP);
|
|
140
|
+
return argv.length === 0 ? 1 : 0;
|
|
141
|
+
}
|
|
142
|
+
const wantPlan = argv.includes("--plan");
|
|
143
|
+
const wantApply = argv.includes("--apply");
|
|
144
|
+
if (wantPlan === wantApply) {
|
|
145
|
+
process.stderr.write("daftari backfill: pass exactly one of --plan or --apply\n");
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
const vaultRoot = resolve(readArg(argv, "--vault") ?? ".");
|
|
149
|
+
const scope = readArg(argv, "--scope");
|
|
150
|
+
const agent = readArg(argv, "--agent") ?? defaultAgent();
|
|
151
|
+
// An explicitly-passed empty --scope ("" or `--scope=`) is a user error in
|
|
152
|
+
// either mode — reject it at parse time rather than letting it slip through as
|
|
153
|
+
// a no-match filter (plan) or fall to the required-scope check (apply). An
|
|
154
|
+
// omitted --scope (undefined) stays valid: optional on plan, caught below on
|
|
155
|
+
// apply.
|
|
156
|
+
if (scope !== undefined && scope.length === 0) {
|
|
157
|
+
process.stderr.write("daftari backfill: --scope cannot be empty\n");
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
const config = loadConfig(vaultRoot);
|
|
161
|
+
if (!config.ok) {
|
|
162
|
+
process.stderr.write(`daftari backfill: ${config.error.message}\n`);
|
|
163
|
+
return 2;
|
|
164
|
+
}
|
|
165
|
+
const identityMap = config.value.backfillIdentityMap;
|
|
166
|
+
if (wantPlan) {
|
|
167
|
+
const result = await generatePlan(vaultRoot, {
|
|
168
|
+
scope,
|
|
169
|
+
identityMap,
|
|
170
|
+
invoker: agent,
|
|
171
|
+
onProgress: planProgress(),
|
|
172
|
+
});
|
|
173
|
+
if (!result.ok) {
|
|
174
|
+
process.stderr.write(`daftari backfill: ${result.error.message}\n`);
|
|
175
|
+
return 2;
|
|
176
|
+
}
|
|
177
|
+
process.stdout.write(renderSummary(result.value.summary, result.value.planPath));
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
// --apply
|
|
181
|
+
if (scope === undefined || scope.length === 0) {
|
|
182
|
+
process.stderr.write("daftari backfill: --apply requires --scope <folder> (per-folder ratification; " +
|
|
183
|
+
"whole-vault apply is intentionally not supported)\n");
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
if (!argv.includes("--yes")) {
|
|
187
|
+
// A non-interactive apply (piped stdin, CI) would block forever on the
|
|
188
|
+
// prompt. Refuse with an actionable message instead of hanging.
|
|
189
|
+
if (!process.stdin.isTTY) {
|
|
190
|
+
process.stderr.write("daftari backfill: --apply needs confirmation but stdin is not a TTY — " +
|
|
191
|
+
"re-run with --yes to apply non-interactively\n");
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
const proceed = await confirm(`Apply backfilled frontmatter to docs under '${scope}' and commit as ${agent}? [y/N] `);
|
|
195
|
+
if (!proceed) {
|
|
196
|
+
process.stderr.write("daftari backfill: aborted\n");
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const result = await applyPlan(vaultRoot, scope, agent);
|
|
201
|
+
if (!result.ok) {
|
|
202
|
+
process.stderr.write(`daftari backfill: ${result.error.message}\n`);
|
|
203
|
+
return 2;
|
|
204
|
+
}
|
|
205
|
+
const r = result.value;
|
|
206
|
+
// No applied, no unchanged, no skipped means the plan had no entry under this
|
|
207
|
+
// scope — either a mistyped folder or a folder already fully backfilled (a
|
|
208
|
+
// re-plan drops conformant docs). Either way nothing was written, so this is
|
|
209
|
+
// an idempotent no-op: exit 0 (a CI loop re-applying every folder must not
|
|
210
|
+
// fail here) with a message that names the likely typo case.
|
|
211
|
+
if (r.applied.length === 0 && r.unchanged.length === 0 && r.skipped.length === 0) {
|
|
212
|
+
process.stdout.write(`No planned docs under '${scope}' — nothing to apply ` +
|
|
213
|
+
"(already backfilled, or check the folder name against the plan summary).\n");
|
|
214
|
+
return 0;
|
|
215
|
+
}
|
|
216
|
+
const out = [];
|
|
217
|
+
out.push(`Backfill applied to '${scope}':`);
|
|
218
|
+
out.push(` written: ${r.applied.length}`);
|
|
219
|
+
out.push(` unchanged: ${r.unchanged.length}`);
|
|
220
|
+
if (r.skipped.length > 0) {
|
|
221
|
+
out.push(` skipped: ${r.skipped.length}`);
|
|
222
|
+
for (const s of r.skipped)
|
|
223
|
+
out.push(` ${s.path}: ${s.reason}`);
|
|
224
|
+
}
|
|
225
|
+
if (r.commit)
|
|
226
|
+
out.push(` commit: ${r.commit}`);
|
|
227
|
+
else if (r.applied.length === 0)
|
|
228
|
+
out.push(" (no changes — already applied)");
|
|
229
|
+
process.stdout.write(`${out.join("\n")}\n`);
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backfill/index.ts"],"names":[],"mappings":"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"}
|