@lemoncode/lemony 0.1.1-alpha.1 → 0.1.1-alpha.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/NOTICE CHANGED
@@ -12,11 +12,13 @@ The catalog components below adapt text or code from the following MIT-licensed
12
12
  sources. Each source's copyright notice is reproduced here; the shared MIT
13
13
  permission notice (reproduced once, at the end of this section) applies to each.
14
14
 
15
- - **mattpocock/skills** — Copyright (c) Matt Pocock
15
+ - **mattpocock/skills** — Copyright (c) 2026 Matt Pocock
16
16
  Source: https://github.com/mattpocock/skills
17
17
  Adapted by:
18
18
  - grill-ui — grill interview engine — one question at a time, decision-by-decision interrogation
19
19
  - grill-with-docs — grill workflow and decision-by-decision interview structure
20
+ - tdd — the red-green cycle, the behavior-over-implementation core principle, the vertical-slice ("tracer bullet") framing, mock-at-system-boundaries guidance, and the ADR three-tests nudge
21
+ - write-adr — ADR format — the three-tests rubric (hard to reverse / surprising / real trade-off), the record template, and the "what qualifies" guidance
20
22
 
21
23
  ### MIT License (applies to each source listed above)
22
24
 
package/catalog/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1-alpha.1
1
+ 0.1.1-alpha.2
@@ -36,18 +36,6 @@
36
36
  "default": {},
37
37
  "type": "object",
