@descent-vtt/spec-harness 0.18.0 → 0.20.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.
Files changed (51) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +372 -0
  4. package/README.md +78 -11
  5. package/dist/briefs.d.ts +45 -0
  6. package/dist/briefs.js +73 -0
  7. package/dist/briefs.js.map +1 -1
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.js +384 -84
  10. package/dist/cli.js.map +1 -1
  11. package/dist/commands.js +7 -2
  12. package/dist/commands.js.map +1 -1
  13. package/dist/config.d.ts +15 -1
  14. package/dist/config.js +16 -3
  15. package/dist/config.js.map +1 -1
  16. package/dist/configure.d.ts +142 -32
  17. package/dist/configure.js +316 -89
  18. package/dist/configure.js.map +1 -1
  19. package/dist/fs.d.ts +150 -3
  20. package/dist/fs.js +459 -17
  21. package/dist/fs.js.map +1 -1
  22. package/dist/git.d.ts +85 -9
  23. package/dist/git.js +140 -16
  24. package/dist/git.js.map +1 -1
  25. package/dist/hooks.d.ts +111 -0
  26. package/dist/hooks.js +172 -16
  27. package/dist/hooks.js.map +1 -1
  28. package/dist/round.d.ts +8 -0
  29. package/dist/round.js +32 -9
  30. package/dist/round.js.map +1 -1
  31. package/dist/sandbox.js +4 -3
  32. package/dist/sandbox.js.map +1 -1
  33. package/dist/server.d.ts +25 -1
  34. package/dist/server.js +194 -27
  35. package/dist/server.js.map +1 -1
  36. package/dist/setup.d.ts +6 -3
  37. package/dist/setup.js +74 -23
  38. package/dist/setup.js.map +1 -1
  39. package/dist/siblings.d.ts +42 -7
  40. package/dist/siblings.js +135 -30
  41. package/dist/siblings.js.map +1 -1
  42. package/dist/types.d.ts +5 -0
  43. package/dist/types.js.map +1 -1
  44. package/dist/usage.d.ts +66 -12
  45. package/dist/usage.js +134 -21
  46. package/dist/usage.js.map +1 -1
  47. package/dist/workspace.d.ts +80 -1
  48. package/dist/workspace.js +188 -8
  49. package/dist/workspace.js.map +1 -1
  50. package/hooks/hooks.json +16 -0
  51. package/package.json +2 -2
package/dist/fs.d.ts CHANGED
@@ -2,12 +2,49 @@
2
2
  * The edge where the harness meets the disk: the configuration, the state
3
3
  * directory outside the work tree, and paths as the filesystem spells them.
4
4
  */
5
+ import type { BriefInputs } from './briefs.js';
5
6
  import { type HarnessConfig } from './config.js';
6
- /** Reads `.spec-harness.json` at the root, or the defaults when there is none. */
7
+ /**
8
+ * Whether a regular file stands at a path, links followed. Only one is read
9
+ * where a file is expected: opened, a named pipe nothing writes to is read
10
+ * without end, and one read as the process waits on it, as the harness reads
11
+ * a few small files, stops every timer with it (ADR-0002).
12
+ */
13
+ export declare function isFile(path: string): boolean;
14
+ /**
15
+ * Reads `.spec-harness.json` at the root, or the defaults when there is none.
16
+ *
17
+ * Only a file is read. A named pipe under the file's name was read without
18
+ * end, by every command and by the hook before every write; and Node's words
19
+ * for a directory, EISDIR, are not the harness's. A file that cannot be read
20
+ * is said as that, with the reason: one the account may not read, or one
21
+ * another process holds open on Windows, was said to be JSON that is not
22
+ * valid, which sent a person to its text. What does not load is thrown with
23
+ * the path it stands at, which the hook lets a write reach (ADR-0005).
24
+ */
7
25
  export declare function loadConfig(root: string): Promise<{
8
26
  config: HarnessConfig;
9
27
  file: string | null;
10
28
  }>;
