@px-lsp/protocol 0.2.0 → 0.2.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.
@@ -1,3 +1,4 @@
1
+ import type { DefSource } from "./types";
1
2
  /** Resolved extension settings, computed client-side (path validation, Steam
2
3
  * detection fallbacks, workspace-folder default) and pushed to the server. */
3
4
  export interface ParadoxSettings {
@@ -164,6 +165,39 @@ export interface LocEntryInfo {
164
165
  source: "vanilla" | "parent" | "mod";
165
166
  value?: string;
166
167
  }
168
+ /**
169
+ * Request: a localization value as the PLAYER reads it;
170
+ * {@link LocTextParams} -> {@link LocTextResult}.
171
+ *
172
+ * {@link lookupLocRequest} answers the value verbatim, which is what an editor
173
+ * needs. A panel that SHOWS the value needs the sentence: the games write a
174
+ * culture parameter as `"The [GetTrait('rough_terrain_expert').GetName(
175
+ * GetNullCharacter )] Commander Trait is more common"` (145 of the 280
176
+ * parameter values with a real call take that one shape), and a modder reading
177
+ * a form must not be shown the brackets.
178
+ *
179
+ * Everything the renderer knows is DERIVED: the words come from the loc index
180
+ * (mod entries shadow the game's), the kind a `Get<Something>('name')` chain
181
+ * names comes from the definition index, and the loc key that kind's names take
182
+ * comes from the active profile's schema. No table of function names, so a
183
+ * workspace of any of the games gets the same behavior from its own schema.
184
+ */
185
+ export declare const locTextRequest = "paradox/locText";
186
+ export interface LocTextParams extends ModScopedParams {
187
+ keys: string[];
188
+ }
189
+ export interface LocTextValue {
190
+ /** The value verbatim, exactly as {@link lookupLocRequest} answers it. */
191
+ raw: string;
192
+ /** The same value as plain text: markup stripped, datafunctions resolved. */
193
+ text: string;
194
+ /** False when any part of the value stayed a word for something unresolved. */
195
+ resolved: boolean;
196
+ }
197
+ export interface LocTextResult {
198
+ /** Loc key -> its rendering. A key the loc index cannot find is ABSENT. */
199
+ values: Record<string, LocTextValue>;
200
+ }
167
201
  /** Notification: data health for the status bar; payload {@link StatusPayload}. */
168
202
  export declare const statusNotification = "paradox/status";
169
203
  export interface StatusPayload {
@@ -206,6 +240,20 @@ export interface OverviewDef {
206
240
  name: string;
207
241
  file: string;
208
242
  line: number;
243
+ /**
244
+ * The loc-resolved display name, when the kind's loc pattern resolves to one
245
+ * ({@link EventVocabularyItem.label}). Set by {@link definitionFormRequest}
246
+ * only, so a creator listing what the mod already has can show the player's
247
+ * word for it; absent everywhere else.
248
+ */
249
+ label?: string;
250
+ /**
251
+ * Where the definition comes from. Set by {@link definitionFormRequest} only,
252
+ * whose list includes the game's and a dependency's definitions (a creator
253
+ * opens one to duplicate or override it) and must say which is which; absent
254
+ * everywhere else, where every definition listed is the mod's own.
255
+ */
256
+ source?: "vanilla" | "parent" | "mod";
209
257
  }
210
258
  export interface OverviewKind {
211
259
  kind: string;
@@ -1336,6 +1384,13 @@ export interface EventGraphParams {
1336
1384
  /** Also read each mod event's `theme`. Off by default: it costs one parse per
1337
1385
  * event file, and only a client that draws the theme's art needs it. */
1338
1386
  themes?: boolean;
1387
+ /**
1388
+ * Leave out every definition that has no edge in the answer. ON by default
1389
+ * (absent = true): the pruned definitions are dropped before their cards
1390
+ * are read, so a mod with hundreds of standalone events stays cheap. `root`
1391
+ * is always kept. Send `false` to see the whole namespace, edges or not.
1392
+ */
1393
+ connectedOnly?: boolean;
1339
1394
  }
1340
1395
  /**
1341
1396
  * One row of a mod event's card, in EXECUTION order (immediate, then the
@@ -1458,10 +1513,38 @@ export interface EventVocabularyItem {
1458
1513
  doc?: string;
1459
1514
  /** Dimmer right-hand label: where the value comes from (mod / vanilla / a kind). */
1460
1515
  hint?: string;
1516
+ /**
1517
+ * The name the PLAYER reads: the loc value of the kind's first loc pattern
1518
+ * with `$` replaced by the definition name (`trait_$` -> `trait_brave` ->
1519
+ * "Brave"). Set by {@link definitionFormRequest} only, and absent when
1520
+ * nothing resolves, so a client shows the key rather than an invented word.
1521
+ */
1522
+ label?: string;
1523
+ /**
1524
+ * The family this definition belongs to, when one folder holds several and
1525
+ * the schema entry names the key that says so (`type = ethos` in
1526
+ * common/culture/pillars). Set by {@link definitionFormRequest} only, so a
1527
+ * creator can draw one picker per family; absent everywhere else.
1528
+ */
1529
+ group?: string;
1461
1530
  }
1462
1531
  /** Caps: an editor lists a page at a time, and these ride on every open. */
1463
1532
  export declare const EVENT_VOCABULARY_MAX_TOKENS = 600;
1464
1533
  export declare const EVENT_VOCABULARY_MAX_VALUES = 400;
1534
+ /**
1535
+ * Most values {@link DefinitionFormKey.sampled} carries, and the point past
1536
+ * which a key is taken to have no value SET at all (a key whose value differs
1537
+ * per definition is a free field, not a list to offer).
1538
+ */
1539
+ export declare const DEFINITION_FORM_MAX_SAMPLED = 80;
1540
+ /**
1541
+ * How long a block body {@link DefinitionFormKey.example} may be. A placeholder
1542
+ * is read at a glance, and the shortest bodies a game writes for a block key
1543
+ * (a trait's `triggered_opinion`, a culture's `parameters`) fit well inside
1544
+ * this; a longer one is cut with an ellipsis rather than dropped, because half
1545
+ * a real body still says what the key wants.
1546
+ */
1547
+ export declare const DEFINITION_FORM_MAX_EXAMPLE = 120;
1465
1548
  /**
1466
1549
  * Request: the value set a VALUE belongs to, resolved through the definition
1467
1550
  * index; {@link EventValueOptionsParams} -> {@link EventValueOptionsResult} |
@@ -1580,6 +1663,59 @@ export interface GuiUseSite {
1580
1663
  */
1581
1664
  via: string[];
1582
1665
  }
1666
+ /**
1667
+ * Request: the code snippets a host can offer for one open script document;
1668
+ * {@link SnippetsParams} -> {@link SnippetsResult}. Answers for OPEN script
1669
+ * documents only (the server reads the client's text, not the disk); a document
1670
+ * it does not know answers with an EMPTY list, never an error.
1671
+ *
1672
+ * Two sources, neither hand-written. The definition and child-block skeletons
1673
+ * are the measured shape of the document folder's own definition kind (at least
1674
+ * half of the game's definitions of that kind carry each key, in the median
1675
+ * order they hold there). The token entries are the block form of the `usage:`
1676
+ * example the game's own script_docs dump ships for an engine trigger or effect,
1677
+ * filtered to the block the cursor sits in.
1678
+ *
1679
+ * Every entry carries BOTH insert forms, exactly like completion does: `snippet`
1680
+ * for a host that expands `${1:…}` tabstops, `plain` for one that does not.
1681
+ */
1682
+ export declare const snippetsRequest = "paradox/snippets";
1683
+ export interface SnippetsParams {
1684
+ uri: string;
1685
+ /** 0-based, as in LSP. Decides which engine block templates fit. */
1686
+ position: {
1687
+ line: number;
1688
+ character: number;
1689
+ };
1690
+ }
1691
+ /** One offer, ready to insert at the cursor. */
1692
+ export interface SnippetItem {
1693
+ /**
1694
+ * Stable id: the definition kind (`event`), the kind and its child block
1695
+ * (`event.option`), or the engine token (`if`) — plus `<token>.full` when the
1696
+ * token's example marks fields optional and an all-fields form follows it.
1697
+ * Suitable as a picker key.
1698
+ */
1699
+ id: string;
1700
+ /** Reads as what it inserts: "new event", "option block", "if". */
1701
+ label: string;
1702
+ /** Provenance, with the measurement behind it. */
1703
+ detail: string;
1704
+ /**
1705
+ * `definition` = a whole definition of the document's kind, including the
1706
+ * file header line when the document declares none; `block` = one child block
1707
+ * of that kind; `token` = an engine trigger/effect's own dumped example.
1708
+ */
1709
+ form: "definition" | "block" | "token";
1710
+ /** `${1:…}` tabstop form. */
1711
+ snippet: string;
1712
+ /** The same shape free of `${`, for hosts without snippet expansion. */
1713
+ plain: string;
1714
+ }
1715
+ export interface SnippetsResult {
1716
+ /** Skeletons first (definition, then its child blocks), then engine tokens. */
1717
+ snippets: SnippetItem[];
1718
+ }
1583
1719
  /**
1584
1720
  * Request: the inferred scope chain at a cursor position;
1585
1721
  * {@link ScopeAtParams} -> {@link ScopeAtResult} | null. Answers for OPEN
@@ -1636,3 +1772,348 @@ export interface ScopeAtResult {
1636
1772
  */
1637
1773
  savedScopes: SavedScopeInfo[];
1638
1774
  }
