@openspecui/core 3.5.2 → 3.6.1

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 (50) hide show
  1. package/dist/hosted-app.d.mts +1 -1
  2. package/dist/hosted-app.mjs +1 -1
  3. package/dist/index.d.mts +74 -632
  4. package/dist/index.mjs +81 -97
  5. package/dist/markdown-facts-BmSmZmpB.mjs +136 -0
  6. package/dist/markdown-facts-f3kXnqXb.d.mts +39 -0
  7. package/dist/markdown-facts.d.mts +2 -0
  8. package/dist/markdown-facts.mjs +3 -0
  9. package/dist/markdown-reading-CrchEfoW.mjs +104 -0
  10. package/dist/markdown-reading-D36W693c.d.mts +74 -0
  11. package/dist/markdown-reading.d.mts +3 -0
  12. package/dist/markdown-reading.mjs +4 -0
  13. package/dist/{notifications-BWvRNkRJ.d.mts → notifications-CCV2bgWG.d.mts} +9 -9
  14. package/dist/{notifications-F81mmO55.mjs → notifications-fD-V5hyP.mjs} +2 -2
  15. package/dist/notifications.d.mts +2 -2
  16. package/dist/notifications.mjs +3 -3
  17. package/dist/openspec-annotations-BMy9nWUe.mjs +436 -0
  18. package/dist/openspec-annotations-CJmYcfAu.d.mts +30 -0
  19. package/dist/openspec-annotations.d.mts +4 -0
  20. package/dist/openspec-annotations.mjs +5 -0
  21. package/dist/openspec-projection-DWqBxedv.mjs +223 -0
  22. package/dist/openspec-projection-DmB448No.d.mts +1142 -0
  23. package/dist/openspec-projection.d.mts +5 -0
  24. package/dist/openspec-projection.mjs +6 -0
  25. package/dist/opsx-display-path.d.mts +1 -1
  26. package/dist/opsx-display-path.mjs +1 -1
  27. package/dist/{sounds-Bw-sSyFZ.d.mts → sounds-B0sH3QwE.d.mts} +5 -5
  28. package/dist/sounds.d.mts +1 -1
  29. package/dist/sounds.mjs +1 -1
  30. package/dist/{terminal-audio-DDwxz9sJ.mjs → terminal-audio-UEv3j655.mjs} +1 -1
  31. package/dist/{terminal-audio-8E82E0AM.d.mts → terminal-audio-qSc6nZUI.d.mts} +2 -2
  32. package/dist/terminal-audio.d.mts +2 -2
  33. package/dist/terminal-audio.mjs +2 -2
  34. package/dist/terminal-control.d.mts +2 -2
  35. package/dist/terminal-control.mjs +1 -1
  36. package/dist/{terminal-invocation-CpdllJff.d.mts → terminal-invocation-BCqjtd4p.d.mts} +36 -36
  37. package/dist/terminal-invocation.d.mts +1 -1
  38. package/dist/terminal-invocation.mjs +1 -1
  39. package/dist/terminal-theme.d.mts +1 -1
  40. package/dist/terminal-theme.mjs +1 -1
  41. package/package.json +25 -3
  42. /package/dist/{hosted-app-CIOJpbzc.mjs → hosted-app-DFFffbJc.mjs} +0 -0
  43. /package/dist/{hosted-app-DaGUbBJn.d.mts → hosted-app-DZrYivji.d.mts} +0 -0
  44. /package/dist/{opsx-display-path-CuQyGB_A.d.mts → opsx-display-path-CkV9sq_j.d.mts} +0 -0
  45. /package/dist/{opsx-display-path-B6Owu17P.mjs → opsx-display-path-D4KLYRXQ.mjs} +0 -0
  46. /package/dist/{sounds-C0dNSFm8.mjs → sounds-BzNKMW05.mjs} +0 -0
  47. /package/dist/{terminal-control-DtBprY6-.mjs → terminal-control-Bxois59k.mjs} +0 -0
  48. /package/dist/{terminal-invocation-Cdi6_Kl6.mjs → terminal-invocation-BRCuSBjE.mjs} +0 -0
  49. /package/dist/{terminal-theme-CMQqJvIQ.mjs → terminal-theme-CIv3YMfi.mjs} +0 -0
  50. /package/dist/{terminal-theme-wbkK9vVH.d.mts → terminal-theme-lPZGfVA_.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- import { x as SoundId } from "./sounds-Bw-sSyFZ.mjs";
1
+ import { x as SoundId } from "./sounds-B0sH3QwE.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/terminal-control.d.ts
@@ -54,18 +54,18 @@ declare function terminalNotificationEventToPublishInput(input: {
54
54
  //#endregion
55
55
  //#region src/notifications.d.ts
56
56
  declare const NOTIFICATION_SOUND_VALUES: readonly ["silent", "soft", "clear", "pulse"];
57
- declare const NotificationSoundSchema: z.ZodEffects<z.ZodUnion<[z.ZodLiteral<"silent">, z.ZodEnum<["builtin:Basso", "builtin:Blow", "builtin:Bottle", "builtin:Frog", "builtin:Funk", "builtin:Glass", "builtin:Hero", "builtin:Morse", "builtin:Ping", "builtin:Pop", "builtin:Purr", "builtin:Sosumi", "builtin:Submarine", "builtin:Tink"]>, z.ZodType<`custom:${string}`, z.ZodTypeDef, `custom:${string}`>]>, "silent" | "builtin:Basso" | "builtin:Blow" | "builtin:Bottle" | "builtin:Frog" | "builtin:Funk" | "builtin:Glass" | "builtin:Hero" | "builtin:Morse" | "builtin:Ping" | "builtin:Pop" | "builtin:Purr" | "builtin:Sosumi" | "builtin:Submarine" | "builtin:Tink" | `custom:${string}`, unknown>;
57
+ declare const NotificationSoundSchema: z.ZodEffects<z.ZodUnion<[z.ZodLiteral<"silent">, z.ZodEnum<["builtin:Basso", "builtin:Blow", "builtin:Bottle", "builtin:Frog", "builtin:Funk", "builtin:Glass", "builtin:Hero", "builtin:Morse", "builtin:Ping", "builtin:Pop", "builtin:Purr", "builtin:Sosumi", "builtin:Submarine", "builtin:Tink"]>, z.ZodType<`custom:${string}`, z.ZodTypeDef, `custom:${string}`>]>, "silent" | "builtin:Tink" | "builtin:Blow" | "builtin:Basso" | "builtin:Bottle" | "builtin:Frog" | "builtin:Funk" | "builtin:Glass" | "builtin:Hero" | "builtin:Morse" | "builtin:Ping" | "builtin:Pop" | "builtin:Purr" | "builtin:Sosumi" | "builtin:Submarine" | `custom:${string}`, unknown>;
58
58
  type NotificationSound = SoundId;
59
59
  declare const NOTIFICATION_SOUND_OPTIONS: readonly {
60
60
  id: NotificationSound;
61
61
  label: string;
62
62
  }[];
63
63
  declare const NotificationSettingsSchema: z.ZodObject<{
64
- sound: z.ZodDefault<z.ZodEffects<z.ZodUnion<[z.ZodLiteral<"silent">, z.ZodEnum<["builtin:Basso", "builtin:Blow", "builtin:Bottle", "builtin:Frog", "builtin:Funk", "builtin:Glass", "builtin:Hero", "builtin:Morse", "builtin:Ping", "builtin:Pop", "builtin:Purr", "builtin:Sosumi", "builtin:Submarine", "builtin:Tink"]>, z.ZodType<`custom:${string}`, z.ZodTypeDef, `custom:${string}`>]>, "silent" | "builtin:Basso" | "builtin:Blow" | "builtin:Bottle" | "builtin:Frog" | "builtin:Funk" | "builtin:Glass" | "builtin:Hero" | "builtin:Morse" | "builtin:Ping" | "builtin:Pop" | "builtin:Purr" | "builtin:Sosumi" | "builtin:Submarine" | "builtin:Tink" | `custom:${string}`, unknown>>;
64
+ sound: z.ZodDefault<z.ZodEffects<z.ZodUnion<[z.ZodLiteral<"silent">, z.ZodEnum<["builtin:Basso", "builtin:Blow", "builtin:Bottle", "builtin:Frog", "builtin:Funk", "builtin:Glass", "builtin:Hero", "builtin:Morse", "builtin:Ping", "builtin:Pop", "builtin:Purr", "builtin:Sosumi", "builtin:Submarine", "builtin:Tink"]>, z.ZodType<`custom:${string}`, z.ZodTypeDef, `custom:${string}`>]>, "silent" | "builtin:Tink" | "builtin:Blow" | "builtin:Basso" | "builtin:Bottle" | "builtin:Frog" | "builtin:Funk" | "builtin:Glass" | "builtin:Hero" | "builtin:Morse" | "builtin:Ping" | "builtin:Pop" | "builtin:Purr" | "builtin:Sosumi" | "builtin:Submarine" | `custom:${string}`, unknown>>;
65
65
  volume: z.ZodDefault<z.ZodNumber>;
66
66
  systemNotificationsEnabled: z.ZodDefault<z.ZodBoolean>;
67
67
  }, "strip", z.ZodTypeAny, {
68
- sound: "silent" | "builtin:Basso" | "builtin:Blow" | "builtin:Bottle" | "builtin:Frog" | "builtin:Funk" | "builtin:Glass" | "builtin:Hero" | "builtin:Morse" | "builtin:Ping" | "builtin:Pop" | "builtin:Purr" | "builtin:Sosumi" | "builtin:Submarine" | "builtin:Tink" | `custom:${string}`;
68
+ sound: "silent" | "builtin:Tink" | "builtin:Blow" | "builtin:Basso" | "builtin:Bottle" | "builtin:Frog" | "builtin:Funk" | "builtin:Glass" | "builtin:Hero" | "builtin:Morse" | "builtin:Ping" | "builtin:Pop" | "builtin:Purr" | "builtin:Sosumi" | "builtin:Submarine" | `custom:${string}`;
69
69
  volume: number;
70
70
  systemNotificationsEnabled: boolean;
71
71
  }, {
@@ -325,6 +325,7 @@ declare const NotificationPublishInputSchema: z.ZodObject<{
325
325
  groupId: string;
326
326
  title?: string | undefined;
327
327
  };
328
+ createdAt?: number | undefined;
328
329
  body?: string | undefined;
329
330
  actions?: ({
330
331
  type: "terminal.focus";
@@ -340,7 +341,6 @@ declare const NotificationPublishInputSchema: z.ZodObject<{
340
341
  label?: string | undefined;
341
342
  })[] | undefined;
342
343
  level?: "info" | "success" | "warning" | "error" | undefined;
343
- createdAt?: number | undefined;
344
344
  }>;
345
345
  type NotificationPublishInput = z.infer<typeof NotificationPublishInputSchema>;
346
346
  declare const NotificationRecordSchema: z.ZodObject<{
@@ -446,6 +446,8 @@ declare const NotificationRecordSchema: z.ZodObject<{
446
446
  createdAt: z.ZodNumber;
447
447
  groupKey: z.ZodString;
448
448
  }, "strip", z.ZodTypeAny, {
449
+ id: string;
450
+ createdAt: number;
449
451
  title: string;
450
452
  body: string;
451
453
  source: {
@@ -479,10 +481,10 @@ declare const NotificationRecordSchema: z.ZodObject<{
479
481
  };
480
482
  })[];
481
483
  level: "info" | "success" | "warning" | "error";
482
- createdAt: number;
483
- id: string;
484
484
  groupKey: string;
485
485
  }, {
486
+ id: string;
487
+ createdAt: number;
486
488
  title: string;
487
489
  source: {
488
490
  type: "terminal";
@@ -501,8 +503,6 @@ declare const NotificationRecordSchema: z.ZodObject<{
501
503
  groupId: string;
502
504
  title?: string | undefined;
503
505
  };
504
- createdAt: number;
505
- id: string;
506
506
  groupKey: string;
507
507
  body?: string | undefined;
508
508
  actions?: ({
@@ -1,5 +1,5 @@
1
- import { g as SoundVolumeSchema, m as SoundConfigIdSchema, u as DEFAULT_NOTIFICATION_SOUND_ID } from "./sounds-C0dNSFm8.mjs";
2
- import { t as TerminalControlParser } from "./terminal-control-DtBprY6-.mjs";
1
+ import { g as SoundVolumeSchema, m as SoundConfigIdSchema, u as DEFAULT_NOTIFICATION_SOUND_ID } from "./sounds-BzNKMW05.mjs";
2
+ import { t as TerminalControlParser } from "./terminal-control-Bxois59k.mjs";
3
3
  import { z } from "zod";
4
4
 
5
5
  //#region src/notifications.ts
@@ -1,3 +1,3 @@
1
- import "./sounds-Bw-sSyFZ.mjs";
2
- import { C as getNotificationAggregateKey, E as groupNotifications, P as terminalNotificationEventToPublishInput, S as aggregateNotifications, T as getNotificationGroupLabel, _ as NotificationSource, a as NotificationAggregate, b as TerminalNotificationParseResult, c as NotificationGroupKeySchema, d as NotificationRecord, f as NotificationRecordSchema, g as NotificationSoundSchema, h as NotificationSound, i as NotificationActionSchema, k as TerminalControlParser, l as NotificationPublishInput, m as NotificationSettingsSchema, n as NOTIFICATION_SOUND_VALUES, o as NotificationGroup, p as NotificationSettings, r as NotificationAction, s as NotificationGroupKey, t as NOTIFICATION_SOUND_OPTIONS, u as NotificationPublishInputSchema, v as NotificationSourceSchema, w as getNotificationGroupKey, x as TerminalNotificationParser, y as TerminalNotificationEvent } from "./notifications-BWvRNkRJ.mjs";
1
+ import "./sounds-B0sH3QwE.mjs";
2
+ import { C as getNotificationAggregateKey, E as groupNotifications, P as terminalNotificationEventToPublishInput, S as aggregateNotifications, T as getNotificationGroupLabel, _ as NotificationSource, a as NotificationAggregate, b as TerminalNotificationParseResult, c as NotificationGroupKeySchema, d as NotificationRecord, f as NotificationRecordSchema, g as NotificationSoundSchema, h as NotificationSound, i as NotificationActionSchema, k as TerminalControlParser, l as NotificationPublishInput, m as NotificationSettingsSchema, n as NOTIFICATION_SOUND_VALUES, o as NotificationGroup, p as NotificationSettings, r as NotificationAction, s as NotificationGroupKey, t as NOTIFICATION_SOUND_OPTIONS, u as NotificationPublishInputSchema, v as NotificationSourceSchema, w as getNotificationGroupKey, x as TerminalNotificationParser, y as TerminalNotificationEvent } from "./notifications-CCV2bgWG.mjs";
3
3
  export { NOTIFICATION_SOUND_OPTIONS, NOTIFICATION_SOUND_VALUES, NotificationAction, NotificationActionSchema, NotificationAggregate, NotificationGroup, NotificationGroupKey, NotificationGroupKeySchema, NotificationPublishInput, NotificationPublishInputSchema, NotificationRecord, NotificationRecordSchema, NotificationSettings, NotificationSettingsSchema, NotificationSound, NotificationSoundSchema, NotificationSource, NotificationSourceSchema, TerminalControlParser, TerminalNotificationEvent, TerminalNotificationParseResult, TerminalNotificationParser, aggregateNotifications, getNotificationAggregateKey, getNotificationGroupKey, getNotificationGroupLabel, groupNotifications, terminalNotificationEventToPublishInput };
@@ -1,5 +1,5 @@
1
- import "./sounds-C0dNSFm8.mjs";
2
- import { n as terminalNotificationEventToPublishInput, t as TerminalControlParser } from "./terminal-control-DtBprY6-.mjs";
3
- import { a as NotificationPublishInputSchema, c as NotificationSoundSchema, d as aggregateNotifications, f as getNotificationAggregateKey, h as groupNotifications, i as NotificationGroupKeySchema, l as NotificationSourceSchema, m as getNotificationGroupLabel, n as NOTIFICATION_SOUND_VALUES, o as NotificationRecordSchema, p as getNotificationGroupKey, r as NotificationActionSchema, s as NotificationSettingsSchema, t as NOTIFICATION_SOUND_OPTIONS, u as TerminalNotificationParser } from "./notifications-F81mmO55.mjs";
1
+ import "./sounds-BzNKMW05.mjs";
2
+ import { n as terminalNotificationEventToPublishInput, t as TerminalControlParser } from "./terminal-control-Bxois59k.mjs";
3
+ import { a as NotificationPublishInputSchema, c as NotificationSoundSchema, d as aggregateNotifications, f as getNotificationAggregateKey, h as groupNotifications, i as NotificationGroupKeySchema, l as NotificationSourceSchema, m as getNotificationGroupLabel, n as NOTIFICATION_SOUND_VALUES, o as NotificationRecordSchema, p as getNotificationGroupKey, r as NotificationActionSchema, s as NotificationSettingsSchema, t as NOTIFICATION_SOUND_OPTIONS, u as TerminalNotificationParser } from "./notifications-fD-V5hyP.mjs";
4
4
 
5
5
  export { NOTIFICATION_SOUND_OPTIONS, NOTIFICATION_SOUND_VALUES, NotificationActionSchema, NotificationGroupKeySchema, NotificationPublishInputSchema, NotificationRecordSchema, NotificationSettingsSchema, NotificationSoundSchema, NotificationSourceSchema, TerminalControlParser, TerminalNotificationParser, aggregateNotifications, getNotificationAggregateKey, getNotificationGroupKey, getNotificationGroupLabel, groupNotifications, terminalNotificationEventToPublishInput };
@@ -0,0 +1,436 @@
1
+ import { t as parseMarkdownFacts } from "./markdown-facts-BmSmZmpB.mjs";
2
+ import { c as getMarkdownHeadingFacts, o as getMarkdownFactSpan, r as createMarkdownReadingDocumentFromFacts, s as getMarkdownHeadingEnd } from "./markdown-reading-CrchEfoW.mjs";
3
+
4
+ //#region src/openspec-annotations.ts
5
+ const OPEN_SPEC_ANNOTATION_RULES = {
6
+ documentTitle: "openspec.heading.document-title.v2",
7
+ purposeSection: "openspec.heading.purpose-section.v2",
8
+ requirementsSection: "openspec.heading.requirements-section.v2",
9
+ requirementPrefix: "openspec.heading.requirement-prefix.v2",
10
+ requirementUnderSection: "openspec.heading.requirement-under-section.v2",
11
+ requirementCapabilityPrefix: "openspec.heading.capability-prefix.v2",
12
+ requirementCapabilityText: "openspec.heading.capability-text.v2",
13
+ scenarioPrefix: "openspec.heading.scenario-prefix.v2",
14
+ scenarioExamplePrefix: "openspec.heading.example-prefix.v2",
15
+ scenarioStepHeading: "openspec.heading.step-backed-scenario.v2",
16
+ scenarioStep: "openspec.list-item.scenario-step.v2",
17
+ keyword: "openspec.inline.keyword.v2"
18
+ };
19
+ const REQUIREMENT_PREFIX_PATTERN = /^(?:Requirement|Capability):\s*/i;
20
+ const SCENARIO_PREFIX_PATTERN = /^(?:Scenario|Example):\s*/i;
21
+ const SCENARIO_STEP_KEYWORDS = [
22
+ "GIVEN",
23
+ "WHEN",
24
+ "THEN",
25
+ "AND",
26
+ "BUT"
27
+ ];
28
+ const REQUIREMENT_KEYWORD_PATTERN = new RegExp(`\\b(${[
29
+ "SHALL",
30
+ "MUST",
31
+ "SHOULD",
32
+ "MAY"
33
+ ].join("|")})\\b`, "g");
34
+ const SCENARIO_STEP_PATTERN = new RegExp(`^\\s*(?:[-*+]\\s+)?(?:\\[[ xX]\\]\\s+)?(?:\\*\\*)?(${SCENARIO_STEP_KEYWORDS.join("|")})\\b(?:\\*\\*)?\\s*:?\\s*(.+?)\\s*$`, "i");
35
+ const REQUIREMENT_SECTION_TERMS = [
36
+ "requirement",
37
+ "specification",
38
+ "capability",
39
+ "capabilities"
40
+ ];
41
+ const PURPOSE_SECTION_TERMS = [
42
+ "purpose",
43
+ "overview",
44
+ "objective",
45
+ "goal",
46
+ "goals"
47
+ ];
48
+ const REQUIREMENT_BODY_SIGNAL_PATTERN = /\b(SHALL|MUST|SHOULD|MAY|CAN|WILL)\b/i;
49
+ const NON_SCENARIO_HEADING_PATTERN = /^(notes?|details?|rationale|reason|migration|examples?|open questions?)$/i;
50
+ const openSpecAnnotationRules = [
51
+ {
52
+ id: OPEN_SPEC_ANNOTATION_RULES.documentTitle,
53
+ annotate(context) {
54
+ return context.facts.flatMap((fact) => {
55
+ if (fact.kind !== "heading" || fact.depth !== 1) return [];
56
+ return [{
57
+ kind: "document-title",
58
+ targetFactId: fact.id,
59
+ confidence: "strong",
60
+ metadata: { title: fact.text }
61
+ }];
62
+ });
63
+ }
64
+ },
65
+ {
66
+ id: OPEN_SPEC_ANNOTATION_RULES.purposeSection,
67
+ annotate(context) {
68
+ return context.facts.flatMap((fact) => {
69
+ if (fact.kind !== "heading" || fact.depth !== 2) return [];
70
+ if (!matchesAnyTerm(fact.text, PURPOSE_SECTION_TERMS)) return [];
71
+ return [{
72
+ kind: "purpose-section",
73
+ targetFactId: fact.id,
74
+ confidence: isExactTerm(fact.text, ["Purpose", "Overview"]) ? "strong" : "weak",
75
+ metadata: { title: fact.text }
76
+ }];
77
+ });
78
+ }
79
+ },
80
+ {
81
+ id: OPEN_SPEC_ANNOTATION_RULES.requirementsSection,
82
+ annotate(context) {
83
+ return context.facts.flatMap((fact) => {
84
+ if (fact.kind !== "heading" || fact.depth !== 2) return [];
85
+ if (!matchesAnyTerm(fact.text, REQUIREMENT_SECTION_TERMS)) return [];
86
+ return [{
87
+ kind: "requirements-section",
88
+ targetFactId: fact.id,
89
+ confidence: fact.text.toLowerCase().includes("requirement") ? "strong" : "weak",
90
+ metadata: { title: fact.text }
91
+ }];
92
+ });
93
+ }
94
+ },
95
+ {
96
+ id: OPEN_SPEC_ANNOTATION_RULES.requirementPrefix,
97
+ annotate(context) {
98
+ return context.facts.flatMap((fact) => {
99
+ if (fact.kind !== "heading" || fact.depth !== 3) return [];
100
+ if (!/^Requirement:\s*/i.test(fact.text)) return [];
101
+ return [createRequirementAnnotation(fact, "strong")];
102
+ });
103
+ }
104
+ },
105
+ {
106
+ id: OPEN_SPEC_ANNOTATION_RULES.requirementCapabilityPrefix,
107
+ annotate(context) {
108
+ return context.facts.flatMap((fact) => {
109
+ if (fact.kind !== "heading" || fact.depth !== 3) return [];
110
+ if (!/^Capability:\s*/i.test(fact.text)) return [];
111
+ return [createRequirementAnnotation(fact, "weak")];
112
+ });
113
+ }
114
+ },
115
+ {
116
+ id: OPEN_SPEC_ANNOTATION_RULES.requirementUnderSection,
117
+ annotate(context) {
118
+ return getRequirementSections(context).flatMap((section) => {
119
+ return getChildHeadings(context, section, 3).flatMap((fact) => {
120
+ if (context.getAnnotation(fact.id, "requirement")) return [];
121
+ if (REQUIREMENT_PREFIX_PATTERN.test(fact.text)) return [];
122
+ if (!hasRequirementBodySignals(context, fact, section.end)) return [];
123
+ return [{
124
+ kind: "requirement",
125
+ targetFactId: fact.id,
126
+ confidence: "weak",
127
+ metadata: { title: fact.text }
128
+ }];
129
+ });
130
+ });
131
+ }
132
+ },
133
+ {
134
+ id: OPEN_SPEC_ANNOTATION_RULES.requirementCapabilityText,
135
+ annotate(context) {
136
+ return getRequirementSections(context).flatMap((section) => {
137
+ return getChildHeadings(context, section, 3).flatMap((fact) => {
138
+ if (context.getAnnotation(fact.id, "requirement")) return [];
139
+ if (!matchesAnyTerm(fact.text, [
140
+ "capability",
141
+ "feature",
142
+ "behavior"
143
+ ])) return [];
144
+ return [{
145
+ kind: "requirement",
146
+ targetFactId: fact.id,
147
+ confidence: "weak",
148
+ metadata: { title: stripRequirementPrefix(fact.text) || fact.text }
149
+ }];
150
+ });
151
+ });
152
+ }
153
+ },
154
+ {
155
+ id: OPEN_SPEC_ANNOTATION_RULES.scenarioPrefix,
156
+ annotate(context) {
157
+ return getRequirementHeadings(context).flatMap((requirement) => {
158
+ return getNestedHeadings(context, requirement).flatMap((fact) => {
159
+ if (fact.depth !== 4 || !/^Scenario:\s*/i.test(fact.text)) return [];
160
+ return [createScenarioAnnotation(fact, "strong")];
161
+ });
162
+ });
163
+ }
164
+ },
165
+ {
166
+ id: OPEN_SPEC_ANNOTATION_RULES.scenarioExamplePrefix,
167
+ annotate(context) {
168
+ return getRequirementHeadings(context).flatMap((requirement) => {
169
+ return getNestedHeadings(context, requirement).flatMap((fact) => {
170
+ if (fact.depth !== 4 || !/^Example:\s*/i.test(fact.text)) return [];
171
+ return [createScenarioAnnotation(fact, "weak")];
172
+ });
173
+ });
174
+ }
175
+ },
176
+ {
177
+ id: OPEN_SPEC_ANNOTATION_RULES.scenarioStepHeading,
178
+ annotate(context) {
179
+ return getRequirementHeadings(context).flatMap((requirement) => {
180
+ return getNestedHeadings(context, requirement).flatMap((fact) => {
181
+ if (fact.depth !== 4) return [];
182
+ if (context.getAnnotation(fact.id, "scenario")) return [];
183
+ if (NON_SCENARIO_HEADING_PATTERN.test(fact.text)) return [];
184
+ if (!hasScenarioStepSignals(context, fact)) return [];
185
+ return [{
186
+ kind: "scenario",
187
+ targetFactId: fact.id,
188
+ confidence: "weak",
189
+ metadata: { title: stripScenarioPrefix(fact.text) || fact.text }
190
+ }];
191
+ });
192
+ });
193
+ }
194
+ },
195
+ {
196
+ id: OPEN_SPEC_ANNOTATION_RULES.scenarioStep,
197
+ annotate(context) {
198
+ const scenarioSections = getScenarioSections(context);
199
+ return context.facts.flatMap((fact) => {
200
+ if (fact.kind !== "listItem") return [];
201
+ if (!isWithinAnySection(fact, scenarioSections)) return [];
202
+ const metadata = parseScenarioStepFact(fact);
203
+ if (!metadata) return [];
204
+ return [{
205
+ kind: "scenario-step",
206
+ targetFactId: fact.id,
207
+ confidence: "strong",
208
+ metadata
209
+ }];
210
+ });
211
+ }
212
+ },
213
+ {
214
+ id: OPEN_SPEC_ANNOTATION_RULES.keyword,
215
+ annotate(context) {
216
+ const scenarioKeywordAnnotations = context.previousAnnotations.flatMap((annotation) => {
217
+ if (annotation.kind !== "scenario-step") return [];
218
+ const fact = context.factById.get(annotation.targetFactId);
219
+ if (!fact) return [];
220
+ return findScenarioStepKeyword(fact, readAnnotationKeyword(annotation.metadata));
221
+ });
222
+ const requirementKeywordAnnotations = context.facts.flatMap((fact) => {
223
+ if (!canAnnotateInlineKeywords(fact)) return [];
224
+ return findRequirementKeywords(fact);
225
+ });
226
+ return [...scenarioKeywordAnnotations, ...requirementKeywordAnnotations];
227
+ }
228
+ }
229
+ ];
230
+ const builtinOpenSpecReadingPlugin = {
231
+ id: "openspec.builtin-reading.v2",
232
+ annotationRules: openSpecAnnotationRules
233
+ };
234
+ function annotateOpenSpecMarkdown(sourceMarkdown, plugins = [builtinOpenSpecReadingPlugin]) {
235
+ return annotateOpenSpecFacts(parseMarkdownFacts(sourceMarkdown), plugins);
236
+ }
237
+ function annotateOpenSpecFacts(document, plugins = [builtinOpenSpecReadingPlugin]) {
238
+ const readingDocument = createMarkdownReadingDocumentFromFacts(document, plugins);
239
+ return {
240
+ ...readingDocument,
241
+ annotations: readingDocument.annotations.filter(isOpenSpecAnnotation)
242
+ };
243
+ }
244
+ function getOpenSpecAnnotationsForFact(document, factId) {
245
+ return document.annotations.filter((annotation) => annotation.targetFactId === factId);
246
+ }
247
+ function getOpenSpecAnnotation(document, factId, kind) {
248
+ return document.annotations.find((annotation) => annotation.targetFactId === factId && annotation.kind === kind);
249
+ }
250
+ function isOpenSpecAnnotation(annotation) {
251
+ return annotation.kind === "document-title" || annotation.kind === "purpose-section" || annotation.kind === "requirements-section" || annotation.kind === "requirement" || annotation.kind === "scenario" || annotation.kind === "scenario-step" || annotation.kind === "keyword";
252
+ }
253
+ function createRequirementAnnotation(fact, confidence) {
254
+ return {
255
+ kind: "requirement",
256
+ targetFactId: fact.id,
257
+ confidence,
258
+ metadata: { title: stripRequirementPrefix(fact.text) || fact.text }
259
+ };
260
+ }
261
+ function createScenarioAnnotation(fact, confidence) {
262
+ return {
263
+ kind: "scenario",
264
+ targetFactId: fact.id,
265
+ confidence,
266
+ metadata: { title: stripScenarioPrefix(fact.text) || "Scenario" }
267
+ };
268
+ }
269
+ function matchesAnyTerm(text, terms) {
270
+ const normalized = text.toLowerCase();
271
+ return terms.some((term) => normalized.includes(term));
272
+ }
273
+ function isExactTerm(text, terms) {
274
+ const normalized = text.trim().toLowerCase();
275
+ return terms.some((term) => normalized === term.toLowerCase());
276
+ }
277
+ function stripRequirementPrefix(text) {
278
+ return text.replace(REQUIREMENT_PREFIX_PATTERN, "").trim();
279
+ }
280
+ function stripScenarioPrefix(text) {
281
+ return text.replace(SCENARIO_PREFIX_PATTERN, "").trim();
282
+ }
283
+ function getHeadingSections(context) {
284
+ const headings = getMarkdownHeadingFacts(context);
285
+ return headings.reduce((sections, fact, index) => {
286
+ const span = getMarkdownFactSpan(fact);
287
+ if (!span) return sections;
288
+ sections.push({
289
+ fact,
290
+ start: span.start,
291
+ end: getMarkdownHeadingEnd(headings, index, context.sourceMarkdown.length)
292
+ });
293
+ return sections;
294
+ }, []);
295
+ }
296
+ function getRequirementSections(context) {
297
+ return getHeadingSections(context).filter((section) => context.getAnnotation(section.fact.id, "requirements-section"));
298
+ }
299
+ function getChildHeadings(context, section, depth) {
300
+ return getMarkdownHeadingFacts(context).filter((fact) => {
301
+ if (fact.depth !== depth) return false;
302
+ const span = getMarkdownFactSpan(fact);
303
+ return !!span && span.start > section.start && span.start < section.end;
304
+ });
305
+ }
306
+ function getRequirementHeadings(context) {
307
+ return getMarkdownHeadingFacts(context).filter((fact) => context.getAnnotation(fact.id, "requirement"));
308
+ }
309
+ function getNestedHeadings(context, parentHeading) {
310
+ const headings = getMarkdownHeadingFacts(context);
311
+ const parentIndex = headings.findIndex((fact) => fact.id === parentHeading.id);
312
+ const parentSpan = getMarkdownFactSpan(parentHeading);
313
+ if (parentIndex < 0 || !parentSpan) return [];
314
+ const end = getMarkdownHeadingEnd(headings, parentIndex, context.sourceMarkdown.length);
315
+ return headings.filter((fact) => {
316
+ const span = getMarkdownFactSpan(fact);
317
+ return !!span && span.start > parentSpan.start && span.start < end;
318
+ });
319
+ }
320
+ function getScenarioSections(context) {
321
+ const headings = getMarkdownHeadingFacts(context);
322
+ return getHeadingSections(context).filter((section) => {
323
+ if (!context.getAnnotation(section.fact.id, "scenario")) return false;
324
+ if (NON_SCENARIO_HEADING_PATTERN.test(section.fact.text)) return false;
325
+ return headings.findIndex((fact) => fact.id === section.fact.id) >= 0;
326
+ });
327
+ }
328
+ function hasRequirementBodySignals(context, requirementHeading, sectionEnd) {
329
+ const span = getMarkdownFactSpan(requirementHeading);
330
+ if (!span) return false;
331
+ const headings = getMarkdownHeadingFacts(context);
332
+ const index = headings.findIndex((fact) => fact.id === requirementHeading.id);
333
+ const end = index >= 0 ? getMarkdownHeadingEnd(headings, index, sectionEnd) : sectionEnd;
334
+ const body = context.sourceMarkdown.slice(span.end, Math.min(end, sectionEnd));
335
+ return REQUIREMENT_BODY_SIGNAL_PATTERN.test(body);
336
+ }
337
+ function hasScenarioStepSignals(context, scenarioHeading) {
338
+ const span = getMarkdownFactSpan(scenarioHeading);
339
+ if (!span) return false;
340
+ const headings = getMarkdownHeadingFacts(context);
341
+ const index = headings.findIndex((fact) => fact.id === scenarioHeading.id);
342
+ const end = index >= 0 ? getMarkdownHeadingEnd(headings, index, context.sourceMarkdown.length) : context.sourceMarkdown.length;
343
+ return context.sourceMarkdown.slice(span.end, end).split("\n").some((line) => SCENARIO_STEP_PATTERN.test(line));
344
+ }
345
+ function isWithinAnySection(fact, sections) {
346
+ const span = getMarkdownFactSpan(fact);
347
+ if (!span) return false;
348
+ return sections.some((section) => span.start > section.start && span.start < section.end);
349
+ }
350
+ function parseScenarioStepFact(fact) {
351
+ const rawMarkdown = fact.range?.rawMarkdown.trim() || fact.text;
352
+ const match = rawMarkdown.match(SCENARIO_STEP_PATTERN) ?? fact.text.match(SCENARIO_STEP_PATTERN);
353
+ if (!match) return void 0;
354
+ return {
355
+ keyword: match[1].toUpperCase(),
356
+ contentMarkdown: match[2].trim(),
357
+ rawMarkdown
358
+ };
359
+ }
360
+ function canAnnotateInlineKeywords(fact) {
361
+ return fact.kind === "paragraph" || fact.kind === "listItem" || fact.kind === "heading" || fact.kind === "tableCell";
362
+ }
363
+ function findScenarioStepKeyword(fact, keyword) {
364
+ if (!isScenarioStepKeywordValue(keyword)) return [];
365
+ const match = fact.text.match(new RegExp(`^\\s*(${SCENARIO_STEP_KEYWORDS.join("|")})\\b`, "i"));
366
+ if (!match) return [];
367
+ const text = match[1];
368
+ const textStart = match.index ?? 0;
369
+ const sourceSpan = findSourceSpanForFactText(fact, text);
370
+ return [{
371
+ kind: "keyword",
372
+ targetFactId: fact.id,
373
+ ...sourceSpan ? { sourceSpan } : {},
374
+ textSpan: {
375
+ start: textStart,
376
+ end: textStart + text.length
377
+ },
378
+ confidence: "strong",
379
+ metadata: {
380
+ keyword,
381
+ keywordText: text,
382
+ keywordRole: "scenario-step"
383
+ }
384
+ }];
385
+ }
386
+ function findRequirementKeywords(fact) {
387
+ const span = getMarkdownFactSpan(fact);
388
+ const text = fact.text;
389
+ if (!span || !text) return [];
390
+ return Array.from(text.matchAll(REQUIREMENT_KEYWORD_PATTERN), (match) => {
391
+ const keyword = match[1].toUpperCase();
392
+ const textStart = match.index;
393
+ const textEnd = textStart + match[1].length;
394
+ const sourceSpan = findSourceSpanForFactText(fact, match[1], textStart);
395
+ return {
396
+ kind: "keyword",
397
+ targetFactId: fact.id,
398
+ ...sourceSpan ? { sourceSpan } : {},
399
+ textSpan: {
400
+ start: textStart,
401
+ end: textEnd
402
+ },
403
+ confidence: "strong",
404
+ metadata: {
405
+ keyword,
406
+ keywordText: match[1],
407
+ keywordRole: isScenarioStepKeyword(keyword) ? "scenario-step" : "requirement-modal"
408
+ }
409
+ };
410
+ });
411
+ }
412
+ function isScenarioStepKeywordValue(value) {
413
+ return typeof value === "string" && SCENARIO_STEP_KEYWORDS.some((stepKeyword) => stepKeyword === value);
414
+ }
415
+ function isScenarioStepKeyword(keyword) {
416
+ return SCENARIO_STEP_KEYWORDS.some((stepKeyword) => stepKeyword === keyword);
417
+ }
418
+ function readAnnotationKeyword(metadata) {
419
+ return metadata && "keyword" in metadata ? metadata.keyword : void 0;
420
+ }
421
+ function findSourceSpanForFactText(fact, text, textStart = 0) {
422
+ const factSpan = getMarkdownFactSpan(fact);
423
+ const rawMarkdown = fact.range?.rawMarkdown;
424
+ if (!factSpan || !rawMarkdown) return void 0;
425
+ const rawStart = rawMarkdown.indexOf(text, Math.min(textStart, rawMarkdown.length));
426
+ const index = rawStart >= 0 ? rawStart : rawMarkdown.indexOf(text);
427
+ if (index < 0) return void 0;
428
+ const start = factSpan.start + index;
429
+ return {
430
+ start,
431
+ end: start + text.length
432
+ };
433
+ }
434
+
435
+ //#endregion
436
+ export { getOpenSpecAnnotationsForFact as a, getOpenSpecAnnotation as i, annotateOpenSpecMarkdown as n, openSpecAnnotationRules as o, builtinOpenSpecReadingPlugin as r, annotateOpenSpecFacts as t };
@@ -0,0 +1,30 @@
1
+ import { r as MarkdownFactsDocument } from "./markdown-facts-f3kXnqXb.mjs";
2
+ import { a as MarkdownAnnotationRule, d as MarkdownReadingPlugin, l as MarkdownReadingDocument, n as MarkdownAnnotationConfidence, t as MarkdownAnnotation } from "./markdown-reading-D36W693c.mjs";
3
+
4
+ //#region src/openspec-annotations.d.ts
5
+ type OpenSpecSemanticKind = 'document-title' | 'purpose-section' | 'requirements-section' | 'requirement' | 'scenario' | 'scenario-step' | 'keyword';
6
+ type OpenSpecAnnotationConfidence = MarkdownAnnotationConfidence;
7
+ type OpenSpecScenarioStepKeyword = 'GIVEN' | 'WHEN' | 'THEN' | 'AND' | 'BUT';
8
+ type OpenSpecRequirementKeyword = 'SHALL' | 'MUST' | 'SHOULD' | 'MAY';
9
+ type OpenSpecKeyword = OpenSpecScenarioStepKeyword | OpenSpecRequirementKeyword;
10
+ type OpenSpecKeywordRole = 'scenario-step' | 'requirement-modal';
11
+ interface OpenSpecAnnotationMetadata {
12
+ title?: string;
13
+ keyword?: OpenSpecKeyword;
14
+ keywordText?: string;
15
+ keywordRole?: OpenSpecKeywordRole;
16
+ contentMarkdown?: string;
17
+ rawMarkdown?: string;
18
+ }
19
+ type OpenSpecAnnotation = MarkdownAnnotation<OpenSpecSemanticKind, OpenSpecAnnotationMetadata>;
20
+ interface AnnotatedOpenSpecDocument extends MarkdownReadingDocument {
21
+ annotations: OpenSpecAnnotation[];
22
+ }
23
+ declare const openSpecAnnotationRules: readonly MarkdownAnnotationRule[];
24
+ declare const builtinOpenSpecReadingPlugin: MarkdownReadingPlugin;
25
+ declare function annotateOpenSpecMarkdown(sourceMarkdown: string, plugins?: readonly MarkdownReadingPlugin[]): AnnotatedOpenSpecDocument;
26
+ declare function annotateOpenSpecFacts(document: MarkdownFactsDocument, plugins?: readonly MarkdownReadingPlugin[]): AnnotatedOpenSpecDocument;
27
+ declare function getOpenSpecAnnotationsForFact(document: AnnotatedOpenSpecDocument, factId: string): OpenSpecAnnotation[];
28
+ declare function getOpenSpecAnnotation(document: AnnotatedOpenSpecDocument, factId: string, kind: OpenSpecSemanticKind): OpenSpecAnnotation | undefined;
29
+ //#endregion
30
+ export { OpenSpecKeyword as a, OpenSpecScenarioStepKeyword as c, annotateOpenSpecMarkdown as d, builtinOpenSpecReadingPlugin as f, openSpecAnnotationRules as h, OpenSpecAnnotationMetadata as i, OpenSpecSemanticKind as l, getOpenSpecAnnotationsForFact as m, OpenSpecAnnotation as n, OpenSpecKeywordRole as o, getOpenSpecAnnotation as p, OpenSpecAnnotationConfidence as r, OpenSpecRequirementKeyword as s, AnnotatedOpenSpecDocument as t, annotateOpenSpecFacts as u };
@@ -0,0 +1,4 @@
1
+ import "./markdown-facts-f3kXnqXb.mjs";
2
+ import "./markdown-reading-D36W693c.mjs";
3
+ import { a as OpenSpecKeyword, c as OpenSpecScenarioStepKeyword, d as annotateOpenSpecMarkdown, f as builtinOpenSpecReadingPlugin, h as openSpecAnnotationRules, i as OpenSpecAnnotationMetadata, l as OpenSpecSemanticKind, m as getOpenSpecAnnotationsForFact, n as OpenSpecAnnotation, o as OpenSpecKeywordRole, p as getOpenSpecAnnotation, r as OpenSpecAnnotationConfidence, s as OpenSpecRequirementKeyword, t as AnnotatedOpenSpecDocument, u as annotateOpenSpecFacts } from "./openspec-annotations-CJmYcfAu.mjs";
4
+ export { AnnotatedOpenSpecDocument, OpenSpecAnnotation, OpenSpecAnnotationConfidence, OpenSpecAnnotationMetadata, OpenSpecKeyword, OpenSpecKeywordRole, OpenSpecRequirementKeyword, OpenSpecScenarioStepKeyword, OpenSpecSemanticKind, annotateOpenSpecFacts, annotateOpenSpecMarkdown, builtinOpenSpecReadingPlugin, getOpenSpecAnnotation, getOpenSpecAnnotationsForFact, openSpecAnnotationRules };
@@ -0,0 +1,5 @@
1
+ import "./markdown-facts-BmSmZmpB.mjs";
2
+ import "./markdown-reading-CrchEfoW.mjs";
3
+ import { a as getOpenSpecAnnotationsForFact, i as getOpenSpecAnnotation, n as annotateOpenSpecMarkdown, o as openSpecAnnotationRules, r as builtinOpenSpecReadingPlugin, t as annotateOpenSpecFacts } from "./openspec-annotations-BMy9nWUe.mjs";
4
+
5
+ export { annotateOpenSpecFacts, annotateOpenSpecMarkdown, builtinOpenSpecReadingPlugin, getOpenSpecAnnotation, getOpenSpecAnnotationsForFact, openSpecAnnotationRules };