workq-mcp 0.1.8 → 0.1.10

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/lib/natural-git.mjs +292 -19
  2. package/package.json +1 -1
@@ -1073,7 +1073,236 @@ function regionsForRoute(file, route) {
1073
1073
  return genericRouteRegions(file);
1074
1074
  }
1075
1075
 
1076
- function screenReadmeDoc(file, route, regions) {
1076
+ const INTERNAL_FEATURE_DEFINITIONS = [
1077
+ {
1078
+ slug: "repository-natural-analysis",
1079
+ title: "레포 코드 자연어 분석 백엔드",
1080
+ purpose: "사용자가 연결한 코드 레포를 읽고 URL 화면, 화면 영역, 검증 근거 중심의 natural-spec repo 초안을 만든다.",
1081
+ match: [/repo-natural-spec/i, /generateNaturalSpecFromRepository/i, /generateNaturalGitDocs/i, /workq_import_natural_git_specs/i],
1082
+ used_by_routes: ["/v2"],
1083
+ related_regions: ["project-repo-registration", "natural-spec-repo"],
1084
+ triggers: ["사용자가 레포 코드 자연어 분석을 요청한다.", "로컬 MCP CLI가 `workq natural-git` 업로드를 실행한다."],
1085
+ outcomes: ["화면/영역 중심 Markdown 명세가 생성된다.", "코드 파일별 상세 구현은 `_evidence`로 분리된다."],
1086
+ failure_impact: ["새 프로젝트의 초기 기능명세가 비어 있거나 코드 중심 문서로 잘못 보일 수 있다."],
1087
+ verification: ["생성 결과에 `natural-git/screens/` 문서와 `_evidence` 문서가 함께 존재하는지 확인한다."]
1088
+ },
1089
+ {
1090
+ slug: "natural-spec-repo-sync",
1091
+ title: "자연어 git 저장소 동기화 백엔드",
1092
+ purpose: "웹에서 편집한 자연어 명세 draft, commit, merge 상태를 natural-spec repo 기준 상태와 맞춘다.",
1093
+ match: [/spec-git/i, /natural-spec-repo/i, /stageNaturalSpecDocs/i, /commitNaturalSpec/i, /readNaturalSpecDocs/i],
1094
+ used_by_routes: ["/v2"],
1095
+ related_regions: ["natural-spec-repo", "natural-spec-editor", "commit-merge-agent-queue"],
1096
+ triggers: ["사용자가 자연어 명세를 저장한다.", "사용자가 자연어 커밋, 머지, 롤백을 실행한다."],
1097
+ outcomes: ["draft와 HEAD commit 상태가 구분된다.", "승인된 자연어 커밋만 Agent 큐 기준이 된다."],
1098
+ failure_impact: ["화면에 보이는 명세와 Agent가 기준으로 읽는 명세가 달라질 수 있다."],
1099
+ verification: ["draft 저장, commit, merge 이후 같은 프로젝트의 문서 상태와 commit id가 유지되는지 확인한다."]
1100
+ },
1101
+ {
1102
+ slug: "report-triage-and-classification",
1103
+ title: "리포트 판단 · 분류 백엔드",
1104
+ purpose: "사용자가 올린 버그, 개선, 기획문의, 개발문의를 승인된 자연어 명세와 비교해 bug, 기획부재, 충돌, 결정 필요로 구분한다.",
1105
+ match: [/triage/i, /classification/i, /classify/i, /analyze-report/i, /mini.ai/i, /report/i],
1106
+ used_by_routes: ["/", "/v2"],
1107
+ related_regions: ["report-intake", "triage-and-spec-map", "decision-needed-mcp"],
1108
+ triggers: ["사용자가 리포트를 제출한다.", "사용자가 기존 리포트를 다시 분석한다."],
1109
+ outcomes: ["판단 결과와 근거 명세가 사용자에게 표시된다.", "승인이 필요한 항목은 자동 개발 큐로 넘어가지 않는다."],
1110
+ failure_impact: ["버그가 아닌 기획부재를 버그로 고치거나, 실제 버그를 문의로 놓칠 수 있다."],
1111
+ verification: ["명세가 있는 동작 차이는 bug 후보로, 명세가 없는 기대 동작은 기획부재/결정 필요로 표시되는지 확인한다."]
1112
+ },
1113
+ {
1114
+ slug: "desktop-agent-mcp-queue",
1115
+ title: "데스크톱 Agent MCP 큐 백엔드",
1116
+ purpose: "승인된 자연어 커밋이나 결정 사항을 로컬 Codex/Claude가 가져갈 작업 패킷으로 만들고 완료 결과를 다시 받는다.",
1117
+ match: [/workq_list_tasks/i, /workq_get_work_packet/i, /workq_finish_task/i, /agent_task/i, /queued_for_agent/i, /MCP/i],
1118
+ used_by_routes: ["/", "/v2"],
1119
+ related_regions: ["agent-queue-and-mcp", "decision-needed-mcp", "existing-workq-queue", "commit-merge-agent-queue"],
1120
+ triggers: ["사용자가 승인된 작업을 Agent 큐로 보낸다.", "로컬 Agent가 MCP로 다음 작업을 조회한다.", "로컬 Agent가 완료 결과를 제출한다."],
1121
+ outcomes: ["작업 패킷에 프로젝트, 레포, 명세 근거, 완료 절차가 포함된다.", "완료 시 검증 결과와 명세 변경 근거가 Work Q에 남는다."],
1122
+ failure_impact: ["로컬 Agent가 잘못된 프로젝트를 고치거나, 완료 작업이 큐에 남을 수 있다."],
1123
+ verification: ["MCP 작업 조회, work packet 수신, finish task 호출 후 큐 상태가 완료로 바뀌는지 확인한다."]
1124
+ },
1125
+ {
1126
+ slug: "project-context-binding",
1127
+ title: "프로젝트 · 로컬 레포 바인딩 백엔드",
1128
+ purpose: "웹의 프로젝트 키와 로컬 데스크톱의 실제 git 레포 정보를 대조해 엉뚱한 레포를 고치지 않도록 한다.",
1129
+ match: [/connect_local_project/i, /local.*project/i, /repository_owner/i, /local_path/i, /git remote/i, /project_key/i],
1130
+ used_by_routes: ["/", "/v2"],
1131
+ related_regions: ["project-context", "project-repo-registration", "project-status-summary"],
1132
+ triggers: ["사용자가 프로젝트를 등록한다.", "로컬 MCP가 현재 git root, remote, branch를 Work Q에 연결한다."],
1133
+ outcomes: ["프로젝트 키, repo owner/name, local path, branch가 같은 대상인지 확인된다."],
1134
+ failure_impact: ["여러 프로젝트를 사용할 때 다른 레포의 리포트나 작업을 처리할 수 있다."],
1135
+ verification: ["웹 프로젝트 정보와 MCP가 제출한 git root, remote, branch가 일치하지 않으면 연결 미검증 상태가 되는지 확인한다."]
1136
+ }
1137
+ ];
1138
+
1139
+ function isUserFacingNavigationFile(file) {
1140
+ if (isTestFile(file) || isApiOrServerFile(file) || isCliEntryFile(file)) return false;
1141
+ return [".tsx", ".jsx", ".html", ".ts", ".js"].includes(file.extension);
1142
+ }
1143
+
1144
+ function routeLiteralForSearch(route) {
1145
+ return route.url_pattern.replace(/\[(.+?)\]/g, "");
1146
+ }
1147
+
1148
+ function hasVisibleNavigationToRoute(route, routeFile, sourceFiles) {
1149
+ if (route.url_pattern === "/" || route.url_pattern === "<product-overview>") return true;
1150
+ const literal = routeLiteralForSearch(route);
1151
+ if (!literal || literal === "/") return true;
1152
+ const escaped = literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1153
+ const navigationPatterns = [
1154
+ new RegExp(`href\\s*=\\s*[{]?["'\`]${escaped}["'\`]`, "i"),
1155
+ new RegExp(`router\\.push\\(\\s*["'\`]${escaped}`, "i"),
1156
+ new RegExp(`navigate\\(\\s*["'\`]${escaped}`, "i"),
1157
+ new RegExp(`location\\.href\\s*=\\s*["'\`]${escaped}`, "i")
1158
+ ];
1159
+ return sourceFiles.some((file) => {
1160
+ if (file.path === routeFile.path || !isUserFacingNavigationFile(file)) return false;
1161
+ return navigationPatterns.some((pattern) => pattern.test(file.content));
1162
+ });
1163
+ }
1164
+
1165
+ function routeEntriesForSourceFiles(sourceFiles) {
1166
+ return sourceFiles.flatMap((file) => {
1167
+ const route = routeInfoForFile(file);
1168
+ if (!route) return [];
1169
+ const regions = regionsForRoute(file, route);
1170
+ return [
1171
+ {
1172
+ file,
1173
+ route,
1174
+ regions,
1175
+ entryless: !hasVisibleNavigationToRoute(route, file, sourceFiles)
1176
+ }
1177
+ ];
1178
+ });
1179
+ }
1180
+
1181
+ function matchingInternalSourcePaths(sourceFiles, definition) {
1182
+ return unique(
1183
+ sourceFiles
1184
+ .filter((file) => !isTestFile(file))
1185
+ .filter((file) => {
1186
+ const haystack = `${file.path}\n${file.content}`;
1187
+ return definition.match.some((pattern) => pattern.test(haystack));
1188
+ })
1189
+ .map((file) => file.path),
1190
+ 10
1191
+ );
1192
+ }
1193
+
1194
+ function detectInternalFeatures(sourceFiles, entries) {
1195
+ const availableRoutes = new Set(entries.map((entry) => entry.route.url_pattern));
1196
+ const fallbackRoute = entries[0]?.route.url_pattern;
1197
+ return INTERNAL_FEATURE_DEFINITIONS.flatMap((definition) => {
1198
+ const sourcePaths = matchingInternalSourcePaths(sourceFiles, definition);
1199
+ if (!sourcePaths.length) return [];
1200
+ const usedByRoutes = definition.used_by_routes.filter((route) => availableRoutes.has(route));
1201
+ const resolvedRoutes = usedByRoutes.length ? usedByRoutes : fallbackRoute ? [fallbackRoute] : [];
1202
+ return [
1203
+ {
1204
+ slug: definition.slug,
1205
+ title: definition.title,
1206
+ purpose: definition.purpose,
1207
+ used_by_routes: resolvedRoutes,
1208
+ related_regions: definition.related_regions,
1209
+ triggers: definition.triggers,
1210
+ outcomes: definition.outcomes,
1211
+ failure_impact: definition.failure_impact,
1212
+ verification: definition.verification,
1213
+ source_paths: sourcePaths,
1214
+ shared: resolvedRoutes.length > 1
1215
+ }
1216
+ ];
1217
+ });
1218
+ }
1219
+
1220
+ function internalFeaturesForRoute(features, route) {
1221
+ return features.filter((feature) => feature.used_by_routes.includes(route.url_pattern));
1222
+ }
1223
+
1224
+ function internalFeaturesForRegion(features, region) {
1225
+ return features.filter((feature) => feature.related_regions.includes(region.slug));
1226
+ }
1227
+
1228
+ function internalFeatureDocPath(feature, entries) {
1229
+ return `natural-git/backend/${feature.slug}/README.md`;
1230
+ }
1231
+
1232
+ function internalFeatureDoc(feature, entries) {
1233
+ return {
1234
+ path: internalFeatureDocPath(feature, entries),
1235
+ title: feature.title,
1236
+ content: [
1237
+ `# ${feature.title}`,
1238
+ NATURAL_SPEC_FORMAT_COMMENT,
1239
+ "",
1240
+ "## 성격",
1241
+ "이 문서는 화면에 직접 보이는 버튼이나 카드가 아니라, 화면 기능의 결과를 만드는 백엔드 기능의 원본 명세다.",
1242
+ "",
1243
+ "## 목적",
1244
+ feature.purpose,
1245
+ "",
1246
+ "## 사용 화면",
1247
+ ...feature.used_by_routes.map((route) => {
1248
+ const entry = entries.find((item) => item.route.url_pattern === route);
1249
+ return `- ${route}: ${entry ? `${entry.route.directory}/README.md` : "연결된 화면 명세"}`;
1250
+ }),
1251
+ "",
1252
+ "## 연결된 화면 영역",
1253
+ ...feature.related_regions.map((region) => `- ${region}`),
1254
+ "",
1255
+ "## 트리거",
1256
+ ...feature.triggers.map((item) => `- ${item}`),
1257
+ "",
1258
+ "## 결과",
1259
+ ...feature.outcomes.map((item) => `- ${item}`),
1260
+ "",
1261
+ "## 실패 시 사용자 영향",
1262
+ ...feature.failure_impact.map((item) => `- ${item}`),
1263
+ "",
1264
+ "## 검증 방법",
1265
+ ...feature.verification.map((item) => `- ${item}`),
1266
+ "",
1267
+ "## 화면 표시 원칙",
1268
+ "- 화면/영역 명세에는 이 문서의 전체 내용을 복사하지 않고 참조 링크만 둔다.",
1269
+ "- Work Q UI에서는 관련 백엔드 기능 칩을 눌렀을 때 현재 문서 아래에 이 명세를 인라인으로 펼쳐 보여준다.",
1270
+ "- 사용자가 보는 결과와 무관한 일반 라이브러리 이름은 기능명세가 아니라 구현 근거로만 취급한다.",
1271
+ "",
1272
+ "## 구현 근거",
1273
+ ...feature.source_paths.map((sourcePath) => `- ${sourceEvidencePath({ path: sourcePath })}`)
1274
+ ].join("\n")
1275
+ };
1276
+ }
1277
+
1278
+ function entrylessScreenDoc(entry) {
1279
+ const slug = slugSegment(entry.route.url_pattern.replace(/^\//, "") || "root");
1280
+ return {
1281
+ path: `natural-git/entryless-screens/${slug}.md`,
1282
+ title: `진입점 없는 화면: ${entry.route.url_pattern}`,
1283
+ content: [
1284
+ `# 진입점 없는 화면: ${entry.route.url_pattern}`,
1285
+ NATURAL_SPEC_FORMAT_COMMENT,
1286
+ "",
1287
+ "## 의미",
1288
+ "이 URL은 화면 파일과 기능명세가 있지만, 다른 사용자 화면에서 명확한 버튼이나 링크 진입점을 발견하지 못했다.",
1289
+ "",
1290
+ "## 기준 화면 명세",
1291
+ `- ${entry.route.directory}/README.md`,
1292
+ "",
1293
+ "## 운영 원칙",
1294
+ "- 직접 URL, 관리자 전용, 실험용, MCP/Agent 전용 화면일 수 있다.",
1295
+ "- 사용자가 일반 화면에서 접근해야 하는 기능이면 별도 메뉴, 버튼, 링크를 추가해야 한다.",
1296
+ "- 진입점이 없는 상태 자체가 제품 의도인지 오너가 확인해야 한다.",
1297
+ "",
1298
+ "## 검증 방법",
1299
+ "- 이 화면으로 이동하는 실제 사용자 진입점이 있는지 확인한다.",
1300
+ "- 진입점이 의도적으로 없다면 이유를 이 문서 또는 화면 README에 기록한다."
1301
+ ].join("\n")
1302
+ };
1303
+ }
1304
+
1305
+ function screenReadmeDoc(file, route, regions, internals, entries) {
1077
1306
  const isWorkQDashboard = isWorkQDashboardPage(file);
1078
1307
  const isWorkQV2 = route.url_pattern === "/v2" && file.path === "src/app/v2/page.tsx";
1079
1308
  const title = isWorkQDashboard ? "Work Q 대시보드 화면 명세" : isWorkQV2 ? "Work Q v2 대시보드 화면 명세" : route.title;
@@ -1098,9 +1327,15 @@ function screenReadmeDoc(file, route, regions) {
1098
1327
  "## 화면 영역",
1099
1328
  ...regions.map((region) => `- ${region.title}: ${region.purpose}`),
1100
1329
  "",
1330
+ "## 관련 백엔드 기능",
1331
+ ...(internals.length
1332
+ ? internals.map((feature) => `- ${feature.title}: ${feature.purpose} (${internalFeatureDocPath(feature, entries)})`)
1333
+ : ["- 이 화면에 연결된 백엔드 기능이 아직 발견되지 않았다."]),
1334
+ "",
1101
1335
  "## 핵심 원칙",
1102
1336
  "- URL 패턴을 최상위 화면 명세로 삼는다.",
1103
1337
  "- 화면 안의 사용자 인식 영역을 region 명세로 나눈다.",
1338
+ "- 화면에 보이지 않지만 이 화면 기능의 결과를 만드는 백엔드 동작은 `natural-git/backend/` 원본 명세로 연결한다.",
1104
1339
  "- 코드 파일 경로는 사용자 기능명세 제목으로 쓰지 않고 evidence로 분리한다.",
1105
1340
  "- 페이지네이션, 게시물 번호, 상세 id처럼 값만 바뀌는 URL은 하나의 URL 패턴으로 추상화한다.",
1106
1341
  "",
@@ -1110,7 +1345,7 @@ function screenReadmeDoc(file, route, regions) {
1110
1345
  };
1111
1346
  }
1112
1347
 
1113
- function screenRulesDoc(route, regions) {
1348
+ function screenRulesDoc(route, regions, internals) {
1114
1349
  return {
1115
1350
  path: `${route.directory}/rules.md`,
1116
1351
  title: `${route.url_pattern} 화면 규칙`,
@@ -1125,12 +1360,23 @@ function screenRulesDoc(route, regions) {
1125
1360
  "- 코드에서 관찰된 구현만으로 제품 의도를 단정하지 않는다.",
1126
1361
  "",
1127
1362
  "## 영역별 핵심 규칙",
1128
- ...regions.flatMap((region) => [`### ${region.title}`, ...region.rules.map((rule) => `- ${rule}`), ""])
1363
+ ...regions.flatMap((region) => [`### ${region.title}`, ...region.rules.map((rule) => `- ${rule}`), ""]),
1364
+ ...(internals.length
1365
+ ? [
1366
+ "## 관련 백엔드 기능 판단 기준",
1367
+ ...internals.flatMap((feature) => [
1368
+ `### ${feature.title}`,
1369
+ `- 이 백엔드 기능은 ${feature.used_by_routes.join(", ")} 화면의 기능을 지원한다.`,
1370
+ ...feature.failure_impact.map((item) => `- 실패 영향: ${item}`),
1371
+ ""
1372
+ ])
1373
+ ]
1374
+ : [])
1129
1375
  ].join("\n")
1130
1376
  };
1131
1377
  }
1132
1378
 
1133
- function screenVerificationDoc(route, regions) {
1379
+ function screenVerificationDoc(route, regions, internals) {
1134
1380
  return {
1135
1381
  path: `${route.directory}/verification.md`,
1136
1382
  title: `${route.url_pattern} 화면 검증`,
@@ -1144,12 +1390,19 @@ function screenVerificationDoc(route, regions) {
1144
1390
  "- Agent 완료 전에는 관련 영역의 verification 항목을 확인하고 Work Q 완료 기록에 남긴다.",
1145
1391
  "",
1146
1392
  "## 영역별 검증",
1147
- ...regions.flatMap((region) => [`### ${region.title}`, ...region.verification.map((item) => `- ${item}`), ""])
1393
+ ...regions.flatMap((region) => [`### ${region.title}`, ...region.verification.map((item) => `- ${item}`), ""]),
1394
+ ...(internals.length
1395
+ ? [
1396
+ "## 관련 백엔드 기능 검증",
1397
+ ...internals.flatMap((feature) => [`### ${feature.title}`, ...feature.verification.map((item) => `- ${item}`), ""])
1398
+ ]
1399
+ : [])
1148
1400
  ].join("\n")
1149
1401
  };
1150
1402
  }
1151
1403
 
1152
- function regionDoc(route, region) {
1404
+ function regionDoc(route, region, internals, entries) {
1405
+ const relatedInternals = internalFeaturesForRegion(internals, region);
1153
1406
  return {
1154
1407
  path: `${route.directory}/regions/${region.slug}.md`,
1155
1408
  title: region.title,
@@ -1169,6 +1422,13 @@ function regionDoc(route, region) {
1169
1422
  "## 핵심 규칙",
1170
1423
  ...region.rules.map((item) => `- ${item}`),
1171
1424
  "",
1425
+ ...(relatedInternals.length
1426
+ ? [
1427
+ "## 관련 백엔드 기능",
1428
+ ...relatedInternals.map((feature) => `- ${feature.title}: ${internalFeatureDocPath(feature, entries)}`),
1429
+ ""
1430
+ ]
1431
+ : []),
1172
1432
  "## 검증 방법",
1173
1433
  ...region.verification.map((item) => `- ${item}`)
1174
1434
  ].join("\n")
@@ -1230,25 +1490,32 @@ function fallbackRegions(sourceFiles) {
1230
1490
  }
1231
1491
 
1232
1492
  function routeScreenDocs(sourceFiles) {
1233
- const docs = sourceFiles.flatMap((file) => {
1234
- const route = routeInfoForFile(file);
1235
- if (!route) return [];
1236
- const regions = regionsForRoute(file, route);
1493
+ const entries = routeEntriesForSourceFiles(sourceFiles);
1494
+ const detectedInternals = detectInternalFeatures(sourceFiles, entries);
1495
+ const docs = entries.flatMap((entry) => {
1496
+ const internals = internalFeaturesForRoute(detectedInternals, entry.route);
1237
1497
  return [
1238
- screenReadmeDoc(file, route, regions),
1239
- screenRulesDoc(route, regions),
1240
- screenVerificationDoc(route, regions),
1241
- ...regions.map((region) => regionDoc(route, region))
1498
+ screenReadmeDoc(entry.file, entry.route, entry.regions, internals, entries),
1499
+ screenRulesDoc(entry.route, entry.regions, internals),
1500
+ screenVerificationDoc(entry.route, entry.regions, internals),
1501
+ ...entry.regions.map((region) => regionDoc(entry.route, region, internals, entries))
1242
1502
  ];
1243
1503
  });
1244
- if (docs.length || !sourceFiles.length) return docs;
1504
+ if (docs.length || !sourceFiles.length) {
1505
+ return [...docs, ...detectedInternals.map((feature) => internalFeatureDoc(feature, entries)), ...entries.filter((entry) => entry.entryless).map((entry) => entrylessScreenDoc(entry))];
1506
+ }
1245
1507
  const route = fallbackRouteInfo();
1246
1508
  const regions = fallbackRegions(sourceFiles);
1509
+ const fallbackEntry = { file: sourceFiles[0], route, regions, entryless: false };
1510
+ const entriesWithFallback = [fallbackEntry];
1511
+ const internals = detectInternalFeatures(sourceFiles, entriesWithFallback);
1512
+ const routeInternals = internalFeaturesForRoute(internals, route);
1247
1513
  return [
1248
- screenReadmeDoc(sourceFiles[0], route, regions),
1249
- screenRulesDoc(route, regions),
1250
- screenVerificationDoc(route, regions),
1251
- ...regions.map((region) => regionDoc(route, region))
1514
+ screenReadmeDoc(sourceFiles[0], route, regions, routeInternals, entriesWithFallback),
1515
+ screenRulesDoc(route, regions, routeInternals),
1516
+ screenVerificationDoc(route, regions, routeInternals),
1517
+ ...regions.map((region) => regionDoc(route, region, routeInternals, entriesWithFallback)),
1518
+ ...internals.map((feature) => internalFeatureDoc(feature, entriesWithFallback))
1252
1519
  ];
1253
1520
  }
1254
1521
 
@@ -1277,11 +1544,17 @@ function overviewDoc({ projectKey, projectName, repository, root, sourceFiles })
1277
1544
  "- `natural-git/screens/<url>/regions/`: 화면 안의 사용자 인식 영역 명세",
1278
1545
  "- `natural-git/screens/<url>/components/`: 여러 화면에서 재사용되는 컴포넌트 명세",
1279
1546
  "- `natural-git/screens/<url>/dialogs/`: 모달, 팝업, 드로어 상태 명세",
1547
+ "- `natural-git/backend/`: 화면 기능의 결과를 만드는 백엔드 기능 원본 명세",
1548
+ "- `natural-git/entryless-screens/`: 화면은 있지만 메뉴나 버튼 진입점이 명확하지 않은 URL 명세",
1280
1549
  "- `natural-git/verification/`: 기능이 실제로 동작하는지 확인하는 검증 시나리오 명세",
1281
1550
  "- `natural-git/_evidence/`: 코드 파일, 설정, 테스트의 구현 근거. 기본 사용자 명세가 아니라 traceability 근거다.",
1282
1551
  "",
1283
1552
  "## 운영 규칙",
1284
1553
  "- 자연어 문서는 URL 화면과 사용자 인식 영역 중심으로 작성한다.",
1554
+ "- 모든 백엔드 기능은 `natural-git/backend/`에 원본 명세를 둔다.",
1555
+ "- 화면에 보이지 않는 동기화, 분류, 큐, 임베딩, 백그라운드 작업은 화면 문서에 길게 복사하지 않고 관련 백엔드 기능 참조로 연결한다.",
1556
+ "- 여러 화면에서 쓰는 백엔드 기능도 `natural-git/backend/` 원본 하나만 두고 각 화면에서 참조한다.",
1557
+ "- 어느 화면에서도 진입점이 없는 화면은 `entryless-screens`에 기록한다.",
1285
1558
  "- 코드 파일 문서는 사용자 기능명세가 아니라 `_evidence` 아래 구현 근거로 보존한다.",
1286
1559
  "- 코드의 현재 동작이 곧 제품 의도라는 뜻은 아니다.",
1287
1560
  "- 오너가 자연어 커밋으로 승인한 내용만 다음 코드 변경의 기준이 된다.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workq-mcp",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Work Q MCP stdio bridge and local repository connection CLI.",
5
5
  "type": "module",
6
6
  "bin": {