cuelo 0.7.1 → 0.8.0
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.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +9 -8
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +27 -3
- package/.next/react-loadable-manifest.json +13 -3
- package/.next/required-server-files.js +2 -2
- package/.next/required-server-files.json +2 -2
- package/.next/routes-manifest.json +6 -0
- package/.next/server/app/_global-error/page.js +3 -3
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +2 -2
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +3 -3
- package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/agent/[id]/account/route.js +1 -1
- package/.next/server/app/api/agent/[id]/bash-output/route.js +1 -1
- package/.next/server/app/api/agent/[id]/events/route.js +2 -2
- package/.next/server/app/api/agent/[id]/route.js +1 -1
- package/.next/server/app/api/agent/new/route.js +1 -1
- package/.next/server/app/api/agent/running/route.js +1 -1
- package/.next/server/app/api/attachments/route.js +2 -2
- package/.next/server/app/api/auth/all-providers/route.js +1 -1
- package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
- package/.next/server/app/api/auth/login/[provider]/route.js +2 -2
- package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
- package/.next/server/app/api/auth/providers/route.js +1 -1
- package/.next/server/app/api/cwd/browse/route.js +1 -1
- package/.next/server/app/api/cwd/validate/route.js +1 -1
- package/.next/server/app/api/default-cwd/route.js +1 -1
- package/.next/server/app/api/display-settings/route.js +1 -1
- package/.next/server/app/api/document-text/route.js +2 -2
- package/.next/server/app/api/experiments/route.js +1 -1
- package/.next/server/app/api/file-index/route.js +1 -1
- package/.next/server/app/api/files/[...path]/route.js +1 -1
- package/.next/server/app/api/git/diff/route.js +1 -1
- package/.next/server/app/api/git/status/route.js +2 -2
- package/.next/server/app/api/gpt6/handles/route.js +1 -1
- package/.next/server/app/api/gpt6/reply/route.js +1 -1
- package/.next/server/app/api/gpt6/token/route.js +1 -1
- package/.next/server/app/api/gpt6/web6-session/route.js +1 -1
- package/.next/server/app/api/home/route.js +1 -1
- package/.next/server/app/api/live/call/[callId]/route.js +1 -1
- package/.next/server/app/api/live/character-voice/route.js +1 -1
- package/.next/server/app/api/live/events/route.js +2 -2
- package/.next/server/app/api/live/offer/route.js +1 -1
- package/.next/server/app/api/live/voices/route.js +1 -1
- package/.next/server/app/api/lounge/events/route.js +2 -2
- package/.next/server/app/api/lounge/route.js +1 -1
- package/.next/server/app/api/mcp/route.js +2 -2
- package/.next/server/app/api/model-roles/route.js +1 -1
- package/.next/server/app/api/models/route.js +1 -1
- package/.next/server/app/api/models-config/catalog/route.js +1 -1
- package/.next/server/app/api/models-config/discover/route.js +1 -1
- package/.next/server/app/api/models-config/route.js +3 -3
- package/.next/server/app/api/models-config/test/route.js +1 -1
- package/.next/server/app/api/plugins/route.js +1 -1
- package/.next/server/app/api/project-trust/route.js +1 -1
- package/.next/server/app/api/projects/route.js +2 -2
- package/.next/server/app/api/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/runs/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/auto-name/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/search/route.js +1 -1
- package/.next/server/app/api/settings/route.js +1 -1
- package/.next/server/app/api/sidecars/[service]/[...path]/route.js +1 -1
- package/.next/server/app/api/skills/check/route.js +1 -1
- package/.next/server/app/api/skills/install/route.js +2 -2
- package/.next/server/app/api/skills/route.js +2 -2
- package/.next/server/app/api/skills/search/route.js +1 -1
- package/.next/server/app/api/skills/update/route.js +1 -1
- package/.next/server/app/api/theme/route.js +1 -1
- package/.next/server/app/api/tool-image/route.js +1 -1
- package/.next/server/app/api/update-maintenance/route.js +2 -2
- package/.next/server/app/api/updates/route.js +1 -1
- package/.next/server/app/api/web-access/recovery/route.js +1 -1
- package/.next/server/app/api/web-access/route.js +1 -1
- package/.next/server/app/api/web6/consults/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/favicon.ico/route.js +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +7 -6
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -4
- package/.next/server/app/index.segments/_full.segment.rsc +7 -6
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/.next/server/app/index.segments/_tree.segment.rsc +4 -3
- package/.next/server/app/manifest.webmanifest/route.js +2 -2
- package/.next/server/app/office-preview/page.js +2 -0
- package/.next/server/app/office-preview/page.js.nft.json +1 -0
- package/.next/server/app/office-preview/page_client-reference-manifest.js +1 -0
- package/.next/server/app/office-preview.html +1 -0
- package/.next/server/app/office-preview.meta +16 -0
- package/.next/server/app/office-preview.rsc +20 -0
- package/.next/server/app/office-preview.segments/_full.segment.rsc +20 -0
- package/.next/server/app/office-preview.segments/_head.segment.rsc +6 -0
- package/.next/server/app/office-preview.segments/_index.segment.rsc +7 -0
- package/.next/server/app/office-preview.segments/_tree.segment.rsc +4 -0
- package/.next/server/app/office-preview.segments/office-preview/__PAGE__.segment.rsc +7 -0
- package/.next/server/app/office-preview.segments/office-preview.segment.rsc +5 -0
- package/.next/server/app/page.js +19 -19
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/recover/page.js +2 -2
- package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
- package/.next/server/app/recover.html +1 -1
- package/.next/server/app/recover.rsc +3 -3
- package/.next/server/app/recover.segments/_full.segment.rsc +3 -3
- package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
- package/.next/server/app/recover.segments/_index.segment.rsc +3 -3
- package/.next/server/app/recover.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
- package/.next/server/app-paths-manifest.json +9 -8
- package/.next/server/chunks/205.js +3 -2
- package/.next/server/chunks/424.js +1 -1
- package/.next/server/chunks/5582.js +2 -2
- package/.next/server/chunks/58.js +353 -0
- package/.next/server/chunks/6429.js +1 -1
- package/.next/server/chunks/7362.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/1937.8900983e70e8e9dc.js +1 -0
- package/.next/static/chunks/{3308.34ea31e24088c85f.js → 3308.8b94b38809d1b8b6.js} +1 -1
- package/.next/static/chunks/4857.cb0735ea310a39f0.js +1 -0
- package/.next/static/chunks/52733464.85a1551044fef357.js +1 -0
- package/.next/static/chunks/6110-681afd060dde5270.js +1 -0
- package/.next/static/chunks/9304.1f940d490ea5c972.js +1 -0
- package/.next/static/chunks/app/{layout-ca001f1e875e854c.js → layout-6aa3580989aedade.js} +1 -1
- package/.next/static/chunks/app/office-preview/page-2151040877dfb7cd.js +1 -0
- package/.next/static/chunks/app/page-f6f024bab16a7232.js +22 -0
- package/.next/static/chunks/b536a0f1.f7e390612229faa9.js +342 -0
- package/.next/static/chunks/bd904a5c.b74776e0b23d0607.js +1 -0
- package/.next/static/chunks/f5ef5e1c.14b6095722ff4f0b.js +12 -0
- package/.next/static/chunks/{framework-32a7466d5cae4a81.js → framework-e405bc515d75023a.js} +1 -1
- package/.next/static/chunks/webpack-93d544f82f48c3fd.js +1 -0
- package/.next/static/css/67b6e19482963224.css +1 -0
- package/.next/static/css/829f44afcc3302e9.css +1 -0
- package/.next/static/css/abd3d00cca9457f7.css +1 -0
- package/.next/static/vaxcaBF-y6afdFHIrgeuN/_buildManifest.js +1 -0
- package/.next/trace +106 -105
- package/.next/trace-build +1 -1
- package/.next/types/app/office-preview/page.ts +87 -0
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/README.md +10 -4
- package/Tools/CUELO_Setup/files/native-runtime-patch.js +5 -5
- package/Tools/OMP_Global_Config/agent/extensions/character-voice.ts +2 -2
- package/Tools/OMP_Global_Config/agent/extensions/jev-runtime.ts +22 -11
- package/Tools/OMP_Global_Config/agent/extensions/korean-reply-guard.ts +174 -0
- package/Tools/OMP_Global_Config/agent/extensions/lib/maker-routing.ts +43 -16
- package/Tools/OMP_Global_Config/agent/rules/verdict.md +3 -0
- package/Tools/OMP_Global_Config/agent/tools/git-finalizer/index.ts +45 -5
- package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +315 -40
- package/install.mjs +6 -2
- package/package.json +10 -7
- package/public/office3d/ASSETS.md +8 -0
- package/.next/static/chunks/2619.9aac8983f30c7c8a.js +0 -1
- package/.next/static/chunks/52733464.3870f99cc446f9ff.js +0 -1
- package/.next/static/chunks/app/page-ce1990eb55a57ad6.js +0 -22
- package/.next/static/chunks/webpack-13c58b226bf07c7e.js +0 -1
- package/.next/static/css/bb6b220f400250d8.css +0 -1
- package/.next/static/css/d0ec5531aef136d6.css +0 -1
- package/.next/static/vl7SKOdL2Zksd2mJ3tjOQ/_buildManifest.js +0 -1
- /package/.next/static/{vl7SKOdL2Zksd2mJ3tjOQ → vaxcaBF-y6afdFHIrgeuN}/_ssgManifest.js +0 -0
|
@@ -85,6 +85,8 @@ export interface RoutingDeps {
|
|
|
85
85
|
candidates?: (ctx: ExtensionContext, policy: RoutingPolicy) => Promise<Candidate[]>;
|
|
86
86
|
/** 후보 provider별 계정 잔량. 생략하면 CUELO usage 사이드카(`OMP_USAGE_PORT`, 기본 30142)를 읽는다. */
|
|
87
87
|
quota?: (providers: string[], signal?: AbortSignal) => Promise<QuotaSnapshot>;
|
|
88
|
+
/** 준비 단계 진단용 단조 시계(ms). 생략하면 performance.now. */
|
|
89
|
+
clock?: () => number;
|
|
88
90
|
/** 발주 이력. 생략하면 기록·history 요약을 하지 않는다. 실패는 발주를 막지 않는다. */
|
|
89
91
|
ledger?: RoutingLedger;
|
|
90
92
|
}
|
|
@@ -540,10 +542,11 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
540
542
|
// 검사를 통과한 발주의 이력 초안. spawn 성공(noteSpawned) 때만 identity와 함께 ledger에 남긴다.
|
|
541
543
|
// 새 초안은 항상 소유 계약을 싣는다. 원장의 과거 row만 ownership이 없을 수 있다.
|
|
542
544
|
type DispatchDraft = Omit<DispatchRecord, "ts" | "ownership" | keyof AttemptIdentity> & { ownership: DispatchOwnership };
|
|
543
|
-
|
|
544
|
-
//
|
|
545
|
-
// 이 예약과 충돌을 검사한다. spawn 관측(noteSpawned)은 실제 owner 목록으로
|
|
546
|
-
|
|
545
|
+
// 검사를 통과했지만 spawn 결과를 아직 받지 못한 task 호출의 실행 초안(toolCallId → 그 호출 tasks[]의 itemIndex별 초안).
|
|
546
|
+
// 초안은 이 호출 실행에만 속한다. 같은 이름·같은 계약의 다른 호출도 자기 초안을 갖고, 준비 판단(bindings)은 그대로 재사용한다.
|
|
547
|
+
// 별도 task 호출의 admission이 이 예약과 충돌을 검사한다. spawn 관측(noteSpawned)은 자기 초안만 소비해 실제 owner 목록으로
|
|
548
|
+
// 넘기며 지우고, spawn 없이 끝난 호출은 releaseCall이 자기 예약만 지운다.
|
|
549
|
+
const reservations = new Map<string, { itemIndex: number; key: string; draft: DispatchDraft }[]>();
|
|
547
550
|
// 거절 진단 전용 색인. 준비된 계약을 이름별로 시간순으로 모아 어긋난 필드를 지목하며,
|
|
548
551
|
// 통과·차단 판정에는 관여하지 않는다.
|
|
549
552
|
const preparedContracts = new Map<string, DispatchContract[]>();
|
|
@@ -555,7 +558,6 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
555
558
|
const reset = () => {
|
|
556
559
|
generation++;
|
|
557
560
|
bindings.clear();
|
|
558
|
-
pendingDispatches.clear();
|
|
559
561
|
reservations.clear();
|
|
560
562
|
preparedContracts.clear();
|
|
561
563
|
decisionCache.clear();
|
|
@@ -730,11 +732,19 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
730
732
|
throw new Error("같은 task 계약에 더 최신 facts 준비가 있어 이전 라우팅 판단은 폐기되었습니다.");
|
|
731
733
|
}
|
|
732
734
|
};
|
|
735
|
+
const clock = deps.clock ?? (() => performance.now());
|
|
736
|
+
const startedAt = clock();
|
|
737
|
+
const elapsed = (from: number, to: number) => Math.max(0, Math.round(to - from));
|
|
738
|
+
// 고정 필드 진단. 숫자만 담으며 task 수와 무관하다. jevStarted는 이 호출이 실제로 시작한 judge 요청 수이고,
|
|
739
|
+
// 분류별 건수와 합산해 해석하지 않는다(한 요청이 decision·placement를 함께 판단할 수 있다).
|
|
740
|
+
const counts = { jevStarted: 0, decisionNew: 0, decisionReused: 0, placementNew: 0, placementReused: 0 };
|
|
733
741
|
let quotaAbort: AbortController | undefined;
|
|
734
742
|
try {
|
|
735
743
|
const ownersByTask = contracts.map((contract) => relevantOwners(contract, allOwners));
|
|
736
744
|
const refreshAttempts: RefreshAttempts = new Map();
|
|
745
|
+
const candidatesStartedAt = clock();
|
|
737
746
|
const { available: candidates, unavailable: unavailableCandidates } = await candidateSet(ctx, current, refreshAttempts);
|
|
747
|
+
const candidatesDoneAt = clock();
|
|
738
748
|
requireLatest();
|
|
739
749
|
// 잔량은 시각마다 바뀌므로 revision·identity·Jev state 밖의 참고 정보로만 붙인다.
|
|
740
750
|
// Jev 판단과 함께 시작하고, 이번 계정 잔량 조회가 끝난 뒤 배정 결과를 반환한다.
|
|
@@ -760,6 +770,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
760
770
|
reason: error instanceof Error ? error.message : String(error),
|
|
761
771
|
});
|
|
762
772
|
}
|
|
773
|
+
const judgeStartedAt = clock();
|
|
763
774
|
const publications = await Promise.all(tasks.map(async (task, index) => {
|
|
764
775
|
const contract = contracts[index]!;
|
|
765
776
|
const owners = ownersByTask[index]!;
|
|
@@ -773,8 +784,14 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
773
784
|
let decisionPending = decisionCache.get(decisionKey);
|
|
774
785
|
let placementPending = placementCache.get(placementKey);
|
|
775
786
|
|
|
787
|
+
// 소유자가 없으면 placement 판단 자체가 없으므로 어느 쪽으로도 세지 않는다. 새 decision 판단은 placement를 함께 덮어쓴다.
|
|
788
|
+
if (decisionPending) counts.decisionReused += 1;
|
|
789
|
+
if (decisionPending && placementPending && owners.length > 0) counts.placementReused += 1;
|
|
776
790
|
if (!decisionPending) {
|
|
777
791
|
const fullQuestions = { ...baseQuestions, ...ownerQuestions };
|
|
792
|
+
counts.jevStarted += 1;
|
|
793
|
+
counts.decisionNew += 1;
|
|
794
|
+
if (owners.length > 0) counts.placementNew += 1;
|
|
778
795
|
const fullPending = judge(ctx, routingState(task.assessment, owners), fullQuestions, signal);
|
|
779
796
|
decisionPending = cacheJudgment(
|
|
780
797
|
decisionCache,
|
|
@@ -795,6 +812,8 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
795
812
|
);
|
|
796
813
|
}
|
|
797
814
|
} else if (!placementPending && owners.length > 0) {
|
|
815
|
+
counts.jevStarted += 1;
|
|
816
|
+
counts.placementNew += 1;
|
|
798
817
|
placementPending = cacheJudgment(
|
|
799
818
|
placementCache,
|
|
800
819
|
placementKey,
|
|
@@ -841,7 +860,9 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
841
860
|
},
|
|
842
861
|
};
|
|
843
862
|
}));
|
|
863
|
+
const quotaWaitStartedAt = clock();
|
|
844
864
|
const quota = await quotaPending;
|
|
865
|
+
const quotaDoneAt = clock();
|
|
845
866
|
requireLatest();
|
|
846
867
|
const allocation = normalAllocation(current, candidates, quota);
|
|
847
868
|
// 이력은 advisory다. revision·identity·Jev state 밖에 두며 읽기 실패는 빈 이력이다.
|
|
@@ -870,7 +891,15 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
870
891
|
const name = tasks[index]!.name.trim();
|
|
871
892
|
preparedContracts.set(name, [...(preparedContracts.get(name) ?? []), contracts[index]!]);
|
|
872
893
|
});
|
|
894
|
+
const diagnostics = {
|
|
895
|
+
totalMs: elapsed(startedAt, quotaDoneAt),
|
|
896
|
+
candidatesMs: elapsed(candidatesStartedAt, candidatesDoneAt),
|
|
897
|
+
judgeWaitMs: elapsed(judgeStartedAt, quotaWaitStartedAt),
|
|
898
|
+
quotaExtraWaitMs: elapsed(quotaWaitStartedAt, quotaDoneAt),
|
|
899
|
+
...counts,
|
|
900
|
+
};
|
|
873
901
|
return {
|
|
902
|
+
diagnostics,
|
|
874
903
|
candidates,
|
|
875
904
|
unavailableCandidates,
|
|
876
905
|
quota,
|
|
@@ -923,7 +952,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
923
952
|
candidateLock ??= { workClass: contract.workClass, primaryDeliverable: contract.primaryDeliverable };
|
|
924
953
|
return contract;
|
|
925
954
|
});
|
|
926
|
-
const drafts: [
|
|
955
|
+
const drafts: [number, DispatchDraft][] = [];
|
|
927
956
|
for (const [itemIndex, item] of tasks.entries()) {
|
|
928
957
|
const requested = typeof item.model === "string" ? item.model : "";
|
|
929
958
|
const task = typeof item.task === "string" ? item.task : "";
|
|
@@ -994,7 +1023,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
994
1023
|
const recommended = candidates.findIndex((candidate) => candidate.profile === profile);
|
|
995
1024
|
const recommendedCandidate = candidates[recommended];
|
|
996
1025
|
const workClass = answers?.workClass?.choice ?? null;
|
|
997
|
-
drafts.push([
|
|
1026
|
+
drafts.push([itemIndex, {
|
|
998
1027
|
type: "dispatch",
|
|
999
1028
|
name,
|
|
1000
1029
|
workClass,
|
|
@@ -1048,8 +1077,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
1048
1077
|
reason: `다른 task 호출이 발주 승인을 받아 spawn 결과를 기다리는 공유 작업공간 OWNED_PATHS와 겹칩니다: ${reserved.slice(0, DIAGNOSTIC_LIST_LIMIT).join("; ")}. 이 호출은 발주하지 않았습니다. 그 호출의 결과가 돌아온 뒤 현재 owner를 확인해 다시 내거나, 경로를 나누거나 isolated로 발주하세요.`,
|
|
1049
1078
|
};
|
|
1050
1079
|
}
|
|
1051
|
-
|
|
1052
|
-
if (callId && drafts.length > 0) reservations.set(callId, drafts.map(([key, draft]) => ({ key, draft })));
|
|
1080
|
+
if (callId && drafts.length > 0) reservations.set(callId, drafts.map(([itemIndex, draft]) => ({ itemIndex, key: briefKey(draft.name, contracts[itemIndex]!), draft })));
|
|
1053
1081
|
return canonicalInput === input ? undefined : { input: canonicalInput };
|
|
1054
1082
|
}
|
|
1055
1083
|
|
|
@@ -1058,9 +1086,6 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
1058
1086
|
* tool_execution_end만 내고, task 실행 오류는 isError tool_result를 낸다. 다른 호출의 예약과 이미 이관된 owner는 건드리지 않는다.
|
|
1059
1087
|
*/
|
|
1060
1088
|
function releaseCall(callId: string): void {
|
|
1061
|
-
for (const { key, draft } of reservations.get(callId) ?? []) {
|
|
1062
|
-
if (pendingDispatches.get(key) === draft) pendingDispatches.delete(key);
|
|
1063
|
-
}
|
|
1064
1089
|
reservations.delete(callId);
|
|
1065
1090
|
}
|
|
1066
1091
|
|
|
@@ -1081,16 +1106,16 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
1081
1106
|
// 원장에서 읽으므로 reload 뒤에도 연결이 유지되고, 관측되지 않은 준비만으로는 연결하지 않는다.
|
|
1082
1107
|
const known = assignmentsByName(deps.ledger?.read() ?? [], sessionId);
|
|
1083
1108
|
let candidateLock = contractLock;
|
|
1109
|
+
const reserved = reservations.get(callId) ?? [];
|
|
1084
1110
|
for (const [index, item] of tasks.entries()) {
|
|
1085
1111
|
const task = typeof item.task === "string" ? item.task : "";
|
|
1086
1112
|
const contract = dispatchContract(task, candidateLock);
|
|
1087
1113
|
if (!contract) continue;
|
|
1088
1114
|
candidateLock ??= { workClass: contract.workClass, primaryDeliverable: contract.primaryDeliverable };
|
|
1089
1115
|
const name = String(item.name ?? "").trim();
|
|
1090
|
-
|
|
1091
|
-
const draft =
|
|
1116
|
+
// 이 호출이 admission에서 받은 그 항목의 초안만 소비한다. 같은 이름·같은 계약의 다른 호출 초안은 그 호출의 것이다.
|
|
1117
|
+
const draft = reserved.find((entry) => entry.itemIndex === index && entry.key === briefKey(name, contract))?.draft;
|
|
1092
1118
|
if (!draft) continue;
|
|
1093
|
-
pendingDispatches.delete(key);
|
|
1094
1119
|
// 다른 guard가 막은 뒤 다른 selector로 다시 낸 발주는 그 호출의 beforeTask 초안만 맞는다.
|
|
1095
1120
|
if (item.model !== `${draft.chosenModel}:${draft.chosenEffort}`) continue;
|
|
1096
1121
|
const linked = sessionId && contract.findingId !== null ? known.get(name) : undefined;
|
|
@@ -1131,7 +1156,9 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
|
|
|
1131
1156
|
const request = params as { context: string; tasks: RouteTask[] };
|
|
1132
1157
|
const batch = await prepareBatch(request.context, request.tasks, ctx, signal, String(callId ?? ""));
|
|
1133
1158
|
// 준비 handle(plan)은 발주 identity가 아니므로(routing_verdict는 spawn identity) 모델 문맥에는 싣지 않고 details에만 둔다.
|
|
1134
|
-
|
|
1159
|
+
// 준비 진단(diagnostics)도 details 전용이다. 모델 문맥에는 싣지 않는다.
|
|
1160
|
+
const { diagnostics: _diagnostics, ...shared } = batch;
|
|
1161
|
+
const view = { ...shared, routes: batch.routes.map(({ plan: _plan, ...route }) => route) };
|
|
1135
1162
|
return { content: [{ type: "text", text: JSON.stringify(view) }], details: batch };
|
|
1136
1163
|
},
|
|
1137
1164
|
});
|
|
@@ -174,6 +174,9 @@ Main은 근거가 있는 finding을 각각 다음 중 하나로 닫는다.
|
|
|
174
174
|
어긴 실행 실수면 기존 규칙 적용을 교정하고, 규칙·Skill 누락일 때만 해당 정본을 보완한다.
|
|
175
175
|
미확정 가설이나 실패율 임계값으로 규칙을 자동 생성·변경하지 않는다. `learn`은 Main 전용이다.
|
|
176
176
|
Maker는 종료 보고에 교훈 후보를 싣고, Main이 저장·기존 교훈 연결·기각을 정한다.
|
|
177
|
+
저장 범위도 Main이 직접 정한다. 여러 프로젝트에 적용되는 사용자 선호·작업 운영 원칙은
|
|
178
|
+
`global`, 특정 저장소의 구현·경로·환경에 종속된 사실은 `project`로 저장한다. 사용자가
|
|
179
|
+
범위를 다시 지정하게 하지 않으며, 이미 있는 교훈은 중복 저장보다 연결·수정을 우선한다.
|
|
177
180
|
전역 `autolearn`도 켜져 있다. 도구 호출 8회 이상 턴이 끝나면 core의 별도 capture Agent가
|
|
178
181
|
(`learn`·`manage_skill`만 가진 채) 교훈을 따로 저장하고, 저장한 경우에만 대화에
|
|
179
182
|
`[교훈 자동 저장]`(`autolearn-saved`) 메시지를 남긴다. 이건 보조일 뿐 Main의 직접 저장 책임은 그대로다.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { access, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -28,6 +28,41 @@ const manifestInstructions = `From cwd Tools/CUELO_Setup, run:
|
|
|
28
28
|
node files/source-build-helper.js create-manifest ../.. files/runtime-integrity.json --output files/source-integrity.json
|
|
29
29
|
node files/source-build-helper.js verify-source ../.. files/source-integrity.json files/runtime-integrity.json
|
|
30
30
|
Then include Tools/CUELO_Setup/files/source-integrity.json in the same commit.`;
|
|
31
|
+
const memorySyncScript = "Tools/OMP_Global_Config/memory-sync/sync.ts";
|
|
32
|
+
const memoryTransport = "Tools/OMP_Global_Config/memory-sync/memories.jsonl";
|
|
33
|
+
|
|
34
|
+
type Exec = (command: string, args: string[], options: { cwd: string }) => Promise<{ code: number; stdout: string; stderr?: string }>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 기억 PC 간 동기화의 export를 커밋 경로에 붙인다. 원래 hook은 손으로 돌리는 export.ps1 끝뿐이라
|
|
38
|
+
* 평소 커밋·배포로는 한 번도 내보내지지 않았다(2026-10-02). 같은 저장소 커밋이면 먼저 export하고,
|
|
39
|
+
* 바뀐 transport 파일을 커밋 목록에 더한다. 실패는 커밋을 막지 않고 결과 문구로 알린다.
|
|
40
|
+
*/
|
|
41
|
+
async function exportMemories(cwd: string, files: string[], exec: Exec): Promise<{ file?: string; note?: string }> {
|
|
42
|
+
const top = await exec("git", ["-C", cwd, "rev-parse", "--show-toplevel"], { cwd });
|
|
43
|
+
if (top.code !== 0) return {};
|
|
44
|
+
const root = resolve(top.stdout.trim());
|
|
45
|
+
try {
|
|
46
|
+
await access(join(root, ...memorySyncScript.split("/")));
|
|
47
|
+
} catch {
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
const inRoot = (path: string) => {
|
|
51
|
+
const rel = relative(root, resolve(cwd, path));
|
|
52
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
53
|
+
};
|
|
54
|
+
if (!files.every(inRoot)) return {};
|
|
55
|
+
const transport = relative(cwd, join(root, ...memoryTransport.split("/"))).split(sep).join("/");
|
|
56
|
+
if (transport.startsWith("../")) return { note: "기억 export 생략: 현재 cwd 밖의 파일이라 이 커밋에 넣을 수 없다." };
|
|
57
|
+
if (files.some((file) => file.replace(/\\/g, "/").toLowerCase() === transport.toLowerCase())) return {};
|
|
58
|
+
const exported = await exec("bun", [join(root, ...memorySyncScript.split("/")), "export", root], { cwd: root });
|
|
59
|
+
if (exported.code !== 0) {
|
|
60
|
+
const reason = (exported.stderr || exported.stdout).trim().split(/\r?\n/).at(-1) || `exit ${exported.code}`;
|
|
61
|
+
return { note: `기억 export 실패(커밋은 진행): ${reason}` };
|
|
62
|
+
}
|
|
63
|
+
const status = await exec("git", ["-C", root, "status", "--porcelain", "--", memoryTransport], { cwd: root });
|
|
64
|
+
return status.code === 0 && status.stdout.trim() ? { file: transport } : {};
|
|
65
|
+
}
|
|
31
66
|
|
|
32
67
|
function isSourcePath(path: string, packagedTools: string[]): boolean {
|
|
33
68
|
if (path.split("/").some((segment) => generatedSourceSegments[segment] || segment.endsWith(".tsbuildinfo"))) return false;
|
|
@@ -137,13 +172,16 @@ const factory: CustomToolFactory = (pi) => ({
|
|
|
137
172
|
}),
|
|
138
173
|
|
|
139
174
|
async execute(_toolCallId, params, onUpdate, _ctx, signal) {
|
|
140
|
-
const
|
|
175
|
+
const requested = params.files.map((value) => value.trim()).filter(Boolean);
|
|
141
176
|
const message = params.message.trim();
|
|
142
|
-
if (
|
|
177
|
+
if (requested.length === 0) throw new Error("git_finalize requires at least one exact file path.");
|
|
143
178
|
if (!message) throw new Error("git_finalize requires a non-empty commit message.");
|
|
144
179
|
if (process.platform !== "win32") throw new Error("git_finalize currently requires Windows PowerShell.");
|
|
145
180
|
|
|
146
|
-
|
|
181
|
+
const exec: Exec = (command, args, options) => pi.exec(command, args, { ...options, signal });
|
|
182
|
+
await checkSourceManifest(pi.cwd, requested, exec);
|
|
183
|
+
const memory = await exportMemories(pi.cwd, requested, exec);
|
|
184
|
+
const files = memory.file ? [...requested, memory.file] : requested;
|
|
147
185
|
|
|
148
186
|
onUpdate?.({
|
|
149
187
|
content: [{ type: "text", text: "Repository finalizer lock을 획득하고 변경 경계를 확인하는 중입니다." }],
|
|
@@ -168,7 +206,9 @@ const factory: CustomToolFactory = (pi) => ({
|
|
|
168
206
|
content: [
|
|
169
207
|
{
|
|
170
208
|
type: "text",
|
|
171
|
-
text: `Committed and pushed ${parsed.commitSha} to ${parsed.remote} ${parsed.upstreamRef}
|
|
209
|
+
text: `Committed and pushed ${parsed.commitSha} to ${parsed.remote} ${parsed.upstreamRef}.`
|
|
210
|
+
+ (memory.file ? ` 기억 transport(${memory.file})를 함께 커밋했다.` : "")
|
|
211
|
+
+ (memory.note ? ` ${memory.note}` : ""),
|
|
172
212
|
},
|
|
173
213
|
],
|
|
174
214
|
details: parsed,
|