@noir-ai/core 1.0.0-beta.1 → 1.2.0-beta.2
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/index.d.ts +76 -5
- package/dist/index.js +203 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
2
|
|
|
3
|
+
type CommentStyle = 'html' | 'hash';
|
|
4
|
+
interface ManagedBlock {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly commentStyle: CommentStyle;
|
|
7
|
+
readonly begin: string;
|
|
8
|
+
readonly end: string;
|
|
9
|
+
}
|
|
10
|
+
/** Build a matched begin/end marker pair for a managed region.
|
|
11
|
+
* `html` → `<!-- noir:<name> begin -->` (markdown / CLAUDE.md / NOIR.md).
|
|
12
|
+
* `hash` → `# >>> noir:<name> >>>` (.gitignore / .dockerignore / .npmignore / yml). */
|
|
13
|
+
declare function managedBlock(name: string, commentStyle?: CommentStyle): ManagedBlock;
|
|
14
|
+
/** Named instances. CONTEXT_BLOCK_* are kept byte-identical for backward compat. */
|
|
15
|
+
declare const CONTEXT_BLOCK: ManagedBlock;
|
|
16
|
+
declare const RULES_BLOCK: ManagedBlock;
|
|
17
|
+
declare const CONTEXT_BLOCK_BEGIN: string;
|
|
18
|
+
declare const CONTEXT_BLOCK_END: string;
|
|
19
|
+
|
|
20
|
+
/** Pick a comment style for a managed region from a file path. */
|
|
21
|
+
declare function commentStyleFor(file: string): CommentStyle;
|
|
22
|
+
/** Remove every `<begin>…<end>` region for `block` from `content`. */
|
|
23
|
+
declare function stripManagedBlock(content: string, block: ManagedBlock): string;
|
|
24
|
+
/** Read the first `<begin>…<end>` region for `block` from `file`, or null if absent/missing. */
|
|
25
|
+
declare function readManagedBlock(file: string, block: ManagedBlock): string | null;
|
|
26
|
+
/** Idempotently write `regionText` (a full `<begin>…<end>` block) into `file`,
|
|
27
|
+
* stripping any prior region for `block` and preserving all other content. */
|
|
28
|
+
declare function writeManagedRegion(file: string, block: ManagedBlock, regionText: string): void;
|
|
29
|
+
|
|
3
30
|
declare const NoirConfigSchema: z.ZodObject<{
|
|
4
|
-
host: z.
|
|
31
|
+
host: z.ZodDefault<z.ZodEnum<{
|
|
32
|
+
claude: "claude";
|
|
33
|
+
"agents-md": "agents-md";
|
|
34
|
+
gemini: "gemini";
|
|
35
|
+
cursor: "cursor";
|
|
36
|
+
opencode: "opencode";
|
|
37
|
+
}>>;
|
|
5
38
|
name: z.ZodOptional<z.ZodString>;
|
|
6
39
|
mode: z.ZodDefault<z.ZodEnum<{
|
|
7
40
|
full: "full";
|
|
@@ -49,10 +82,48 @@ declare const NoirConfigSchema: z.ZodObject<{
|
|
|
49
82
|
types: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
50
83
|
}, z.core.$strip>>;
|
|
51
84
|
}, z.core.$strip>>;
|
|
85
|
+
rules: z.ZodDefault<z.ZodObject<{
|
|
86
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
87
|
+
lengthBudgetKb: z.ZodDefault<z.ZodNumber>;
|
|
88
|
+
}, z.core.$strip>>;
|
|
89
|
+
prd: z.ZodDefault<z.ZodObject<{
|
|
90
|
+
mandatoryFor: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
91
|
+
feature: "feature";
|
|
92
|
+
epic: "epic";
|
|
93
|
+
enhancement: "enhancement";
|
|
94
|
+
bugfix: "bugfix";
|
|
95
|
+
spike: "spike";
|
|
96
|
+
"quick-task": "quick-task";
|
|
97
|
+
refactor: "refactor";
|
|
98
|
+
}>>>;
|
|
99
|
+
}, z.core.$strip>>;
|
|
100
|
+
integrations: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
101
|
+
auth: z.ZodDefault<z.ZodObject<{
|
|
102
|
+
tokenEnv: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
103
|
+
}, z.core.$strip>>;
|
|
104
|
+
runtime: z.ZodDefault<z.ZodEnum<{
|
|
105
|
+
none: "none";
|
|
106
|
+
"gated-write-proxy": "gated-write-proxy";
|
|
107
|
+
"mcp-stdio": "mcp-stdio";
|
|
108
|
+
"external-mcp": "external-mcp";
|
|
109
|
+
}>>;
|
|
110
|
+
teamId: z.ZodOptional<z.ZodString>;
|
|
111
|
+
listId: z.ZodOptional<z.ZodString>;
|
|
112
|
+
spaceId: z.ZodOptional<z.ZodString>;
|
|
113
|
+
}, z.core.$strip>>>;
|
|
52
114
|
}, z.core.$strip>;
|
|
53
115
|
type NoirConfig = z.infer<typeof NoirConfigSchema>;
|
|
54
116
|
declare function parseConfig(raw: unknown): NoirConfig;
|
|
55
117
|
|
|
118
|
+
/** Managed-region marker for ignore-style files (hash comments). */
|
|
119
|
+
declare const IGNORE_BLOCK: ManagedBlock;
|
|
120
|
+
/** Idempotently write Noir's managed ignore block into each configured ignore
|
|
121
|
+
* file under `root`, preserving all user content outside the block. Returns
|
|
122
|
+
* the list of files touched. Safe to re-run (managed-block replacement). */
|
|
123
|
+
declare function syncIgnores(root: string): {
|
|
124
|
+
files: string[];
|
|
125
|
+
};
|
|
126
|
+
|
|
56
127
|
declare const NOIR_DIR = ".noir";
|
|
57
128
|
/**
|
|
58
129
|
* User-global Noir home: `~/.noir` (HOME-relative, NOT project `.noir/`).
|
|
@@ -76,12 +147,15 @@ declare function modelsDir(): string;
|
|
|
76
147
|
declare const paths: {
|
|
77
148
|
readonly noirDir: (root: string) => string;
|
|
78
149
|
readonly noirMd: (root: string) => string;
|
|
150
|
+
readonly rulesMd: (root: string) => string;
|
|
79
151
|
readonly config: (root: string) => string;
|
|
80
152
|
readonly projectId: (root: string) => string;
|
|
81
153
|
readonly storeDir: (root: string) => string;
|
|
82
154
|
readonly storeDb: (root: string, projectId: string) => string;
|
|
83
155
|
readonly specsDir: (root: string) => string;
|
|
84
156
|
readonly specFile: (root: string, taskId: string, slug: string) => string;
|
|
157
|
+
readonly prdDir: (root: string) => string;
|
|
158
|
+
readonly prdFile: (root: string, taskId: string, slug: string) => string;
|
|
85
159
|
readonly plansDir: (root: string) => string;
|
|
86
160
|
readonly planFile: (root: string, taskId: string, slug: string) => string;
|
|
87
161
|
readonly tasksDir: (root: string) => string;
|
|
@@ -92,9 +166,6 @@ declare const paths: {
|
|
|
92
166
|
readonly auditFile: (root: string, taskId: string) => string;
|
|
93
167
|
};
|
|
94
168
|
|
|
95
|
-
declare const CONTEXT_BLOCK_BEGIN = "<!-- noir:context begin -->";
|
|
96
|
-
declare const CONTEXT_BLOCK_END = "<!-- noir:context end -->";
|
|
97
|
-
|
|
98
169
|
/** Canonical, machine-stable project identity. NEVER a filesystem path. */
|
|
99
170
|
type ProjectId = string;
|
|
100
171
|
declare function createProjectId(): ProjectId;
|
|
@@ -109,4 +180,4 @@ declare function loadProjectInfo(root: string): ProjectInfo;
|
|
|
109
180
|
|
|
110
181
|
declare const NOIR_VERSION: string;
|
|
111
182
|
|
|
112
|
-
export { CONTEXT_BLOCK_BEGIN, CONTEXT_BLOCK_END, NOIR_DIR, NOIR_VERSION, type NoirConfig, NoirConfigSchema, type ProjectId, type ProjectInfo, createProjectId, loadProjectInfo, modelsDir, noirHome, parseConfig, paths };
|
|
183
|
+
export { CONTEXT_BLOCK, CONTEXT_BLOCK_BEGIN, CONTEXT_BLOCK_END, type CommentStyle, IGNORE_BLOCK, type ManagedBlock, NOIR_DIR, NOIR_VERSION, type NoirConfig, NoirConfigSchema, type ProjectId, type ProjectInfo, RULES_BLOCK, commentStyleFor, createProjectId, loadProjectInfo, managedBlock, modelsDir, noirHome, parseConfig, paths, readManagedBlock, stripManagedBlock, syncIgnores, writeManagedRegion };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,61 @@
|
|
|
1
|
+
// src/block-writer.ts
|
|
2
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
3
|
+
import { basename, extname } from "path";
|
|
4
|
+
var HASH_FILES = /* @__PURE__ */ new Set([
|
|
5
|
+
".gitignore",
|
|
6
|
+
".dockerignore",
|
|
7
|
+
".npmignore",
|
|
8
|
+
".prettierignore",
|
|
9
|
+
".eslintignore",
|
|
10
|
+
".ignore"
|
|
11
|
+
]);
|
|
12
|
+
function escapeRe(s) {
|
|
13
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14
|
+
}
|
|
15
|
+
function commentStyleFor(file) {
|
|
16
|
+
const lower = file.toLowerCase();
|
|
17
|
+
if (HASH_FILES.has(basename(lower))) return "hash";
|
|
18
|
+
const ext = extname(lower);
|
|
19
|
+
if (ext === ".yml" || ext === ".yaml") return "hash";
|
|
20
|
+
return "html";
|
|
21
|
+
}
|
|
22
|
+
function stripManagedBlock(content, block) {
|
|
23
|
+
const re = new RegExp(`${escapeRe(block.begin)}[\\s\\S]*?${escapeRe(block.end)}\\n?`, "g");
|
|
24
|
+
return content.replace(re, "");
|
|
25
|
+
}
|
|
26
|
+
function readManagedBlock(file, block) {
|
|
27
|
+
let content;
|
|
28
|
+
try {
|
|
29
|
+
content = readFileSync(file, "utf8");
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const m = content.match(new RegExp(`${escapeRe(block.begin)}[\\s\\S]*?${escapeRe(block.end)}`));
|
|
34
|
+
return m?.[0] ? m[0] : null;
|
|
35
|
+
}
|
|
36
|
+
function writeManagedRegion(file, block, regionText) {
|
|
37
|
+
let content = "";
|
|
38
|
+
try {
|
|
39
|
+
content = readFileSync(file, "utf8");
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
const stripped = stripManagedBlock(content, block);
|
|
43
|
+
const next = `${stripped ? `${stripped.trimEnd()}
|
|
44
|
+
|
|
45
|
+
` : ""}${regionText}`;
|
|
46
|
+
writeFileSync(file, next, "utf8");
|
|
47
|
+
}
|
|
48
|
+
|
|
1
49
|
// src/config.ts
|
|
2
50
|
import * as z from "zod";
|
|
3
51
|
var NoirConfigSchema = z.object({
|
|
4
|
-
host: z.literal(
|
|
52
|
+
// S10 multi-host: widens from `z.literal('claude')` to a 5-value enum. The
|
|
53
|
+
// canonical `HostId` union lives in @noir-ai/adapters (single owner); core
|
|
54
|
+
// owns the enum STRING here so it does not import adapters (no core→adapters
|
|
55
|
+
// cycle — mirrors the existing pattern where `model`/`memory`/`context`/`prd`
|
|
56
|
+
// redeclare shapes their resolvers consume). `claude` remains the default so
|
|
57
|
+
// existing single-host projects are byte-equivalent (regression anchor).
|
|
58
|
+
host: z.enum(["claude", "agents-md", "gemini", "cursor", "opencode"]).default("claude"),
|
|
5
59
|
name: z.string().optional(),
|
|
6
60
|
mode: z.enum(["full", "quick"]).default("full"),
|
|
7
61
|
daemon: z.object({
|
|
@@ -112,63 +166,170 @@ var NoirConfigSchema = z.object({
|
|
|
112
166
|
// Restrict candidates to these types (default: every non-`lesson`).
|
|
113
167
|
types: z.array(z.string()).optional()
|
|
114
168
|
}).default({ enabled: false })
|
|
115
|
-
}).default({ consolidation: { enabled: false } })
|
|
169
|
+
}).default({ consolidation: { enabled: false } }),
|
|
170
|
+
// Debt-batch A — `rules:` block. Additive, no-op when absent (defaults make it
|
|
171
|
+
// a pass-through). Reserved for the upcoming rule-driven lint surface (the
|
|
172
|
+
// `@noir-ai/workflow` rule registry + future `noir check`); for v1.x this
|
|
173
|
+
// block is parsed + validated but no consumer reads it yet — declaring it
|
|
174
|
+
// here lets early adopters pin `enabled: false` or a non-default budget in
|
|
175
|
+
// `.noir/config.yml` without a schema churn when the rule engine ships.
|
|
176
|
+
rules: z.object({
|
|
177
|
+
// Master switch (default true — the rule registry is opt-OUT; a project
|
|
178
|
+
// that wants no part of it sets `enabled: false`). When the rule engine
|
|
179
|
+
// ships, false ⇒ no rules registered + `noir check` is a no-op.
|
|
180
|
+
enabled: z.boolean().default(true),
|
|
181
|
+
// Soft per-rule body budget in KB (targets file-size discipline for the
|
|
182
|
+
// markdown rules; the future rule registry clips over-budget rule bodies
|
|
183
|
+
// and surfaces a warning rather than rejecting the file). Positive int.
|
|
184
|
+
lengthBudgetKb: z.number().int().positive().default(6)
|
|
185
|
+
}).default({ enabled: true, lengthBudgetKb: 6 }),
|
|
186
|
+
// Slice P (PRD) — `prd:` block. Additive, escapable-soft-gate config for the
|
|
187
|
+
// pre-SDD Product Requirements Document. The workflow engine reads
|
|
188
|
+
// `mandatoryFor` to decide when a missing PRD warrants an observable,
|
|
189
|
+
// escapable recommendation at the spec gate (the advance still proceeds —
|
|
190
|
+
// never a hard block; `--force <reason>` is the explicit override). The
|
|
191
|
+
// `TaskClass` enum mirrors @noir-ai/workflow's; duplicated HERE (as a literal
|
|
192
|
+
// z.enum) so core never imports workflow (no core→workflow cycle), exactly
|
|
193
|
+
// as `model`/`memory`/`context` declare provider shapes that their resolvers
|
|
194
|
+
// in other packages consume.
|
|
195
|
+
//
|
|
196
|
+
// Defaults: `mandatoryFor: ['feature', 'epic']` — the noir-prd skill's "when
|
|
197
|
+
// to draft" rule. Quick-mode + non-mandatory taskClasses skip the check
|
|
198
|
+
// entirely; a present-but-empty `prd:` block also degrades to the default.
|
|
199
|
+
prd: z.object({
|
|
200
|
+
mandatoryFor: z.array(
|
|
201
|
+
z.enum(["feature", "epic", "enhancement", "bugfix", "spike", "quick-task", "refactor"])
|
|
202
|
+
).default(["feature", "epic"])
|
|
203
|
+
}).default({ mandatoryFor: ["feature", "epic"] }),
|
|
204
|
+
// Slice X integration layer (@noir-ai/skills `integrations/<name>/`). Additive
|
|
205
|
+
// block keyed by integration name — every field optional + default-`{}` so a
|
|
206
|
+
// config with NO `integrations:` block still parses and behaves as "no
|
|
207
|
+
// integrations wired" (degraded by default; the skill playbook still ships
|
|
208
|
+
// and works in manual-paste mode regardless of this block — it only carries
|
|
209
|
+
// the per-workspace binding like team_id/list_id for the gated proxy). The
|
|
210
|
+
// declaration shape lives in @noir-ai/skills' Zod schema; this block is the
|
|
211
|
+
// USER-facing overlay (which integration is enabled + where it points), not
|
|
212
|
+
// a re-statement of the declaration.
|
|
213
|
+
//
|
|
214
|
+
// Doctrine (slice-x spec + Q4b): the auth TOKEN stays in env (tokenEnv name
|
|
215
|
+
// is declared in integration.json, NOT here); ClickUp-specific ids are
|
|
216
|
+
// optional workspace binding; `runtime` mirrors the declaration tiers so a
|
|
217
|
+
// user can DOWNGRADE an integration locally (e.g. force `none` for a
|
|
218
|
+
// read-only run).
|
|
219
|
+
integrations: z.record(
|
|
220
|
+
z.string(),
|
|
221
|
+
z.object({
|
|
222
|
+
auth: z.object({
|
|
223
|
+
// Override the token env var name (defaults to the declaration's
|
|
224
|
+
// `auth.tokenEnv` when undefined). Min(1) matches the declaration
|
|
225
|
+
// schema's invariant (`integrations-schema.ts` tokenEnv is non-empty)
|
|
226
|
+
// — an empty-string override must FAIL validation, not silently
|
|
227
|
+
// disable the integration (env[''] is always undefined).
|
|
228
|
+
tokenEnv: z.string().min(1).optional()
|
|
229
|
+
}).partial().default({}),
|
|
230
|
+
runtime: z.enum(["none", "gated-write-proxy", "mcp-stdio", "external-mcp"]).default("none"),
|
|
231
|
+
// ClickUp-workspace binding (optional; flows 3 + 5 need a list_id).
|
|
232
|
+
teamId: z.string().optional(),
|
|
233
|
+
listId: z.string().optional(),
|
|
234
|
+
spaceId: z.string().optional()
|
|
235
|
+
})
|
|
236
|
+
).default({})
|
|
116
237
|
});
|
|
117
238
|
function parseConfig(raw) {
|
|
118
239
|
return NoirConfigSchema.parse(raw);
|
|
119
240
|
}
|
|
120
241
|
|
|
242
|
+
// src/ignore-manager.ts
|
|
243
|
+
import { join } from "path";
|
|
244
|
+
|
|
245
|
+
// src/markers.ts
|
|
246
|
+
function managedBlock(name, commentStyle = "html") {
|
|
247
|
+
if (commentStyle === "hash") {
|
|
248
|
+
return { name, commentStyle, begin: `# >>> noir:${name} >>>`, end: `# <<< noir:${name} <<<` };
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
name,
|
|
252
|
+
commentStyle,
|
|
253
|
+
begin: `<!-- noir:${name} begin -->`,
|
|
254
|
+
end: `<!-- noir:${name} end -->`
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
var CONTEXT_BLOCK = managedBlock("context", "html");
|
|
258
|
+
var RULES_BLOCK = managedBlock("rules", "html");
|
|
259
|
+
var CONTEXT_BLOCK_BEGIN = CONTEXT_BLOCK.begin;
|
|
260
|
+
var CONTEXT_BLOCK_END = CONTEXT_BLOCK.end;
|
|
261
|
+
|
|
262
|
+
// src/ignore-manager.ts
|
|
263
|
+
var IGNORE_BLOCK = managedBlock("ignore", "hash");
|
|
264
|
+
var IGNORE_ENTRIES = [
|
|
265
|
+
[".gitignore", ["/.noir/store/", "/.noir/*.sock", "/.noir/daemon.pid", "/.noir/state/"]],
|
|
266
|
+
[".dockerignore", [".noir/"]],
|
|
267
|
+
[".npmignore", ["/.noir/"]],
|
|
268
|
+
[".prettierignore", ["/.noir/"]]
|
|
269
|
+
];
|
|
270
|
+
function syncIgnores(root) {
|
|
271
|
+
const files = [];
|
|
272
|
+
for (const [name, entries] of IGNORE_ENTRIES) {
|
|
273
|
+
const region = `${IGNORE_BLOCK.begin}
|
|
274
|
+
${entries.join("\n")}
|
|
275
|
+
${IGNORE_BLOCK.end}
|
|
276
|
+
`;
|
|
277
|
+
writeManagedRegion(join(root, name), IGNORE_BLOCK, region);
|
|
278
|
+
files.push(name);
|
|
279
|
+
}
|
|
280
|
+
return { files };
|
|
281
|
+
}
|
|
282
|
+
|
|
121
283
|
// src/layout.ts
|
|
122
284
|
import { homedir } from "os";
|
|
123
|
-
import { join } from "path";
|
|
285
|
+
import { join as join2 } from "path";
|
|
124
286
|
var NOIR_DIR = ".noir";
|
|
125
287
|
function noirHome() {
|
|
126
|
-
return
|
|
288
|
+
return join2(homedir(), NOIR_DIR);
|
|
127
289
|
}
|
|
128
290
|
function modelsDir() {
|
|
129
|
-
return
|
|
291
|
+
return join2(noirHome(), "models");
|
|
130
292
|
}
|
|
131
293
|
var paths = {
|
|
132
|
-
noirDir: (root) =>
|
|
133
|
-
noirMd: (root) =>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
294
|
+
noirDir: (root) => join2(root, NOIR_DIR),
|
|
295
|
+
noirMd: (root) => join2(root, NOIR_DIR, "NOIR.md"),
|
|
296
|
+
rulesMd: (root) => join2(root, NOIR_DIR, "rules", "RULES.md"),
|
|
297
|
+
config: (root) => join2(root, NOIR_DIR, "config.yml"),
|
|
298
|
+
projectId: (root) => join2(root, NOIR_DIR, "project.id"),
|
|
299
|
+
storeDir: (root) => join2(root, NOIR_DIR, "store"),
|
|
300
|
+
storeDb: (root, projectId) => join2(root, NOIR_DIR, "store", `${projectId}.db`),
|
|
138
301
|
// Artifact directories and files
|
|
139
|
-
specsDir: (root) =>
|
|
140
|
-
specFile: (root, taskId, slug) =>
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
302
|
+
specsDir: (root) => join2(root, NOIR_DIR, "specs"),
|
|
303
|
+
specFile: (root, taskId, slug) => join2(root, NOIR_DIR, "specs", `${taskId}-${slug}.md`),
|
|
304
|
+
prdDir: (root) => join2(root, NOIR_DIR, "prd"),
|
|
305
|
+
prdFile: (root, taskId, slug) => join2(root, NOIR_DIR, "prd", `${taskId}-${slug}.md`),
|
|
306
|
+
plansDir: (root) => join2(root, NOIR_DIR, "plans"),
|
|
307
|
+
planFile: (root, taskId, slug) => join2(root, NOIR_DIR, "plans", `${taskId}-${slug}.md`),
|
|
308
|
+
tasksDir: (root) => join2(root, NOIR_DIR, "tasks"),
|
|
309
|
+
taskFile: (root, taskId, taskName) => join2(root, NOIR_DIR, "tasks", `${taskId}-${taskName}.md`),
|
|
310
|
+
decisionsDir: (root) => join2(root, NOIR_DIR, "decisions"),
|
|
311
|
+
decisionFile: (root, n) => join2(root, NOIR_DIR, "decisions", `${String(n).padStart(4, "0")}.md`),
|
|
312
|
+
auditDir: (root) => join2(root, NOIR_DIR, "audit"),
|
|
313
|
+
auditFile: (root, taskId) => join2(root, NOIR_DIR, "audit", `${taskId}.json`)
|
|
149
314
|
};
|
|
150
315
|
|
|
151
|
-
// src/markers.ts
|
|
152
|
-
var CONTEXT_BLOCK_BEGIN = "<!-- noir:context begin -->";
|
|
153
|
-
var CONTEXT_BLOCK_END = "<!-- noir:context end -->";
|
|
154
|
-
|
|
155
316
|
// src/project.ts
|
|
156
|
-
import { readFileSync } from "fs";
|
|
157
|
-
import { basename } from "path";
|
|
317
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
318
|
+
import { basename as basename2 } from "path";
|
|
158
319
|
import { parse as parseYaml } from "yaml";
|
|
159
320
|
function loadProjectInfo(root) {
|
|
160
321
|
let rawId;
|
|
161
322
|
let rawConfig;
|
|
162
323
|
try {
|
|
163
|
-
rawId =
|
|
164
|
-
rawConfig = parseYaml(
|
|
324
|
+
rawId = readFileSync2(paths.projectId(root), "utf8").trim();
|
|
325
|
+
rawConfig = parseYaml(readFileSync2(paths.config(root), "utf8"));
|
|
165
326
|
} catch {
|
|
166
327
|
throw new Error(`Noir is not initialized in ${root}. Run \`noir init\` first.`);
|
|
167
328
|
}
|
|
168
329
|
const config = parseConfig(rawConfig);
|
|
169
330
|
return {
|
|
170
331
|
id: rawId,
|
|
171
|
-
name: config.name ??
|
|
332
|
+
name: config.name ?? basename2(root),
|
|
172
333
|
root,
|
|
173
334
|
config
|
|
174
335
|
};
|
|
@@ -181,21 +342,30 @@ function createProjectId() {
|
|
|
181
342
|
}
|
|
182
343
|
|
|
183
344
|
// src/version.ts
|
|
184
|
-
import { readFileSync as
|
|
345
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
185
346
|
import { fileURLToPath } from "url";
|
|
186
347
|
var pkgPath = fileURLToPath(new URL("../package.json", import.meta.url));
|
|
187
|
-
var NOIR_VERSION = JSON.parse(
|
|
348
|
+
var NOIR_VERSION = JSON.parse(readFileSync3(pkgPath, "utf8")).version ?? "0.0.0";
|
|
188
349
|
export {
|
|
350
|
+
CONTEXT_BLOCK,
|
|
189
351
|
CONTEXT_BLOCK_BEGIN,
|
|
190
352
|
CONTEXT_BLOCK_END,
|
|
353
|
+
IGNORE_BLOCK,
|
|
191
354
|
NOIR_DIR,
|
|
192
355
|
NOIR_VERSION,
|
|
193
356
|
NoirConfigSchema,
|
|
357
|
+
RULES_BLOCK,
|
|
358
|
+
commentStyleFor,
|
|
194
359
|
createProjectId,
|
|
195
360
|
loadProjectInfo,
|
|
361
|
+
managedBlock,
|
|
196
362
|
modelsDir,
|
|
197
363
|
noirHome,
|
|
198
364
|
parseConfig,
|
|
199
|
-
paths
|
|
365
|
+
paths,
|
|
366
|
+
readManagedBlock,
|
|
367
|
+
stripManagedBlock,
|
|
368
|
+
syncIgnores,
|
|
369
|
+
writeManagedRegion
|
|
200
370
|
};
|
|
201
371
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/layout.ts","../src/markers.ts","../src/project.ts","../src/project-id.ts","../src/version.ts"],"sourcesContent":["import * as z from 'zod';\n\nexport const NoirConfigSchema = z.object({\n host: z.literal('claude'),\n name: z.string().optional(),\n mode: z.enum(['full', 'quick']).default('full'),\n daemon: z\n .object({\n idleTimeoutSec: z.number().int().positive().default(900),\n port: z.number().int().min(0).max(65535).optional(),\n })\n .default({ idleTimeoutSec: 900 }),\n // Slice S6 context layer (@noir-ai/context). Mirrors the `daemon` idiom — a\n // top-level object with `.default({})` so a config with NO `context:` block\n // still parses and behaves as local-embedder-attempted (AC-7 / NFR-6). The\n // embedder shape is `kind`-based to match the discriminated `EmbedderConfig`\n // the context factory consumes; `resolveEmbedderConfig` (@noir-ai/context) is\n // the single bridge from this user-facing schema to the factory input, so core\n // never imports context (no core→context cycle). Provider-explicit, NEVER\n // silent remote (blueprint D6): `kind:'remote'`/`'ollama'` are opt-in only;\n // the default `'local'` is in-process, offline, free, private.\n context: z\n .object({\n embedder: z\n .object({\n kind: z.enum(['local', 'remote', 'ollama', 'none']).default('local'),\n // HF repo id (local) / provider model id (remote) / Ollama tag.\n model: z.string().optional(),\n // Remote provider key, e.g. 'openai' (only meaningful when kind:'remote').\n // Free-form string so openai-compatible providers stay expressible; the\n // resolver maps known names (openai/voyage/cohere) to their API-key env var.\n provider: z.string().optional(),\n // Ollama base URL, e.g. http://localhost:11434 (only when kind:'ollama').\n baseURL: z.string().optional(),\n // Target dimensionality — must be 384 to match the existing vec0 table.\n dim: z.number().int().positive().default(384),\n })\n .default({ kind: 'local', dim: 384 }),\n // Configured index roots (informational in core; the daemon/indexer consume).\n roots: z.array(z.string()).default([]),\n // Default token budget for a `context_search` result set (retriever default).\n budgetTokens: z.number().int().positive().default(4096),\n })\n // Zod v4 requires the outer default to match the parsed output shape (every\n // inner field already carries its own default, so an absent `context:` block\n // still resolves to local-embedder/empty-roots/4096). Mirrors `daemon:`.\n .default({ embedder: { kind: 'local', dim: 384 }, roots: [], budgetTokens: 4096 }),\n // Slice S8 bounded model layer (@noir-ai/model). Mirrors the `daemon` idiom —\n // a top-level object with `.default({})` so a config with NO `model:` block\n // still parses and behaves as fully-degraded (every `complete()` call returns\n // `null`; callers substitute a template — the always-available offline path,\n // blueprint D5 / DS-5). `resolveModelConfig` (@noir-ai/model) is the single\n // bridge from this user-facing schema to the runtime shape `complete()`\n // consumes, so core never imports model (no core→model cycle).\n //\n // Provider-EXPLICIT, never silent paid (blueprint D5 / DS-6): the provider is\n // resolved ONLY from explicit `defaultProvider` / a tier's provider key. Env-\n // var presence is NEVER consulted to pick a provider — `ANTHROPIC_API_KEY`\n // being set for another tool does NOT activate Anthropic in Noir. No explicit,\n // configured provider ⇒ `null`. Secrets live in env vars only (DS-8):\n // `apiKeyEnv` stores the env-var NAME (`ANTHROPIC_API_KEY`), never the value,\n // so `.noir/config.yml` stays safe to commit and share; `complete()` reads the\n // value at call time. `tiers` map a tier name → provider block key; each\n // `providers[name]` declares the model id, optional `baseURL` (openai-compat),\n // and optional `apiKeyEnv` (omit for anonymous local providers like Ollama).\n model: z\n .object({\n // Fallback provider name (key into `providers`) when a call's tier resolves\n // no explicit provider. Free-form string so openai-compatible providers stay\n // expressible without an enum churn.\n defaultProvider: z.string().optional(),\n // Per-tier provider-key overrides (draft / title / summarize / consolidate).\n // Each value is a key into `providers{}`; resolution is the consumer's job\n // (tier → tier.provider → defaultProvider → providers[name]).\n tiers: z\n .object({\n draft: z.string().optional(),\n title: z.string().optional(),\n summarize: z.string().optional(),\n consolidate: z.string().optional(),\n })\n .optional(),\n // Configured provider blocks, keyed by name. `model` is required (a provider\n // without a model id is meaningless); `apiKeyEnv` is omitted for anonymous\n // local providers (Ollama / LM Studio) which then send no auth header.\n providers: z\n .record(\n z.string(),\n z.object({\n model: z.string(),\n baseURL: z.string().optional(),\n apiKeyEnv: z.string().optional(),\n }),\n )\n .optional(),\n })\n // Absent `model:` block ⇒ `{}` ⇒ every tier/provider is undefined ⇒ full\n // degradation (offline, free, the default). Inner fields are `.optional()`\n // (no inner `.default()`) so a present-but-empty block also degrades.\n .default({}),\n // Slice S7 cross-session memory (@noir-ai/memory). Mirrors the `daemon` idiom —\n // a top-level object with `.default({})` so a config with NO `memory:` block\n // still parses and behaves as consolidation-disabled (the safe default —\n // capture/store/retrieve are always local + free; consolidation is the ONLY\n // LLM touch and it is opt-in + provider-explicit). `resolveMemoryConfig`\n // (@noir-ai/memory) is the single bridge from this user-facing schema to the\n // runtime `MemoryConfig` the engine consumes, so core never imports memory\n // (no core→memory cycle; mirrors @noir-ai/context + @noir-ai/model).\n //\n // Provider-EXPLICIT, never silent paid (blueprint D6 / DS-6): the provider is\n // resolved ONLY from explicit `consolidation.provider`. Env-var presence is\n // NEVER consulted to pick a provider — `ANTHROPIC_API_KEY` being set for\n // another tool does NOT activate consolidation. No explicit, enabled provider\n // ⇒ `runConsolidation` refuses with `'no-provider'` + writes a miss audit, and\n // NO S8 `complete()` call is made (the Agent-Memory anti-pattern, §9). The\n // outer default matches the parsed output shape (Zod v4 requirement).\n memory: z\n .object({\n consolidation: z\n .object({\n // Master switch (default false). When false, `consolidate` refuses +\n // logs (`no-provider`) regardless of provider/model — the first gate.\n enabled: z.boolean().default(false),\n // Provider key, e.g. 'anthropic' | 'openai' | 'ollama'. Free-form\n // string so openai-compatible providers stay expressible without an\n // enum churn; required (alongside enabled) for consolidation to run.\n provider: z.string().optional(),\n // Provider-specific model id (consumed by S8 complete(); optional\n // here only because a future anonymous local provider may not need it\n // — runConsolidation still refuses when model is absent).\n model: z.string().optional(),\n // Restrict candidates to these types (default: every non-`lesson`).\n types: z.array(z.string()).optional(),\n })\n // Absent consolidation block ⇒ disabled. Outer shape matches output.\n .default({ enabled: false }),\n })\n .default({ consolidation: { enabled: false } }),\n});\n\nexport type NoirConfig = z.infer<typeof NoirConfigSchema>;\n\nexport function parseConfig(raw: unknown): NoirConfig {\n return NoirConfigSchema.parse(raw);\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const NOIR_DIR = '.noir';\n\n/**\n * User-global Noir home: `~/.noir` (HOME-relative, NOT project `.noir/`).\n *\n * Hosts cross-project, user-scoped state — today the daemon record\n * (`~/.noir/daemon.json`, written by @noir-ai/daemon) and the embedding-model\n * cache ({@link modelsDir}). Kept HOME-relative so a single project checkout\n * stays portable across machines (blueprint: `ProjectId` is canonical, never a\n * filesystem path; the project `.noir/` dir never holds machine-local caches).\n */\nexport function noirHome(): string {\n return join(homedir(), NOIR_DIR);\n}\n\n/**\n * User-global cache for downloaded embedding-model weights: `~/.noir/models/`.\n *\n * Used by @noir-ai/context's local embedder (`@huggingface/transformers` pins\n * `env.cacheDir` here on first load). HOME-relative per spec OQ-7 (resolved) —\n * the ~22 MB MiniLM download is user-scoped, not per-project, so projects stay\n * portable and the weight is fetched at most once per machine.\n */\nexport function modelsDir(): string {\n return join(noirHome(), 'models');\n}\n\nexport const paths = {\n noirDir: (root: string) => join(root, NOIR_DIR),\n noirMd: (root: string) => join(root, NOIR_DIR, 'NOIR.md'),\n config: (root: string) => join(root, NOIR_DIR, 'config.yml'),\n projectId: (root: string) => join(root, NOIR_DIR, 'project.id'),\n storeDir: (root: string) => join(root, NOIR_DIR, 'store'),\n storeDb: (root: string, projectId: string) => join(root, NOIR_DIR, 'store', `${projectId}.db`),\n // Artifact directories and files\n specsDir: (root: string) => join(root, NOIR_DIR, 'specs'),\n specFile: (root: string, taskId: string, slug: string) =>\n join(root, NOIR_DIR, 'specs', `${taskId}-${slug}.md`),\n plansDir: (root: string) => join(root, NOIR_DIR, 'plans'),\n planFile: (root: string, taskId: string, slug: string) =>\n join(root, NOIR_DIR, 'plans', `${taskId}-${slug}.md`),\n tasksDir: (root: string) => join(root, NOIR_DIR, 'tasks'),\n taskFile: (root: string, taskId: string, taskName: string) =>\n join(root, NOIR_DIR, 'tasks', `${taskId}-${taskName}.md`),\n decisionsDir: (root: string) => join(root, NOIR_DIR, 'decisions'),\n decisionFile: (root: string, n: number) =>\n join(root, NOIR_DIR, 'decisions', `${String(n).padStart(4, '0')}.md`),\n auditDir: (root: string) => join(root, NOIR_DIR, 'audit'),\n auditFile: (root: string, taskId: string) => join(root, NOIR_DIR, 'audit', `${taskId}.json`),\n} as const;\n","export const CONTEXT_BLOCK_BEGIN = '<!-- noir:context begin -->';\nexport const CONTEXT_BLOCK_END = '<!-- noir:context end -->';\n","import { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { type NoirConfig, parseConfig } from './config.js';\nimport { paths } from './layout.js';\nimport type { ProjectId } from './project-id.js';\n\nexport interface ProjectInfo {\n id: ProjectId;\n name: string;\n root: string;\n config: NoirConfig;\n}\n\nexport function loadProjectInfo(root: string): ProjectInfo {\n let rawId: string;\n let rawConfig: unknown;\n try {\n rawId = readFileSync(paths.projectId(root), 'utf8').trim();\n rawConfig = parseYaml(readFileSync(paths.config(root), 'utf8'));\n } catch {\n throw new Error(`Noir is not initialized in ${root}. Run \\`noir init\\` first.`);\n }\n const config = parseConfig(rawConfig);\n return {\n id: rawId,\n name: config.name ?? basename(root),\n root,\n config,\n };\n}\n","import { randomUUID } from 'node:crypto';\n\n/** Canonical, machine-stable project identity. NEVER a filesystem path. */\nexport type ProjectId = string;\n\nexport function createProjectId(): ProjectId {\n return randomUUID();\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n// Read the version from THIS package's package.json at module load (NOT a hardcoded\n// constant) so a release bump (scripts/bump-version.mjs) is reflected everywhere\n// `noir` self-identifies — `noir --version`, `noir doctor`/`status`, the MCP\n// initialize handshake — with zero drift between package.json and the binary.\n//\n// `import.meta.url` resolves correctly in every layout the package ships in:\n// src (vitest): packages/core/src/version.ts → ../package.json = packages/core/package.json\n// dist (tsup): packages/core/dist/index.js → ../package.json = packages/core/package.json\n// published: node_modules/@noir-ai/core/dist/... → ../package.json = @noir-ai/core/package.json\n// (npm ALWAYS ships package.json alongside dist/, so the read is safe in the tarball.)\nconst pkgPath = fileURLToPath(new URL('../package.json', import.meta.url));\nexport const NOIR_VERSION: string =\n (JSON.parse(readFileSync(pkgPath, 'utf8')) as { version?: string }).version ?? '0.0.0';\n"],"mappings":"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","names":["readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/block-writer.ts","../src/config.ts","../src/ignore-manager.ts","../src/markers.ts","../src/layout.ts","../src/project.ts","../src/project-id.ts","../src/version.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'node:fs';\nimport { basename, extname } from 'node:path';\nimport type { CommentStyle, ManagedBlock } from './markers.js';\n\nconst HASH_FILES = new Set([\n '.gitignore',\n '.dockerignore',\n '.npmignore',\n '.prettierignore',\n '.eslintignore',\n '.ignore',\n]);\n\nfunction escapeRe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Pick a comment style for a managed region from a file path. */\nexport function commentStyleFor(file: string): CommentStyle {\n const lower = file.toLowerCase();\n if (HASH_FILES.has(basename(lower))) return 'hash';\n const ext = extname(lower);\n if (ext === '.yml' || ext === '.yaml') return 'hash';\n return 'html';\n}\n\n/** Remove every `<begin>…<end>` region for `block` from `content`. */\nexport function stripManagedBlock(content: string, block: ManagedBlock): string {\n const re = new RegExp(`${escapeRe(block.begin)}[\\\\s\\\\S]*?${escapeRe(block.end)}\\\\n?`, 'g');\n return content.replace(re, '');\n}\n\n/** Read the first `<begin>…<end>` region for `block` from `file`, or null if absent/missing. */\nexport function readManagedBlock(file: string, block: ManagedBlock): string | null {\n let content: string;\n try {\n content = readFileSync(file, 'utf8');\n } catch {\n return null;\n }\n const m = content.match(new RegExp(`${escapeRe(block.begin)}[\\\\s\\\\S]*?${escapeRe(block.end)}`));\n return m?.[0] ? m[0] : null;\n}\n\n/** Idempotently write `regionText` (a full `<begin>…<end>` block) into `file`,\n * stripping any prior region for `block` and preserving all other content. */\nexport function writeManagedRegion(file: string, block: ManagedBlock, regionText: string): void {\n let content = '';\n try {\n content = readFileSync(file, 'utf8');\n } catch {\n /* missing → treat as empty */\n }\n const stripped = stripManagedBlock(content, block);\n const next = `${stripped ? `${stripped.trimEnd()}\\n\\n` : ''}${regionText}`;\n writeFileSync(file, next, 'utf8');\n}\n","import * as z from 'zod';\n\nexport const NoirConfigSchema = z.object({\n // S10 multi-host: widens from `z.literal('claude')` to a 5-value enum. The\n // canonical `HostId` union lives in @noir-ai/adapters (single owner); core\n // owns the enum STRING here so it does not import adapters (no core→adapters\n // cycle — mirrors the existing pattern where `model`/`memory`/`context`/`prd`\n // redeclare shapes their resolvers consume). `claude` remains the default so\n // existing single-host projects are byte-equivalent (regression anchor).\n host: z.enum(['claude', 'agents-md', 'gemini', 'cursor', 'opencode']).default('claude'),\n name: z.string().optional(),\n mode: z.enum(['full', 'quick']).default('full'),\n daemon: z\n .object({\n idleTimeoutSec: z.number().int().positive().default(900),\n port: z.number().int().min(0).max(65535).optional(),\n })\n .default({ idleTimeoutSec: 900 }),\n // Slice S6 context layer (@noir-ai/context). Mirrors the `daemon` idiom — a\n // top-level object with `.default({})` so a config with NO `context:` block\n // still parses and behaves as local-embedder-attempted (AC-7 / NFR-6). The\n // embedder shape is `kind`-based to match the discriminated `EmbedderConfig`\n // the context factory consumes; `resolveEmbedderConfig` (@noir-ai/context) is\n // the single bridge from this user-facing schema to the factory input, so core\n // never imports context (no core→context cycle). Provider-explicit, NEVER\n // silent remote (blueprint D6): `kind:'remote'`/`'ollama'` are opt-in only;\n // the default `'local'` is in-process, offline, free, private.\n context: z\n .object({\n embedder: z\n .object({\n kind: z.enum(['local', 'remote', 'ollama', 'none']).default('local'),\n // HF repo id (local) / provider model id (remote) / Ollama tag.\n model: z.string().optional(),\n // Remote provider key, e.g. 'openai' (only meaningful when kind:'remote').\n // Free-form string so openai-compatible providers stay expressible; the\n // resolver maps known names (openai/voyage/cohere) to their API-key env var.\n provider: z.string().optional(),\n // Ollama base URL, e.g. http://localhost:11434 (only when kind:'ollama').\n baseURL: z.string().optional(),\n // Target dimensionality — must be 384 to match the existing vec0 table.\n dim: z.number().int().positive().default(384),\n })\n .default({ kind: 'local', dim: 384 }),\n // Configured index roots (informational in core; the daemon/indexer consume).\n roots: z.array(z.string()).default([]),\n // Default token budget for a `context_search` result set (retriever default).\n budgetTokens: z.number().int().positive().default(4096),\n })\n // Zod v4 requires the outer default to match the parsed output shape (every\n // inner field already carries its own default, so an absent `context:` block\n // still resolves to local-embedder/empty-roots/4096). Mirrors `daemon:`.\n .default({ embedder: { kind: 'local', dim: 384 }, roots: [], budgetTokens: 4096 }),\n // Slice S8 bounded model layer (@noir-ai/model). Mirrors the `daemon` idiom —\n // a top-level object with `.default({})` so a config with NO `model:` block\n // still parses and behaves as fully-degraded (every `complete()` call returns\n // `null`; callers substitute a template — the always-available offline path,\n // blueprint D5 / DS-5). `resolveModelConfig` (@noir-ai/model) is the single\n // bridge from this user-facing schema to the runtime shape `complete()`\n // consumes, so core never imports model (no core→model cycle).\n //\n // Provider-EXPLICIT, never silent paid (blueprint D5 / DS-6): the provider is\n // resolved ONLY from explicit `defaultProvider` / a tier's provider key. Env-\n // var presence is NEVER consulted to pick a provider — `ANTHROPIC_API_KEY`\n // being set for another tool does NOT activate Anthropic in Noir. No explicit,\n // configured provider ⇒ `null`. Secrets live in env vars only (DS-8):\n // `apiKeyEnv` stores the env-var NAME (`ANTHROPIC_API_KEY`), never the value,\n // so `.noir/config.yml` stays safe to commit and share; `complete()` reads the\n // value at call time. `tiers` map a tier name → provider block key; each\n // `providers[name]` declares the model id, optional `baseURL` (openai-compat),\n // and optional `apiKeyEnv` (omit for anonymous local providers like Ollama).\n model: z\n .object({\n // Fallback provider name (key into `providers`) when a call's tier resolves\n // no explicit provider. Free-form string so openai-compatible providers stay\n // expressible without an enum churn.\n defaultProvider: z.string().optional(),\n // Per-tier provider-key overrides (draft / title / summarize / consolidate).\n // Each value is a key into `providers{}`; resolution is the consumer's job\n // (tier → tier.provider → defaultProvider → providers[name]).\n tiers: z\n .object({\n draft: z.string().optional(),\n title: z.string().optional(),\n summarize: z.string().optional(),\n consolidate: z.string().optional(),\n })\n .optional(),\n // Configured provider blocks, keyed by name. `model` is required (a provider\n // without a model id is meaningless); `apiKeyEnv` is omitted for anonymous\n // local providers (Ollama / LM Studio) which then send no auth header.\n providers: z\n .record(\n z.string(),\n z.object({\n model: z.string(),\n baseURL: z.string().optional(),\n apiKeyEnv: z.string().optional(),\n }),\n )\n .optional(),\n })\n // Absent `model:` block ⇒ `{}` ⇒ every tier/provider is undefined ⇒ full\n // degradation (offline, free, the default). Inner fields are `.optional()`\n // (no inner `.default()`) so a present-but-empty block also degrades.\n .default({}),\n // Slice S7 cross-session memory (@noir-ai/memory). Mirrors the `daemon` idiom —\n // a top-level object with `.default({})` so a config with NO `memory:` block\n // still parses and behaves as consolidation-disabled (the safe default —\n // capture/store/retrieve are always local + free; consolidation is the ONLY\n // LLM touch and it is opt-in + provider-explicit). `resolveMemoryConfig`\n // (@noir-ai/memory) is the single bridge from this user-facing schema to the\n // runtime `MemoryConfig` the engine consumes, so core never imports memory\n // (no core→memory cycle; mirrors @noir-ai/context + @noir-ai/model).\n //\n // Provider-EXPLICIT, never silent paid (blueprint D6 / DS-6): the provider is\n // resolved ONLY from explicit `consolidation.provider`. Env-var presence is\n // NEVER consulted to pick a provider — `ANTHROPIC_API_KEY` being set for\n // another tool does NOT activate consolidation. No explicit, enabled provider\n // ⇒ `runConsolidation` refuses with `'no-provider'` + writes a miss audit, and\n // NO S8 `complete()` call is made (the Agent-Memory anti-pattern, §9). The\n // outer default matches the parsed output shape (Zod v4 requirement).\n memory: z\n .object({\n consolidation: z\n .object({\n // Master switch (default false). When false, `consolidate` refuses +\n // logs (`no-provider`) regardless of provider/model — the first gate.\n enabled: z.boolean().default(false),\n // Provider key, e.g. 'anthropic' | 'openai' | 'ollama'. Free-form\n // string so openai-compatible providers stay expressible without an\n // enum churn; required (alongside enabled) for consolidation to run.\n provider: z.string().optional(),\n // Provider-specific model id (consumed by S8 complete(); optional\n // here only because a future anonymous local provider may not need it\n // — runConsolidation still refuses when model is absent).\n model: z.string().optional(),\n // Restrict candidates to these types (default: every non-`lesson`).\n types: z.array(z.string()).optional(),\n })\n // Absent consolidation block ⇒ disabled. Outer shape matches output.\n .default({ enabled: false }),\n })\n .default({ consolidation: { enabled: false } }),\n // Debt-batch A — `rules:` block. Additive, no-op when absent (defaults make it\n // a pass-through). Reserved for the upcoming rule-driven lint surface (the\n // `@noir-ai/workflow` rule registry + future `noir check`); for v1.x this\n // block is parsed + validated but no consumer reads it yet — declaring it\n // here lets early adopters pin `enabled: false` or a non-default budget in\n // `.noir/config.yml` without a schema churn when the rule engine ships.\n rules: z\n .object({\n // Master switch (default true — the rule registry is opt-OUT; a project\n // that wants no part of it sets `enabled: false`). When the rule engine\n // ships, false ⇒ no rules registered + `noir check` is a no-op.\n enabled: z.boolean().default(true),\n // Soft per-rule body budget in KB (targets file-size discipline for the\n // markdown rules; the future rule registry clips over-budget rule bodies\n // and surfaces a warning rather than rejecting the file). Positive int.\n lengthBudgetKb: z.number().int().positive().default(6),\n })\n // Outer default matches the parsed output shape (Zod v4 requirement): an\n // absent `rules:` block resolves to enabled/6 — the registry-active default.\n .default({ enabled: true, lengthBudgetKb: 6 }),\n // Slice P (PRD) — `prd:` block. Additive, escapable-soft-gate config for the\n // pre-SDD Product Requirements Document. The workflow engine reads\n // `mandatoryFor` to decide when a missing PRD warrants an observable,\n // escapable recommendation at the spec gate (the advance still proceeds —\n // never a hard block; `--force <reason>` is the explicit override). The\n // `TaskClass` enum mirrors @noir-ai/workflow's; duplicated HERE (as a literal\n // z.enum) so core never imports workflow (no core→workflow cycle), exactly\n // as `model`/`memory`/`context` declare provider shapes that their resolvers\n // in other packages consume.\n //\n // Defaults: `mandatoryFor: ['feature', 'epic']` — the noir-prd skill's \"when\n // to draft\" rule. Quick-mode + non-mandatory taskClasses skip the check\n // entirely; a present-but-empty `prd:` block also degrades to the default.\n prd: z\n .object({\n mandatoryFor: z\n .array(\n z.enum(['feature', 'epic', 'enhancement', 'bugfix', 'spike', 'quick-task', 'refactor']),\n )\n .default(['feature', 'epic']),\n })\n .default({ mandatoryFor: ['feature', 'epic'] }),\n // Slice X integration layer (@noir-ai/skills `integrations/<name>/`). Additive\n // block keyed by integration name — every field optional + default-`{}` so a\n // config with NO `integrations:` block still parses and behaves as \"no\n // integrations wired\" (degraded by default; the skill playbook still ships\n // and works in manual-paste mode regardless of this block — it only carries\n // the per-workspace binding like team_id/list_id for the gated proxy). The\n // declaration shape lives in @noir-ai/skills' Zod schema; this block is the\n // USER-facing overlay (which integration is enabled + where it points), not\n // a re-statement of the declaration.\n //\n // Doctrine (slice-x spec + Q4b): the auth TOKEN stays in env (tokenEnv name\n // is declared in integration.json, NOT here); ClickUp-specific ids are\n // optional workspace binding; `runtime` mirrors the declaration tiers so a\n // user can DOWNGRADE an integration locally (e.g. force `none` for a\n // read-only run).\n integrations: z\n .record(\n z.string(),\n z.object({\n auth: z\n .object({\n // Override the token env var name (defaults to the declaration's\n // `auth.tokenEnv` when undefined). Min(1) matches the declaration\n // schema's invariant (`integrations-schema.ts` tokenEnv is non-empty)\n // — an empty-string override must FAIL validation, not silently\n // disable the integration (env[''] is always undefined).\n tokenEnv: z.string().min(1).optional(),\n })\n .partial()\n .default({}),\n runtime: z.enum(['none', 'gated-write-proxy', 'mcp-stdio', 'external-mcp']).default('none'),\n // ClickUp-workspace binding (optional; flows 3 + 5 need a list_id).\n teamId: z.string().optional(),\n listId: z.string().optional(),\n spaceId: z.string().optional(),\n }),\n )\n .default({}),\n});\n\nexport type NoirConfig = z.infer<typeof NoirConfigSchema>;\n\nexport function parseConfig(raw: unknown): NoirConfig {\n return NoirConfigSchema.parse(raw);\n}\n","import { join } from 'node:path';\nimport { writeManagedRegion } from './block-writer.js';\nimport { managedBlock } from './markers.js';\n\n/** Managed-region marker for ignore-style files (hash comments). */\nexport const IGNORE_BLOCK = managedBlock('ignore', 'hash');\n\n/** Default Noir entries per ignore file (derived/runtime artifacts only). */\nconst IGNORE_ENTRIES: ReadonlyArray<[file: string, entries: readonly string[]]> = [\n ['.gitignore', ['/.noir/store/', '/.noir/*.sock', '/.noir/daemon.pid', '/.noir/state/']],\n ['.dockerignore', ['.noir/']],\n ['.npmignore', ['/.noir/']],\n ['.prettierignore', ['/.noir/']],\n];\n\n/** Idempotently write Noir's managed ignore block into each configured ignore\n * file under `root`, preserving all user content outside the block. Returns\n * the list of files touched. Safe to re-run (managed-block replacement). */\nexport function syncIgnores(root: string): { files: string[] } {\n const files: string[] = [];\n for (const [name, entries] of IGNORE_ENTRIES) {\n const region = `${IGNORE_BLOCK.begin}\\n${entries.join('\\n')}\\n${IGNORE_BLOCK.end}\\n`;\n writeManagedRegion(join(root, name), IGNORE_BLOCK, region);\n files.push(name);\n }\n return { files };\n}\n","export type CommentStyle = 'html' | 'hash';\n\nexport interface ManagedBlock {\n readonly name: string;\n readonly commentStyle: CommentStyle;\n readonly begin: string;\n readonly end: string;\n}\n\n/** Build a matched begin/end marker pair for a managed region.\n * `html` → `<!-- noir:<name> begin -->` (markdown / CLAUDE.md / NOIR.md).\n * `hash` → `# >>> noir:<name> >>>` (.gitignore / .dockerignore / .npmignore / yml). */\nexport function managedBlock(name: string, commentStyle: CommentStyle = 'html'): ManagedBlock {\n if (commentStyle === 'hash') {\n return { name, commentStyle, begin: `# >>> noir:${name} >>>`, end: `# <<< noir:${name} <<<` };\n }\n return {\n name,\n commentStyle,\n begin: `<!-- noir:${name} begin -->`,\n end: `<!-- noir:${name} end -->`,\n };\n}\n\n/** Named instances. CONTEXT_BLOCK_* are kept byte-identical for backward compat. */\nexport const CONTEXT_BLOCK = managedBlock('context', 'html');\nexport const RULES_BLOCK = managedBlock('rules', 'html');\nexport const CONTEXT_BLOCK_BEGIN = CONTEXT_BLOCK.begin;\nexport const CONTEXT_BLOCK_END = CONTEXT_BLOCK.end;\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport const NOIR_DIR = '.noir';\n\n/**\n * User-global Noir home: `~/.noir` (HOME-relative, NOT project `.noir/`).\n *\n * Hosts cross-project, user-scoped state — today the daemon record\n * (`~/.noir/daemon.json`, written by @noir-ai/daemon) and the embedding-model\n * cache ({@link modelsDir}). Kept HOME-relative so a single project checkout\n * stays portable across machines (blueprint: `ProjectId` is canonical, never a\n * filesystem path; the project `.noir/` dir never holds machine-local caches).\n */\nexport function noirHome(): string {\n return join(homedir(), NOIR_DIR);\n}\n\n/**\n * User-global cache for downloaded embedding-model weights: `~/.noir/models/`.\n *\n * Used by @noir-ai/context's local embedder (`@huggingface/transformers` pins\n * `env.cacheDir` here on first load). HOME-relative per spec OQ-7 (resolved) —\n * the ~22 MB MiniLM download is user-scoped, not per-project, so projects stay\n * portable and the weight is fetched at most once per machine.\n */\nexport function modelsDir(): string {\n return join(noirHome(), 'models');\n}\n\nexport const paths = {\n noirDir: (root: string) => join(root, NOIR_DIR),\n noirMd: (root: string) => join(root, NOIR_DIR, 'NOIR.md'),\n rulesMd: (root: string) => join(root, NOIR_DIR, 'rules', 'RULES.md'),\n config: (root: string) => join(root, NOIR_DIR, 'config.yml'),\n projectId: (root: string) => join(root, NOIR_DIR, 'project.id'),\n storeDir: (root: string) => join(root, NOIR_DIR, 'store'),\n storeDb: (root: string, projectId: string) => join(root, NOIR_DIR, 'store', `${projectId}.db`),\n // Artifact directories and files\n specsDir: (root: string) => join(root, NOIR_DIR, 'specs'),\n specFile: (root: string, taskId: string, slug: string) =>\n join(root, NOIR_DIR, 'specs', `${taskId}-${slug}.md`),\n prdDir: (root: string) => join(root, NOIR_DIR, 'prd'),\n prdFile: (root: string, taskId: string, slug: string) =>\n join(root, NOIR_DIR, 'prd', `${taskId}-${slug}.md`),\n plansDir: (root: string) => join(root, NOIR_DIR, 'plans'),\n planFile: (root: string, taskId: string, slug: string) =>\n join(root, NOIR_DIR, 'plans', `${taskId}-${slug}.md`),\n tasksDir: (root: string) => join(root, NOIR_DIR, 'tasks'),\n taskFile: (root: string, taskId: string, taskName: string) =>\n join(root, NOIR_DIR, 'tasks', `${taskId}-${taskName}.md`),\n decisionsDir: (root: string) => join(root, NOIR_DIR, 'decisions'),\n decisionFile: (root: string, n: number) =>\n join(root, NOIR_DIR, 'decisions', `${String(n).padStart(4, '0')}.md`),\n auditDir: (root: string) => join(root, NOIR_DIR, 'audit'),\n auditFile: (root: string, taskId: string) => join(root, NOIR_DIR, 'audit', `${taskId}.json`),\n} as const;\n","import { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { type NoirConfig, parseConfig } from './config.js';\nimport { paths } from './layout.js';\nimport type { ProjectId } from './project-id.js';\n\nexport interface ProjectInfo {\n id: ProjectId;\n name: string;\n root: string;\n config: NoirConfig;\n}\n\nexport function loadProjectInfo(root: string): ProjectInfo {\n let rawId: string;\n let rawConfig: unknown;\n try {\n rawId = readFileSync(paths.projectId(root), 'utf8').trim();\n rawConfig = parseYaml(readFileSync(paths.config(root), 'utf8'));\n } catch {\n throw new Error(`Noir is not initialized in ${root}. Run \\`noir init\\` first.`);\n }\n const config = parseConfig(rawConfig);\n return {\n id: rawId,\n name: config.name ?? basename(root),\n root,\n config,\n };\n}\n","import { randomUUID } from 'node:crypto';\n\n/** Canonical, machine-stable project identity. NEVER a filesystem path. */\nexport type ProjectId = string;\n\nexport function createProjectId(): ProjectId {\n return randomUUID();\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n// Read the version from THIS package's package.json at module load (NOT a hardcoded\n// constant) so a release bump (scripts/bump-version.mjs) is reflected everywhere\n// `noir` self-identifies — `noir --version`, `noir doctor`/`status`, the MCP\n// initialize handshake — with zero drift between package.json and the binary.\n//\n// `import.meta.url` resolves correctly in every layout the package ships in:\n// src (vitest): packages/core/src/version.ts → ../package.json = packages/core/package.json\n// dist (tsup): packages/core/dist/index.js → ../package.json = packages/core/package.json\n// published: node_modules/@noir-ai/core/dist/... → ../package.json = @noir-ai/core/package.json\n// (npm ALWAYS ships package.json alongside dist/, so the read is safe in the tarball.)\nconst pkgPath = fileURLToPath(new URL('../package.json', import.meta.url));\nexport const NOIR_VERSION: string =\n (JSON.parse(readFileSync(pkgPath, 'utf8')) as { version?: string }).version ?? '0.0.0';\n"],"mappings":"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","names":["join","readFileSync","basename","readFileSync","basename","readFileSync"]}
|
package/package.json
CHANGED