29
+ /**
30
+ * Whether every path of a write names `file` and nothing else: a file that
31
+ * stands under that name alone, which the path names as the hook resolves a
32
+ * path to decide it ({@link realSpelling}), and as the filesystem resolves
33
+ * it to write, which on Linux and macOS follows a link before a `..` where
34
+ * the hook reads the `..` first. A path that only reads like it, a link to
35
+ * it, a second name of it, and a file of another work tree are none of
36
+ * these. `cwd` is what a relative path is read from, its words kept as
37
+ * written.
38
+ */
39
+ export declare function writesOnly(paths: readonly string[], file: string, cwd: string): boolean;
40
+ /**
41
+ * A path where the harness keeps its state that holds something else: said
42
+ * in a line, exit 2, where Node's ENOTDIR and a stack sent a person looking
43
+ * for a defect (spec-core ADR-0005).
44
+ */
45
+ export declare class StateError extends Error {
46
+ constructor(message: string);
47
+ }
11
48
  /**
12
49
  * The real spelling of a path: links resolved and, on a filesystem that
13
50
  * ignores case, the case the directory entries have. A path that does not
@@ -25,6 +62,15 @@ export declare function realSpelling(path: string): string;
25
62
  * for what it would say from the other.
26
63
  */
27
64
  export declare function isTop(directory: string, top: string): boolean;
65
+ /**
66
+ * The repository's main work tree, where git keeps the repository as that
67
+ * work tree's `.git`, as `git init` and `git clone` do and every linked
68
+ * worktree's common directory then is: `null` for a common directory of any
69
+ * other name, a bare repository's, a submodule's under its superproject's
70
+ * `modules`, or one kept apart with `--separate-git-dir`. Read from the
71
+ * name, with no process: it says only where an install is looked for.
72
+ */
73
+ export declare function mainWorkTree(commonDir: string): string | null;
28
74
  /** Whether a `.git` stands in `directory`, a repository's or the file that names one, as at the top of a work tree. */
29
75
  export declare function holdsGit(directory: string): boolean;
30
76
  /**
@@ -32,12 +78,113 @@ export declare function holdsGit(directory: string): boolean;
32
78
  * real spelling - or `null` when it lies outside the root.
33
79
  */
34
80
  export declare function repositoryPath(given: string, root: string, cwd: string): string | null;
35
- /** The harness's own directory under the git common directory, created on demand (ADR-0003). */
81
+ /**
82
+ * The top of every work tree of the repository whose common directory is
83
+ * `common`, `top` among them, read with no process: the main work tree,
84
+ * whose `.git` the common directory is, and each linked worktree, by the
85
+ * `gitdir` file git keeps for it under the common directory's `worktrees`,
86
+ * which names the worktree's `.git` (gitrepository-layout(5)), absolute or
87
+ * from its own directory. `null` where they cannot all be named: a common
88
+ * directory of any other name, whose main work tree only its configuration
89
+ * names, and an entry under `worktrees` that cannot be read.
90
+ */
91
+ export declare function workTrees(top: string, common: string): string[] | null;
92
+ /**
93
+ * Whether every path lies outside every work tree of the repository whose
94
+ * top and common directory are given: such a path is no file of the
95
+ * repository's, so no brief of its decides it, whatever is wrong with the
96
+ * brief or the configuration (ADR-0005). Where the work trees cannot all
97
+ * be named, a path is not known to be outside them, and this is `false`.
98
+ */
99
+ export declare function outsideEvery(paths: readonly string[], top: string, common: string, cwd: string): boolean;
100
+ /**
101
+ * The harness's own directory under the git common directory, created on
102
+ * demand (ADR-0003). Where something that is no directory stands at its path,
103
+ * or at one between it and git's, Node refuses to make it, with ENOTDIR or
104
+ * EEXIST, and the harness says which path holds what.
105
+ */
36
106
  export declare function stateDirectory(commonDir: string, ...parts: string[]): Promise<string>;