1775
+ /**
1776
+ * Request: everything a visual creator needs to draw a form for one definition
1777
+ * kind; {@link DefinitionFormParams} -> {@link DefinitionForm} | null (null =
1778
+ * the active game's schema has no such kind, which is the honest answer for a
1779
+ * client asking about content this game does not have).
1780
+ *
1781
+ * Nothing in the answer is hand-written for the creator: the folder, the loc
1782
+ * key patterns and the icon folder come from the schema table, the keys from
1783
+ * the harvested `_*.info` structures, the option lists from the definition
1784
+ * index (the same resolver {@link eventValueOptionsRequest} answers with) and
1785
+ * `existing` from the same index walk {@link modOverviewRequest} does. A game
1786
+ * patch that adds a key or a value changes the form without a release.
1787
+ */
1788
+ export declare const definitionFormRequest = "paradox/definitionForm";
1789
+ export interface DefinitionFormParams {
1790
+ /** Definition kind, as the schema table spells it ("trait"). */
1791
+ kind: string;
1792
+ /** Load this definition into `current` (edit rather than create). */
1793
+ name?: string;
1794
+ /** Restrict mod-side entries to one workspace mod (plus vanilla/parents). */
1795
+ modRoot?: string | null;
1796
+ }
1797
+ /** One key of a definition body, with what is known about the values it takes. */
1798
+ export interface DefinitionFormKey {
1799
+ key: string;
1800
+ /** The game's own one-line documentation, capped. Absent when it has none. */
1801
+ doc?: string;
1802
+ /** Coarse value hint from the schema: `loc`, `bool`, `block`, `enum:a|b|c`. */
1803
+ values?: string;
1804
+ /** Vanilla usage count from the harvest, the order the keys arrive in. */
1805
+ freq?: number;
1806
+ /**
1807
+ * Definition kinds this key's value names, when the profile says so. The
1808
+ * lists live in {@link DefinitionForm.options}, keyed by kind, so several
1809
+ * keys naming the same kind share one list.
1810
+ */
1811
+ refKinds?: string[];
1812
+ /**
1813
+ * The values the indexed definitions of this kind actually write for this
1814
+ * key, most used first, for keys no definition index can answer (a culture's
1815
+ * `clothing_gfx` names an art set, not a definition). Measured from the game
1816
+ * and mod files the server has indexed, at request time, so a patch changes
1817
+ * the list without a release; absent when the key has no refKinds-free value
1818
+ * set of at most {@link DEFINITION_FORM_MAX_SAMPLED} entries, which is the
1819
+ * honest answer for a key whose value is different in every definition.
1820
+ */
1821
+ sampled?: string[];
1822
+ /**
1823
+ * The literal the indexed definitions of this kind write most often for this
1824
+ * key: a real value, so a form can show it as the input's placeholder
1825
+ * instead of inventing one. Unlike {@link sampled} it counts numbers and
1826
+ * quoted text too (quotes stripped), and it survives the cap, so a key whose
1827
+ * value differs in every definition still has an example.
1828
+ *
1829
+ * A key whose value is a BLOCK gets the most written body instead, collapsed
1830
+ * onto one line and capped at {@link DEFINITION_FORM_MAX_EXAMPLE}
1831
+ * characters, so a script field has a placeholder too.
1832
+ *
1833
+ * A key whose value set is already stated (`bool`, `enum:`) carries an
1834
+ * example as well, though no {@link sampled}: a dropdown showing the value
1835
+ * the game itself writes says more than one reading "not set".
1836
+ */
1837
+ example?: string;
1838
+ }
1839
+ export interface DefinitionForm {
1840
+ kind: string;
1841
+ /** Schema path the definition is written into, e.g. `common/traits`. */
1842
+ folder: string;
1843
+ /**
1844
+ * Every loc key the game reads for this kind, `$` being the definition name
1845
+ * (`trait_$_desc`). The full set a form should offer, not the conservative
1846
+ * `requiredLoc` subset a diagnostic is allowed to demand.
1847
+ */
1848
+ locPatterns: string[];
1849
+ /** Where the game looks for this kind's icon, e.g. `gfx/interface/icons/traits`. */
1850
+ iconFolder?: string;
1851
+ /** Top-level keys, harvest order (most used first), curated keys ahead. */
1852
+ keys: DefinitionFormKey[];
1853
+ /** Named sub-blocks with their own keys, when the harvest has them. */
1854
+ blocks?: Record<string, DefinitionFormKey[]>;
1855
+ /** Ref kind -> every indexed definition of it, mod entries first, capped. */
1856
+ options: Record<string, EventVocabularyItem[]>;
1857
+ /**
1858
+ * Trigger name -> the values that trigger accepts, for the handful of
1859
+ * triggers a no-code condition builder offers rows for (`has_dlc_feature`,
1860
+ * `has_game_rule`, `scripted_trigger`). Which triggers those are, and where
1861
+ * each list comes from, is the game profile's own table; the values
1862
+ * themselves are read from what the server already holds (the trigger's own
1863
+ * script_docs entry, the definition index), never written for the creator.
1864
+ * A trigger with no resolvable list is ABSENT rather than empty, so a client
1865
+ * offers a free input instead of a picker with nothing in it.
1866
+ */
1867
+ conditions?: Record<string, EventVocabularyItem[]>;
1868
+ /** The modifier vocabulary, most used first: what a modifier row may offer. */
1869
+ modifiers: {
1870
+ name: string;
1871
+ doc?: string;
1872
+ }[];
1873
+ /** Definitions of this kind the mod already has (modRoot or every workspace mod). */
1874
+ existing: OverviewDef[];
1875
+ /** The definition `params.name` asked for, when it is indexed. */
1876
+ current?: {
1877
+ file: string;
1878
+ /** 0-based. */
1879
+ line: number;
1880
+ source: DefSource;
1881
+ /** The block verbatim, `name = { ... }`, exactly as the file has it. */
1882
+ text: string;
1883
+ };
1884
+ }
1885
+ /**
1886
+ * Request: text edits that write a definition into a script file;
1887
+ * {@link DefinitionEditParams} -> {@link DefinitionEditResult}. The script
1888
+ * sibling of {@link guiSourceEditRequest}, over the same span model, and with
1889
+ * the same division of labour: the server never writes, it returns offsets
1890
+ * into the text it was handed and the host applies them as ONE
1891
+ * `WorkspaceEdit`, which keeps undo and dirty state in the editor.
1892
+ *
1893
+ * Offsets are UTF-16 into `params.text` (the document text, with no BOM, the
1894
+ * way an editor delivers it), computed against that one text and applied
1895
+ * end-first. Every edit is surgical, so a file's other definitions, its
1896
+ * comments, its CRLF and its indentation stay byte-identical.
1897
+ */
1898
+ export declare const definitionEditRequest = "paradox/definitionEdit";
1899
+ export interface DefinitionEditParams {
1900
+ /** For display only; the text is authoritative. */
1901
+ uri: string;
1902
+ /** Authoritative document text every offset refers to. */
1903
+ text: string;
1904
+ /** Computed in order against the one text and answered as one edit set. */
1905
+ ops: DefinitionOp[];
1906
+ }
1907
+ export type DefinitionOp =
1908
+ /**
1909
+ * Set or (with a null value) remove keys on the top-level definition `name`.
1910
+ * `value` is raw script text: `2`, `{ craven }`, `"quoted"`.
1911
+ */
1912
+ {
1913
+ op: "setProperties";
1914
+ name: string;
1915
+ properties: {
1916
+ key: string;
1917
+ value: string | null;
1918
+ }[];
1919
+ }
1920
+ /**
1921
+ * Write the whole `name = { ... }` block: replaces the top-level block of
1922
+ * that name, or appends it after a blank separator line when the file has
1923
+ * none.
1924
+ */
1925
+ | {
1926
+ op: "upsertBlock";
1927
+ name: string;
1928
+ text: string;
1929
+ };
1930
+ export interface DefinitionEditResult {
1931
+ /** Every applied op's edits together. Apply the whole set as ONE change. */
1932
+ edits: GuiTextEdit[];
1933
+ /** One verdict per requested op, in request order; `refused` names why it wrote nothing. */
1934
+ ops: {
1935
+ refused?: string;
1936
+ }[];
1937
+ }
1938
+ /**
1939
+ * Request: how the GAME prints each modifier; {@link ModifierFormatsParams} ->
1940
+ * {@link ModifierFormatsResult} | null (null = the active profile names no
1941
+ * formats source, or the game folder is not configured).
1942
+ *
1943
+ * A creator that lets a modder add `monthly_income = 0.5` has to show what the
1944
+ * player will see, and the player sees "[gold_i] +0.50 Monthly Income" in
1945
+ * green. None of that is written here: the flags come from the game's own
1946
+ * `common/modifier_definition_formats/` (documented by `_definitions.info`
1947
+ * there), every word comes from the loc index, and every icon comes from the
1948
+ * `texticon` blocks of the game's `gui/texticons.gui`. A modifier no format
1949
+ * block names gets the file's documented defaults, so the answer covers every
1950
+ * modifier token the server knows rather than only the formatted ones.
1951
+ */
1952
+ export declare const modifierFormatsRequest = "paradox/modifierFormats";
1953
+ export interface ModifierFormatsParams extends ModScopedParams {
1954
+ /**
1955
+ * Loc keys to render as parts too, through the same texticon chain the
1956
+ * prefixes take. A client that prints a line of the game's own UI (a cost
1957
+ * line such as `"[prestige_i] $VALUE|0$"`) asks for the key and gets its
1958
+ * icon and text back; a key the loc index cannot resolve is absent.
1959
+ */
1960
+ lines?: string[];
1961
+ }
1962
+ /**
1963
+ * One piece of a prefix or suffix: a word, or a texticon. `[gold_i]` in a loc
1964
+ * value resolves through `game_concept_gold_i` = `"@gold_icon!"` to the
1965
+ * `texticon` block naming the sprite, which is what an icon part carries.
1966
+ */
1967
+ export type FormatPart = {
1968
+ text: string;
1969
+ } | {
1970
+ icon: {
1971
+ texture: string;
1972
+ uv?: [number, number, number, number];
1973
+ };
1974
+ };
1975
+ /** How one modifier is printed, straight out of the game's own format files. */
1976
+ export interface ModifierFormat {
1977
+ /** The player's word for the modifier, loc-resolved; the key title-cased when it has none. */
1978
+ label: string;
1979
+ /** Digits after the point. The file's documented default is 2. */
1980
+ decimals: number;
1981
+ /** Scale the value by 100 and print a `%`. */
1982
+ percent?: boolean;
1983
+ /** Print a `%` without scaling: the value already is one. */
1984
+ alreadyPercent?: boolean;
1985
+ /** Which direction is good for the player. The file's documented default is `bad`. */
1986
+ color: "good" | "neutral" | "bad";
1987
+ /** `no_difference_sign`: print the number without a leading `+`/`-`. */
1988
+ noSign?: boolean;
1989
+ /** The game does not show this modifier at all. */
1990
+ hidden?: boolean;
1991
+ /** Drawn before the number (`[gold_i]`). */
1992
+ prefix?: FormatPart[];
1993
+ /** Drawn after the number (`/month`). */
1994
+ suffix?: FormatPart[];
1995
+ /** Used in place of `suffix` for negative values, when the game defines one. */
1996
+ negativeSuffix?: FormatPart[];
1997
+ }
1998
+ export interface ModifierFormatsResult {
1999
+ /** Modifier name -> its format. Every modifier token the server knows. */
2000
+ formats: Record<string, ModifierFormat>;
2001
+ /** Loc key -> its parts, for each `lines` entry the loc index resolved. */
2002
+ lines?: Record<string, FormatPart[]>;
2003
+ }
2004
+ /**
2005
+ * Request: a dynasty as a family tree; {@link DynastyTreeParams} ->
2006
+ * {@link DynastyTreeResult}.
2007
+ *
2008
+ * Two answers behind one method. Without `dynasty` the result is the picker
2009
+ * list: every dynasty the index knows, mod entries first. With `dynasty` it is
2010
+ * that dynasty's houses and members, read out of the game's own
2011
+ * `history/characters` files.
2012
+ *
2013
+ * Everything is DERIVED: the folders come from the active profile's schema
2014
+ * (`dynasty`, `dynasty_house`, `character` kinds), the members from the
2015
+ * character blocks themselves, the display names from the loc index. A profile
2016
+ * whose schema has no `dynasty` kind answers `supported: false` and empty
2017
+ * lists, which is what a client shows instead of an empty tree.
2018
+ */
2019
+ export declare const dynastyTreeRequest = "paradox/dynastyTree";
2020
+ export interface DynastyTreeParams extends ModScopedParams {
2021
+ /** A dynasty id: answer that dynasty's houses and members instead of the list. */
2022
+ dynasty?: string;
2023
+ }
2024
+ /** One dynasty, as the picker lists it. */
2025
+ export interface DynastySummary {
2026
+ /** The block's own key, which is what a character's `dynasty = ` names. */
2027
+ id: string;
2028
+ /** The `name = ` value, a loc key (`dynn_Karling`). */
2029
+ nameKey: string;
2030
+ /** The loc text when the server can resolve it, else `nameKey` itself. */
2031
+ name: string;
2032
+ culture?: string;
2033
+ source: DefSource;
2034
+ file: string;
2035
+ /** 0-based. */
2036
+ line: number;
2037
+ /** Characters whose `dynasty`, or whose house's dynasty, is this one. */
2038
+ characterCount: number;
2039
+ houseCount: number;
2040
+ }
2041
+ /** One house of a dynasty (`house_karling = { name = … dynasty = 25061 }`). */
2042
+ export interface DynastyHouse {
2043
+ id: string;
2044
+ nameKey: string;
2045
+ name: string;
2046
+ /** The dynasty id the house belongs to. */
2047
+ dynasty: string;
2048
+ source: DefSource;
2049
+ file: string;
2050
+ /** 0-based. */
2051
+ line: number;
2052
+ }
2053
+ /**
2054
+ * The character-level skill keys, in the order a client shows them. MEASURED
2055
+ * over the vanilla `history/characters` corpus (2026-09-03): stewardship 8 964,
2056
+ * martial 8 940, diplomacy 8 908, intrigue 8 892, learning 495, prowess 150.
2057
+ */
2058
+ export declare const DYNASTY_SKILLS: readonly ["diplomacy", "martial", "stewardship", "intrigue", "learning", "prowess"];
2059
+ /**
2060
+ * One character of `history/characters`. Dates are the game's own
2061
+ * `Y.M.D` strings, taken from the dated block that carries the `birth`/`death`
2062
+ * statement.
2063
+ */
2064
+ export interface DynastyCharacter {
2065
+ /** The block's own key: numeric in vanilla, but `han_1234` shapes exist too. */
2066
+ id: string;
2067
+ /** The `name = ` value, a plain string in history, not a loc key. */
2068
+ name: string;
2069
+ female: boolean;
2070
+ dynasty?: string;
2071
+ /** `dynasty_house = `; a character carries the house OR the dynasty, not both. */
2072
+ house?: string;
2073
+ father?: string;
2074
+ mother?: string;
2075
+ culture?: string;
2076
+ religion?: string;
2077
+ /** `Y.M.D` of the dated block holding `birth`. */
2078
+ birth?: string;
2079
+ death?: string;
2080
+ /**
2081
+ * `dna = `, the portrait DNA name, without the quotes the file may put
2082
+ * around it (350 of 438 vanilla statements write it bare).
2083
+ */
2084
+ dna?: string;
2085
+ /**
2086
+ * The skills the block sets, keyed by {@link DYNASTY_SKILLS}. A skill the
2087
+ * block does not name is absent, which is not the same as zero: the game
2088
+ * rolls one it was not given.
2089
+ */
2090
+ skills?: Record<string, number>;
2091
+ traits: string[];
2092
+ /** Ids this character is married to (`add_spouse`), in file order. */
2093
+ spouses: string[];
2094
+ /**
2095
+ * Set when the character belongs to ANOTHER dynasty and is only in the
2096
+ * answer because a member names them as a parent or a spouse. A client draws
2097
+ * them, but the tree is not theirs.
2098
+ */
2099
+ external?: true;
2100
+ source: DefSource;
2101
+ file: string;
2102
+ /** 0-based. */
2103
+ line: number;
2104
+ }
2105
+ export interface DynastyTreeResult {
2106
+ /** False when the active profile's schema has no `dynasty` kind. */
2107
+ supported: boolean;
2108
+ /** The picker list. Empty when `params.dynasty` asked for one dynasty. */
2109
+ dynasties: DynastySummary[];
2110
+ /** Present exactly when `params.dynasty` named a dynasty the index knows. */
2111
+ dynasty?: DynastySummary;
2112
+ houses?: DynastyHouse[];
2113
+ /** Members plus the external parents and spouses they name. */
2114
+ characters?: DynastyCharacter[];
2115
+ /** Largest numeric character id across game and mods, plus one. */
2116
+ nextCharacterId?: string;
2117
+ /** Largest numeric dynasty id across game and mods, plus one. */
2118
+ nextDynastyId?: string;
2119
+ }
package/dist/protocol.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.scopeAtRequest = exports.dependenciesRequest = exports.eventValueOptionsRequest = exports.EVENT_VOCABULARY_MAX_VALUES = exports.EVENT_VOCABULARY_MAX_TOKENS = exports.eventVocabularyRequest = exports.eventBannerRequest = exports.eventGraphRequest = exports.guiWidgetEditRequest = exports.guiSourceEditRequest = exports.guiSaveValuesRequest = exports.GUI_PREVIEW_MAX = exports.guiPreviewRequest = exports.guiVocabularyRequest = exports.guiDependenciesRequest = exports.guiWidgetInfoRequest = exports.guiLayoutRequest = exports.guiTreeRequest = exports.exampleWikiEntryRequest = exports.exampleWikiVocabularyKinds = exports.exampleWikiVariableKinds = exports.exampleWikiRequest = exports.eventDetailRequest = exports.overridesRequest = exports.locCoverageRequest = exports.modOverviewRequest = exports.progressNotification = exports.indexChangedNotification = exports.statusNotification = exports.lookupLocRequest = exports.indexStatsRequest = exports.reloadDocsRequest = exports.modFileChangedNotification = exports.configChangedNotification = exports.allClientCommandIds = exports.clientCommands = void 0;
3
+ exports.DYNASTY_SKILLS = exports.dynastyTreeRequest = exports.modifierFormatsRequest = exports.definitionEditRequest = exports.definitionFormRequest = exports.scopeAtRequest = exports.snippetsRequest = exports.dependenciesRequest = exports.eventValueOptionsRequest = exports.DEFINITION_FORM_MAX_EXAMPLE = exports.DEFINITION_FORM_MAX_SAMPLED = exports.EVENT_VOCABULARY_MAX_VALUES = exports.EVENT_VOCABULARY_MAX_TOKENS = exports.eventVocabularyRequest = exports.eventBannerRequest = exports.eventGraphRequest = exports.guiWidgetEditRequest = exports.guiSourceEditRequest = exports.guiSaveValuesRequest = exports.GUI_PREVIEW_MAX = exports.guiPreviewRequest = exports.guiVocabularyRequest = exports.guiDependenciesRequest = exports.guiWidgetInfoRequest = exports.guiLayoutRequest = exports.guiTreeRequest = exports.exampleWikiEntryRequest = exports.exampleWikiVocabularyKinds = exports.exampleWikiVariableKinds = exports.exampleWikiRequest = exports.eventDetailRequest = exports.overridesRequest = exports.locCoverageRequest = exports.modOverviewRequest = exports.progressNotification = exports.indexChangedNotification = exports.statusNotification = exports.locTextRequest = exports.lookupLocRequest = exports.indexStatsRequest = exports.reloadDocsRequest = exports.modFileChangedNotification = exports.configChangedNotification = exports.allClientCommandIds = exports.clientCommands = void 0;
4
4
  // ---- client command ids ----------------------------------------------------
