@parity-app/cli 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parity-app/cli",
3
- "version": "0.0.0",
3
+ "version": "0.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Drive the Parity app from a terminal or an agent: read state, run edits, take screenshots, serve MCP.",
@@ -34,6 +34,11 @@
34
34
  "dist",
35
35
  "skills"
36
36
  ],
37
+ "scripts": {
38
+ "build": "vp pack",
39
+ "prepack": "vp pack",
40
+ "try-packed": "node scripts/try-packed.ts"
41
+ },
37
42
  "publishConfig": {
38
43
  "access": "public"
39
44
  },
@@ -42,12 +47,9 @@
42
47
  "typescript": "6.0.3"
43
48
  },
44
49
  "devDependencies": {
50
+ "@parity-app/agent": "0.0.0",
45
51
  "@parity-app/core": "0.0.0",
46
52
  "@parity-app/libgen": "0.0.0",
47
53
  "@parity-app/registry": "0.0.0"
48
- },
49
- "scripts": {
50
- "build": "vp pack",
51
- "try-packed": "node scripts/try-packed.ts"
52
54
  }
53
- }
55
+ }
package/skills/SKILL.md CHANGED
@@ -22,25 +22,62 @@ it.
22
22
 
23
23
  ## Tools
24
24
 
25
- The same tools are MCP tools and `parity` commands in a terminal. They act on a tab, which is one open project; the
26
- active tab is the default.
25
+ The same tools are MCP tools and `parity` commands in a terminal. They act on a tab, which is one open project. Without
26
+ `tab`, they act on the open project your working folder is in, and otherwise on `active`: what the person is looking at,
27
+ the active tab of the Parity window they used last. When the person says "this" or "what I've selected" without naming a
28
+ project, pass `tab: "active"` (`--tab active`) and read `get_app_state` for the selection.
27
29
 
28
30
  | MCP | CLI | What it does |
29
31
  | --------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
32
  | `get_app_state` | `parity state` | Designs, the selection, modes, components and token names, and what Parity detected (builder and config, package manager, installed versions). Start here. |
31
- | `execute` | `parity exec` | Runs a JavaScript snippet against the designs. All changes land as one undo step. |
33
+ | `get_status` | `parity status` | The revision, whether anything is unsaved and which files and tokens, the last save, and undo and redo; `summary` names them. |
34
+ | `get_modes` | `parity modes [design]` | Viewports (the ids `Responsive` takes), modes (the ids renders take) and what each design shows; a design adds its frames. |
35
+ | `execute` | `parity exec` | Runs a JavaScript snippet against the designs. Its changes land as one undo step, merged per design with edits made meanwhile. |
32
36
  | `screenshot` | `parity screenshot <design>` | Renders a design in its states and modes, offscreen, and returns the images. |
33
37
  | `find_problems` | `parity problems <design>` | Render errors, overflow, clipping and unknown components, per frame. |
34
38
  | `check_accessibility` | `parity a11y <design>` | axe-core against WCAG 2.2 AA, per frame, on the layers that break each rule. |
35
39
  | `get_console` | `parity console` | What the project's own code wrote to the console, on the canvas and offscreen. |
40
+ | `get_tokens` | `parity tokens` | Tokens filtered by category, source or name, with values in every theme. |
41
+ | `get_components` | `parity components` | Components, libraries, icon sets and exports left out or failing to render. |
42
+ | `get_props` | `parity props <Component>` | Props from source; `all` includes passed-through attributes. |
36
43
  | `get_tabs` | `parity tabs` | The open projects. |
37
44
  | `open_project` | `parity open <folder>` | Opens a project in a new tab. |
38
45
  | `read_skill` | `parity skill [file]` | This skill. |
39
46
 
