pi-cicd 1.0.13 → 1.0.14

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/config.ts +30 -27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cicd",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Extension for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/src/config.ts CHANGED
@@ -51,6 +51,29 @@ const DEFAULT_CONFIG: PiCiConfig = {
51
51
  },
52
52
  };
53
53
 
54
+ /** Recursively merge `override` into `base`, handling nested objects.
55
+ * Does not mutate either argument.
56
+ */
57
+ function deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown> {
58
+ const result: Record<string, unknown> = { ...base };
59
+ for (const key of Object.keys(override)) {
60
+ const bv = base[key];
61
+ const ov = override[key];
62
+ if (
63
+ bv !== undefined && ov !== undefined &&
64
+ typeof bv === "object" && !Array.isArray(bv) &&
65
+ typeof ov === "object" && !Array.isArray(ov)
66
+ ) {
67
+ result[key] = deepMerge(bv as Record<string, unknown>, ov as Record<string, unknown>);
68
+ } else {
69
+ result[key] = ov;
70
+ }
71
+ }
72
+ return result;
73
+ }
74
+
75
+ export { deepMerge };
76
+
54
77
  /**
55
78
  * Load pi-ci configuration from `.pi/pi-ci.json` (if present) merged with defaults.
56
79
  */
@@ -62,38 +85,18 @@ export async function loadCiConfig(cwd?: string): Promise<PiCiConfig> {
62
85
  try {
63
86
  text = await readFile(configPath, "utf-8");
64
87
  } catch {
65
- return { ...DEFAULT_CONFIG };
88
+ return structuredClone(DEFAULT_CONFIG) as PiCiConfig;
66
89
  }
67
90
 
68
91
  const raw: unknown = JSON.parse(text);
69
92
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
70
- return { ...DEFAULT_CONFIG };
93
+ return structuredClone(DEFAULT_CONFIG) as PiCiConfig;
71
94
  }
72
95
 
73
- const user = raw as Record<string, unknown>;
74
- return {
75
- enabled: typeof user.enabled === "boolean" ? user.enabled : DEFAULT_CONFIG.enabled,
76
- idleTimeoutMs:
77
- typeof user.idleTimeoutMs === "number" ? user.idleTimeoutMs : DEFAULT_CONFIG.idleTimeoutMs,
78
- maxRetries:
79
- typeof user.maxRetries === "number" ? user.maxRetries : DEFAULT_CONFIG.maxRetries,
80
- retryBackoffMaxMs:
81
- typeof user.retryBackoffMaxMs === "number"
82
- ? user.retryBackoffMaxMs
83
- : DEFAULT_CONFIG.retryBackoffMaxMs,
84
- exitCodes: {
85
- ...DEFAULT_CONFIG.exitCodes,
86
- ...(typeof user.exitCodes === "object" && user.exitCodes !== null
87
- ? (user.exitCodes as Partial<PiCiExitCodeConfig>)
88
- : {}),
89
- },
90
- report: {
91
- ...DEFAULT_CONFIG.report,
92
- ...(typeof user.report === "object" && user.report !== null
93
- ? (user.report as Partial<PiCiReportConfig>)
94
- : {}),
95
- },
96
- };
96
+ return deepMerge(
97
+ structuredClone(DEFAULT_CONFIG) as unknown as Record<string, unknown>,
98
+ raw as Record<string, unknown>,
99
+ ) as PiCiConfig;
97
100
  }
98
101
 
99
- export { DEFAULT_CONFIG };
102
+ export { DEFAULT_CONFIG };