5
5
  /**
6
6
  * Client commands the server references in code actions and hover links (part
@@ -30,6 +30,24 @@ exports.indexStatsRequest = "paradox/indexStats";
30
30
  /** Request: look up localization entries for a key; {@link LookupLocParams} -> {@link LocEntryInfo}[].
31
31
  * Mod entries shadow vanilla ones (the full list is returned, mod first). */
32
32
  exports.lookupLocRequest = "paradox/lookupLoc";
33
+ /**
34
+ * Request: a localization value as the PLAYER reads it;
35
+ * {@link LocTextParams} -> {@link LocTextResult}.
36
+ *
37
+ * {@link lookupLocRequest} answers the value verbatim, which is what an editor
38
+ * needs. A panel that SHOWS the value needs the sentence: the games write a
39
+ * culture parameter as `"The [GetTrait('rough_terrain_expert').GetName(
40
+ * GetNullCharacter )] Commander Trait is more common"` (145 of the 280
41
+ * parameter values with a real call take that one shape), and a modder reading
42
+ * a form must not be shown the brackets.
43
+ *
44
+ * Everything the renderer knows is DERIVED: the words come from the loc index
45
+ * (mod entries shadow the game's), the kind a `Get<Something>('name')` chain
46
+ * names comes from the definition index, and the loc key that kind's names take
47
+ * comes from the active profile's schema. No table of function names, so a
48
+ * workspace of any of the games gets the same behavior from its own schema.
49
+ */
50
+ exports.locTextRequest = "paradox/locText";
33
51
  // ---- server -> client ------------------------------------------------------
