engineering-loop 1.0.1 → 1.0.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.
@@ -1,7 +1,15 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { readFile } from "node:fs/promises";
3
- import { join } from "node:path";
3
+ import { isAbsolute, join, relative, resolve } from "node:path";
4
4
  import { validateConfig } from "../schema.js";
5
+ // engineering-loop.json is often a file the current user didn't author
6
+ // themselves (e.g. `doctor` run against a cloned project). memory.directory
7
+ // and memory.required_files come straight from it, so a crafted "../../"
8
+ // entry must not let a filesystem existence check escape the project dir.
9
+ function isInside(parentDir, candidate) {
10
+ const rel = relative(resolve(parentDir), resolve(candidate));
11
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
12
+ }
5
13
  export async function runDoctor(dir) {
6
14
  const checks = [];
7
15
  const configPath = join(dir, "engineering-loop.json");
@@ -38,11 +46,28 @@ export async function runDoctor(dir) {
38
46
  if (valid) {
39
47
  const config = parsed;
40
48
  const memoryDir = join(dir, config.memory.directory);
49
+ if (!isInside(dir, memoryDir)) {
50
+ checks.push({
51
+ name: "memory.directory stays inside the project",
52
+ passed: false,
53
+ detail: `"${config.memory.directory}" resolves outside ${dir}`,
54
+ });
55
+ return { ok: false, checks };
56
+ }
41
57
  for (const file of config.memory.required_files) {
42
58
  const filePath = join(memoryDir, file);
59
+ const label = `memory file present: ${config.memory.directory}/${file}`;
60
+ if (!isInside(memoryDir, filePath)) {
61
+ checks.push({
62
+ name: label,
63
+ passed: false,
64
+ detail: `"${file}" resolves outside ${memoryDir}`,
65
+ });
66
+ continue;
67
+ }
43
68
  const exists = existsSync(filePath);
44
69
  checks.push({
45
- name: `memory file present: ${config.memory.directory}/${file}`,
70
+ name: label,
46
71
  passed: exists,
47
72
  detail: exists ? undefined : `missing at ${filePath}`,
48
73
  });
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAc9C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;IAEtD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,8BAA8B;YACpC,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,gBAAgB,UAAU,EAAE;SACrC,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpE,IAAI,GAAW,CAAC;IAChB,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,qCAAqC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,qCAAqC;YAC3C,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC/D,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,0CAA0C;QAChD,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;KAC9C,CAAC,CAAC;IAEH,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,MAAM,GAAG,MAA+B,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YACvC,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,wBAAwB,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE;gBAC/D,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,QAAQ,EAAE;aACtD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engineering-loop",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "CLI for the Engineering Loop Standard: scaffold engineering-loop.json, persistent project memory, and multi-tool AI agent adapters.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,7 +33,7 @@
33
33
  "@types/node": "^20.14.0",
34
34
  "tsx": "^4.16.0",
35
35
  "typescript": "^5.5.0",
36
- "vitest": "^1.6.0"
36
+ "vitest": "^4.1.10"
37
37
  },
38
38
  "keywords": [
39
39
  "engineering-loop",