107
+ /**
108
+ * A work tree and its git directories as the files git keeps name them, read
109
+ * with no process: the nearest directory at or above `root` that holds a
110
+ * `.git`; the git directory, that `.git` or the one a `.git` file names
111
+ * (`gitdir: <path>`, relative to the file's directory); and the common
112
+ * directory, the one that git directory's `commondir` file names, relative
113
+ * to it, or the git directory itself (gitrepository-layout(5)). `exact` is
114
+ * whether git, asked, would name the same work tree: not where
115
+ * `GIT_DIR` or `GIT_WORK_TREE` sends it elsewhere, and not where the
116
+ * repository's configuration names a `worktree`, which `core.worktree`
117
+ * moves it to (git-config(1)), or keeps one of its own for a worktree.
118
+ * `null` where no directory up to the top of the filesystem holds one, or
119
+ * a `.git` file names none.
120
+ */
121
+ export declare function gitDirectories(root: string, env: Readonly<Record<string, string | undefined>>): {
122
+ readonly top: string;
123
+ readonly git: string;
124
+ readonly common: string;
125
+ readonly exact: boolean;
126
+ } | null;
127
+ /**
128
+ * How long a call's decisions are kept for a run after the write that does
129
+ * not come: a call refused by the person, one that failed, one stopped
130
+ * (ADR-0002). A day, since a call waits on a person's prompt for as long as
131
+ * the person is away, and an entry removed too soon costs only that call's
132
+ * answer being decided again.
133
+ */
134
+ export declare const CALL_LIFE_MS: number;
135
+ /**
136
+ * Keeps what a run before a write decided, under the common directory, for
137
+ * the run after it, and removes what no run after a write read in a day.
138
+ * Nothing here may change the answer before the write: whatever fails is
139
+ * passed over, and the run after the write then decides as it did.
140
+ */
141
+ export declare function keepCall(commonDir: string, name: string, text: string, now?: number): Promise<void>;
142
+ /** What was kept for a call, taken away as it is read; `null` where nothing was. */
143
+ export declare function takeCall(commonDir: string, name: string): Promise<string | null>;
144
+ /** SHA-256 of a text or of bytes, in hex. */
145
+ export type Hash = (data: string | Uint8Array) => string;
146
+ /** SHA-256, loaded where something is hashed: a run that keeps no answer loads no hash (ADR-0002). */
147
+ export declare function hasher(): Promise<Hash>;
148
+ /**
149
+ * How long a session's answer of spec-brief's is kept once it was last
150
+ * kept (ADR-0003). A day, as a call's: an answer removed costs one start of
151
+ * spec-brief, and one kept is a few kilobytes.
152
+ */
153
+ export declare const ANSWER_LIFE_MS: number;
154
+ /**
155
+ * Keeps a session's answer of spec-brief's under the common directory, with
156
+ * the key it answers, and removes what was kept over a day ago. Whatever
157
+ * fails is passed over: the answer is the one given whether or not it is
158
+ * kept.
159
+ */
160
+ export declare function keepAnswer(commonDir: string, name: string, key: string, answer: string, now?: number): Promise<void>;
161
+ /**
162
+ * The answer kept under `name` for `key`, or `null` where there is none:
163
+ * nothing there, something that is not a file, a text that is not what
164
+ * `keepAnswer` writes, or another key's.
165
+ */
166
+ export declare function keptAnswer(commonDir: string, name: string, key: string): Promise<string | null>;
167
+ /**
168
+ * Whether every input of an answer reads as listed, with no process
169
+ * started: each file by the digest of its bytes, or as not there; each
170
+ * directory by its entries; and, where git was asked, the index of the work
171
+ * tree's git directory and each ignore file. A path is read from the work
172
+ * tree's top, or as it stands where it is absolute. Anything that cannot be
173
+ * read, and an index that is not the one git reads for the work tree, is a
174
+ * doubt, and answers `false` (ADR-0002).
175
+ */
176
+ export declare function readsAsListed(root: string, inputs: BriefInputs, hash: Hash, env?: Readonly<Record<string, string | undefined>>): Promise<boolean>;
37
177
  /** Writes a file whole or not at all: a temporary file renamed over the target. */
38
178
  export declare function writeAtomic(file: string, content: string): Promise<void>;
39
- /** A JSON object from a file: `null` when there is no file, `'unreadable'` when it holds anything else. */
179
+ /**
180
+ * A JSON object from a file: `null` when there is no file, `'unreadable'`
181
+ * when it holds anything else. Only a file is read: a named pipe where a
182
+ * settings file is expected was read without end, and neither doctor nor
183
+ * init came back. What is neither a file nor a directory holds no JSON
184
+ * object, as a directory holds none.
185
+ */
40
186
  export declare function readJsonObject(file: string): Promise<Record<string, unknown> | null | 'unreadable'>;
41
187
  /** Whether a path names a directory that is there; one that cannot be read names none. */
42
188
  export declare function isDirectory(path: string): boolean;
189
+ /** A file's text, or `null` where it cannot be read or is no file: a brief, a document one cites, a shim. */
43
190
  export declare function readText(file: string): Promise<string | null>;