38
38
  "properties": {
39
- "state": {
40
- "default": ".claude/state",
41
- "type": "string"
42
- },
43
- "skills": {
44
- "default": ".claude/skills",
45
- "type": "string"
46
- },
47
- "agents": {
48
- "default": ".claude/agents",
49
- "type": "string"
50
- },
51
39
  "playbooks": {
52
40
  "default": "docs/playbooks",
53
41
  "type": "string"
@@ -9,6 +9,7 @@ attribution:
9
9
  author: Matt Pocock
10
10
  url: https://github.com/mattpocock/skills
11
11
  license: MIT
12
+ copyright: Copyright (c) 2026 Matt Pocock
12
13
  relationship: derived-from
13
14
  note: grill interview engine — one question at a time, decision-by-decision interrogation
14
15
  ---
@@ -9,6 +9,7 @@ attribution:
9
9
  author: Matt Pocock
10
10
  url: https://github.com/mattpocock/skills
11
11
  license: MIT
12
+ copyright: Copyright (c) 2026 Matt Pocock
12
13
  relationship: derived-from
13
14
  note: grill workflow and decision-by-decision interview structure
14
15
  ---
@@ -5,6 +5,14 @@ origin: vendor
5
5
  vendor_version: '{{vendor_version}}'
6
6
  phase: during-implementation
7
7
  invoked-by: [implementer]
8
+ attribution:
9
+ - source: mattpocock/skills
10
+ author: Matt Pocock
11
+ url: https://github.com/mattpocock/skills
12
+ license: MIT
13
+ copyright: Copyright (c) 2026 Matt Pocock
14
+ relationship: derived-from
15
+ note: the red-green cycle, the behavior-over-implementation core principle, the vertical-slice ("tracer bullet") framing, mock-at-system-boundaries guidance, and the ADR three-tests nudge
8
16
  ---
9
17
 
10
18
  # Test-Driven Development
@@ -5,6 +5,14 @@ origin: vendor
5
5
  vendor_version: '{{vendor_version}}'
6
6
  invoked-by: [architect]
7
7
  trigger-condition: a resolved decision is worth recording (a discovery resolution, or an explicit request)
8
+ attribution:
9
+ - source: mattpocock/skills
10
+ author: Matt Pocock
11
+ url: https://github.com/mattpocock/skills
12
+ license: MIT
13
+ copyright: Copyright (c) 2026 Matt Pocock
14
+ relationship: derived-from
15
+ note: ADR format — the three-tests rubric (hard to reverse / surprising / real trade-off), the record template, and the "what qualifies" guidance
8
16
  ---
9
17
 
10
18
  # Write ADR
@@ -19,9 +19,6 @@ task_storage:
19
19
 
20
20
  # Paths (relative; defaults shown — declare only overrides).
21
21
  paths:
22
- state: .claude/state
23
- skills: .claude/skills
24
- agents: .claude/agents
25
22
  # Project-local playbooks (how-to-build patterns). Looked up by convention
26
23
  # `<topic>.md`, local then global; the local entry overrides the global one.
27
24
  # The require/suggest hooks read these two keys directly on every fire, so a
package/dist/cli.mjs CHANGED
@@ -5,7 +5,7 @@ import { delimiter, dirname, extname, join, relative, resolve, sep } from "node:
5
5
  import { argv, cwd, env, exit, stderr, stdin, stdout } from "node:process";
6
6
  import { createInterface } from "node:readline/promises";
7
7
  import { promisify } from "node:util";
8
- import { parse, parseDocument } from "yaml";
8
+ import { isMap, parse, parseDocument } from "yaml";
9
9
  import { z } from "zod";
10
10
  import { createHash, randomBytes } from "node:crypto";
11
11
  import { constants } from "node:fs";
@@ -18,6 +18,11 @@ const appendEvent = async (eventsPath, event) => {
18
18
  //#region src/config/config.constant.ts
19
19
  const HARNESS_CONFIG_FILENAME = "harness.config.yml";
20
20
  const DEPRECATED_CONFIG_KEYS = ["profile", "agents"];
21
+ const DEPRECATED_PATHS_KEYS = [
22
+ "state",
23
+ "skills",
24
+ "agents"
25
+ ];
21
26
  const HARNESS_CONFIG_SCHEMA_FILENAME = "harness.config.schema.json";
22
27
  const TASK_STORAGE_REPO_PLACEHOLDER = "OWNER/REPO";
23
28
  const TARGETS = ["claude-code"];
@@ -26,9 +31,6 @@ const TASK_STORAGE_REPO_PATTERN = /^[^\s/]+\/[^\s/]+$/;
26
31
  const VENDOR_VERSION_REGEX = /^\d+\.\d+\.\d+(-(alpha|beta|rc)\.\d+)?$/;
27
32
  const VENDOR_VERSION_EXAMPLE = "0.1.0-alpha.0";
28
33
  const PATHS_DEFAULTS = {
29
- state: ".claude/state",
30
- skills: ".claude/skills",
31
- agents: ".claude/agents",
32
34
  playbooks: "docs/playbooks",
33
35
  playbooks_global: "~/.claude/playbooks"
34
36
  };
@@ -97,9 +99,6 @@ const levenshtein = (a, b) => {
97
99
  //#endregion
98
100
  //#region src/config/config.schema.ts
99
101
  const pathsSchema = z.object({
100
- state: z.string().default(PATHS_DEFAULTS.state),
101
- skills: z.string().default(PATHS_DEFAULTS.skills),
102
- agents: z.string().default(PATHS_DEFAULTS.agents),
103
102
  playbooks: z.string().default(PATHS_DEFAULTS.playbooks),
104
103
  playbooks_global: z.string().default(PATHS_DEFAULTS.playbooks_global)
105
104
  }).strict().prefault({});
@@ -139,6 +138,12 @@ const readHarnessConfig = async (repoRoot) => {
139
138
  if (!parsed || typeof parsed !== "object") throw new Error(`${HARNESS_CONFIG_FILENAME} is empty or malformed.`);
140
139
  const candidate = { ...parsed };
141
140
  for (const key of DEPRECATED_CONFIG_KEYS) delete candidate[key];
141
+ const paths = candidate.paths;
142
+ if (paths && typeof paths === "object" && !Array.isArray(paths)) {
143
+ const pathsCandidate = { ...paths };
144
+ for (const key of DEPRECATED_PATHS_KEYS) delete pathsCandidate[key];
145
+ candidate.paths = pathsCandidate;
146
+ }
142
147
  const result = harnessConfigSchema.safeParse(candidate);
143
148
  if (!result.success) throw new Error(`${HARNESS_CONFIG_FILENAME} is invalid:\n${formatConfigError(harnessConfigSchema, result.error)}`);
144
149
  return result.data;
@@ -194,6 +199,9 @@ const setConfigValues = (rawYaml, updates) => {
194
199
  const doc = parseDocument(rawYaml);
195
200
  for (const [key, value] of Object.entries(updates)) if (doc.has(key)) doc.set(key, value);
196
201
  for (const key of DEPRECATED_CONFIG_KEYS) if (doc.has(key)) doc.delete(key);
202
+ for (const key of DEPRECATED_PATHS_KEYS) if (doc.hasIn(["paths", key])) doc.deleteIn(["paths", key]);
203
+ const pathsNode = doc.get("paths", true);
204
+ if (isMap(pathsNode) && pathsNode.items.length === 0) doc.delete("paths");
197
205
  return doc.toString();
198
206
  };
199
207
  const writeConfigValues = async (repoRoot, updates) => {
@@ -216,6 +224,19 @@ const pointerFrontmatterSchema = z.object({
216
224
  });
217
225
  Object.keys(pointerFrontmatterSchema.shape);
218
226
  //#endregion
227
+ //#region src/paths/claude-paths.constant.ts
228
+ const CLAUDE_DIR = ".claude";
229
+ const STATE_DIR = join(CLAUDE_DIR, "state");
230
+ const SKILLS_DIR = join(CLAUDE_DIR, "skills");
231
+ const AGENTS_DIR = join(CLAUDE_DIR, "agents");
232
+ const HOOKS_DIR = join(CLAUDE_DIR, "hooks");
233
+ const COMMANDS_DIR = join(CLAUDE_DIR, "commands");
234
+ const SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
235
+ const HARNESS_DIR = join(CLAUDE_DIR, ".harness");
236
+ const BASELINE_ROOT_REL = join(HARNESS_DIR, "baseline");
237
+ const SNAPSHOTS_ROOT_REL = join(HARNESS_DIR, "snapshots");
238
+ const EVENTS_RELPATH = join(STATE_DIR, "events.jsonl");
239
+ //#endregion
219
240
  //#region src/events/envelope.ts
220
241
  const buildEnvelope = (input) => {
221
242
  const ts = (input.now ?? /* @__PURE__ */ new Date()).toISOString();
@@ -389,7 +410,6 @@ const NUMERIC_FIELDS = /* @__PURE__ */ new Set([
389
410
  "review_iterations"
390
411
  ]);
391
412
  const BOOLEAN_FIELDS = /* @__PURE__ */ new Set(["auto_close"]);
392
- const EVENTS_RELPATH$1 = join(".claude", "state", "events.jsonl");
393
413
  const isEventType = (value) => EVENT_TYPES.includes(value);
394
414
  const coerceField = (key, raw) => {
395
415
  if (NUMERIC_FIELDS.has(key)) {
@@ -444,7 +464,7 @@ const runEmit = async (options) => {
444
464
  const issues = parsed.error.issues.map((issue) => ` - ${issue.path.join(".") || "(root)"}: ${issue.message}`).join("\n");
445
465
  throw new Error(`Event validation failed for type "${rawType}":\n${issues}`);
446
466
  }
447
- const eventsPath = join(repoRoot, EVENTS_RELPATH$1);
467
+ const eventsPath = join(repoRoot, EVENTS_RELPATH);
448
468
  await appendEvent(eventsPath, parsed.data);
449
469
  return {
450
470
  event: parsed.data,
@@ -2211,9 +2231,8 @@ const sanitizeLine = (raw, tier) => {
2211
2231
  };
2212
2232
  //#endregion
2213
2233
  //#region src/telemetry/telemetry.constant.ts
2214
- const EVENTS_RELPATH = join(".claude", "state", "events.jsonl");
2215
- const CURSOR_RELPATH = join(".claude", "state", "telemetry-cursor.json");
2216
- const REJECTED_RELPATH = join(".claude", "state", "telemetry-rejected.jsonl");
2234
+ const CURSOR_RELPATH = join(STATE_DIR, "telemetry-cursor.json");
2235
+ const REJECTED_RELPATH = join(STATE_DIR, "telemetry-rejected.jsonl");
2217
2236
  const PAYLOAD_CAP_BYTES = 1e6;
2218
2237
  const DEFAULT_TIMEOUT_MS = 3e3;
2219
2238
  const PRUNE_THRESHOLD_BYTES = 5e6;
@@ -2275,7 +2294,7 @@ const chunkTail = (rawTail, tier, capBytes = PAYLOAD_CAP_BYTES) => {
2275
2294
  };
2276
2295
  //#endregion
2277
2296
  //#region src/telemetry/consent.constant.ts
2278
- const CONSENT_RELPATH = join(".claude", "state", "telemetry-consent.json");
2297
+ const CONSENT_RELPATH = join(STATE_DIR, "telemetry-consent.json");
2279
2298
  const ENV_DISABLE_VALUES = [
2280
2299
  "1",
2281
2300
  "true",
@@ -2671,7 +2690,7 @@ const formatTelemetryShow = (report) => {
2671
2690
  };
2672
2691
  //#endregion
2673
2692
  //#region src/telemetry/telemetry-notice.constant.ts
2674
- const NOTICE_SENTINEL_RELPATH = join(".claude", "state", ".telemetry-notice-shown");
2693
+ const NOTICE_SENTINEL_RELPATH = join(STATE_DIR, ".telemetry-notice-shown");
2675
2694
  const NOTICE_MESSAGE = "Anonymous telemetry is ON — run `lemony telemetry disable` to opt out. See PRIVACY.md.";
2676
2695
  //#endregion
2677
2696
  //#region src/telemetry/telemetry-notice.ts
@@ -3061,7 +3080,7 @@ const checkLabels = async (deps, config) => {
3061
3080
  };
3062
3081
  const checkHooks = async (repoRoot) => {
3063
3082
  const name = "hooks";
3064
- const settingsPath = join(repoRoot, ".claude", "settings.json");
3083
+ const settingsPath = join(repoRoot, SETTINGS_FILE);
3065
3084
  let raw;
3066
3085
  try {
3067
3086
  raw = await readFile(settingsPath, "utf8");
@@ -3317,7 +3336,7 @@ const readPointer = async (repoRoot, readGitUserEmail) => {
3317
3336
  if (!email) return empty;
3318
3337
  const slug = email.split("@")[0] ?? "";
3319
3338
  if (!slug || slug.includes("/") || slug.includes("\\") || slug.includes("..")) return empty;
3320
- const pointerPath = join(repoRoot, ".claude", "state", `current-${slug}.md`);
3339
+ const pointerPath = join(repoRoot, STATE_DIR, `current-${slug}.md`);
3321
3340
  let raw;
3322
3341
  try {
3323
3342
  raw = await readFile(pointerPath, "utf8");
@@ -3450,7 +3469,6 @@ const renderTemplate = (template, vars) => template.replace(PLACEHOLDER, (_match
3450
3469
  });
3451
3470
  //#endregion
3452
3471
  //#region src/baseline/baseline.ts
3453
- const BASELINE_ROOT_REL = join(".claude", ".harness", "baseline");
3454
3472
  const STAGING_DIR$1 = ".staging";
3455
3473
  const isENOENT$1 = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
3456
3474
  const baselineRootDir = (repoRoot) => join(repoRoot, BASELINE_ROOT_REL);
@@ -3515,7 +3533,6 @@ const findBaselineVersion = async (repoRoot) => {
3515
3533
  };
3516
3534
  //#endregion
3517
3535
  //#region src/snapshot/snapshot.ts
3518
- const SNAPSHOTS_ROOT_REL = join(".claude", ".harness", "snapshots");
3519
3536
  const STAGING_DIR = ".staging";
3520
3537
  const WORKING_SUBDIR = "working";
3521
3538
  const BASELINE_SUBDIR = "baseline";
@@ -3775,12 +3792,11 @@ const lcsMatches = (base, other) => {
3775
3792
  };
3776
3793
  //#endregion
3777
3794
  //#region src/update/engine.ts
3778
- const SKILLS_PREFIX = join(".claude", "skills");
3779
3795
  const cohesionKey = (relPath) => {
3780
- const prefix = SKILLS_PREFIX + sep;
3796
+ const prefix = SKILLS_DIR + sep;
3781
3797
  if (!relPath.startsWith(prefix)) return relPath;
3782
3798
  const name = relPath.slice(prefix.length).split(sep)[0];
3783
- return name ? join(SKILLS_PREFIX, name) : relPath;
3799
+ return name ? join(SKILLS_DIR, name) : relPath;
3784
3800
  };
3785
3801
  const runEngine = async (inputs) => {
3786
3802
  const { baseline, readClient, onConflict } = inputs;
@@ -3925,23 +3941,23 @@ const materializeVendorFiles = async (ctx) => {
3925
3941
  const templateRoot = join(vendorRoot, "templates", target);
3926
3942
  const vendorVersion = vars.vendor_version ?? "";
3927
3943
  const entryProtocol = await renderFile(join(templateRoot, "agents.md.tpl"), "agents.md", vars);
3928
- const agentFiles = await Promise.all(CORE_AGENTS.map(async (role) => withAssetFrontmatter(await renderFile(join(vendorRoot, "agents", `${role}.md`), join(".claude", "agents", `${role}.md`), {
3944
+ const agentFiles = await Promise.all(CORE_AGENTS.map(async (role) => withAssetFrontmatter(await renderFile(join(vendorRoot, "agents", `${role}.md`), join(AGENTS_DIR, `${role}.md`), {
3929
3945
  SKILLS: renderRoleSkills(skills, role),
3930
3946
  vendor_version: vendorVersion
3931
3947
  }), vendorVersion)));
3932
- const fitAssessment = await copyFileEntry(join(vendorRoot, "agents", "fit-assessment.md"), join(".claude", "agents", "fit-assessment.md"));
3948
+ const fitAssessment = await copyFileEntry(join(vendorRoot, "agents", "fit-assessment.md"), join(AGENTS_DIR, "fit-assessment.md"));
3933
3949
  const skillFiles = (await Promise.all(skills.map(async (skill) => {
3934
3950
  const skillDir = join(vendorRoot, "skills", skill.name);
3935
3951
  const rels = await listFiles(skillDir);
3936
- return Promise.all(rels.map(async (rel) => withAssetFrontmatter(await copyFileEntry(join(skillDir, rel), join(".claude", "skills", skill.name, rel)), vendorVersion)));
3952
+ return Promise.all(rels.map(async (rel) => withAssetFrontmatter(await copyFileEntry(join(skillDir, rel), join(SKILLS_DIR, skill.name, rel)), vendorVersion)));
3937
3953
  }))).flat();
3938
3954
  const playbooksReadme = await renderFile(join(templateRoot, "docs", "playbooks", "README.md.tpl"), join("docs", "playbooks", "README.md"), vars);
3939
3955
  const hooksSrc = join(vendorRoot, "hooks");
3940
- const hookFiles = await Promise.all((await listFiles(hooksSrc)).filter((rel) => rel.endsWith(".sh") && !rel.includes(sep)).map((rel) => copyFileEntry(join(hooksSrc, rel), join(".claude", "hooks", rel), true)));
3956
+ const hookFiles = await Promise.all((await listFiles(hooksSrc)).filter((rel) => rel.endsWith(".sh") && !rel.includes(sep)).map((rel) => copyFileEntry(join(hooksSrc, rel), join(HOOKS_DIR, rel), true)));
3941
3957
  const hookLibSrc = join(hooksSrc, "lib");
3942
- const hookLibFiles = await pathExists(hookLibSrc) ? await Promise.all((await listFiles(hookLibSrc)).filter((rel) => rel.endsWith(".sh")).map((rel) => copyFileEntry(join(hookLibSrc, rel), join(".claude", "hooks", "lib", rel), true))) : [];
3958
+ const hookLibFiles = await pathExists(hookLibSrc) ? await Promise.all((await listFiles(hookLibSrc)).filter((rel) => rel.endsWith(".sh")).map((rel) => copyFileEntry(join(hookLibSrc, rel), join(HOOKS_DIR, "lib", rel), true))) : [];
3943
3959
  const commandsSrc = join(vendorRoot, "commands");
3944
- const commandFiles = await pathExists(commandsSrc) ? await Promise.all((await listFiles(commandsSrc)).map(async (rel) => withAssetFrontmatter(await copyFileEntry(join(commandsSrc, rel), join(".claude", "commands", rel)), vendorVersion))) : [];
3960
+ const commandFiles = await pathExists(commandsSrc) ? await Promise.all((await listFiles(commandsSrc)).map(async (rel) => withAssetFrontmatter(await copyFileEntry(join(commandsSrc, rel), join(COMMANDS_DIR, rel)), vendorVersion))) : [];
3945
3961
  const configSchema = await copyFileEntry(join(vendorRoot, HARNESS_CONFIG_SCHEMA_FILENAME), HARNESS_CONFIG_SCHEMA_FILENAME);
3946
3962
  return [
3947
3963
  entryProtocol,
@@ -4071,7 +4087,7 @@ const diffLostCommands = (existingHooks, templateHooks) => {
4071
4087
  //#endregion
4072
4088
  //#region src/install/resync.ts
4073
4089
  const resyncSpecialCased = async (repoRoot, templateRoot) => {
4074
- const { lostCommands } = await mergeSettingsHooks(join(templateRoot, ".claude", "settings.json.tpl"), join(repoRoot, ".claude", "settings.json"));
4090
+ const { lostCommands } = await mergeSettingsHooks(join(templateRoot, CLAUDE_DIR, "settings.json.tpl"), join(repoRoot, SETTINGS_FILE));
4075
4091
  return {
4076
4092
  lostHookCommands: lostCommands,
4077
4093
  gitignorePath: await appendGitignoreBlock(repoRoot)
@@ -4118,11 +4134,11 @@ const runInstall = async (options) => {
4118
4134
  });
4119
4135
  await assertNoSymlinkTraversal(repoRoot, [
4120
4136
  ...vendorFiles.map((file) => file.relPath),
4121
- join(".claude", "settings.json"),
4137
+ SETTINGS_FILE,
4122
4138
  ".gitignore",
4123
- join(".claude", "state", "history.md"),
4124
- join(".claude", "state", "sessions"),
4125
- ...COMMITTED_STATE_DIRS.map((dir) => join(".claude", "state", dir, ".gitkeep")),
4139
+ join(STATE_DIR, "history.md"),
4140
+ join(STATE_DIR, "sessions"),
4141
+ ...COMMITTED_STATE_DIRS.map((dir) => join(STATE_DIR, dir, ".gitkeep")),
4126
4142
  HARNESS_CONFIG_FILENAME
4127
4143
  ]);
4128
4144
  const readClient = async (relPath) => {
@@ -4176,9 +4192,8 @@ const runInstall = async (options) => {
4176
4192
  await writeBaseline(repoRoot, vendorVersion, vendorFiles);
4177
4193
  const claudeMdPresent = await pathExists(join(repoRoot, CLAUDE_MD_FILENAME));
4178
4194
  const devDependencyMissing = await inspectDevDependency(repoRoot) === "missing";
4179
- const stateFiles = await Promise.all([writeOut(repoRoot, join(".claude", "state", "history.md"), renderTemplate(await readFile(join(templateRoot, "state", "history.md.tpl"), "utf8"), vars)), ...COMMITTED_STATE_DIRS.map((dir) => writeOut(repoRoot, join(".claude", "state", dir, ".gitkeep"), ""))]);
4180
- await mkdir(join(repoRoot, ".claude", "state", "sessions"), { recursive: true });
4181
- const settingsRelPath = join(".claude", "settings.json");
4195
+ const stateFiles = await Promise.all([writeOut(repoRoot, join(STATE_DIR, "history.md"), renderTemplate(await readFile(join(templateRoot, "state", "history.md.tpl"), "utf8"), vars)), ...COMMITTED_STATE_DIRS.map((dir) => writeOut(repoRoot, join(STATE_DIR, dir, ".gitkeep"), ""))]);
4196
+ await mkdir(join(repoRoot, STATE_DIR, "sessions"), { recursive: true });
4182
4197
  const { lostHookCommands, gitignorePath: gitignore } = await resyncSpecialCased(repoRoot, templateRoot);
4183
4198
  const configFile = await writeOut(repoRoot, HARNESS_CONFIG_FILENAME, renderTemplate(await readFile(join(templateRoot, "harness.config.yml.tpl"), "utf8"), vars));
4184
4199
  return {
@@ -4191,7 +4206,7 @@ const runInstall = async (options) => {
4191
4206
  filesWritten: [
4192
4207
  ...vendorPaths,
4193
4208
  ...stateFiles,
4194
- settingsRelPath,
4209
+ SETTINGS_FILE,
4195
4210
  ...gitignore ? [gitignore] : [],
4196
4211
  configFile
4197
4212
  ],
@@ -4266,7 +4281,7 @@ const runReconcile = async (inputs) => {
4266
4281
  await refuseOnResidualMarkers(managedPaths, readClient);
4267
4282
  await assertNoSymlinkTraversal(repoRoot, [
4268
4283
  ...managedPaths,
4269
- join(".claude", "settings.json"),
4284
+ SETTINGS_FILE,
4270
4285
  ".gitignore"
4271
4286
  ]);
4272
4287
  const actions = await runEngine({
@@ -4407,8 +4422,6 @@ const runRepair = async (options) => {
4407
4422
  };
4408
4423
  //#endregion
4409
4424
  //#region src/uninstall/uninstall.ts
4410
- const HARNESS_DIR = join(".claude", ".harness");
4411
- const SETTINGS_RELPATH = join(".claude", "settings.json");
4412
4425
  const DOCS_PREFIX = `docs${sep}`;
4413
4426
  const runUninstall = async (options) => {
4414
4427
  const { repoRoot } = options;
@@ -4419,14 +4432,14 @@ const runUninstall = async (options) => {
4419
4432
  const removedFiles = [...(await readBaseline(repoRoot, baselineVersion)).keys()].filter((relPath) => !relPath.startsWith(DOCS_PREFIX)).toSorted();
4420
4433
  await assertNoSymlinkTraversal(repoRoot, [
4421
4434
  ...removedFiles,
4422
- SETTINGS_RELPATH,
4435
+ SETTINGS_FILE,
4423
4436
  ".gitignore",
4424
4437
  HARNESS_DIR,
4425
4438
  HARNESS_CONFIG_FILENAME
4426
4439
  ]);
4427
4440
  await Promise.all(removedFiles.map((relPath) => rm(join(repoRoot, relPath), { force: true })));
4428
4441
  await pruneEmptyDirs(repoRoot, removedFiles);
4429
- const settings = await removeSettingsHooks(join(repoRoot, SETTINGS_RELPATH));
4442
+ const settings = await removeSettingsHooks(join(repoRoot, SETTINGS_FILE));
4430
4443
  const gitignoreStripped = await removeGitignoreBlock(repoRoot) !== null;
4431
4444
  await rm(join(repoRoot, HARNESS_DIR), {
4432
4445
  recursive: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lemoncode/lemony",
3
- "version": "0.1.1-alpha.1",
3
+ "version": "0.1.1-alpha.2",
4
4
  "description": "Lemony — a Harness for AI Coding. Vendor package: installer, agent role catalog, generic skill catalog, hooks, and templates for a Spec-Driven Development workflow.",
5
5
  "type": "module",
6
6
  "private": false,