workq-mcp 0.1.8 → 0.1.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/lib/natural-git.mjs +288 -19
  2. package/package.json +1 -1
@@ -1073,7 +1073,233 @@ 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
+ if (feature.shared || feature.used_by_routes.length !== 1) return `natural-git/shared-internals/${feature.slug}.md`;
1230
+ const entry = entries.find((item) => item.route.url_pattern === feature.used_by_routes[0]);
1231
+ return `${entry?.route.directory ?? "natural-git/shared-internals"}/internals/${feature.slug}.md`;
1232
+ }
1233
+
1234
+ function internalFeatureDoc(feature, entries) {
1235
+ return {
1236
+ path: internalFeatureDocPath(feature, entries),
1237
+ title: feature.title,
1238
+ content: [
1239
+ `# ${feature.title}`,
1240
+ NATURAL_SPEC_FORMAT_COMMENT,
1241
+ "",
1242
+ "## 성격",
1243
+ "이 문서는 화면에 직접 보이는 버튼이나 카드가 아니라, 화면 기능을 가능하게 하는 내부/백그라운드 기능 명세다.",
1244
+ "",
1245
+ "## 목적",
1246
+ feature.purpose,
1247
+ "",
1248
+ "## 사용 화면",
1249
+ ...feature.used_by_routes.map((route) => {
1250
+ const entry = entries.find((item) => item.route.url_pattern === route);
1251
+ return `- ${route}: ${entry ? `${entry.route.directory}/README.md` : "연결된 화면 명세"}`;
1252
+ }),
1253
+ "",
1254
+ "## 연결된 화면 영역",
1255
+ ...feature.related_regions.map((region) => `- ${region}`),
1256
+ "",
1257
+ "## 트리거",
1258
+ ...feature.triggers.map((item) => `- ${item}`),
1259
+ "",
1260
+ "## 결과",
1261
+ ...feature.outcomes.map((item) => `- ${item}`),
1262
+ "",
1263
+ "## 실패 시 사용자 영향",
1264
+ ...feature.failure_impact.map((item) => `- ${item}`),
1265
+ "",
1266
+ "## 검증 방법",
1267
+ ...feature.verification.map((item) => `- ${item}`),
1268
+ "",
1269
+ "## 구현 근거",
1270
+ ...feature.source_paths.map((sourcePath) => `- ${sourceEvidencePath({ path: sourcePath })}`)
1271
+ ].join("\n")
1272
+ };
1273
+ }
1274
+
1275
+ function entrylessScreenDoc(entry) {
1276
+ const slug = slugSegment(entry.route.url_pattern.replace(/^\//, "") || "root");
1277
+ return {
1278
+ path: `natural-git/entryless-screens/${slug}.md`,
1279
+ title: `진입점 없는 화면: ${entry.route.url_pattern}`,
1280
+ content: [
1281
+ `# 진입점 없는 화면: ${entry.route.url_pattern}`,
1282
+ NATURAL_SPEC_FORMAT_COMMENT,
1283
+ "",
1284
+ "## 의미",
1285
+ "이 URL은 화면 파일과 기능명세가 있지만, 다른 사용자 화면에서 명확한 버튼이나 링크 진입점을 발견하지 못했다.",
1286
+ "",
1287
+ "## 기준 화면 명세",
1288
+ `- ${entry.route.directory}/README.md`,
1289
+ "",
1290
+ "## 운영 원칙",
1291
+ "- 직접 URL, 관리자 전용, 실험용, MCP/Agent 전용 화면일 수 있다.",
1292
+ "- 사용자가 일반 화면에서 접근해야 하는 기능이면 별도 메뉴, 버튼, 링크를 추가해야 한다.",
1293
+ "- 진입점이 없는 상태 자체가 제품 의도인지 오너가 확인해야 한다.",
1294
+ "",
1295
+ "## 검증 방법",
1296
+ "- 이 화면으로 이동하는 실제 사용자 진입점이 있는지 확인한다.",
1297
+ "- 진입점이 의도적으로 없다면 이유를 이 문서 또는 화면 README에 기록한다."
1298
+ ].join("\n")
1299
+ };
1300
+ }
1301
+
1302
+ function screenReadmeDoc(file, route, regions, internals, entries) {
1077
1303
  const isWorkQDashboard = isWorkQDashboardPage(file);
1078
1304
  const isWorkQV2 = route.url_pattern === "/v2" && file.path === "src/app/v2/page.tsx";
1079
1305
  const title = isWorkQDashboard ? "Work Q 대시보드 화면 명세" : isWorkQV2 ? "Work Q v2 대시보드 화면 명세" : route.title;
@@ -1098,9 +1324,15 @@ function screenReadmeDoc(file, route, regions) {
1098
1324
  "## 화면 영역",
1099
1325
  ...regions.map((region) => `- ${region.title}: ${region.purpose}`),
1100
1326
  "",
1327
+ "## 관련 내부 기능",
1328
+ ...(internals.length
1329
+ ? internals.map((feature) => `- ${feature.title}: ${feature.purpose} (${internalFeatureDocPath(feature, entries)})`)
1330
+ : ["- 이 화면에 연결된 내부/백그라운드 기능이 아직 발견되지 않았다."]),
1331
+ "",
1101
1332
  "## 핵심 원칙",
1102
1333
  "- URL 패턴을 최상위 화면 명세로 삼는다.",
1103
1334
  "- 화면 안의 사용자 인식 영역을 region 명세로 나눈다.",
1335
+ "- 화면에 보이지 않지만 이 화면 기능을 가능하게 하는 백그라운드 동작은 관련 내부 기능으로 연결한다.",
1104
1336
  "- 코드 파일 경로는 사용자 기능명세 제목으로 쓰지 않고 evidence로 분리한다.",
1105
1337
  "- 페이지네이션, 게시물 번호, 상세 id처럼 값만 바뀌는 URL은 하나의 URL 패턴으로 추상화한다.",
1106
1338
  "",
@@ -1110,7 +1342,7 @@ function screenReadmeDoc(file, route, regions) {
1110
1342
  };
1111
1343
  }
1112
1344
 
1113
- function screenRulesDoc(route, regions) {
1345
+ function screenRulesDoc(route, regions, internals) {
1114
1346
  return {
1115
1347
  path: `${route.directory}/rules.md`,
1116
1348
  title: `${route.url_pattern} 화면 규칙`,
@@ -1125,12 +1357,23 @@ function screenRulesDoc(route, regions) {
1125
1357
  "- 코드에서 관찰된 구현만으로 제품 의도를 단정하지 않는다.",
1126
1358
  "",
1127
1359
  "## 영역별 핵심 규칙",
1128
- ...regions.flatMap((region) => [`### ${region.title}`, ...region.rules.map((rule) => `- ${rule}`), ""])
1360
+ ...regions.flatMap((region) => [`### ${region.title}`, ...region.rules.map((rule) => `- ${rule}`), ""]),
1361
+ ...(internals.length
1362
+ ? [
1363
+ "## 관련 내부 기능 판단 기준",
1364
+ ...internals.flatMap((feature) => [
1365
+ `### ${feature.title}`,
1366
+ `- 이 내부 기능은 ${feature.used_by_routes.join(", ")} 화면의 기능을 지원한다.`,
1367
+ ...feature.failure_impact.map((item) => `- 실패 영향: ${item}`),
1368
+ ""
1369
+ ])
1370
+ ]
1371
+ : [])
1129
1372
  ].join("\n")
1130
1373
  };
1131
1374
  }
1132
1375
 
1133
- function screenVerificationDoc(route, regions) {
1376
+ function screenVerificationDoc(route, regions, internals) {
1134
1377
  return {
1135
1378
  path: `${route.directory}/verification.md`,
1136
1379
  title: `${route.url_pattern} 화면 검증`,
@@ -1144,12 +1387,19 @@ function screenVerificationDoc(route, regions) {
1144
1387
  "- Agent 완료 전에는 관련 영역의 verification 항목을 확인하고 Work Q 완료 기록에 남긴다.",
1145
1388
  "",
1146
1389
  "## 영역별 검증",
1147
- ...regions.flatMap((region) => [`### ${region.title}`, ...region.verification.map((item) => `- ${item}`), ""])
1390
+ ...regions.flatMap((region) => [`### ${region.title}`, ...region.verification.map((item) => `- ${item}`), ""]),
1391
+ ...(internals.length
1392
+ ? [
1393
+ "## 관련 내부 기능 검증",
1394
+ ...internals.flatMap((feature) => [`### ${feature.title}`, ...feature.verification.map((item) => `- ${item}`), ""])
1395
+ ]
1396
+ : [])
1148
1397
  ].join("\n")
1149
1398
  };
1150
1399
  }
1151
1400
 
1152
- function regionDoc(route, region) {
1401
+ function regionDoc(route, region, internals, entries) {
1402
+ const relatedInternals = internalFeaturesForRegion(internals, region);
1153
1403
  return {
1154
1404
  path: `${route.directory}/regions/${region.slug}.md`,
1155
1405
  title: region.title,
@@ -1169,6 +1419,13 @@ function regionDoc(route, region) {
1169
1419
  "## 핵심 규칙",
1170
1420
  ...region.rules.map((item) => `- ${item}`),
1171
1421
  "",
1422
+ ...(relatedInternals.length
1423
+ ? [
1424
+ "## 관련 내부 기능",
1425
+ ...relatedInternals.map((feature) => `- ${feature.title}: ${internalFeatureDocPath(feature, entries)}`),
1426
+ ""
1427
+ ]
1428
+ : []),
1172
1429
  "## 검증 방법",
1173
1430
  ...region.verification.map((item) => `- ${item}`)
1174
1431
  ].join("\n")
@@ -1230,25 +1487,32 @@ function fallbackRegions(sourceFiles) {
1230
1487
  }
1231
1488
 
1232
1489
  function routeScreenDocs(sourceFiles) {
1233
- const docs = sourceFiles.flatMap((file) => {
1234
- const route = routeInfoForFile(file);
1235
- if (!route) return [];
1236
- const regions = regionsForRoute(file, route);
1490
+ const entries = routeEntriesForSourceFiles(sourceFiles);
1491
+ const detectedInternals = detectInternalFeatures(sourceFiles, entries);
1492
+ const docs = entries.flatMap((entry) => {
1493
+ const internals = internalFeaturesForRoute(detectedInternals, entry.route);
1237
1494
  return [
1238
- screenReadmeDoc(file, route, regions),
1239
- screenRulesDoc(route, regions),
1240
- screenVerificationDoc(route, regions),
1241
- ...regions.map((region) => regionDoc(route, region))
1495
+ screenReadmeDoc(entry.file, entry.route, entry.regions, internals, entries),
1496
+ screenRulesDoc(entry.route, entry.regions, internals),
1497
+ screenVerificationDoc(entry.route, entry.regions, internals),
1498
+ ...entry.regions.map((region) => regionDoc(entry.route, region, internals, entries))
1242
1499
  ];
1243
1500
  });
1244
- if (docs.length || !sourceFiles.length) return docs;
1501
+ if (docs.length || !sourceFiles.length) {
1502
+ return [...docs, ...detectedInternals.map((feature) => internalFeatureDoc(feature, entries)), ...entries.filter((entry) => entry.entryless).map((entry) => entrylessScreenDoc(entry))];
1503
+ }
1245
1504
  const route = fallbackRouteInfo();
1246
1505
  const regions = fallbackRegions(sourceFiles);
1506
+ const fallbackEntry = { file: sourceFiles[0], route, regions, entryless: false };
1507
+ const entriesWithFallback = [fallbackEntry];
1508
+ const internals = detectInternalFeatures(sourceFiles, entriesWithFallback);
1509
+ const routeInternals = internalFeaturesForRoute(internals, route);
1247
1510
  return [
1248
- screenReadmeDoc(sourceFiles[0], route, regions),
1249
- screenRulesDoc(route, regions),
1250
- screenVerificationDoc(route, regions),
1251
- ...regions.map((region) => regionDoc(route, region))
1511
+ screenReadmeDoc(sourceFiles[0], route, regions, routeInternals, entriesWithFallback),
1512
+ screenRulesDoc(route, regions, routeInternals),
1513
+ screenVerificationDoc(route, regions, routeInternals),
1514
+ ...regions.map((region) => regionDoc(route, region, routeInternals, entriesWithFallback)),
1515
+ ...internals.map((feature) => internalFeatureDoc(feature, entriesWithFallback))
1252
1516
  ];
1253
1517
  }
1254
1518
 
@@ -1275,13 +1539,18 @@ function overviewDoc({ projectKey, projectName, repository, root, sourceFiles })
1275
1539
  "## 디렉토리 구조",
1276
1540
  "- `natural-git/screens/`: URL 패턴별 최상위 화면 명세",
1277
1541
  "- `natural-git/screens/<url>/regions/`: 화면 안의 사용자 인식 영역 명세",
1542
+ "- `natural-git/screens/<url>/internals/`: 특정 화면 기능을 가능하게 하는 내부/백그라운드 기능 명세",
1278
1543
  "- `natural-git/screens/<url>/components/`: 여러 화면에서 재사용되는 컴포넌트 명세",
1279
1544
  "- `natural-git/screens/<url>/dialogs/`: 모달, 팝업, 드로어 상태 명세",
1545
+ "- `natural-git/shared-internals/`: 여러 화면에서 같이 쓰는 내부/백그라운드 기능 명세",
1546
+ "- `natural-git/entryless-screens/`: 화면은 있지만 메뉴나 버튼 진입점이 명확하지 않은 URL 명세",
1280
1547
  "- `natural-git/verification/`: 기능이 실제로 동작하는지 확인하는 검증 시나리오 명세",
1281
1548
  "- `natural-git/_evidence/`: 코드 파일, 설정, 테스트의 구현 근거. 기본 사용자 명세가 아니라 traceability 근거다.",
1282
1549
  "",
1283
1550
  "## 운영 규칙",
1284
1551
  "- 자연어 문서는 URL 화면과 사용자 인식 영역 중심으로 작성한다.",
1552
+ "- 화면에 보이지 않는 동기화, 분류, 큐, 임베딩, 백그라운드 작업은 그 기능을 사용하는 화면에 관련 내부 기능으로 연결한다.",
1553
+ "- 여러 화면에서 쓰는 내부 기능은 `shared-internals`에 두고, 어느 화면에서도 진입점이 없는 화면은 `entryless-screens`에 기록한다.",
1285
1554
  "- 코드 파일 문서는 사용자 기능명세가 아니라 `_evidence` 아래 구현 근거로 보존한다.",
1286
1555
  "- 코드의 현재 동작이 곧 제품 의도라는 뜻은 아니다.",
1287
1556
  "- 오너가 자연어 커밋으로 승인한 내용만 다음 코드 변경의 기준이 된다.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workq-mcp",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Work Q MCP stdio bridge and local repository connection CLI.",
5
5
  "type": "module",
6
6
  "bin": {