34
52
  /** Notification: data health for the status bar; payload {@link StatusPayload}. */
35
53
  exports.statusNotification = "paradox/status";
@@ -204,6 +222,20 @@ exports.eventVocabularyRequest = "paradox/eventVocabulary";
204
222
  /** Caps: an editor lists a page at a time, and these ride on every open. */
205
223
  exports.EVENT_VOCABULARY_MAX_TOKENS = 600;
206
224
  exports.EVENT_VOCABULARY_MAX_VALUES = 400;
225
+ /**
226
+ * Most values {@link DefinitionFormKey.sampled} carries, and the point past
227
+ * which a key is taken to have no value SET at all (a key whose value differs
228
+ * per definition is a free field, not a list to offer).
229
+ */
230
+ exports.DEFINITION_FORM_MAX_SAMPLED = 80;
231
+ /**
232
+ * How long a block body {@link DefinitionFormKey.example} may be. A placeholder
233
+ * is read at a glance, and the shortest bodies a game writes for a block key
234
+ * (a trait's `triggered_opinion`, a culture's `parameters`) fit well inside
235
+ * this; a longer one is cut with an ellipsis rather than dropped, because half
236
+ * a real body still says what the key wants.
237
+ */
238
+ exports.DEFINITION_FORM_MAX_EXAMPLE = 120;
207
239
  /**
208
240
  * Request: the value set a VALUE belongs to, resolved through the definition
209
241
  * index; {@link EventValueOptionsParams} -> {@link EventValueOptionsResult} |
@@ -222,6 +254,23 @@ exports.eventValueOptionsRequest = "paradox/eventValueOptions";
222
254
  * (uri + position) or by name (optionally disambiguated by kind).
223
255
  */
