@programinglive/dev-workflow-mcp-server 1.13.8 → 1.13.9

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/workflow-state.js +43 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/dev-workflow-mcp-server",
3
- "version": "1.13.8",
3
+ "version": "1.13.9",
4
4
  "description": "MCP server to enforce development workflow discipline",
5
5
  "homepage": "https://devworkflow.programinglive.com/",
6
6
  "mcpName": "io.github.programinglive/dev-workflow-mcp-server",
package/workflow-state.js CHANGED
@@ -223,18 +223,55 @@ function getUserScopedDir(baseDir) {
223
223
  return path.join(baseDir, "users", userId);
224
224
  }
225
225
 
226
- function getCurrentUserId() {
226
+ /**
227
+ * Identitas user untuk baris database milik state ini.
228
+ *
229
+ * MENGAPA TIDAK MEMBACA CACHE MODUL
230
+ * ---------------------------------
231
+ * Versi sebelumnya hanya memakai `cachedUserId`, yang terisi lewat
232
+ * `resolveUserId()` - dan itu hanya dipanggil dari `resolveStateFile()`.
233
+ * Pemanggil yang membuat `WorkflowState` dengan path EKSPLISIT (skrip
234
+ * perbaikan, CLI, tes) tidak pernah memicunya, sehingga `syncToDatabase()`
235
+ * diam-diam menulis baris dengan `user_id = "default"`.
236
+ *
237
+ * Akibat nyata 30 Oktober 2026: satu proyek punya riwayat di dua identitas
238
+ * (`user-…` dan `default`) dalam database yang sama, dan 150 baris duplikat
239
+ * harus dibersihkan manual.
240
+ *
241
+ * Membaca langsung dari direktori `.state` milik state ini membuat hasilnya
242
+ * tidak bergantung pada direktori kerja proses, tidak bergantung pada urutan
243
+ * pemanggilan, dan tidak bocor antar proyek dalam satu proses.
244
+ */
245
+ function getCurrentUserId(stateFile = null) {
227
246
  const envUserId = (process.env.DEV_WORKFLOW_USER_ID || "").trim();
228
247
  if (envUserId) {
229
248
  return envUserId;
230
249
  }
231
250
 
232
- if (cachedUserId) {
233
- return cachedUserId;
251
+ if (stateFile) {
252
+ const stateDir = path.dirname(path.resolve(stateFile));
253
+ const userIdFile = path.join(stateDir, USER_ID_FILENAME);
254
+
255
+ try {
256
+ const stored = readFileSync(userIdFile, "utf-8").trim();
257
+ if (stored) {
258
+ return stored;
259
+ }
260
+ } catch {
261
+ // Berkas belum ada: jatuh ke pencarian di bawah.
262
+ }
263
+
264
+ // .state langsung (bukan .state/users/<id>): pakai resolveUserId, yang
265
+ // menangani migrasi id lama maupun pembuatan id baru.
266
+ try {
267
+ return resolveUserId(stateDir);
268
+ } catch {
269
+ // Biarkan jatuh ke nilai cadangan di bawah.
270
+ }
234
271
  }
235
272
 
236
- if (cachedUserStateDir) {
237
- return resolveUserId(cachedUserStateDir);
273
+ if (cachedUserId) {
274
+ return cachedUserId;
238
275
  }
239
276
 
240
277
  return "default";
@@ -1014,7 +1051,7 @@ export class WorkflowState {
1014
1051
  async syncToDatabase(options = {}) {
1015
1052
  assertSafeKnowledge(this.state);
1016
1053
  const db = options.db ?? (await import("./db/index.js"));
1017
- const userId = getCurrentUserId();
1054
+ const userId = getCurrentUserId(this.stateFile);
1018
1055
  // projectRoot dipakai sebagai identitas proyek di database. Ditentukan
1019
1056
  // lewat resolveProjectRootForState, bukan dengan menghitung `dirname`
1020
1057
  // berkali-kali: jumlah itu hanya benar untuk satu kedalaman tertentu.