@cleocode/cleo 2026.10.27 → 2026.11.1-canary.3
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/README.md +28 -365
- package/dist/.source-stamp.json +4 -0
- package/dist/cli/{adapter-ZIB3OAPD.js → adapter-H6LGOEXR.js} +3 -3
- package/dist/cli/{add-TBJUMJW7.js → add-JTLUT54D.js} +3 -3
- package/dist/cli/{add-batch-GGKVPTS5.js → add-batch-ZK7SIYA5.js} +3 -3
- package/dist/cli/{admin-PEYBYMZN.js → admin-AA4M7JBW.js} +15 -5
- package/dist/cli/{admin-NGPG2LSO.js → admin-EPHDAQHU.js} +3 -3
- package/dist/cli/{adr-2XVNDYZ7.js → adr-6DUCKEGZ.js} +3 -3
- package/dist/cli/{analyze-A44RDCSX.js → analyze-C7PDKTLW.js} +3 -3
- package/dist/cli/{archive-QQB6M2RF.js → archive-4XUV2TNE.js} +3 -3
- package/dist/cli/{archive-stats-K4YKKYQV.js → archive-stats-P35RNTOG.js} +3 -3
- package/dist/cli/{attention-KAHDF6KD.js → attention-CRI2XJ62.js} +3 -3
- package/dist/cli/{backup-IYFULQTM.js → backup-JMHKBESP.js} +6 -5
- package/dist/cli/{blockers-KYNJJKZQ.js → blockers-GIYEINJM.js} +3 -3
- package/dist/cli/{briefing-J6PDDZ2C.js → briefing-CS6JNKV7.js} +3 -3
- package/dist/cli/{cancel-A4OCUVDI.js → cancel-I5WG5BR4.js} +3 -3
- package/dist/cli/{chunk-SXXOC6KZ.js → canon-docs-ZXWC4AFI.js} +51 -4
- package/dist/cli/{check-HHT4J5ZM.js → check-3KDTDUNQ.js} +3 -3
- package/dist/cli/{check-ZT6O5JDS.js → check-4XUOQNLG.js} +15 -19
- package/dist/cli/{chunk-PGR4RWQL.js → chunk-2AT5ALNQ.js} +2 -2
- package/dist/cli/{chunk-TUUKU4H7.js → chunk-5AL6B3J2.js} +7 -3
- package/dist/cli/{owner-override-cap-53HYZHIL.js → chunk-6C5X2J6S.js} +3 -2
- package/dist/cli/{chunk-OIS3BDSL.js → chunk-K6I66OSL.js} +2 -2
- package/dist/cli/chunk-RYGY5LG4.js +89 -0
- package/dist/cli/{chunk-JRDAITPC.js → chunk-V3ZUZYBZ.js} +12 -12
- package/dist/cli/{claim-MFFSWD64.js → claim-XGA4LKYO.js} +3 -3
- package/dist/cli/{cli-5PJ2B6ZH.js → cli-2U6BPCPH.js} +3 -3
- package/dist/cli/{complete-2IN4YEWL.js → complete-NCS2BCZB.js} +4 -4
- package/dist/cli/{complexity-JVEIZE5M.js → complexity-KJHXAWTC.js} +3 -3
- package/dist/cli/{compliance-MC3X2M34.js → compliance-GP6P63ZI.js} +3 -3
- package/dist/cli/{conduit-XYYPJYUF.js → conduit-NJL4YUDZ.js} +3 -3
- package/dist/cli/{config-Z5BXGRZB.js → config-FMLBYCVS.js} +5 -5
- package/dist/cli/{consensus-T6UARQTD.js → consensus-ALD6ADOC.js} +3 -3
- package/dist/cli/{context-M4F3YXZE.js → context-CVZBNZUZ.js} +3 -3
- package/dist/cli/{contribution-76FJYJKR.js → contribution-YQG6IHME.js} +3 -3
- package/dist/cli/{current-EFRCVSWL.js → current-GNHA4AK3.js} +3 -3
- package/dist/cli/{daemon-UAAMDN6C.js → daemon-VGOWNKWU.js} +3 -3
- package/dist/cli/{dash-ZEBYLYPV.js → dash-EP46P2SO.js} +3 -3
- package/dist/cli/{decompose-XTK2DXSM.js → decompose-J2RHLS4P.js} +3 -3
- package/dist/cli/{decomposition-ZDACSPOU.js → decomposition-RILQKAX7.js} +3 -3
- package/dist/cli/{delete-6YZADILS.js → delete-CBMXPES6.js} +3 -3
- package/dist/cli/{deps-WTASB2GB.js → deps-GPBTDYTW.js} +3 -3
- package/dist/cli/{detect-IITE5EBW.js → detect-OGQCROVY.js} +3 -3
- package/dist/cli/{diagnostics-MFUOSLSQ.js → diagnostics-4I2JUW5R.js} +3 -3
- package/dist/cli/{docs-NF5COLOB.js → docs-MNOBMDNV.js} +148 -16
- package/dist/cli/{docs-AIZLN3ZE.js → docs-YI47KPN7.js} +150 -93
- package/dist/cli/{doctor-4DWCNDOP.js → doctor-AYEY3IAL.js} +9 -4
- package/dist/cli/{doctor-tool-locks-VXKJZKAY.js → doctor-tool-locks-3ZT2LXRY.js} +2 -2
- package/dist/cli/{canon-docs-2GTOLF7Y.js → doctor-type-matrix-DD233VK2.js} +8 -8
- package/dist/cli/{done-A7ITQSJT.js → done-TZ5KBKEY.js} +73 -5
- package/dist/cli/{export-OTDQUAQQ.js → export-2PN64KYZ.js} +3 -3
- package/dist/cli/{export-tasks-BKVXMFLD.js → export-tasks-VDM7OZG5.js} +3 -3
- package/dist/cli/{find-BWKYKZEN.js → find-5XG5EKE3.js} +3 -3
- package/dist/cli/{focus-772SYK7Z.js → focus-ZL4LN3ME.js} +3 -3
- package/dist/cli/{goal-TG74GKBK.js → goal-TIQWF5PH.js} +2 -2
- package/dist/cli/{grade-BZYBWDA7.js → grade-4Q4VAS6D.js} +3 -3
- package/dist/cli/{graph-LB2TBRH6.js → graph-T5NO6IO5.js} +3 -3
- package/dist/cli/{history-XIYAXOUF.js → history-LMP6PSUW.js} +3 -3
- package/dist/cli/{import-C2QISQC7.js → import-RDVVHET4.js} +3 -3
- package/dist/cli/{import-tasks-P6FYXAAS.js → import-tasks-GQAD4JBU.js} +3 -3
- package/dist/cli/index.js +141 -103
- package/dist/cli/{inject-EDZVSPTW.js → inject-Y4LSXMTC.js} +3 -3
- package/dist/cli/{intelligence-OE7SIVR5.js → intelligence-HCB3COXY.js} +3 -3
- package/dist/cli/{issue-S67EZXN7.js → issue-7NLECBVN.js} +3 -3
- package/dist/cli/{labels-M7GIBYAQ.js → labels-BEKX5LIS.js} +3 -3
- package/dist/cli/{lifecycle-NO5QDJ2J.js → lifecycle-NXFDMNMA.js} +3 -3
- package/dist/cli/{list-VH6DPZ4V.js → list-H4DJHDQR.js} +3 -3
- package/dist/cli/{llm-P35U52I5.js → llm-24YWOGPN.js} +3 -3
- package/dist/cli/{log-XIPOX6UM.js → log-DKATGXVT.js} +3 -3
- package/dist/cli/{manifest-A5F2YD35.js → manifest-6W3LB3O4.js} +3 -3
- package/dist/cli/{map-AOMU72RY.js → map-LQUG4G6N.js} +3 -3
- package/dist/cli/{memory-4WNZWJG7.js → memory-FQKOIV43.js} +3 -3
- package/dist/cli/{memory-GK5WDYWT.js → memory-Z47B7XNL.js} +2 -2
- package/dist/cli/{migrate-claude-mem-OTSYHYBZ.js → migrate-claude-mem-MSXQ33SR.js} +3 -3
- package/dist/cli/{next-YUZ4X7NB.js → next-OU44ZHDS.js} +3 -3
- package/dist/cli/{nexus-YHPP3RZU.js → nexus-2O3D5KBD.js} +23 -15
- package/dist/cli/{nexus-RYH4IAG3.js → nexus-X6YLFJLZ.js} +2 -2
- package/dist/cli/{ops-XPJK3WBN.js → ops-MKGFUA4I.js} +3 -3
- package/dist/cli/{orchestrate-TWV43SAR.js → orchestrate-CIYXIPWJ.js} +3 -3
- package/dist/cli/{orchestrate-AYBDAVOQ.js → orchestrate-HSYARDD4.js} +2 -2
- package/dist/cli/owner-override-cap-3B7UXQXA.js +29 -0
- package/dist/cli/{phase-CFH2NZU5.js → phase-NJDN3EIY.js} +3 -3
- package/dist/cli/{pipeline-LW5HWLBI.js → pipeline-KQGUL5BQ.js} +2 -2
- package/dist/cli/{pivot-LEBKDG22.js → pivot-K3FL4H4Z.js} +3 -3
- package/dist/cli/{plan-6VK5I4BT.js → plan-TDBKUPE6.js} +3 -3
- package/dist/cli/{playbook-4GKDYZYW.js → playbook-UF7FCJ4U.js} +3 -3
- package/dist/cli/{promote-4V4ZLAL3.js → promote-Q3A7C7GI.js} +3 -3
- package/dist/cli/{provenance-2SFRY42O.js → provenance-J7OB5YAT.js} +3 -3
- package/dist/cli/{provider-G6MBFVHR.js → provider-T37WWONR.js} +3 -3
- package/dist/cli/{reason-2AYZ6SGZ.js → reason-D6W5GCAS.js} +3 -3
- package/dist/cli/{reconcile-7CBD7AHH.js → reconcile-FK2AVHTK.js} +3 -3
- package/dist/cli/{relates-FP43JAOK.js → relates-4UYF5ZTG.js} +3 -3
- package/dist/cli/{release-NW7XHRVB.js → release-NHPX6QOO.js} +128 -3
- package/dist/cli/{release-OWPFPUQG.js → release-XT2L6BZ6.js} +80 -4
- package/dist/cli/release-authorize-IV4MF6OV.js +84 -0
- package/dist/cli/{reorder-M457CQRR.js → reorder-3WRIRG5F.js} +3 -3
- package/dist/cli/{reparent-53T6IUUS.js → reparent-OBDMBMHO.js} +3 -3
- package/dist/cli/{req-ORMMU5PV.js → req-IC66XI36.js} +3 -3
- package/dist/cli/{research-LFGCGIEP.js → research-637G66T4.js} +3 -3
- package/dist/cli/{restore-ZYRIZQUJ.js → restore-VJ6UVTFO.js} +3 -3
- package/dist/cli/review-2VXZEKW6.js +131 -0
- package/dist/cli/{roadmap-EK6LXBQ4.js → roadmap-H26JEE34.js} +3 -3
- package/dist/cli/{run-PZJCIRFD.js → run-SUK5J7SL.js} +42 -2
- package/dist/cli/{safestop-NO57J3RK.js → safestop-G5LYH3B6.js} +3 -3
- package/dist/cli/{saga-NIJMIJE5.js → saga-CPNWFLGG.js} +3 -3
- package/dist/cli/{selfimprove-6HSEV3RG.js → selfimprove-T2IZGLE5.js} +3 -3
- package/dist/cli/{selfimprove-IYKG5PF4.js → selfimprove-UI4KV3LE.js} +2 -2
- package/dist/cli/{sequence-T42KPEEQ.js → sequence-DRHAPZP5.js} +3 -3
- package/dist/cli/{service-CBEZWGHC.js → service-L3XGRXZZ.js} +3 -3
- package/dist/cli/{session-XDADM7O4.js → session-WYKXKKPM.js} +3 -3
- package/dist/cli/{session-TFVW42XK.js → session-XGFWBFKH.js} +2 -2
- package/dist/cli/{show-I2TEU6MP.js → show-244XCU7Q.js} +3 -3
- package/dist/cli/{skills-ZBYRPFRL.js → skills-V4IH2LVI.js} +3 -3
- package/dist/cli/{snapshot-GMN7LZ4A.js → snapshot-BM2YSX23.js} +3 -3
- package/dist/cli/{start-FQWDRGJE.js → start-OUWHVDCT.js} +3 -3
- package/dist/cli/{stats-D2AU77GH.js → stats-SNANUIE4.js} +3 -3
- package/dist/cli/{sticky-FKZFQYNV.js → sticky-AXOXP64I.js} +3 -3
- package/dist/cli/{stop-ZCL7RZPH.js → stop-7XU7WJZP.js} +3 -3
- package/dist/cli/{sync-WM4JLGXF.js → sync-I7D4OMS5.js} +3 -3
- package/dist/cli/{tasks-RU6AAJKD.js → tasks-S4UR3OMN.js} +2 -2
- package/dist/cli/{tasks-54WNYQZS.js → tasks-VI633MO2.js} +3 -3
- package/dist/cli/{testing-S7FCPHW5.js → testing-444KOW72.js} +3 -3
- package/dist/cli/{token-BDRGEO3E.js → token-LEAY3YMC.js} +3 -3
- package/dist/cli/{update-BD77ORMO.js → update-2FKKXUZ5.js} +3 -3
- package/dist/cli/{verify-VOJRQQE2.js → verify-FJPE666T.js} +4 -4
- package/dist/cli/{worktree-2HHJT5BS.js → worktree-MRP3XN33.js} +3 -3
- package/package.json +16 -13
- package/studio-dist/client/_app/immutable/chunks/BBz_Ewst.js +3 -0
- package/studio-dist/client/_app/immutable/chunks/{CwQ8nAoh.js → BaXJwlsi.js} +1 -1
- package/studio-dist/client/_app/immutable/chunks/CERVObi_.js +1 -0
- package/studio-dist/client/_app/immutable/chunks/{Dv66614U.js → D4A9lkPs.js} +1 -1
- package/studio-dist/client/_app/immutable/entry/{app.C2oQiIiz.js → app.BxBC-th_.js} +2 -2
- package/studio-dist/client/_app/immutable/entry/start.Dm43jY1A.js +1 -0
- package/studio-dist/client/_app/immutable/nodes/{0.DaE6eVaG.js → 0.D7Aem8uF.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{1.D0Mb3i_7.js → 1.Cf9AgcGX.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{15.ChRO-4dz.js → 15.C1O3unvk.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{16.fltF2wse.js → 16.DTsmQMdQ.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{17.DnYjMhyj.js → 17.C7L1u1QT.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{18.DYVIAC9a.js → 18.DJGn1-Wv.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{20.CVBcbjBW.js → 20.CN2uQb5o.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{24.Bfswm8Y5.js → 24.Bpbm5FXA.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/25.B91AFY13.js +39 -0
- package/studio-dist/client/_app/immutable/nodes/{26.D3RoTHoD.js → 26.3enLLx87.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{3.ezhkaJvt.js → 3.yCO3XTid.js} +1 -1
- package/studio-dist/client/_app/version.json +1 -1
- package/studio-dist/server/chunks/{0-BKQLYEeE.js → 0-DEtAbPw-.js} +3 -3
- package/studio-dist/server/chunks/1-h2LMUAHs.js +9 -0
- package/studio-dist/server/chunks/{15-DuSvkmiZ.js → 15-BiobEJ2m.js} +3 -3
- package/studio-dist/server/chunks/{16-DJVePzvS.js → 16-6xqNydr5.js} +3 -3
- package/studio-dist/server/chunks/{17-D8K9-EPJ.js → 17-DUBxUGhx.js} +3 -3
- package/studio-dist/server/chunks/{18-D5FUPGnv.js → 18-CENJ-ItU.js} +3 -3
- package/studio-dist/server/chunks/{20-CmHgNZFV.js → 20-CEgw_UdZ.js} +3 -3
- package/studio-dist/server/chunks/{24-CfuHWHgd.js → 24-6ZDsPicw.js} +3 -3
- package/studio-dist/server/chunks/{25-bm3BDSum.js → 25-Cyivs_zg.js} +207 -6
- package/studio-dist/server/chunks/{26-DRlhAbrf.js → 26-D2WIE_xK.js} +3 -3
- package/studio-dist/server/chunks/{3-BrE1-gTA.js → 3-cYpnCm5s.js} +3 -3
- package/studio-dist/server/chunks/{_layout.svelte-BeqNMCvk.js → _layout.svelte-DCokBVYx.js} +4 -4
- package/studio-dist/server/chunks/{_page.svelte-DnmZYECG.js → _page.svelte-4E3K3DKC.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-Bchzzf-O.js → _page.svelte-BHV_avWv.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-CJVF_ySt.js → _page.svelte-BKKxE82V.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-DIx7Hcw-.js → _page.svelte-BT9WBxAM.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-Ds0GMs_q.js → _page.svelte-Bk7asdHX.js} +4 -4
- package/studio-dist/server/chunks/{_page.svelte-V7BTZinR.js → _page.svelte-DG8jeXro.js} +6 -6
- package/studio-dist/server/chunks/{_page.svelte-DM-MP-Vl.js → _page.svelte-DdYeG19n.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-CkXCx1iz.js → _page.svelte-NTbWZ5Ki.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-B7xxx6BP.js → _page.svelte-QmZ5QQQz.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-DdCviCsN.js → _server.ts-B66SEpEd.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-Ck-oreiA.js → _server.ts-C1Eh35Y2.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-b2YIpIsi.js → _server.ts-C2pAmHkw.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-Cd_KHxRr.js → _server.ts-DFYxm8-q.js} +2 -2
- package/studio-dist/server/chunks/{_server.ts-YtGAClvW.js → _server.ts-DWzrbU8h.js} +3 -3
- package/studio-dist/server/chunks/{client-DR3j81J8.js → client-BHWQAkS2.js} +2 -2
- package/studio-dist/server/chunks/{error.svelte-NY-X_Qdt.js → error.svelte-IFrcuYEO.js} +3 -3
- package/studio-dist/server/chunks/{http-Dz72j56i.js → http-BkrDO_qh.js} +2 -2
- package/studio-dist/server/chunks/{internal-y7btLoII.js → internal-DftpbYWE.js} +2 -2
- package/studio-dist/server/chunks/{operations-registry-DKEHmggR.js → operations-registry-zTLuSrVZ.js} +194 -1
- package/studio-dist/server/chunks/{stores-Cm-Qj76R.js → stores-BW6MI1eb.js} +2 -2
- package/studio-dist/server/index.js +1 -1
- package/studio-dist/server/manifest.js +17 -17
- package/studio-dist/client/_app/immutable/chunks/BXnpxR_0.js +0 -1
- package/studio-dist/client/_app/immutable/chunks/Js_lZuOv.js +0 -3
- package/studio-dist/client/_app/immutable/entry/start.BolRa540.js +0 -1
- package/studio-dist/client/_app/immutable/nodes/25.B_7VqHJ6.js +0 -39
- package/studio-dist/server/chunks/1-ClOr3JN3.js +0 -9
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
})();
|
|
16
16
|
import {
|
|
17
17
|
lazyOperation
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-V3ZUZYBZ.js";
|
|
19
19
|
import {
|
|
20
20
|
defineTypedHandler,
|
|
21
21
|
lafsError,
|
|
@@ -29,13 +29,14 @@ import {
|
|
|
29
29
|
} from "./chunk-XD25OCUE.js";
|
|
30
30
|
|
|
31
31
|
// packages/cleo/src/dispatch/domains/docs.ts
|
|
32
|
-
import { randomUUID } from "node:crypto";
|
|
32
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
33
33
|
import { readFile } from "node:fs/promises";
|
|
34
34
|
import { join, resolve } from "node:path";
|
|
35
35
|
import { DocKindRegistry } from "@cleocode/contracts/docs-taxonomy.js";
|
|
36
36
|
import { ExitCode } from "@cleocode/contracts/exit-codes.js";
|
|
37
37
|
import { LLM_OUTPUT_MODES } from "@cleocode/contracts/operations/docs";
|
|
38
38
|
import { parseChangesetFrontmatter } from "@cleocode/core/changesets/parse-frontmatter";
|
|
39
|
+
import { resolveInvokingCheckout } from "@cleocode/core/core-paths";
|
|
39
40
|
import { readAuditLog, verifyAuditTrail, writeAuditEntry } from "@cleocode/core/docs/docs-audit";
|
|
40
41
|
import { createDocsReadModel } from "@cleocode/core/docs/docs-read-model";
|
|
41
42
|
import {
|
|
@@ -75,6 +76,12 @@ var allocateAdrSlug = lazyOperation(
|
|
|
75
76
|
var allocateAutoSlugForDispatch = lazyOperation(
|
|
76
77
|
async () => (await import("@cleocode/core/docs/numbering")).allocateAutoSlugForDispatch
|
|
77
78
|
);
|
|
79
|
+
var docNameViolation = lazyOperation(
|
|
80
|
+
async () => (await import("@cleocode/core/docs/doc-name-rule")).docNameViolation
|
|
81
|
+
);
|
|
82
|
+
var describeDocNameViolation = lazyOperation(
|
|
83
|
+
async () => (await import("@cleocode/core/docs/doc-name-rule")).describeDocNameViolation
|
|
84
|
+
);
|
|
78
85
|
var exportDocument = lazyOperation(
|
|
79
86
|
async () => (await import("@cleocode/core/docs/export-document")).exportDocument
|
|
80
87
|
);
|
|
@@ -130,6 +137,12 @@ var triageDocs = lazyOperation(
|
|
|
130
137
|
var computeDocsStats = lazyOperation(
|
|
131
138
|
async () => (await import("@cleocode/core/docs/stats")).computeDocsStats
|
|
132
139
|
);
|
|
140
|
+
var runDocsModernize = lazyOperation(
|
|
141
|
+
async () => (await import("@cleocode/core/docs/modernize/index")).runDocsModernize
|
|
142
|
+
);
|
|
143
|
+
var scanDocsRot = lazyOperation(
|
|
144
|
+
async () => (await import("@cleocode/core/docs/rot")).scanDocsRot
|
|
145
|
+
);
|
|
133
146
|
var runLegacyDocMigration = lazyOperation(
|
|
134
147
|
async () => (await import("@cleocode/core/docs/legacy-doc-migration")).runLegacyDocMigration
|
|
135
148
|
);
|
|
@@ -284,12 +297,9 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
284
297
|
const model = createDocsReadModel();
|
|
285
298
|
const backend = await currentAttachmentBackend();
|
|
286
299
|
if (isProjectScope) {
|
|
287
|
-
const docs = await model.listProjectDocs({
|
|
288
|
-
kind: typeFilter,
|
|
289
|
-
limit: Number.isFinite(effectiveLimit) ? effectiveLimit : void 0
|
|
290
|
-
});
|
|
300
|
+
const docs = await model.listProjectDocs({ kind: typeFilter });
|
|
291
301
|
const totalCount = docs.length;
|
|
292
|
-
const
|
|
302
|
+
const allProjected = docs.map((doc) => ({
|
|
293
303
|
id: doc.id,
|
|
294
304
|
// Full content hash — a SHA-256 field in a machine envelope must be the
|
|
295
305
|
// real digest, never a display-truncated form (T11294: the per-doc
|
|
@@ -312,12 +322,13 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
312
322
|
ownerId: doc.ownerId,
|
|
313
323
|
ownerType: doc.ownerType
|
|
314
324
|
}));
|
|
315
|
-
|
|
325
|
+
allProjected.sort(
|
|
316
326
|
(a, b) => comparator(
|
|
317
327
|
{ sha256: a.sha256, slug: a.slug, createdAt: a.createdAt },
|
|
318
328
|
{ sha256: b.sha256, slug: b.slug, createdAt: b.createdAt }
|
|
319
329
|
)
|
|
320
330
|
);
|
|
331
|
+
const projected = Number.isFinite(effectiveLimit) ? allProjected.slice(0, effectiveLimit) : allProjected;
|
|
321
332
|
const truncated = totalCount > projected.length;
|
|
322
333
|
if (truncated) {
|
|
323
334
|
hintParts.push(
|
|
@@ -332,6 +343,12 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
332
343
|
...typeFilter !== void 0 ? { type: typeFilter } : {},
|
|
333
344
|
count: projected.length,
|
|
334
345
|
...truncated ? { totalCount } : {},
|
|
346
|
+
population: {
|
|
347
|
+
matched: totalCount,
|
|
348
|
+
returned: projected.length,
|
|
349
|
+
truncated,
|
|
350
|
+
limit: Number.isFinite(effectiveLimit) ? effectiveLimit : null
|
|
351
|
+
},
|
|
335
352
|
limit: Number.isFinite(effectiveLimit) ? effectiveLimit : 0,
|
|
336
353
|
orderBy,
|
|
337
354
|
...hintParts.length > 0 ? { hint: hintParts.join(" ") } : {},
|
|
@@ -381,6 +398,12 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
381
398
|
...typeFilter !== void 0 ? { type: typeFilter } : {},
|
|
382
399
|
count: slicedOwner.length,
|
|
383
400
|
...truncatedOwner ? { totalCount: totalCountOwner } : {},
|
|
401
|
+
population: {
|
|
402
|
+
matched: totalCountOwner,
|
|
403
|
+
returned: slicedOwner.length,
|
|
404
|
+
truncated: truncatedOwner,
|
|
405
|
+
limit: Number.isFinite(effectiveLimit) ? effectiveLimit : null
|
|
406
|
+
},
|
|
384
407
|
limit: Number.isFinite(effectiveLimit) ? effectiveLimit : 0,
|
|
385
408
|
orderBy,
|
|
386
409
|
...hintParts.length > 0 ? { hint: hintParts.join(" ") } : {},
|
|
@@ -572,7 +595,12 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
572
595
|
apply,
|
|
573
596
|
repair,
|
|
574
597
|
...params.olderThanDays !== void 0 ? { olderThanDays: params.olderThanDays } : {},
|
|
575
|
-
...
|
|
598
|
+
...typeof params.only === "string" ? {
|
|
599
|
+
only: params.only.split(",").map((c) => c.trim()).filter((c) => c.length > 0)
|
|
600
|
+
} : {},
|
|
601
|
+
...backupReceiptPath !== void 0 ? { backupReceiptPath } : {},
|
|
602
|
+
// T14188: mirrors and git come from the invoking checkout.
|
|
603
|
+
checkoutRoot: resolveInvokingCheckout()
|
|
576
604
|
});
|
|
577
605
|
if (!result.ok) {
|
|
578
606
|
return lafsError(result.error.code, result.error.message, "doctor");
|
|
@@ -616,6 +644,33 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
616
644
|
"migrate"
|
|
617
645
|
);
|
|
618
646
|
},
|
|
647
|
+
// ── docs.modernize (T14113 — messy docs folder → linked CleoDocs) ─────────
|
|
648
|
+
modernize: async (params) => {
|
|
649
|
+
let result;
|
|
650
|
+
try {
|
|
651
|
+
result = await runDocsModernize(
|
|
652
|
+
getProjectRoot(),
|
|
653
|
+
{
|
|
654
|
+
...params,
|
|
655
|
+
exclude: params.exclude?.split(",").map((e) => e.trim()).filter(Boolean)
|
|
656
|
+
},
|
|
657
|
+
// T14188: the folder and plan files are the invoking checkout's.
|
|
658
|
+
{ checkoutRoot: resolveInvokingCheckout() }
|
|
659
|
+
);
|
|
660
|
+
} catch (err) {
|
|
661
|
+
const code = err instanceof Error && "code" in err ? String(err.code) : "";
|
|
662
|
+
if (!code.startsWith("E_MODERNIZE")) throw err;
|
|
663
|
+
return lafsError(
|
|
664
|
+
code,
|
|
665
|
+
// @sync-invariant none:input-shape a stale plan, missing root or unknown receipt is refused; the receipt holds any earlier step
|
|
666
|
+
err instanceof Error ? err.message : code,
|
|
667
|
+
"modernize"
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
const counts = result.plan?.counts;
|
|
671
|
+
const summary = result.mode === "rollback" ? `rolled back ${result.receipt?.runId} (${result.receipt?.ops.length ?? 0} steps reversed)` : (result.plan?.mode === "store" ? `${result.plan.storeRows?.length ?? 0} stored docs to re-kind or re-slug` : `${result.plan?.rows.length ?? 0} files: ${counts?.keep ?? 0} keep, ${counts?.rename ?? 0} rename, ${counts?.["merge-into"] ?? 0} merge, ${counts?.delete ?? 0} delete, ${result.plan?.linkFixes?.length ?? 0} link-fix in kept files`) + (result.receipt ? `; applied as ${result.receipt.runId} (${result.receipt.ops.length} steps, ${result.receipt.edgeCount} graph edges)` : "; dry run, nothing written");
|
|
672
|
+
return lafsSuccess({ ...result, summary }, "modernize");
|
|
673
|
+
},
|
|
619
674
|
// ── docs.add ───────────────────────────────────────────────────────────────
|
|
620
675
|
add: async (params) => {
|
|
621
676
|
const {
|
|
@@ -629,7 +684,8 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
629
684
|
slug: rawSlug,
|
|
630
685
|
title: rawTitle,
|
|
631
686
|
type: rawType,
|
|
632
|
-
strict: strictMode
|
|
687
|
+
strict: strictMode,
|
|
688
|
+
newBecause
|
|
633
689
|
} = params;
|
|
634
690
|
if (!ownerId) {
|
|
635
691
|
return lafsError("E_INVALID_INPUT", "ownerId is required", "add");
|
|
@@ -841,6 +897,71 @@ var _docsTypedHandler = defineTypedHandler("docs", {
|
|
|
841
897
|
);
|
|
842
898
|
}
|
|
843
899
|
}
|
|
900
|
+
if (slug !== void 0) {
|
|
901
|
+
const nameCheck = await docNameViolation(slug, type);
|
|
902
|
+
if (nameCheck !== null) {
|
|
903
|
+
if (adrNumber !== void 0) releaseReservedSlug(slug);
|
|
904
|
+
return lafsError(
|
|
905
|
+
"E_DOC_NAME_RULE",
|
|
906
|
+
// @sync-invariant none:input-shape a slug that breaks the doc naming rule is refused before anything is written
|
|
907
|
+
await describeDocNameViolation(slug, nameCheck),
|
|
908
|
+
"add",
|
|
909
|
+
`cleo docs add ... --slug ${nameCheck.suggestion}`,
|
|
910
|
+
{ suggestion: nameCheck.suggestion, reasons: nameCheck.reasons }
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
{
|
|
915
|
+
const reason = typeof newBecause === "string" ? newBecause.trim() : void 0;
|
|
916
|
+
const dup = await import("@cleocode/core/docs/duplicate-check");
|
|
917
|
+
if (reason !== void 0 && reason.length < dup.NEW_BECAUSE_MIN_LENGTH) {
|
|
918
|
+
if (adrNumber !== void 0 && slug !== void 0) releaseReservedSlug(slug);
|
|
919
|
+
return lafsError(
|
|
920
|
+
"E_INVALID_INPUT",
|
|
921
|
+
// @sync-invariant none:input-shape a too-short --new-because reason is refused before anything is written
|
|
922
|
+
`--new-because needs a reason of at least ${dup.NEW_BECAUSE_MIN_LENGTH} characters saying why this is not an existing doc`,
|
|
923
|
+
"add"
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
const bytes = typeof inlineContent === "string" ? Buffer.from(inlineContent, "utf-8") : filePath ? await readFile(resolve(String(filePath))).catch(() => null) : null;
|
|
927
|
+
const text = bytes?.toString("utf-8");
|
|
928
|
+
const title = (typeof rawTitle === "string" && rawTitle.trim() ? rawTitle : null) ?? (text ? dup.markdownTitle(text) : null);
|
|
929
|
+
const match = type === void 0 ? null : dup.findDuplicateDoc(
|
|
930
|
+
{
|
|
931
|
+
...slug !== void 0 ? { slug } : {},
|
|
932
|
+
...type !== void 0 ? { kind: type } : {},
|
|
933
|
+
...title !== null ? { title } : {},
|
|
934
|
+
...text !== void 0 ? { content: text } : {},
|
|
935
|
+
...bytes ? { sha256: createHash("sha256").update(bytes).digest("hex") } : {}
|
|
936
|
+
},
|
|
937
|
+
await dup.loadDuplicateCandidates(projectRoot, { kind: type }),
|
|
938
|
+
await dup.readDuplicateThresholds(projectRoot)
|
|
939
|
+
);
|
|
940
|
+
if (match && reason === void 0) {
|
|
941
|
+
if (adrNumber !== void 0 && slug !== void 0) releaseReservedSlug(slug);
|
|
942
|
+
const { message, fix } = dup.describeDuplicate(match);
|
|
943
|
+
return lafsError(
|
|
944
|
+
"E_DOC_DUPLICATE",
|
|
945
|
+
// @sync-invariant none:input-shape a likely duplicate doc is refused before anything is written
|
|
946
|
+
message,
|
|
947
|
+
"add",
|
|
948
|
+
fix,
|
|
949
|
+
{
|
|
950
|
+
existing: { slug: match.slug, kind: match.kind, title: match.title },
|
|
951
|
+
rule: match.rule,
|
|
952
|
+
score: match.score
|
|
953
|
+
}
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
if (match && reason !== void 0) {
|
|
957
|
+
await dup.recordNewBecause(projectRoot, {
|
|
958
|
+
slug: slug ?? null,
|
|
959
|
+
kind: type ?? null,
|
|
960
|
+
resembles: match,
|
|
961
|
+
reason
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
}
|
|
844
965
|
if (slug !== void 0 && adrNumber === void 0) {
|
|
845
966
|
const reservation = await reserveSlugForDispatch(projectRoot, {
|
|
846
967
|
kind: type ?? "",
|
|
@@ -1541,7 +1662,8 @@ var QUERY_OPS = /* @__PURE__ */ new Set([
|
|
|
1541
1662
|
"audit",
|
|
1542
1663
|
"doctor",
|
|
1543
1664
|
"triage",
|
|
1544
|
-
"stats"
|
|
1665
|
+
"stats",
|
|
1666
|
+
"rot"
|
|
1545
1667
|
]);
|
|
1546
1668
|
var MUTATE_OPS = /* @__PURE__ */ new Set([
|
|
1547
1669
|
"add",
|
|
@@ -1555,7 +1677,8 @@ var MUTATE_OPS = /* @__PURE__ */ new Set([
|
|
|
1555
1677
|
"sync",
|
|
1556
1678
|
"import",
|
|
1557
1679
|
"doctor",
|
|
1558
|
-
"migrate"
|
|
1680
|
+
"migrate",
|
|
1681
|
+
"modernize"
|
|
1559
1682
|
]);
|
|
1560
1683
|
async function dispatchDocsLegacyQuery(operation, params) {
|
|
1561
1684
|
const projectRoot = getProjectRoot();
|
|
@@ -1614,7 +1737,7 @@ async function dispatchDocsLegacyQuery(operation, params) {
|
|
|
1614
1737
|
return readAuditLog(projectRoot, params["slug"]);
|
|
1615
1738
|
case "status": {
|
|
1616
1739
|
const model = createDocsReadModel();
|
|
1617
|
-
return model.status(projectRoot);
|
|
1740
|
+
return model.status(projectRoot, resolveInvokingCheckout());
|
|
1618
1741
|
}
|
|
1619
1742
|
case "triage":
|
|
1620
1743
|
return triageDocs({
|
|
@@ -1625,6 +1748,11 @@ async function dispatchDocsLegacyQuery(operation, params) {
|
|
|
1625
1748
|
});
|
|
1626
1749
|
case "stats":
|
|
1627
1750
|
return computeDocsStats({ projectRoot });
|
|
1751
|
+
case "rot":
|
|
1752
|
+
return scanDocsRot({
|
|
1753
|
+
projectRoot: resolveInvokingCheckout(),
|
|
1754
|
+
...typeof params["changed"] === "string" ? { changed: params["changed"] } : {}
|
|
1755
|
+
});
|
|
1628
1756
|
default:
|
|
1629
1757
|
throw new Error(`Unsupported docs query operation: ${operation}`);
|
|
1630
1758
|
}
|
|
@@ -1645,6 +1773,8 @@ async function dispatchDocsLegacyMutate(operation, params) {
|
|
|
1645
1773
|
toPath: String(params["toPath"]),
|
|
1646
1774
|
attachmentId: typeof params["attachmentId"] === "string" ? params["attachmentId"] : void 0,
|
|
1647
1775
|
projectRoot,
|
|
1776
|
+
// T14135: run from a canonical CLEO worktree, a relative --to lands in it.
|
|
1777
|
+
cwd: process.cwd(),
|
|
1648
1778
|
// T13919: a dry run runs the real checks and writes nothing.
|
|
1649
1779
|
...params["dryRun"] === true ? { dryRun: true } : {}
|
|
1650
1780
|
});
|
|
@@ -1855,7 +1985,8 @@ var DocsHandler = class {
|
|
|
1855
1985
|
"audit",
|
|
1856
1986
|
"doctor",
|
|
1857
1987
|
"triage",
|
|
1858
|
-
"stats"
|
|
1988
|
+
"stats",
|
|
1989
|
+
"rot"
|
|
1859
1990
|
],
|
|
1860
1991
|
mutate: [
|
|
1861
1992
|
"add",
|
|
@@ -1869,7 +2000,8 @@ var DocsHandler = class {
|
|
|
1869
2000
|
"sync",
|
|
1870
2001
|
"import",
|
|
1871
2002
|
"doctor",
|
|
1872
|
-
"migrate"
|
|
2003
|
+
"migrate",
|
|
2004
|
+
"modernize"
|
|
1873
2005
|
]
|
|
1874
2006
|
};
|
|
1875
2007
|
}
|
|
@@ -1877,4 +2009,4 @@ var DocsHandler = class {
|
|
|
1877
2009
|
export {
|
|
1878
2010
|
DocsHandler
|
|
1879
2011
|
};
|
|
1880
|
-
//# sourceMappingURL=docs-
|
|
2012
|
+
//# sourceMappingURL=docs-MNOBMDNV.js.map
|
|
@@ -25,14 +25,11 @@ import {
|
|
|
25
25
|
dispatchFromCli,
|
|
26
26
|
dispatchRaw,
|
|
27
27
|
handleRawError
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-K6I66OSL.js";
|
|
29
29
|
import "./chunk-6N6WGLXE.js";
|
|
30
30
|
import {
|
|
31
31
|
resolve
|
|
32
32
|
} from "./chunk-4VASFLUW.js";
|
|
33
|
-
import {
|
|
34
|
-
loadCanonRegistry
|
|
35
|
-
} from "./chunk-SXXOC6KZ.js";
|
|
36
33
|
import {
|
|
37
34
|
UnknownFlagError,
|
|
38
35
|
assertKnownFlags
|
|
@@ -49,11 +46,11 @@ import {
|
|
|
49
46
|
} from "./chunk-ESI6Q4OS.js";
|
|
50
47
|
import "./chunk-6JSJNYH2.js";
|
|
51
48
|
import "./chunk-D7BAQNV2.js";
|
|
52
|
-
import "./chunk-
|
|
49
|
+
import "./chunk-V3ZUZYBZ.js";
|
|
53
50
|
|
|
54
51
|
// packages/cleo/src/cli/commands/docs.ts
|
|
55
52
|
import { existsSync } from "node:fs";
|
|
56
|
-
import {
|
|
53
|
+
import { mkdir as mkdir3, readdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
57
54
|
import { dirname as dirname3, isAbsolute, join as join4, resolve as resolve3 } from "node:path";
|
|
58
55
|
import {
|
|
59
56
|
DocKindConfigError,
|
|
@@ -67,11 +64,6 @@ import {
|
|
|
67
64
|
resolveWorktreeRouting
|
|
68
65
|
} from "@cleocode/core/core-paths";
|
|
69
66
|
import { createDocsReadModel } from "@cleocode/core/docs/docs-read-model";
|
|
70
|
-
import {
|
|
71
|
-
checkSlugSimilarity,
|
|
72
|
-
DEFAULT_SIMILARITY_MODE,
|
|
73
|
-
DEFAULT_SIMILARITY_THRESHOLD
|
|
74
|
-
} from "@cleocode/core/docs/similarity-check";
|
|
75
67
|
import { CleoError as CleoError2 } from "@cleocode/core/errors";
|
|
76
68
|
import { pushWarning } from "@cleocode/core/output";
|
|
77
69
|
import { getProjectRoot as getProjectRoot3 } from "@cleocode/core/project-scope";
|
|
@@ -291,6 +283,118 @@ var migrateCommand = defineCommand({
|
|
|
291
283
|
}
|
|
292
284
|
});
|
|
293
285
|
|
|
286
|
+
// packages/cleo/src/cli/commands/docs/modernize.ts
|
|
287
|
+
var modernizeCommand = defineCommand({
|
|
288
|
+
meta: {
|
|
289
|
+
name: "modernize",
|
|
290
|
+
description: "Turn a messy docs folder into clean, linked CleoDocs (T14113). Dry run by default: per file a kind, a stable slug (no task, session or date tokens) and keep/rename/merge-into/delete with reasons; ambiguous classify and merge calls go to System One (cleo decide) with a rule fallback. --apply stores docs, merges duplicates, records supersession, moves files and writes wikilink edges, with a receipt under .cleo/modernize/; --rollback <runId> reverses a run."
|
|
291
|
+
},
|
|
292
|
+
args: {
|
|
293
|
+
path: {
|
|
294
|
+
type: "positional",
|
|
295
|
+
description: "Folder to modernize (required unless --rollback or --plan)",
|
|
296
|
+
required: false
|
|
297
|
+
},
|
|
298
|
+
apply: {
|
|
299
|
+
type: "boolean",
|
|
300
|
+
description: "Execute the plan (default: dry run, nothing written)"
|
|
301
|
+
},
|
|
302
|
+
plan: {
|
|
303
|
+
type: "string",
|
|
304
|
+
description: "Apply this saved plan JSON verbatim (with --apply)"
|
|
305
|
+
},
|
|
306
|
+
out: {
|
|
307
|
+
type: "string",
|
|
308
|
+
description: "Save the plan JSON to this path for review"
|
|
309
|
+
},
|
|
310
|
+
rollback: {
|
|
311
|
+
type: "string",
|
|
312
|
+
description: "Roll back the apply run with this id (from the receipt)"
|
|
313
|
+
},
|
|
314
|
+
exclude: {
|
|
315
|
+
type: "string",
|
|
316
|
+
description: "Extra folder names to skip, comma-separated"
|
|
317
|
+
},
|
|
318
|
+
overrides: {
|
|
319
|
+
type: "string",
|
|
320
|
+
description: "Reviewer decisions JSON keyed by path; they win over rules and System One"
|
|
321
|
+
},
|
|
322
|
+
kind: {
|
|
323
|
+
type: "string",
|
|
324
|
+
description: "Use this kind for every file instead of classifying (bulk ingest)"
|
|
325
|
+
},
|
|
326
|
+
wikilinks: {
|
|
327
|
+
type: "boolean",
|
|
328
|
+
description: "Rewrite relative links to planned docs as [[slug]] wikilinks (default: keep markdown links that render on GitHub, re-pointed at the new paths)"
|
|
329
|
+
},
|
|
330
|
+
"allow-dirty": {
|
|
331
|
+
type: "boolean",
|
|
332
|
+
description: "Apply even when the root is not a clean git checkout (default: refuse)"
|
|
333
|
+
},
|
|
334
|
+
store: {
|
|
335
|
+
type: "boolean",
|
|
336
|
+
description: "Modernize the docs already in the store: re-kind, re-slug (old slugs stay as aliases), renumber colliding ADRs"
|
|
337
|
+
},
|
|
338
|
+
"store-only": {
|
|
339
|
+
type: "boolean",
|
|
340
|
+
description: "Ingest every file into the store (task-owned) and leave the folder untouched"
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
async run({ args }) {
|
|
344
|
+
await dispatchFromCli(
|
|
345
|
+
"mutate",
|
|
346
|
+
"docs",
|
|
347
|
+
"modernize",
|
|
348
|
+
{
|
|
349
|
+
...typeof args.path === "string" ? { path: args.path } : {},
|
|
350
|
+
apply: args.apply === true,
|
|
351
|
+
...typeof args.plan === "string" ? { planFile: args.plan } : {},
|
|
352
|
+
...typeof args.out === "string" ? { out: args.out } : {},
|
|
353
|
+
...typeof args.rollback === "string" ? { rollback: args.rollback } : {},
|
|
354
|
+
...typeof args.exclude === "string" ? { exclude: args.exclude } : {},
|
|
355
|
+
...typeof args.overrides === "string" ? { overrides: args.overrides } : {},
|
|
356
|
+
...typeof args.kind === "string" ? { kind: args.kind } : {},
|
|
357
|
+
storeOnly: args["store-only"] === true,
|
|
358
|
+
allowDirty: args["allow-dirty"] === true,
|
|
359
|
+
wikilinks: args.wikilinks === true,
|
|
360
|
+
store: args.store === true
|
|
361
|
+
},
|
|
362
|
+
{ command: "docs modernize" }
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// packages/cleo/src/cli/commands/docs/rot.ts
|
|
368
|
+
var rotCommand = defineCommand({
|
|
369
|
+
meta: {
|
|
370
|
+
name: "rot",
|
|
371
|
+
description: "Docs-rot report from git alone (T14111): docs whose covers: code changed after them (stale), duplicate docs, and orphaned docs (dead covers globs, unreferenced docs/ files). --changed <base>..<head> also lists the docs a merged change left stale; --strict exits 2 on any finding."
|
|
372
|
+
},
|
|
373
|
+
args: {
|
|
374
|
+
changed: {
|
|
375
|
+
type: "string",
|
|
376
|
+
description: "Git range <base>..<head> of a merged change to flag docs for"
|
|
377
|
+
},
|
|
378
|
+
strict: {
|
|
379
|
+
type: "boolean",
|
|
380
|
+
description: "Exit 2 when the report finds stale, duplicate, orphaned or flagged docs"
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
async run({ args }) {
|
|
384
|
+
const params = typeof args.changed === "string" ? { changed: args.changed } : {};
|
|
385
|
+
if (args.strict !== true) {
|
|
386
|
+
await dispatchFromCli("query", "docs", "rot", params, { command: "docs rot" });
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const response = await dispatchRaw("query", "docs", "rot", params);
|
|
390
|
+
handleRawError(response, { command: "docs rot", operation: "docs.rot" });
|
|
391
|
+
const report = response.data;
|
|
392
|
+
cliOutput(report, { command: "docs rot", message: report.summary });
|
|
393
|
+
const findings = report.stale.length + report.duplicates.length + report.orphans.length + report.flagged.length;
|
|
394
|
+
if (findings > 0) process.exit(2);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
|
|
294
398
|
// packages/cleo/src/cli/commands/docs/set-alias.ts
|
|
295
399
|
import { ExitCode as ExitCode3 } from "@cleocode/contracts/exit-codes.js";
|
|
296
400
|
import { setDisplayAlias } from "@cleocode/core/docs/display-alias";
|
|
@@ -1272,7 +1376,7 @@ async function runGapCheck(_projectRoot, filterId) {
|
|
|
1272
1376
|
var addCommand = defineCommand({
|
|
1273
1377
|
meta: {
|
|
1274
1378
|
name: "add",
|
|
1275
|
-
description: 'Usage: cleo docs add <OWNER-ID> [<file>] [--content <text> | --url <url>] [--slug <kebab>] [--type <kind>]\n OWNER-ID is the FIRST positional; the file is the SECOND. Examples:\n cleo docs add T123 ./docs/rfc.md --slug my-rfc --type spec\n cleo docs add T123 --content "# Note" --slug my-note\n\nAttach a local file or remote URL to a CLEO entity (task, session, observation). Owner type is inferred from the ID prefix: T### \u2192 task, ses_* \u2192 session, O-* \u2192 observation. Use --slug to set a human-friendly alias (unique per project) (T9636).\n\nPositional arguments:\n <owner-id> Owner entity ID (T###, ses_*, O-*) \u2014 required\n [file] Local file path to attach \u2014 optional when --url/--content is set\n\nNamed arguments:\n --url <url> Remote URL to attach (instead of a local file)\n --content <text> Inline document body \u2014 author without a file (T10965); \'-\' reads stdin\n --desc <text> Free-text description of this attachment\n --labels <csv> Comma-separated labels (e.g. rfc,spec)\n --attached-by <name> Agent identity that created the attachment (default: "human")\n --slug <kebab> Human-friendly alias, unique per project (T9636)\n --title <text> Human-readable title \u2014 REQUIRED for --type adr when --slug is omitted (T10360)\n --type <kind> Taxonomy classification \u2014 run `cleo docs schema` for kinds\n --
|
|
1379
|
+
description: 'Usage: cleo docs add <OWNER-ID> [<file>] [--content <text> | --url <url>] [--slug <kebab>] [--type <kind>]\n OWNER-ID is the FIRST positional; the file is the SECOND. Examples:\n cleo docs add T123 ./docs/rfc.md --slug my-rfc --type spec\n cleo docs add T123 --content "# Note" --slug my-note\n\nAttach a local file or remote URL to a CLEO entity (task, session, observation). Owner type is inferred from the ID prefix: T### \u2192 task, ses_* \u2192 session, O-* \u2192 observation. Use --slug to set a human-friendly alias (unique per project) (T9636).\n\nPositional arguments:\n <owner-id> Owner entity ID (T###, ses_*, O-*) \u2014 required\n [file] Local file path to attach \u2014 optional when --url/--content is set\n\nNamed arguments:\n --url <url> Remote URL to attach (instead of a local file)\n --content <text> Inline document body \u2014 author without a file (T10965); \'-\' reads stdin\n --desc <text> Free-text description of this attachment\n --labels <csv> Comma-separated labels (e.g. rfc,spec)\n --attached-by <name> Agent identity that created the attachment (default: "human")\n --slug <kebab> Human-friendly alias, unique per project (T9636)\n --title <text> Human-readable title \u2014 REQUIRED for --type adr when --slug is omitted (T10360)\n --type <kind> Taxonomy classification \u2014 run `cleo docs schema` for kinds\n --new-because <why> Add a doc that resembles an existing one; the reason is\n recorded in .cleo/audit/docs-new-because.jsonl (T14109)\n --strict Enforce body-schema (requiredSections) \u2014 fail with\n E_DOC_SCHEMA_MISMATCH instead of warning (T10160)\n' + docsOutputFlagHelp + "\n\nValidation behaviors:\n \u2022 Unknown flags \u2192 E_UNKNOWN_FLAG with did-you-mean suggestions (T10359)\n \u2022 Slug collision \u2192 E_SLUG_RESERVED + 3 alternative slugs (T10386)\n \u2022 Likely duplicate (same content, or similar slug, title or text) \u2192 E_DOC_DUPLICATE,\n naming the existing doc, `cleo docs fetch <slug>` and `cleo docs update <slug>`,\n unless --new-because <why> (T14109)\n \u2022 For --type adr without --slug, slug auto-allocates as `adr-NNN-<kebab-title>` via the\n central allocator (T10360 \u2014 closes T10153). --title is required in this case."
|
|
1276
1380
|
},
|
|
1277
1381
|
args: {
|
|
1278
1382
|
"owner-id": {
|
|
@@ -1317,9 +1421,13 @@ var addCommand = defineCommand({
|
|
|
1317
1421
|
type: "string",
|
|
1318
1422
|
description: "Taxonomy classification \u2014 run `cleo docs schema` to enumerate registered kinds (T9637 / T9788 / T11142)"
|
|
1319
1423
|
},
|
|
1424
|
+
"new-because": {
|
|
1425
|
+
type: "string",
|
|
1426
|
+
description: "Why this doc is new although it resembles an existing one (T14109). A likely duplicate (same content, or a similar slug, title or text) is refused with E_DOC_DUPLICATE and routed to `cleo docs update <slug>` unless this states the reason (15+ characters); the reason is recorded in .cleo/audit/docs-new-because.jsonl."
|
|
1427
|
+
},
|
|
1320
1428
|
"allow-similar": {
|
|
1321
1429
|
type: "boolean",
|
|
1322
|
-
description: "
|
|
1430
|
+
description: "Deprecated (T14109): needs --new-because <reason>, which is what lets a likely duplicate through."
|
|
1323
1431
|
},
|
|
1324
1432
|
strict: {
|
|
1325
1433
|
type: "boolean",
|
|
@@ -1399,83 +1507,17 @@ var addCommand = defineCommand({
|
|
|
1399
1507
|
process.exit(ExitCode6.FILE_ERROR);
|
|
1400
1508
|
}
|
|
1401
1509
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
mode = canon.similarity.mode;
|
|
1411
|
-
}
|
|
1412
|
-
} catch {
|
|
1413
|
-
}
|
|
1414
|
-
try {
|
|
1415
|
-
const sim = await checkSlugSimilarity({
|
|
1416
|
-
slug: args.slug,
|
|
1417
|
-
type: args.type,
|
|
1418
|
-
projectRoot,
|
|
1419
|
-
threshold: warnThreshold
|
|
1420
|
-
});
|
|
1421
|
-
if (sim.mostSimilarSlug !== null) {
|
|
1422
|
-
const scoreFixed = sim.score.toFixed(2);
|
|
1423
|
-
const hint = `Similar to '${sim.mostSimilarSlug}' (score ${scoreFixed}) \u2014 did you mean: cleo docs update ${sim.mostSimilarSlug}? Pass --allow-similar to bypass.`;
|
|
1424
|
-
if (mode === "block" && !allowSimilar) {
|
|
1425
|
-
cliError(hint, ExitCode6.VALIDATION_ERROR, {
|
|
1426
|
-
name: "E_SLUG_SIMILARITY",
|
|
1427
|
-
fix: `Use \`cleo docs update ${sim.mostSimilarSlug}\` if updating, or pass --allow-similar to add as a new doc.`,
|
|
1428
|
-
alternatives: [
|
|
1429
|
-
{
|
|
1430
|
-
action: `update '${sim.mostSimilarSlug}' instead`,
|
|
1431
|
-
command: `cleo docs update ${sim.mostSimilarSlug}`
|
|
1432
|
-
},
|
|
1433
|
-
{
|
|
1434
|
-
action: "bypass the similarity check",
|
|
1435
|
-
command: `cleo docs add ${ownerId} ${fileArg ?? `--url ${url}`} --slug ${args.slug} --type ${args.type} --allow-similar`
|
|
1436
|
-
}
|
|
1437
|
-
],
|
|
1438
|
-
details: {
|
|
1439
|
-
proposedSlug: args.slug,
|
|
1440
|
-
mostSimilarSlug: sim.mostSimilarSlug,
|
|
1441
|
-
score: sim.score,
|
|
1442
|
-
threshold: warnThreshold,
|
|
1443
|
-
kind: args.type
|
|
1444
|
-
}
|
|
1445
|
-
});
|
|
1446
|
-
process.exit(ExitCode6.VALIDATION_ERROR);
|
|
1447
|
-
}
|
|
1448
|
-
humanInfo(hint);
|
|
1449
|
-
if (allowSimilar) {
|
|
1450
|
-
const auditLine = `${JSON.stringify({
|
|
1451
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1452
|
-
reason: "allow-similar-bypass",
|
|
1453
|
-
proposedSlug: args.slug,
|
|
1454
|
-
mostSimilarSlug: sim.mostSimilarSlug,
|
|
1455
|
-
score: sim.score,
|
|
1456
|
-
threshold: warnThreshold,
|
|
1457
|
-
kind: args.type,
|
|
1458
|
-
ownerId
|
|
1459
|
-
})}
|
|
1460
|
-
`;
|
|
1461
|
-
try {
|
|
1462
|
-
await mkdir3(join4(projectRoot, ".cleo", "audit"), { recursive: true });
|
|
1463
|
-
await appendFile(
|
|
1464
|
-
join4(projectRoot, ".cleo", "audit", "similar-bypass.jsonl"),
|
|
1465
|
-
auditLine,
|
|
1466
|
-
"utf-8"
|
|
1467
|
-
);
|
|
1468
|
-
} catch {
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
} catch (err) {
|
|
1473
|
-
if (process.env["CLEO_DEBUG"]) {
|
|
1474
|
-
humanInfo(
|
|
1475
|
-
`similarity check skipped: ${err instanceof Error ? err.message : String(err)}`
|
|
1476
|
-
);
|
|
1510
|
+
const newBecause = args["new-because"];
|
|
1511
|
+
if (allowSimilar && typeof newBecause !== "string") {
|
|
1512
|
+
cliError(
|
|
1513
|
+
"--allow-similar no longer bypasses the duplicate check on its own; say why this doc is new",
|
|
1514
|
+
6,
|
|
1515
|
+
{
|
|
1516
|
+
name: "E_VALIDATION",
|
|
1517
|
+
fix: 'Pass --new-because "<why this is not the existing doc>" (recorded in .cleo/audit/docs-new-because.jsonl), or update the existing doc with cleo docs update <slug>.'
|
|
1477
1518
|
}
|
|
1478
|
-
|
|
1519
|
+
);
|
|
1520
|
+
process.exit(6);
|
|
1479
1521
|
}
|
|
1480
1522
|
await dispatchFromCli(
|
|
1481
1523
|
"mutate",
|
|
@@ -1492,7 +1534,8 @@ var addCommand = defineCommand({
|
|
|
1492
1534
|
...args.slug ? { slug: args.slug } : {},
|
|
1493
1535
|
...args.title ? { title: args.title } : {},
|
|
1494
1536
|
...args.type ? { type: args.type } : {},
|
|
1495
|
-
...args.strict === true ? { strict: true } : {}
|
|
1537
|
+
...args.strict === true ? { strict: true } : {},
|
|
1538
|
+
...typeof newBecause === "string" ? { newBecause } : {}
|
|
1496
1539
|
},
|
|
1497
1540
|
{ command: "docs add" }
|
|
1498
1541
|
);
|
|
@@ -2562,7 +2605,7 @@ function parseOlderThanDays(raw) {
|
|
|
2562
2605
|
var doctorCommand = defineCommand({
|
|
2563
2606
|
meta: {
|
|
2564
2607
|
name: "doctor",
|
|
2565
|
-
description: "Docs store health diagnostics + safe repairs: dangling local-file pointers, docVersion skew vs the audit log, empty topics/related_tasks provenance, docs_wikilinks drift, legacy store surfaces, blob-store coverage, stale drafts. Dry-run by default; --apply executes repairs (a fresh backup is created automatically first); --repair runs only the hash-verified legacy-bytes \u2192 blob-store backfill (T13653)."
|
|
2608
|
+
description: "Docs store health diagnostics + safe repairs: dangling local-file pointers, docVersion skew vs the audit log, empty topics/related_tasks provenance, docs_wikilinks drift, legacy store surfaces, blob-store coverage, stale drafts, publication-ledger drift (rows whose mirror is gone or stale; T14117). Dry-run by default; --apply executes repairs (a fresh backup is created automatically first); --repair runs only the hash-verified legacy-bytes \u2192 blob-store backfill (T13653); --only <class,\u2026> scopes the plan and --apply to those repair classes (T14174)."
|
|
2566
2609
|
},
|
|
2567
2610
|
args: {
|
|
2568
2611
|
apply: {
|
|
@@ -2577,17 +2620,27 @@ var doctorCommand = defineCommand({
|
|
|
2577
2620
|
type: "string",
|
|
2578
2621
|
description: "Age threshold in days for the stale-drafts check (default 30)"
|
|
2579
2622
|
},
|
|
2623
|
+
only: {
|
|
2624
|
+
type: "string",
|
|
2625
|
+
description: "Comma-separated repair classes to plan and apply (T14174): dangling-pointers, doc-version-skew, empty-provenance, wikilinks-drift, legacy-blob-coverage, conduit-history-gaps, publication-ledger-drift. Other classes are left untouched."
|
|
2626
|
+
},
|
|
2580
2627
|
...docsOutputArgs
|
|
2581
2628
|
},
|
|
2582
2629
|
async run({ args }) {
|
|
2583
2630
|
const apply = args.apply === true;
|
|
2584
2631
|
const repair = args.repair === true;
|
|
2585
2632
|
const olderThanDays = parseOlderThanDays(args["older-than-days"]);
|
|
2633
|
+
const only = typeof args.only === "string" ? args.only : void 0;
|
|
2586
2634
|
await dispatchFromCli(
|
|
2587
2635
|
apply || repair ? "mutate" : "query",
|
|
2588
2636
|
"docs",
|
|
2589
2637
|
"doctor",
|
|
2590
|
-
{
|
|
2638
|
+
{
|
|
2639
|
+
apply,
|
|
2640
|
+
repair,
|
|
2641
|
+
...olderThanDays !== void 0 ? { olderThanDays } : {},
|
|
2642
|
+
...only !== void 0 ? { only } : {}
|
|
2643
|
+
},
|
|
2591
2644
|
{ command: "docs doctor" }
|
|
2592
2645
|
);
|
|
2593
2646
|
}
|
|
@@ -2875,8 +2928,12 @@ var docsCommand = defineCommand({
|
|
|
2875
2928
|
triage: triageCommand,
|
|
2876
2929
|
// T13363 — docs.stats adoption metrics (read-only)
|
|
2877
2930
|
stats: statsCommand,
|
|
2931
|
+
// T14111 — docs.rot stale/duplicate/orphaned report (read-only, git only)
|
|
2932
|
+
rot: rotCommand,
|
|
2878
2933
|
// T13360 — docs.migrate legacy docs import (harness-bracketed, idempotent)
|
|
2879
2934
|
migrate: migrateCommand,
|
|
2935
|
+
// T14113 — docs.modernize (dry run / apply / rollback)
|
|
2936
|
+
modernize: modernizeCommand,
|
|
2880
2937
|
// Drift status — agent-facing, kept per cleodocs-rearch-design §6 (T13361 retired gap-check only)
|
|
2881
2938
|
status: statusCommand,
|
|
2882
2939
|
// T9645 reingest — retained: the docs-reingest workflow invokes `docs sync --from/--for/--name`
|
|
@@ -2897,4 +2954,4 @@ export {
|
|
|
2897
2954
|
_llmOutputCommand,
|
|
2898
2955
|
docsCommand
|
|
2899
2956
|
};
|
|
2900
|
-
//# sourceMappingURL=docs-
|
|
2957
|
+
//# sourceMappingURL=docs-YI47KPN7.js.map
|