224
256
  exports.dependenciesRequest = "paradox/dependencies";
257
+ /**
258
+ * Request: the code snippets a host can offer for one open script document;
259
+ * {@link SnippetsParams} -> {@link SnippetsResult}. Answers for OPEN script
260
+ * documents only (the server reads the client's text, not the disk); a document
261
+ * it does not know answers with an EMPTY list, never an error.
262
+ *
263
+ * Two sources, neither hand-written. The definition and child-block skeletons
264
+ * are the measured shape of the document folder's own definition kind (at least
265
+ * half of the game's definitions of that kind carry each key, in the median
266
+ * order they hold there). The token entries are the block form of the `usage:`
267
+ * example the game's own script_docs dump ships for an engine trigger or effect,
268
+ * filtered to the block the cursor sits in.
269
+ *
270
+ * Every entry carries BOTH insert forms, exactly like completion does: `snippet`
271
+ * for a host that expands `${1:…}` tabstops, `plain` for one that does not.
272
+ */
273
+ exports.snippetsRequest = "paradox/snippets";
225
274
  /**
226
275
  * Request: the inferred scope chain at a cursor position;
227
276
  * {@link ScopeAtParams} -> {@link ScopeAtResult} | null. Answers for OPEN
@@ -234,3 +283,76 @@ exports.dependenciesRequest = "paradox/dependencies";
234
283
  * asserts more than the derived link tables actually say.
235
284
  */
