etymd 0.1.0 → 0.2.1
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 +32 -1
- package/README.md +111 -12
- package/dist/{approve-WM6OJHQG.js → approve-X3AW7KLD.js} +4 -4
- package/dist/audit-YH74YZFQ.js +9 -0
- package/dist/{brief-2MPNTITQ.js → brief-RT6KE4CN.js} +4 -4
- package/dist/{chunk-FXL4554F.js → chunk-4UZBCCFJ.js} +2 -2
- package/dist/chunk-6W3J4PJ6.js +60 -0
- package/dist/{chunk-I566LDX7.js → chunk-ANCCGYSH.js} +10 -3
- package/dist/{chunk-U33XLT5I.js → chunk-C4Z6NXDO.js} +1 -1
- package/dist/{chunk-TCWKIMCU.js → chunk-E2Q7WFPN.js} +75 -4
- package/dist/{ledger-YFTYCOIC.js → chunk-EUIHYD6F.js} +2 -2
- package/dist/{chunk-SMM2TW35.js → chunk-FZSIOCOZ.js} +1 -1
- package/dist/{chunk-N64ZTBCW.js → chunk-KBF3SW3N.js} +1 -1
- package/dist/{chunk-WVYKYPKS.js → chunk-LBRNZZZF.js} +28 -1
- package/dist/{chunk-5D7WNJ6N.js → chunk-SS7VGLJ5.js} +251 -82
- package/dist/cli.js +73 -13
- package/dist/{context-TT5H76LA.js → context-GYCLR3TG.js} +3 -3
- package/dist/doctor-EAA4IP4Y.js +16 -0
- package/dist/fleet-IS6YWDDV.js +1004 -0
- package/dist/{gates-KPDEUC36.js → gates-3NPKF4IZ.js} +4 -4
- package/dist/index.d.ts +223 -3
- package/dist/index.js +1061 -13
- package/dist/{init-V627UXKU.js → init-ISEFZWPV.js} +5 -5
- package/dist/ledger-RHQJH5EA.js +4 -0
- package/dist/{scan-YL7JHLUA.js → scan-ADZ2RKYY.js} +4 -4
- package/package.json +1 -1
- package/dist/audit-OHOSWOWA.js +0 -8
- package/dist/doctor-NNRJTNIY.js +0 -15
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { planWorkflow, applyFiles } from './chunk-
|
|
3
|
-
import { scanProject } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import { section, print, glyph, theme, renderPlan, git } from './chunk-
|
|
2
|
+
import { planWorkflow, applyFiles } from './chunk-4UZBCCFJ.js';
|
|
3
|
+
import { scanProject } from './chunk-E2Q7WFPN.js';
|
|
4
|
+
import './chunk-C4Z6NXDO.js';
|
|
5
|
+
import { section, print, glyph, theme, renderPlan, git } from './chunk-LBRNZZZF.js';
|
|
6
6
|
import { confirm, isCancel, cancel } from '@clack/prompts';
|
|
7
7
|
|
|
8
8
|
async function run(opts) {
|
package/dist/index.d.ts
CHANGED
|
@@ -26,9 +26,42 @@ interface DetectedArtifact {
|
|
|
26
26
|
label: string;
|
|
27
27
|
path: string;
|
|
28
28
|
/** What role it plays: the single source of truth, a per-agent pointer, a skill, a gate, etc. */
|
|
29
|
-
kind: "contract" | "state" | "adapter" | "skill" | "gate" | "map" | "sessions" | "other";
|
|
29
|
+
kind: "contract" | "state" | "decisions" | "adapter" | "skill" | "gate" | "map" | "sessions" | "other";
|
|
30
30
|
exists: boolean;
|
|
31
31
|
}
|
|
32
|
+
/** Committer-date freshness for one state/decisions artifact — a git fact, never mtime. */
|
|
33
|
+
interface ArtifactFreshness {
|
|
34
|
+
/** Matches `DetectedArtifact.id`. */
|
|
35
|
+
artifactId: string;
|
|
36
|
+
path: string;
|
|
37
|
+
/** ISO committer date (`git log -1 --format=%cI`) of the artifact's last commit. */
|
|
38
|
+
lastCommit: string;
|
|
39
|
+
/** True when the repo has commits newer than the artifact's last commit. */
|
|
40
|
+
commitsSince: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* True when the working tree carries uncommitted changes to this artifact — the refresh is
|
|
43
|
+
* on disk, not yet committed. Treated fresh-now and disclosed, never flagged stale.
|
|
44
|
+
*/
|
|
45
|
+
dirty?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Freshness of the "this describes now" artifacts (state/decisions), judged from git alone.
|
|
49
|
+
* mtime is never read — checkouts, syncs, and editors rewrite it freely; the committer date is
|
|
50
|
+
* the only clock the repo itself vouches for.
|
|
51
|
+
*/
|
|
52
|
+
interface FreshnessFacts {
|
|
53
|
+
/** ISO committer date of the repo's last commit. */
|
|
54
|
+
repoLastCommit?: string;
|
|
55
|
+
artifacts: ArtifactFreshness[];
|
|
56
|
+
/**
|
|
57
|
+
* Artifacts whose dates git cannot vouch for (untracked file, shallow clone, not a repo) —
|
|
58
|
+
* the fact is absent and the lens discloses why; absence is never itself a finding.
|
|
59
|
+
*/
|
|
60
|
+
unverifiable: {
|
|
61
|
+
path: string;
|
|
62
|
+
reason: string;
|
|
63
|
+
}[];
|
|
64
|
+
}
|
|
32
65
|
interface GitFacts {
|
|
33
66
|
isRepo: boolean;
|
|
34
67
|
branch?: string;
|
|
@@ -72,6 +105,8 @@ interface ProjectFacts {
|
|
|
72
105
|
};
|
|
73
106
|
hooks: HookFacts;
|
|
74
107
|
artifacts: DetectedArtifact[];
|
|
108
|
+
/** Optional: baselines approved by older versions predate this fact. */
|
|
109
|
+
freshness?: FreshnessFacts;
|
|
75
110
|
tree: {
|
|
76
111
|
dirs: {
|
|
77
112
|
name: string;
|
|
@@ -97,12 +132,19 @@ interface ContextBudget {
|
|
|
97
132
|
extractionCandidates: ContextFile[];
|
|
98
133
|
}
|
|
99
134
|
|
|
135
|
+
interface ScanOptions {
|
|
136
|
+
/**
|
|
137
|
+
* Fleet: measure repo freshness on fork-authored commits only (`HEAD --not --remotes=<name>`).
|
|
138
|
+
* The caller verifies the remote exists and discloses the fallback when it does not.
|
|
139
|
+
*/
|
|
140
|
+
upstreamRemote?: string;
|
|
141
|
+
}
|
|
100
142
|
/**
|
|
101
143
|
* The deterministic half of a reckoning: everything knowable without an LLM. Kept pure of any
|
|
102
144
|
* terminal output so it can back both the CLI and programmatic use, and so it is trivially
|
|
103
145
|
* testable against a fixture directory.
|
|
104
146
|
*/
|
|
105
|
-
declare function scanProject(root: string): Promise<ProjectFacts>;
|
|
147
|
+
declare function scanProject(root: string, opts?: ScanOptions): Promise<ProjectFacts>;
|
|
106
148
|
|
|
107
149
|
/**
|
|
108
150
|
* Default word count above which a single always-loaded file is worth extracting into an
|
|
@@ -159,9 +201,16 @@ interface ContextBudgets {
|
|
|
159
201
|
/** Total always-loaded words past which the footprint itself is a finding. */
|
|
160
202
|
totalWords: number;
|
|
161
203
|
}
|
|
204
|
+
interface StateBudgets {
|
|
205
|
+
/** Days of commit traffic a state doc may trail the repo by before it counts as stale. */
|
|
206
|
+
staleAfterDays: number;
|
|
207
|
+
/** Chars in a state doc past which the file is a finding (session hooks truncate ~10k). */
|
|
208
|
+
maxChars: number;
|
|
209
|
+
}
|
|
162
210
|
interface EtymdConfig {
|
|
163
211
|
instructions: InstructionScope;
|
|
164
212
|
context: ContextBudgets;
|
|
213
|
+
state: StateBudgets;
|
|
165
214
|
}
|
|
166
215
|
interface LoadedConfig {
|
|
167
216
|
config: EtymdConfig;
|
|
@@ -317,6 +366,20 @@ interface AuditOptions {
|
|
|
317
366
|
lensIds?: string[];
|
|
318
367
|
/** Persist the reconciled ledger (the default; false = read-only report). */
|
|
319
368
|
persistLedger?: boolean;
|
|
369
|
+
/**
|
|
370
|
+
* Fleet: the audited root is READ-ONLY — write nothing into it, not even the scan cache
|
|
371
|
+
* where `.etymd` already exists there. A corp worktree is never written, regardless of flags.
|
|
372
|
+
*/
|
|
373
|
+
readOnlyRoot?: boolean;
|
|
374
|
+
/**
|
|
375
|
+
* Fleet: read/write the ledger at this root instead of the audited one. Corp findings persist
|
|
376
|
+
* under the manifest's `corp/<name>/`, never inside the corp worktree.
|
|
377
|
+
*/
|
|
378
|
+
ledgerRoot?: string;
|
|
379
|
+
/** Fleet: per-entry state-budget overlay (registry `staleAfterDays` / `stateBudget`). */
|
|
380
|
+
stateBudgets?: Partial<StateBudgets>;
|
|
381
|
+
/** Fleet: judge repo freshness on fork-authored commits only (see `ScanOptions`). */
|
|
382
|
+
upstreamRemote?: string;
|
|
320
383
|
}
|
|
321
384
|
interface AuditResult {
|
|
322
385
|
facts: ProjectFacts;
|
|
@@ -331,6 +394,149 @@ interface AuditResult {
|
|
|
331
394
|
}
|
|
332
395
|
declare function runAudit(root: string, opts?: AuditOptions): Promise<AuditResult>;
|
|
333
396
|
|
|
397
|
+
type FleetProfile = "personal" | "corp";
|
|
398
|
+
interface FleetContract {
|
|
399
|
+
state?: string;
|
|
400
|
+
decisions?: string;
|
|
401
|
+
goals?: string;
|
|
402
|
+
/** `"none"` = the contract file is legitimately absent (a declared state, not a gap). */
|
|
403
|
+
placement?: string;
|
|
404
|
+
}
|
|
405
|
+
interface FleetEntry {
|
|
406
|
+
name: string;
|
|
407
|
+
kind?: string;
|
|
408
|
+
profile: FleetProfile;
|
|
409
|
+
private: boolean;
|
|
410
|
+
/** Root-relative path as DECLARED in the tracked manifest (personal entries only). */
|
|
411
|
+
path?: string;
|
|
412
|
+
/** Remote name of the upstream this repo forks — freshness measures fork-authored commits. */
|
|
413
|
+
upstream?: string;
|
|
414
|
+
/** `"public-repo"` marks an outside-contribution surface (hygiene needles apply). */
|
|
415
|
+
trust?: string;
|
|
416
|
+
staleAfterDays?: number;
|
|
417
|
+
/** Per-entry state char-budget override (ships unset — the schema slot exists). */
|
|
418
|
+
stateBudget?: number;
|
|
419
|
+
contract: FleetContract;
|
|
420
|
+
links: Record<string, string>;
|
|
421
|
+
/** Absolute directory on THIS machine, when the manifest pair resolves one. */
|
|
422
|
+
resolvedRoot?: string;
|
|
423
|
+
/** Why `resolvedRoot` is absent — always disclosed, never a silent skip. */
|
|
424
|
+
unresolved?: string;
|
|
425
|
+
}
|
|
426
|
+
interface ManifestProblem {
|
|
427
|
+
kind: "parse-error" | "bad-shape" | "local-missing";
|
|
428
|
+
/** The file the problem lives in (manifest-relative basename). */
|
|
429
|
+
file: string;
|
|
430
|
+
detail: string;
|
|
431
|
+
}
|
|
432
|
+
interface FleetManifest {
|
|
433
|
+
shape: "registry" | "corpus";
|
|
434
|
+
/** Absolute path of the tracked manifest file. */
|
|
435
|
+
manifestPath: string;
|
|
436
|
+
/** Its directory — corp persistence roots and the sweep delta file live beside it. */
|
|
437
|
+
dir: string;
|
|
438
|
+
/** Resolved absolute fleet root (registry shape), when declared. */
|
|
439
|
+
root?: string;
|
|
440
|
+
machineProfile?: FleetProfile;
|
|
441
|
+
corpHosts: string[];
|
|
442
|
+
labels: Record<string, string>;
|
|
443
|
+
localDirs: Record<string, string>;
|
|
444
|
+
/** Absolute path where the gitignored local sibling is expected. */
|
|
445
|
+
localPath: string;
|
|
446
|
+
localPresent: boolean;
|
|
447
|
+
entries: FleetEntry[];
|
|
448
|
+
/** Structural problems — disclosed by every consumer, never defaulted away. */
|
|
449
|
+
problems: ManifestProblem[];
|
|
450
|
+
}
|
|
451
|
+
/** `~`-expansion is the CONSUMER's job — the tracked manifest never records a machine home. */
|
|
452
|
+
declare function expandTilde(p: string): string;
|
|
453
|
+
/**
|
|
454
|
+
* Load and resolve a fleet manifest (either shape) against this machine. Never throws on
|
|
455
|
+
* content problems — they land in `problems` / per-entry `unresolved` so every consumer can
|
|
456
|
+
* disclose them. Throws only when the manifest file itself cannot be read at all.
|
|
457
|
+
*/
|
|
458
|
+
declare function loadFleetManifest(manifestPath: string): Promise<FleetManifest>;
|
|
459
|
+
|
|
460
|
+
declare const FLEET_LENS = "fleet-manifest";
|
|
461
|
+
/** The fleet `--json` schema marker — EXPERIMENTAL through 0.2.x, declared in the output. */
|
|
462
|
+
declare const FLEET_JSON_SCHEMA = "fleet-experimental-0.2";
|
|
463
|
+
interface FleetSweepOptions {
|
|
464
|
+
/** Restrict to these registered names (unknown names throw — a typo must not skip silently). */
|
|
465
|
+
only?: string[];
|
|
466
|
+
profile?: "personal" | "corp";
|
|
467
|
+
/** Truth lenses only per repo (the doctor subset). */
|
|
468
|
+
kind?: LensKind;
|
|
469
|
+
/**
|
|
470
|
+
* Persist per-repo ledgers — ONLY for personal-profile entries that already carry `.etymd`.
|
|
471
|
+
* The sweep never creates `.etymd` anywhere, and corp worktrees are never written at all.
|
|
472
|
+
*/
|
|
473
|
+
persistLedgers?: boolean;
|
|
474
|
+
}
|
|
475
|
+
interface FleetProjectSweep {
|
|
476
|
+
name: string;
|
|
477
|
+
profile: "personal" | "corp";
|
|
478
|
+
kind?: string;
|
|
479
|
+
resolvedRoot?: string;
|
|
480
|
+
/** Why this entry could not be audited — mirrored into `outOfScope`. */
|
|
481
|
+
unresolved?: string;
|
|
482
|
+
staleAfterDays: number;
|
|
483
|
+
/** Days the newest state artifact trails the repo clock; null = nothing datable. */
|
|
484
|
+
stateAgeDays: number | null;
|
|
485
|
+
counts: Record<FindingTier, number>;
|
|
486
|
+
/** Ranked, ledger-quieted findings from this repo's audit. */
|
|
487
|
+
findings: Finding[];
|
|
488
|
+
disclosures: string[];
|
|
489
|
+
}
|
|
490
|
+
interface FleetSweepResult {
|
|
491
|
+
schema: typeof FLEET_JSON_SCHEMA;
|
|
492
|
+
manifest: string;
|
|
493
|
+
sweptAt: string;
|
|
494
|
+
projects: FleetProjectSweep[];
|
|
495
|
+
/** Fleet-scope wall findings (`fleet-manifest`) — not ledger-quietable in 0.2. */
|
|
496
|
+
wall: Finding[];
|
|
497
|
+
wallDisclosures: string[];
|
|
498
|
+
/** Entry names that could not be audited — named here, never silently dropped. */
|
|
499
|
+
outOfScope: string[];
|
|
500
|
+
/** Manifest problems, verbatim — disclosed by every renderer, never defaulted away. */
|
|
501
|
+
problems: string[];
|
|
502
|
+
/** Defect classes open in ≥2 projects — the class-fix candidates (see recurringClasses()). */
|
|
503
|
+
recurringClasses: RecurringClass[];
|
|
504
|
+
}
|
|
505
|
+
interface RecurringClass {
|
|
506
|
+
/** The `<lens>/<class>` id prefix — minted by the engine's lenses, identical across repos. */
|
|
507
|
+
classId: string;
|
|
508
|
+
tier: FindingTier;
|
|
509
|
+
/** Project names (corp entries by alias) where the class is currently open. */
|
|
510
|
+
projects: string[];
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Where a corp entry's audit state persists: beside the manifest, never in the worktree.
|
|
514
|
+
* Belt-and-braces to the loader's safe-name rule: a name that resolves anywhere but directly
|
|
515
|
+
* under `<dir>/corp/` is refused — the manifest can lie, and a lie must never steer a write.
|
|
516
|
+
*/
|
|
517
|
+
declare function corpPersistenceRoot(manifest: FleetManifest, name: string): string;
|
|
518
|
+
/**
|
|
519
|
+
* Validate the manifest pair itself: parse problems, dangling mappings (the live ghost-entry
|
|
520
|
+
* class), duplicate names, privacy leaks, dead links, machine paths. Pure manifest truth —
|
|
521
|
+
* no lenses run, no repo is audited, nothing is written.
|
|
522
|
+
*/
|
|
523
|
+
declare function checkManifest(manifest: FleetManifest): Promise<{
|
|
524
|
+
findings: Finding[];
|
|
525
|
+
disclosures: string[];
|
|
526
|
+
}>;
|
|
527
|
+
/** All fleet-scope wall checks. Each check that cannot run says so — undetermined, not clean. */
|
|
528
|
+
declare function collectWallFindings(manifest: FleetManifest): Promise<{
|
|
529
|
+
findings: Finding[];
|
|
530
|
+
disclosures: string[];
|
|
531
|
+
}>;
|
|
532
|
+
/**
|
|
533
|
+
* The fleet sweep: one read-only audit per resolved entry + the fleet-scope wall checks.
|
|
534
|
+
* Invariants (each pinned by test): never creates `.etymd` anywhere; never writes into a corp
|
|
535
|
+
* worktree regardless of flags or a stray `.etymd` there; unresolvable entries land in
|
|
536
|
+
* `outOfScope` with a disclosure, never a silent skip.
|
|
537
|
+
*/
|
|
538
|
+
declare function sweepFleet(manifest: FleetManifest, opts?: FleetSweepOptions): Promise<FleetSweepResult>;
|
|
539
|
+
|
|
334
540
|
/**
|
|
335
541
|
* The truth lens: does what the instruction files CLAIM still hold against the actual repo?
|
|
336
542
|
* Commands must exist as scripts, paths must exist on disk, files must agree on the package
|
|
@@ -391,6 +597,20 @@ declare const TOTAL_BUDGET_WORDS: number;
|
|
|
391
597
|
*/
|
|
392
598
|
declare const contextEconomyLens: Lens;
|
|
393
599
|
|
|
600
|
+
/**
|
|
601
|
+
* The marker that opts a decisions file into per-entry format checks. Forward-only by design:
|
|
602
|
+
* mandatory-field checks apply to files that declared the format, never retroactively to
|
|
603
|
+
* pre-existing records — old decisions are history, not defects.
|
|
604
|
+
*/
|
|
605
|
+
declare const DECISIONS_FORMAT_MARKER = "<!-- decisions-format: 1 -->";
|
|
606
|
+
/**
|
|
607
|
+
* Freshness lens: does the layer that claims "this describes now" still describe now? Staleness
|
|
608
|
+
* is RELATIVE — a state doc is stale only when the repo moved past it, so a dormant repo's old
|
|
609
|
+
* state is current by definition and produces zero findings. Every date is a git committer date
|
|
610
|
+
* (never mtime); everything git cannot vouch for is disclosed, never flagged.
|
|
611
|
+
*/
|
|
612
|
+
declare const stateFreshnessLens: Lens;
|
|
613
|
+
|
|
394
614
|
type GateTool = "typecheck" | "lint" | "format-check" | "format-write" | "test" | "coverage" | "e2e" | "sonar" | "codecov" | "commitlint" | "size" | "chromatic";
|
|
395
615
|
interface CiJobGate {
|
|
396
616
|
job: string;
|
|
@@ -441,4 +661,4 @@ declare const PACK_VERSION = "2";
|
|
|
441
661
|
declare const VERSION: string;
|
|
442
662
|
declare const NAME: string;
|
|
443
663
|
|
|
444
|
-
export { type ApplyResult, type AuditOptions, type AuditResult, type Baseline, CONFIG_FILE, type ContextBudget, type ContextBudgets, type ContextFile, DEFAULT_CONFIG, type DetectedArtifact, type DiscoveredCommands, EXTRACTION_THRESHOLD, type EtymdConfig, type Finding, type GateInventory, type GateTool, type GeneratedFile, type HookFacts, type InstructionFileSet, type InstructionScope, LENSES, type Ledger, type LedgerDiff, type LedgerEntry, type Lens, type LensReport, type LoadedConfig, NAME, PACK_VERSION, type PackageManager, type PathClaims, type PlanOptions, type ProjectFacts, TOTAL_BUDGET_WORDS, VERSION, type WorkflowProfile, type WorkspaceKind, applyFiles, baselineCarriesMachinePath, baselinePath, buildGateInventory, cacheFactsPath, configPath, contextEconomyLens, deriveProfile, extractCommandClaims, extractPathClaims, gateIntegrityLens, instructionTruthLens, isAlwaysAppliedCursorRule, listInstructionFiles, measureContext, planWorkflow, rankFindings, readBaseline, readCachedFacts, readConfig, readLedger, reconcileLedger, runAudit, scanProject, withoutMachinePath, writeBaseline, writeCachedFacts, writeLedger };
|
|
664
|
+
export { type ApplyResult, type ArtifactFreshness, type AuditOptions, type AuditResult, type Baseline, CONFIG_FILE, type ContextBudget, type ContextBudgets, type ContextFile, DECISIONS_FORMAT_MARKER, DEFAULT_CONFIG, type DetectedArtifact, type DiscoveredCommands, EXTRACTION_THRESHOLD, type EtymdConfig, FLEET_JSON_SCHEMA, FLEET_LENS, type Finding, type FleetContract, type FleetEntry, type FleetManifest, type FleetProfile, type FleetProjectSweep, type FleetSweepOptions, type FleetSweepResult, type FreshnessFacts, type GateInventory, type GateTool, type GeneratedFile, type HookFacts, type InstructionFileSet, type InstructionScope, LENSES, type Ledger, type LedgerDiff, type LedgerEntry, type Lens, type LensReport, type LoadedConfig, type ManifestProblem, NAME, PACK_VERSION, type PackageManager, type PathClaims, type PlanOptions, type ProjectFacts, type StateBudgets, TOTAL_BUDGET_WORDS, VERSION, type WorkflowProfile, type WorkspaceKind, applyFiles, baselineCarriesMachinePath, baselinePath, buildGateInventory, cacheFactsPath, checkManifest, collectWallFindings, configPath, contextEconomyLens, corpPersistenceRoot, deriveProfile, expandTilde, extractCommandClaims, extractPathClaims, gateIntegrityLens, instructionTruthLens, isAlwaysAppliedCursorRule, listInstructionFiles, loadFleetManifest, measureContext, planWorkflow, rankFindings, readBaseline, readCachedFacts, readConfig, readLedger, reconcileLedger, runAudit, scanProject, stateFreshnessLens, sweepFleet, withoutMachinePath, writeBaseline, writeCachedFacts, writeLedger };
|