@gmickel/gno 1.30.7 → 1.32.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.
Files changed (71) hide show
  1. package/README.md +6 -5
  2. package/assets/skill/SKILL.md +25 -0
  3. package/assets/skill/mcp-reference.md +6 -0
  4. package/browser-extension/artifacts/{gno-browser-clipper-v1.30.7.zip → gno-browser-clipper-v1.32.0.zip} +0 -0
  5. package/browser-extension/artifacts/gno-browser-clipper-v1.32.0.zip.sha256 +1 -0
  6. package/browser-extension/dist/manifest.json +1 -1
  7. package/package.json +1 -1
  8. package/spec/cli.md +19 -0
  9. package/spec/db/schema.sql +55 -0
  10. package/spec/mcp.md +176 -11
  11. package/spec/output-schemas/file-refactor-apply-result.schema.json +305 -0
  12. package/spec/output-schemas/file-refactor-preview.schema.json +393 -0
  13. package/spec/output-schemas/section-target-create-result.schema.json +20 -0
  14. package/spec/output-schemas/section-target-resolve-result.schema.json +194 -0
  15. package/spec/output-schemas/section-target.schema.json +118 -0
  16. package/spec/output-schemas/section.schema.json +113 -0
  17. package/src/core/document-capabilities.ts +13 -0
  18. package/src/core/file-ops.ts +129 -1
  19. package/src/core/file-refactor-adapter.ts +329 -0
  20. package/src/core/file-refactor-apply-edits.ts +61 -0
  21. package/src/core/file-refactor-apply-fs.ts +512 -0
  22. package/src/core/file-refactor-apply-safety.ts +340 -0
  23. package/src/core/file-refactor-apply-validate.ts +401 -0
  24. package/src/core/file-refactor-contract.ts +486 -0
  25. package/src/core/file-refactor-destination.ts +123 -0
  26. package/src/core/file-refactor-from-snapshot.ts +148 -0
  27. package/src/core/file-refactor-journal-port.ts +150 -0
  28. package/src/core/file-refactor-journal.ts +347 -0
  29. package/src/core/file-refactor-paths.ts +60 -0
  30. package/src/core/file-refactor-plan-classify.ts +208 -0
  31. package/src/core/file-refactor-plan-validate.ts +169 -0
  32. package/src/core/file-refactor-planner-types.ts +62 -0
  33. package/src/core/file-refactor-planner.ts +423 -0
  34. package/src/core/file-refactor-resolve.ts +280 -0
  35. package/src/core/file-refactor-service.ts +468 -0
  36. package/src/core/file-refactors.ts +84 -56
  37. package/src/core/link-destination-parse.ts +275 -0
  38. package/src/core/link-inventory-markdown.ts +454 -0
  39. package/src/core/link-inventory-opaque.ts +244 -0
  40. package/src/core/link-inventory-types.ts +47 -0
  41. package/src/core/link-inventory.ts +182 -0
  42. package/src/core/link-relevance.ts +150 -0
  43. package/src/core/section-parse.ts +187 -0
  44. package/src/core/section-target-link.ts +154 -0
  45. package/src/core/section-target-resolve.ts +351 -0
  46. package/src/core/section-target-transport.ts +519 -0
  47. package/src/core/section-target.ts +263 -0
  48. package/src/core/sections.ts +60 -115
  49. package/src/mcp/AGENTS.md +1 -0
  50. package/src/mcp/CLAUDE.md +1 -0
  51. package/src/mcp/http-egress.ts +1 -0
  52. package/src/mcp/tools/index.ts +37 -17
  53. package/src/mcp/tools/sections.ts +512 -0
  54. package/src/mcp/tools/workspace-write.ts +215 -97
  55. package/src/sdk/client.ts +238 -116
  56. package/src/sdk/index.ts +12 -0
  57. package/src/sdk/types.ts +61 -3
  58. package/src/serve/file-refactor-http.ts +239 -0
  59. package/src/serve/public/components/RefactorImpactPreview.tsx +227 -0
  60. package/src/serve/public/globals.built.css +1 -1
  61. package/src/serve/public/lib/section-links.ts +189 -0
  62. package/src/serve/public/pages/DocView.tsx +395 -77
  63. package/src/serve/routes/api.ts +191 -104
  64. package/src/serve/routes/section-targets.ts +221 -0
  65. package/src/serve/server.ts +34 -0
  66. package/src/store/migrations/026-file-refactor-recovery-journal.ts +72 -0
  67. package/src/store/migrations/index.ts +2 -0
  68. package/src/store/sqlite/adapter.ts +452 -0
  69. package/src/store/sqlite/file-refactor-journal-store.ts +275 -0
  70. package/src/store/types.ts +84 -0
  71. package/browser-extension/artifacts/gno-browser-clipper-v1.30.7.zip.sha256 +0 -1
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Readable section deep links and optional citation-safe selectors.
3
+ *
4
+ * Copy-link stays human-readable (`#anchor` only). Citation links add a
5
+ * bounded, versioned `st` query param for conservative recovery.
6
+ *
7
+ * @module src/serve/public/lib/section-links
8
+ */
9
+
10
+ import {
11
+ createSectionTarget,
12
+ decodeSectionTargetLinkParam,
13
+ encodeSectionTargetLinkParam,
14
+ isNavigableSectionResolution,
15
+ resolveSectionTarget,
16
+ SECTION_TARGET_LINK_PARAM,
17
+ type SectionResolutionStatus,
18
+ type SectionTargetV1,
19
+ } from "../../../core/sections";
20
+ import { buildDocDeepLink, type DocumentDeepLinkTarget } from "./deep-links";
21
+
22
+ export interface SectionLinkTarget extends DocumentDeepLinkTarget {
23
+ /** Readable heading anchor (HTML id). */
24
+ anchor: string;
25
+ }
26
+
27
+ export type SectionLinkNoticeKind =
28
+ | "copied_link"
29
+ | "copied_citation"
30
+ | "citation_unavailable"
31
+ | "clipboard_unavailable"
32
+ | SectionResolutionStatus
33
+ | "invalid_citation";
34
+
35
+ /** Ephemeral, content-free status copy for outline/rail feedback. */
36
+ export const SECTION_LINK_NOTICE_COPY: Record<SectionLinkNoticeKind, string> = {
37
+ copied_link: "Copied section link",
38
+ copied_citation: "Copied citation link",
39
+ citation_unavailable: "Citation unavailable for this section",
40
+ clipboard_unavailable: "Could not copy link",
41
+ exact: "Exact section match",
42
+ recovered: "Section recovered",
43
+ ambiguous: "Ambiguous section link — not navigating",
44
+ stale: "Stale section link — not navigating",
45
+ missing: "Section link not found — not navigating",
46
+ invalid_citation: "Invalid section citation — not navigating",
47
+ };
48
+
49
+ /** Absolute readable section URL for human sharing (no durable selector). */
50
+ export function buildReadableSectionUrl(
51
+ origin: string,
52
+ target: SectionLinkTarget
53
+ ): string {
54
+ const path = `${buildDocDeepLink({
55
+ uri: target.uri,
56
+ view: target.view ?? "rendered",
57
+ })}#${target.anchor}`;
58
+ return `${origin}${path}`;
59
+ }
60
+
61
+ /**
62
+ * Absolute citation URL: readable `#anchor` plus bounded `st` selector.
63
+ * Returns null when a faithful bounded encoding cannot be produced.
64
+ */
65
+ export function buildCitationSectionUrl(
66
+ origin: string,
67
+ target: SectionLinkTarget,
68
+ sectionTarget: SectionTargetV1
69
+ ): string | null {
70
+ const encoded = encodeSectionTargetLinkParam(sectionTarget);
71
+ if (!encoded) {
72
+ return null;
73
+ }
74
+ const params = new URLSearchParams({ uri: target.uri });
75
+ params.set("view", target.view ?? "rendered");
76
+ params.set(SECTION_TARGET_LINK_PARAM, encoded);
77
+ return `${origin}/doc?${params.toString()}#${target.anchor}`;
78
+ }
79
+
80
+ /** Read the raw `st` query value from a location search string. */
81
+ export function readSectionTargetLinkParam(search: string): string | null {
82
+ const value = new URLSearchParams(search).get(SECTION_TARGET_LINK_PARAM);
83
+ return value && value.length > 0 ? value : null;
84
+ }
85
+
86
+ /** Strip the additive `st` param while preserving other query fields. */
87
+ export function stripSectionTargetLinkParam(search: string): string {
88
+ const params = new URLSearchParams(
89
+ search.startsWith("?") ? search.slice(1) : search
90
+ );
91
+ params.delete(SECTION_TARGET_LINK_PARAM);
92
+ const serialized = params.toString();
93
+ return serialized.length > 0 ? `?${serialized}` : "";
94
+ }
95
+
96
+ export interface ResolveSectionLinkInput {
97
+ content: string;
98
+ uri: string;
99
+ /** Raw `st` query value. */
100
+ encodedTarget: string | null;
101
+ /** Readable hash without leading `#`. */
102
+ hashAnchor: string;
103
+ }
104
+
105
+ export interface ResolveSectionLinkResult {
106
+ /** When true, hash-only scroll must not run. */
107
+ blockHashNavigation: boolean;
108
+ /** Anchor to scroll to when navigable. */
109
+ navigateAnchor: string | null;
110
+ notice: SectionLinkNoticeKind | null;
111
+ /** Drop `st` from the address bar after a successful recovery. */
112
+ cleanCitationParam: boolean;
113
+ }
114
+
115
+ /**
116
+ * Resolve an optional durable selector against current document content.
117
+ * Readable `#anchor`-only links keep legacy behavior (no block).
118
+ */
119
+ export async function resolveSectionLinkNavigation(
120
+ input: ResolveSectionLinkInput
121
+ ): Promise<ResolveSectionLinkResult> {
122
+ if (!input.encodedTarget) {
123
+ return {
124
+ blockHashNavigation: false,
125
+ navigateAnchor: input.hashAnchor || null,
126
+ notice: null,
127
+ cleanCitationParam: false,
128
+ };
129
+ }
130
+
131
+ const target = decodeSectionTargetLinkParam(input.encodedTarget);
132
+ if (!target) {
133
+ return {
134
+ blockHashNavigation: true,
135
+ navigateAnchor: null,
136
+ notice: "invalid_citation",
137
+ cleanCitationParam: false,
138
+ };
139
+ }
140
+
141
+ const resolution = await resolveSectionTarget({
142
+ content: input.content,
143
+ target,
144
+ uri: input.uri,
145
+ });
146
+
147
+ if (isNavigableSectionResolution(resolution)) {
148
+ return {
149
+ blockHashNavigation: false,
150
+ navigateAnchor: resolution.section.anchor,
151
+ notice: resolution.status,
152
+ cleanCitationParam: true,
153
+ };
154
+ }
155
+
156
+ return {
157
+ blockHashNavigation: true,
158
+ navigateAnchor: null,
159
+ notice: resolution.status,
160
+ cleanCitationParam: false,
161
+ };
162
+ }
163
+
164
+ /** Create a citation URL for an outline section using shared core create. */
165
+ export async function createCitationSectionUrl(input: {
166
+ origin: string;
167
+ uri: string;
168
+ content: string;
169
+ anchor: string;
170
+ view?: "rendered" | "source";
171
+ }): Promise<string | null> {
172
+ const target = await createSectionTarget({
173
+ content: input.content,
174
+ uri: input.uri,
175
+ anchor: input.anchor,
176
+ });
177
+ if (!target) {
178
+ return null;
179
+ }
180
+ return buildCitationSectionUrl(
181
+ input.origin,
182
+ {
183
+ uri: input.uri,
184
+ view: input.view ?? "rendered",
185
+ anchor: input.anchor,
186
+ },
187
+ target
188
+ );
189
+ }