40
- In a terminal, `parity tokens`, `parity components` and `parity props <Component>` read what designs can use without
41
- writing a snippet. `parity components` also says which of the app's exports aren't components and why, which components
42
- fail to draw on the canvas and why (often a missing provider, which a decorator adds), and what the person listed or
43
- took off the list by hand.
47
+ The token, component and prop tools read what designs can use without writing a snippet in either transport.
48
+ `parity components` also says which of the app's exports aren't components and why, which components fail to draw on the
49
+ canvas and why (often a missing provider, which a decorator adds), and what the person listed or took off the list by
50
+ hand.
51
+
52
+ CLI commands and MCP tools share validation and defaults. Screenshot scale defaults to 1 and accepts 0.25 to 3. Audits
53
+ check every state and shown mode unless narrowed; a single-element selector list is equivalent to a string. Screenshot
54
+ failures and audit findings exit with 1 in the CLI and set MCP `isError`, with details retained. `get_console` defaults
55
+ `clear` to false; `get_props` defaults `all` to false. MCP project paths must be absolute; the CLI resolves relative
56
+ folders from its working directory. Skill reading is local and needs no running app.
57
+
58
+ Several copies of Parity can run at once, each with its own projects open. Each call goes to the copy that has its
59
+ project open, so naming the project is enough; `get_tabs` lists every copy's projects. A project open in two copies goes
60
+ to the one that has been running longest. A copy kept apart with `PARITY_AGENT_FILE` is reached only through that file:
61
+
62
+ ```sh
63
+ parity tabs # every project open in any copy
64
+ parity state --tab active # what the person is looking at, and their selection
65
+ PARITY_AGENT_FILE=copy/agent.json pnpm dev & # a copy of Parity kept apart
66
+ PARITY_AGENT_FILE=copy/agent.json parity tabs # just that copy
67
+ ```
68
+
69
+ Every tool returns its result as data too: MCP `structuredContent`, or `--json` in the CLI. Read that rather than the
70
+ text. A failure has `error.code` to branch on, `retryable` (send it again unchanged), `path` (the input at fault) and
71
+ `alternatives` (valid ids for one it didn't know), so a mistyped id is fixed in one retry:
72
+
73
+ ```sh
74
+ parity problems button --state loading --json
75
+ # {"error": {"code": "unknown_state", "path": "/state", "alternatives": ["default", "outline", "destructive", "disabled"], ...}}
76
+ parity problems button --state disabled --json
77
+ ```
78
+
79
+ `get_tokens` returns the first 100 tokens and `get_console` the newest 50 messages, with `total` and `truncated`; narrow
80
+ the read or raise `limit` when `truncated` is true.
44
81
 
45
82
  When a library's components, tokens or icons don't show, `parity lib <package> --root <project>` describes the package
46
83
  in a `.lib.par`: its components, tokens and the providers its frames need. It writes `./<id>.lib.par` in the current
@@ -54,7 +91,8 @@ keeping the designs there, so ask before running that in someone's project.
54
91
  2. **Look before you change.** Read the design with `Get("design-id", { depth: 3 })` in `execute`, and take a screenshot
55
92
  of what's there. Find the components you need with `Components()` and their props with `Props()`.
56
93
  3. **Change it in one snippet.** Build or edit the design with `Insert`, `Update`, `Replace`, `Move` and the rest. A
57
- snippet either applies whole, as one step the person can undo, or changes nothing. Name the layouts you make.
94
+ snippet either applies whole, as one step the person can undo, or changes nothing. Name the layouts you make. If it
95
+ fails because the person changed a design it changes, run it again by its `editId`.
58
96
  4. **Cover every state.** A screen that loads has a loading state, a list has an empty one, a form has an error one. Add
59
97
  them with `AddState`, as changes to the base design, not as copies.
60
98
  5. **Check every frame.** Screenshot the design in all its states and the modes it shows (`state: "all"`,
@@ -65,7 +103,15 @@ keeping the designs there, so ask before running that in someone's project.
65
103
 
66
104
  Your changes to designs are on the canvas but not saved: the person saves (Ctrl+S) or undoes them, as with their own
67
105
  edits. Don't say they're saved. Token values from `SetTokens` are the same: they show at once, and go into the project's
68
- stylesheet when the person saves.
106
+ stylesheet when the person saves. `get_status` says what's saved and what isn't, and its `revision` (also in
107
+ `get_app_state`) stays the same until something changes, so compare it before reading the board again:
108
+
109
+ ```sh
110
+ parity status --summary
111
+ # shadcn-vite is at revision 7c612c04:1.
112
+ # 1 file isn't saved. They wait for the person to save; agents can't.
113
+ # shadcn-vite.par: changed button
114
+ ```
69
115
 
70
116
  ## Rules
71
117
 
@@ -86,11 +132,12 @@ stylesheet when the person saves.
86
132
  - **Reuse what repeats.** When a row, card or list item appears more than twice, make it a component design with
87
133
  `ExtractComponent`, so each copy is an instance with its own content.
88
134
  - **Leave the canvas tidy.** New designs go into empty space (`FindEmptySpace`); `Overlaps()` tells you if boards
89
- collide.
135
+ collide, sizing boards the canvas hasn't drawn yet from their frames (`estimated: true`).
90
136
 
91
137
  ## When something fails
92
138
 
93
- `execute` returns an `editId` when a snippet throws, and nothing changes. Fix it with `editId` and `edits` (exact find
94
- and replace on the snippet) instead of sending it all again. The error names the line. Common causes: a node path that
95
- matches two designs (write it as `design/node`), a node property that doesn't exist, and a state change to something
96
- states can't change (only `hidden`, `text`, `props` and `style`).
139
+ `execute` returns an `editId` when a snippet throws, and nothing changes; `error.code` says why, and
140
+ `error.alternatives` names the valid ids when a design, state, mode or component wasn't found. Fix it with `editId` and
141
+ `edits` (exact find and replace on the snippet) instead of sending it all again. The error names the line. Common
142
+ causes: a node path that matches two designs (write it as `design/node`), a node property that doesn't exist, and a
143
+ state change to something states can't change (only `hidden`, `text`, `props` and `style`).
@@ -120,6 +120,10 @@ type name a token from `GetTokens()`, without the `--`.
120
120
  | `transform`, `decoration`, `italic` | `uppercase` and the like, `underline` or `line-through`, `true` |
121
121
  | `lines` | Lines of text before an ellipsis |
122
122
 
123
+ A text layer sizes as Figma's text does, by its `width` and `height`: `width: "hug"` is auto width, one line as wide as
124
+ its text, wrapped only by a `maxWidth`; any other width, or none, with no `height` is auto height, wrapping at its width
125
+ and growing down; a `height` as well is fixed.
126
+
123
127
  Type set on a layout applies to the text inside it. A component's own look comes from its props, so reach for a variant
124
128
  (`variant: "secondary"`) before styling a component from outside.
125
129
 
@@ -150,7 +154,8 @@ or hides the node. `ExtractComponent` sets all of this up from the occurrences i
150
154
  A **variant** is a param whose `options` each patch the component design, the way a state does: a size or a tone the
151
155
  instance chooses. Its `default` is an option's id, else the first option. An instance picks one in its `args`, and
152
156
  `view.variants` picks which one the component's own board shows. Patches apply in this order: the viewport's, the
153
- variant options', the state's, then the instance's overrides.
157
+ variant options', the state's, then the instance's overrides. `Get` returns the stored node, with the text it was given;
158
+ `Get(path, { state })` returns it as the board shows it, the param's value filled in and `bind` kept (see execute.md).
154
159
 
155
160
  ```json
156
161
  "params": {
package/skills/execute.md CHANGED
@@ -4,12 +4,30 @@
4
4
  `await` works at the top level. When the snippet finishes, every change lands on the canvas as one step the person can
5
5
  undo; when it throws, nothing changes and you get an `editId` to fix it with.
6
6
 
7
- - Pass `description`: 3 to 8 words the person sees while it runs, such as "Add a pricing section".
7
+ The person, and other agents, can change the tab while your snippet runs. Only the designs your snippet changed, created
8
+ or deleted are applied, over what's there by then, so their edits to other designs, even in the same file, stay. If a
9
+ design you changed was changed or deleted in the meantime, or the modes were and you set them, nothing is applied and
10
+ the call fails naming it:
11
+
12
+ ```text
13
+ Failed, nothing changed: Not applied: since this call read the tab, "Pricing" (app.par) was changed in the editor, and
14
+ this call changes it too. Run the call again to work from what's there now.
15
+ ```
16
+
17
+ Run it again with its `editId` and no edits (`parity exec --edit-id <id>`, or `execute` with just `editId`): the snippet
18
+ reads the tab afresh, so it works from their change. Read the design again first if your snippet depends on what it
19
+ held.
20
+
21
+ - Prefer a `description` of 3 to 8 words, such as "Add a pricing section". CLI `exec` calls it `--label`. Both default
22
+ to "Edit designs" if omitted.
8
23
  - `Print(...)` (or `console.log`) is how you see values. Objects print as JSON.
9
24
  - Values assigned without `const` or `let` carry over to your next snippet in the same tab.
10
25
  - A snippet has 5 seconds of computing time. Rendering (screenshots and checks) doesn't count against it.
11
26
  - To retry a failed snippet, send `editId` with `edits`, each an exact `{ find, replace }` on the snippet text (`all` to
12
- replace every match).
27
+ replace every match). Omitted edits default to an empty list. Do not send a new snippet with `editId`.
28
+ - Both CLI and MCP validate the same request: a nonblank snippet or `editId`, nonblank label and tab when supplied, and
29
+ patches with a nonempty `find`, string `replace` (which can be empty), and optional boolean `all`. Invalid requests
30
+ are rejected before reaching the app.
13
31
 
14
32
  ## API
15
33
 
@@ -17,12 +35,15 @@ undo; when it throws, nothing changes and you get an `editId` to fix it with.
17
35
  // Reading
18
36
  Designs(): DesignSummary[] // every design: id, name, kind, states, what it shows, size
19
37
  GetDesign(design): Design // a whole design, as in document.md
20
- Get(path, { depth?, state? }?): Node // a design's root or a node; depth cuts children off with "…"
38
+ Get(path, { depth?, state?, mode? }?): Node // a design's root or a node; depth cuts children off with "…"
21
39
  Get(path?, visit): any[] // walks nodes, collecting what visit returns
40
+ Get(path, visit, { state?, mode? }): any[] // walks nodes as a frame draws them
22
41
  Components(): string[] // the components designs can use
23
42
  Props(component, { all? }?): PropsInfo // a component's props, from its source
43
+ Icons(): IconSet[] // the project's icon sets, with their styles
44
+ Icons(set, { search?, style?, limit? }): Icon[] // async: a set's icons, as component nodes name them
24
45
  GetTokens({ category?, source?, search? }?): Token[]
25
- GetModes(): { settings, modes } // the project's modes, and each resolved
46
+ GetModes(design?): { settings, variables, viewports, modes, designs } // modes resolved; what each design shows
26
47
  Selection(): { design?, node?, mode? } // what the person has selected
27
48
 
28
49
  // Designs
@@ -80,11 +101,27 @@ canvas, the main mode and the modes beside it. Start here to find ids.
80
101
  ### Get
81
102
 
82
103
  `Get("dashboard", { depth: 2 })` returns the design's root with two levels of children; deeper ones show as `"…"`. Read
83
- a branch with a node path, as in `Get("dashboard/Stats", { depth: 2 })`. With `state`, the result shows the nodes as
84
- that state changes them.
104
+ a branch with a node path, as in `Get("dashboard/Stats", { depth: 2 })`. Without `state` or `mode`, Get returns the
105
+ nodes as stored, which is what `Update` and the other edits change.
106
+
107
+ With `state`, `mode` or both, Get returns the nodes as that frame of the board draws them: the design's variant options
108
+ (`view.variants`), its params' defaults filled into bound values, its responsive patches for the mode, then the state's
109
+ patches. `mode` is a mode id from `GetModes()`, as Screenshot takes. A state alone is read in the design's main mode,
110
+ and a mode alone in the state the design shows. A bound value comes back filled in, with its `bind` kept so you can tell
111
+ it comes from a param. An instance comes back as its own node with the args it's drawn with; read what's inside it by
112
+ its path, `design/instance/inner`, which only works with `state` or `mode`.
113
+
114
+ ```js
115
+ // A component whose title is bound to its "title" param: stored, then as the board shows it.
116
+ Print(Get("card/title").text) // "Title"
117
+ Print(Get("card/title", { state: "base" }).text) // "Card title", the param's default
118
+ // A copy of the card on a screen, inside the instance, in a state and on mobile.
119
+ Print(Get("profile/person/title", { state: "selected", mode: "mobile-light" }).text) // "Selected"
120
+ ```
85
121
 
86
122
  `Get(path, visit)` walks the nodes under `path`, or every design without one, and returns what `visit` returns for each.
87
- `visit(node, { design, path, depth, index, parent, skipChildren })`. Return `undefined` to collect nothing.
123
+ `visit(node, { design, path, depth, index, parent, skipChildren })`. Return `undefined` to collect nothing. Given a
124
+ path, `Get(path, visit, { state, mode })` visits the nodes as that frame draws them, as above.
88
125
 
89
126
  ```js
90
127
  // Every Button in the project, with where it is.
@@ -97,6 +134,26 @@ Print(Get((node, at) => (node.type === "component" && node.component === "Button
97
134
  source: variants with their options (`variant`, `size`), its own props, and with `{ all: true }` the attributes it
98
135
  passes to its element. A prop that isn't listed, or a variant value outside its options, comes back as a warning.
99
136
 
137
+ ### Icons
138
+
139
+ `Icons()` lists the project's icon sets: each one's `id`, `name`, `package`, `styles` (such as `outline` and `solid`,
140
+ empty when it has one) and the `style` used when none is asked for. An icon is a component node named `<set>/<Icon>`,
141
+ with no children. `await Icons("lucide", { search: "settings" })` finds icons by name, by the other names the set
142
+ exports them under and by the tags it publishes, best first; each comes back with its `label` and the `component` (and
143
+ `props`, for sets that take the style as a prop) to insert it with. Without `search` it lists the set's icons in order.
144
+ It returns 50 unless `limit` says otherwise, in the set's default style unless `style` names another.
145
+
146
+ ```js
147
+ // A settings button with the project's own settings icon.
148
+ const [icon] = await Icons(Icons()[0].id, { search: "settings", limit: 1 })
149
+ Insert("dashboard/Toolbar", {
150
+ type: "component",
151
+ component: "Button",
152
+ props: { variant: "ghost", "aria-label": "Settings" },
153
+ slots: { children: [{ type: "component", component: icon.component, props: icon.props }] }
154
+ })
155
+ ```
156
+
100
157
  ### GetTokens
101
158
 
102
159
  Each token has a `name`, a `category` (`color`, `font-size`, `radius`, `shadow`, `spacing`, `font`, `font-weight`,
@@ -217,6 +274,18 @@ ExtractComponent("team-members", rows.nodes, { name: "Member row", params: { [ro
217
274
  `SetModes(settings)` replaces the project's modes: take `GetModes().settings`, change it, and pass it back. Modes are
218
275
  shared by every design.
219
276
 
277
+ `GetModes()` also gives `viewports`, the ids `Responsive` takes, each with its width and window height; `modes`, the ids
278
+ `Screenshot` and the checks take, each with its `values` (one option per variable), width, window height, classes and
279
+ attributes; and `designs`, each design's `state` (or `states` when it shows every state), `main` mode and `beside`
280
+ modes. `GetModes("dashboard")` gives just that design, with each frame's width, fixed `height` if it has one, and
281
+ `window`.
282
+
283
+ ```js
284
+ const { viewports, designs } = GetModes("dashboard")
285
+ Print(viewports.map((viewport) => viewport.id)) // ["desktop", "tablet", "mobile"]: for Responsive
286
+ Print(designs[0].frames.map((frame) => `${frame.mode} ${frame.window.width}x${frame.window.height}`))
287
+ ```
288
+
220
289
  `SetTokens` changes token values in the project's stylesheets: `SetTokens({ primary: "oklch(0.55 0.2 260)" })` for every
221
290
  theme, or `SetTokens({ primary: { default: "…", dark: "…" } })` per theme. Every frame shows the new values at once, and
222
291
  saving writes them into the project's code, so do it only when the person asks to change the design system, not to style
@@ -228,15 +297,34 @@ one design. They're undone with the call's other changes.
228
297
  result. `state` and `mode` take an id, a list, or `"all"`; `mode` also takes `"shown"`, the modes the design shows. The
229
298
  defaults are the state on the canvas and the main mode.
230
299
 
300
+ Frames draw as the canvas does: instances of a library's component designs (from its `.lib.par`) draw that design, and
301
+ token values not yet saved show, the person's edits and this call's own `SetTokens` alike, so
302
+ `SetTokens({ primary: "red" }); await Screenshot(id)` shows the new value in the same call.
303
+
231
304
  `Measure` lays out one frame and returns its size, whether it overflows sideways, and every node's box (`clipped` when a
232
305
  parent cuts it off). `Problems` checks frames for render errors, overflow, clipping and unknown components.
233
306
  `Accessibility` returns axe-core's findings per node and frame, with the rule, its impact and what's wrong.
234
307
 
308
+ These frames are drawn in the same window as the canvas's: as wide as the frame, and as tall as the design's fixed
309
+ height for the viewport, else the viewport's screen height, else the device nearest its width. So `100vh` and window
310
+ size checks measure the same in `Measure` and `Screenshot` as on the canvas, even when the frame grows past that height.
311
+
235
312
  ## The canvas
236
313
 
237
314
  `FindEmptySpace({ width, height })` finds room for a new board, to the right of the others unless `direction: "below"`,
238
315
  or next to the design named in `near`. `Overlaps()` lists boards that collide, titles included; move one with
239
- `UpdateDesign(design, { x, y })`.
316
+ `UpdateDesign(design, { x, y })`. A board is as big as the canvas last drew it. One it hasn't drawn yet is sized from
317
+ its frames, laid out as the canvas lays them out: each shown mode's frame size (`frames` on the design, else the mode's
318
+ width), companions shrunk to 640 wide, and a frame without a fixed height as tall as its window. Those overlaps say
319
+ `estimated: true`.
320
+
321
+ ```js
322
+ // With the default modes: a 1280 main frame, the dark one beside it at half size and the 390 phone, 2505 wide in all.
323
+ const dashboard = CreateDesign({ name: "Dashboard", x: 0, y: 0 })
324
+ UpdateDesign(dashboard, { showModes: ["desktop-dark", "mobile-light"] })
325
+ CreateDesign({ name: "Settings", x: 2200, y: 0 })
326
+ Print(Overlaps(dashboard)) // Dashboard and Settings, 305 across, estimated: true
327
+ ```
240
328
 
241
329
  ## Examples
242
330
 
@@ -30,9 +30,11 @@ Modes are the project's, shared by every design. Each mode picks one option of e
30
30
  - **Theme:** a class on the frame, such as `dark`, that switches the project's tokens.
31
31
  - **Locale:** `lang` and `dir` attributes, for languages and right-to-left scripts.
32
32
 
33
- `GetModes()` lists them. A design shows its main mode and, beside it, any others you choose with
34
- `UpdateDesign(design, { showModes: ["desktop-dark", "mobile-light"] })`. Show the modes that matter for the design: a
35
- dashboard in desktop and mobile, a component in light and dark.
33
+ `get_modes` (`parity modes`) lists them, and `get_modes` with a design gives its frames: run it before a responsive
34
+ change, since the ids `Responsive` takes are viewports (`mobile`) and the ids screenshots take are modes
35
+ (`mobile-light`). `GetModes()` gives the same in a snippet. A design shows its main mode and, beside it, any others you
36
+ choose with `UpdateDesign(design, { showModes: ["desktop-dark", "mobile-light"] })`. Show the modes that matter for the
37
+ design: a dashboard in desktop and mobile, a component in light and dark.
36
38
 
37
39
  ## Viewports and responsive patches
38
40
 
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Andrew Craswell
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.