236
285
  exports.scopeAtRequest = "paradox/scopeAt";
286
+ // ---- content creators --------------------------------------------------------
287
+ /**
288
+ * Request: everything a visual creator needs to draw a form for one definition
289
+ * kind; {@link DefinitionFormParams} -> {@link DefinitionForm} | null (null =
290
+ * the active game's schema has no such kind, which is the honest answer for a
291
+ * client asking about content this game does not have).
292
+ *
293
+ * Nothing in the answer is hand-written for the creator: the folder, the loc
294
+ * key patterns and the icon folder come from the schema table, the keys from
295
+ * the harvested `_*.info` structures, the option lists from the definition
296
+ * index (the same resolver {@link eventValueOptionsRequest} answers with) and
297
+ * `existing` from the same index walk {@link modOverviewRequest} does. A game
298
+ * patch that adds a key or a value changes the form without a release.
299
+ */
300
+ exports.definitionFormRequest = "paradox/definitionForm";
301
+ /**
302
+ * Request: text edits that write a definition into a script file;
303
+ * {@link DefinitionEditParams} -> {@link DefinitionEditResult}. The script
304
+ * sibling of {@link guiSourceEditRequest}, over the same span model, and with
305
+ * the same division of labour: the server never writes, it returns offsets
306
+ * into the text it was handed and the host applies them as ONE
307
+ * `WorkspaceEdit`, which keeps undo and dirty state in the editor.
308
+ *
309
+ * Offsets are UTF-16 into `params.text` (the document text, with no BOM, the
310
+ * way an editor delivers it), computed against that one text and applied
311
+ * end-first. Every edit is surgical, so a file's other definitions, its
312
+ * comments, its CRLF and its indentation stay byte-identical.
313
+ */
314
+ exports.definitionEditRequest = "paradox/definitionEdit";
315
+ /**
316
+ * Request: how the GAME prints each modifier; {@link ModifierFormatsParams} ->
317
+ * {@link ModifierFormatsResult} | null (null = the active profile names no
318
+ * formats source, or the game folder is not configured).
319
+ *
320
+ * A creator that lets a modder add `monthly_income = 0.5` has to show what the
321
+ * player will see, and the player sees "[gold_i] +0.50 Monthly Income" in
322
+ * green. None of that is written here: the flags come from the game's own
323
+ * `common/modifier_definition_formats/` (documented by `_definitions.info`
324
+ * there), every word comes from the loc index, and every icon comes from the
325
+ * `texticon` blocks of the game's `gui/texticons.gui`. A modifier no format
326
+ * block names gets the file's documented defaults, so the answer covers every
327
+ * modifier token the server knows rather than only the formatted ones.
328
+ */
329
+ exports.modifierFormatsRequest = "paradox/modifierFormats";
330
+ /**
331
+ * Request: a dynasty as a family tree; {@link DynastyTreeParams} ->
332
+ * {@link DynastyTreeResult}.
333
+ *
334
+ * Two answers behind one method. Without `dynasty` the result is the picker
335
+ * list: every dynasty the index knows, mod entries first. With `dynasty` it is
336
+ * that dynasty's houses and members, read out of the game's own
337
+ * `history/characters` files.
338
+ *
339
+ * Everything is DERIVED: the folders come from the active profile's schema
340
+ * (`dynasty`, `dynasty_house`, `character` kinds), the members from the
341
+ * character blocks themselves, the display names from the loc index. A profile
342
+ * whose schema has no `dynasty` kind answers `supported: false` and empty
343
+ * lists, which is what a client shows instead of an empty tree.
344
+ */
345
+ exports.dynastyTreeRequest = "paradox/dynastyTree";
346
+ /**
347
+ * The character-level skill keys, in the order a client shows them. MEASURED
348
+ * over the vanilla `history/characters` corpus (2026-09-03): stewardship 8 964,
349
+ * martial 8 940, diplomacy 8 908, intrigue 8 892, learning 495, prowess 150.
350
+ */
351
+ exports.DYNASTY_SKILLS = [
352
+ "diplomacy",
353
+ "martial",
354
+ "stewardship",
355
+ "intrigue",
356
+ "learning",
357
+ "prowess",
358
+ ];