grooph 0.0.0-stage → 0.4.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.
- package/LICENSE +21 -0
- package/README.md +62 -2
- package/THIRD-PARTY-NOTICES.md +450 -0
- package/dist/app/assets/App-48y1Ec5B.js +5 -0
- package/dist/app/assets/App-Cv1auMeh.css +1 -0
- package/dist/app/assets/EmbedApp-390Z2d4x.js +1 -0
- package/dist/app/assets/EmbedApp-CWb_HGpW.css +1 -0
- package/dist/app/assets/ExportPanel-Ca3wBB38.js +8 -0
- package/dist/app/assets/Import-ByMI7Uz9.js +1 -0
- package/dist/app/assets/base-CeJeskZg.css +1 -0
- package/dist/app/assets/brakes-BJPDrrJT.js +1 -0
- package/dist/app/assets/builtins-D_22fKRF.js +1 -0
- package/dist/app/assets/compile-BAvi-rd0.js +15 -0
- package/dist/app/assets/fonts/OFL-atkinson-hyperlegible-mono.txt +93 -0
- package/dist/app/assets/fonts/OFL-atkinson-hyperlegible-next.txt +93 -0
- package/dist/app/assets/fonts/atkinson-hyperlegible-mono.v1.woff2 +0 -0
- package/dist/app/assets/fonts/atkinson-hyperlegible-next-italic.v1.woff2 +0 -0
- package/dist/app/assets/fonts/atkinson-hyperlegible-next.v1.woff2 +0 -0
- package/dist/app/assets/front-BRl7rl-u.js +107 -0
- package/dist/app/assets/graph-more-393HTgQE.js +2 -0
- package/dist/app/assets/graph-stage-BkrQGQ-z.js +4 -0
- package/dist/app/assets/graph-views-COQF_QTQ.js +2 -0
- package/dist/app/assets/groups-CjEPiwfv.js +1 -0
- package/dist/app/assets/index-CeaKwKuU.js +10 -0
- package/dist/app/assets/offline-Byh4d-Wf.js +49 -0
- package/dist/app/assets/plan-templates-BQu8G2sX.js +1 -0
- package/dist/app/assets/runs-DcjRi7S6.js +1 -0
- package/dist/app/assets/screens-DWbqIw6l.css +1 -0
- package/dist/app/assets/screens-aIjMSzZg.js +16 -0
- package/dist/app/assets/share-BzIzB4EY.js +8 -0
- package/dist/app/assets/site-icons.v1.svg +9 -0
- package/dist/app/assets/space-DWgrlnfB.js +1 -0
- package/dist/app/assets/styles-BA1aVO9R.css +1 -0
- package/dist/app/assets/templates-CoNTzuuz.js +2 -0
- package/dist/app/assets/themes-DtOBrLk0.js +1 -0
- package/dist/app/assets/units-DOIUgOIU.js +1 -0
- package/dist/app/assets/views-CLwg5VNv.js +1 -0
- package/dist/app/demo/run.txt +1 -0
- package/dist/app/favicon.svg +1 -0
- package/dist/app/grooph-app.json +1 -0
- package/dist/app/icon-192.png +0 -0
- package/dist/app/icon-512.png +0 -0
- package/dist/app/icon-maskable-512.png +0 -0
- package/dist/app/index.html +42 -0
- package/dist/app/llms.txt +26 -0
- package/dist/app/manifest.webmanifest +16 -0
- package/dist/app/og.png +0 -0
- package/dist/app/routes.json +81 -0
- package/dist/app/sw.js +217 -0
- package/dist/bundle/grooph.js +18109 -0
- package/dist/patterns/contradiction-seeker.grooph.json +189 -0
- package/dist/patterns/debate-then-build.grooph.json +307 -0
- package/dist/patterns/dual-bar.grooph.json +200 -0
- package/dist/patterns/fresh-grind-rare-judge.grooph.json +252 -0
- package/dist/patterns/gauntlet-decomposed.grooph.json +427 -0
- package/dist/patterns/glyphs/contradiction-seeker.svg +13 -0
- package/dist/patterns/glyphs/debate-then-build.svg +28 -0
- package/dist/patterns/glyphs/dual-bar.svg +13 -0
- package/dist/patterns/glyphs/fresh-grind-rare-judge.svg +21 -0
- package/dist/patterns/glyphs/gauntlet-decomposed.svg +39 -0
- package/dist/patterns/glyphs/grind-loop.svg +13 -0
- package/dist/patterns/glyphs/heterogeneous-critic.svg +18 -0
- package/dist/patterns/glyphs/human-gated-irreversible.svg +11 -0
- package/dist/patterns/glyphs/merge-queue.svg +20 -0
- package/dist/patterns/glyphs/metric-sandwich.svg +18 -0
- package/dist/patterns/glyphs/ownership-not-swarm.svg +25 -0
- package/dist/patterns/glyphs/patrol-pulse.svg +21 -0
- package/dist/patterns/glyphs/ralph-loop.svg +18 -0
- package/dist/patterns/glyphs/red-team-loop.svg +13 -0
- package/dist/patterns/glyphs/retrospective-rewrite.svg +16 -0
- package/dist/patterns/glyphs/review-gate.svg +18 -0
- package/dist/patterns/glyphs/spec-then-loop.svg +19 -0
- package/dist/patterns/glyphs/specialist-critic-bank.svg +36 -0
- package/dist/patterns/glyphs/taste-polish.svg +18 -0
- package/dist/patterns/glyphs/tournament-then-judge.svg +22 -0
- package/dist/patterns/grind-loop.grooph.json +130 -0
- package/dist/patterns/heterogeneous-critic.grooph.json +218 -0
- package/dist/patterns/human-gated-irreversible.grooph.json +94 -0
- package/dist/patterns/index.json +580 -0
- package/dist/patterns/merge-queue.grooph.json +199 -0
- package/dist/patterns/metric-sandwich.grooph.json +214 -0
- package/dist/patterns/ownership-not-swarm.grooph.json +289 -0
- package/dist/patterns/patrol-pulse.grooph.json +213 -0
- package/dist/patterns/ralph-loop.grooph.json +188 -0
- package/dist/patterns/red-team-loop.grooph.json +193 -0
- package/dist/patterns/retrospective-rewrite.grooph.json +166 -0
- package/dist/patterns/review-gate.grooph.json +216 -0
- package/dist/patterns/spec-then-loop.grooph.json +235 -0
- package/dist/patterns/specialist-critic-bank.grooph.json +384 -0
- package/dist/patterns/taste-polish.grooph.json +232 -0
- package/dist/patterns/tournament-then-judge.grooph.json +247 -0
- package/dist/plans/literature-review.grooph.json +306 -0
- package/dist/plans/research-study.grooph.json +367 -0
- package/dist/plans/solo-project.grooph.json +210 -0
- package/dist/plans/team-handoffs.grooph.json +203 -0
- package/hooks/grooph-event.mjs +103 -0
- package/hooks/grooph-events-push.mjs +954 -0
- package/package.json +38 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Joseph Kamp
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,63 @@
|
|
|
1
|
-
#
|
|
1
|
+
# grooph
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Loop graphs for coding agents.** You, or an agent working with you, say who builds, who checks, where a person decides and when the work stops, in one small JSON document. grooph checks that every loop names a stop and every bar names what a critic can inspect, then compiles the graph into a prompt package for Claude Code or for Codex. Your harness runs the package. grooph never runs an agent and never calls a model.
|
|
4
|
+
|
|
5
|
+
A graph can also be a plan for people: `grooph plan` writes a plan people can follow, for any graph that reads.
|
|
6
|
+
|
|
7
|
+
This package is the command line, the built-in templates, an MCP server and the app `grooph watch` serves. It has no dependencies, and one optional one: `@resvg/resvg-js`, the PNG renderer, which has no install script.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx grooph --help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## A first graph
|
|
14
|
+
|
|
15
|
+
Node 22 or later. This makes a graph from a template, checks it, draws it, and writes the package Claude Code runs:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx grooph template use grind-loop --name "Fix the flaky test" --set task="make the checkout test pass ten times in a row" --set test-command="pnpm test checkout" --out flaky.grooph.json
|
|
19
|
+
npx grooph validate --for-export flaky.grooph.json
|
|
20
|
+
npx grooph image flaky.grooph.json --out flaky.svg
|
|
21
|
+
npx grooph export flaky.grooph.json --target claude-code --into .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A package is for Claude Code or for Codex: `--target codex` writes one for a graph that names Codex. `grooph template list` shows every template with when to use it. `grooph explain flaky.grooph.json` says in plain words what the graph's brakes are. `grooph share flaky.grooph.json` prints a link that opens the graph in the [grooph app](https://ryanjosephkamp.github.io/grooph/) on any device; the graph travels after the `#`, which a browser sends to no server.
|
|
25
|
+
|
|
26
|
+
Install it once to drop the `npx`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install --global grooph
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A PNG (`--out flaky.png`) needs the optional renderer `@resvg/resvg-js`, which npm installs with grooph where a build for the platform exists. The SVG is the same drawing and needs nothing.
|
|
33
|
+
|
|
34
|
+
## For an agent
|
|
35
|
+
|
|
36
|
+
`grooph mcp` is an MCP server over standard input and output. An agent with nothing but tool calls can pick a template, fill it, change it, check it, draw it and hand back a link. Documents go in and come back as JSON, so no file has to exist.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
claude mcp add grooph -- npx -y grooph mcp # Claude Code
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```toml
|
|
43
|
+
# Codex, in ~/.codex/config.toml
|
|
44
|
+
[mcp_servers.grooph]
|
|
45
|
+
command = "npx"
|
|
46
|
+
args = ["-y", "grooph", "mcp", "--harness", "codex"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{ "mcpServers": { "grooph": { "command": "npx", "args": ["-y", "grooph", "mcp", "--chat"] } } }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The last one is for a chat in Claude's desktop app (`claude_desktop_config.json`): `--chat` offers the authoring tools only, and reads and writes no file of yours.
|
|
54
|
+
|
|
55
|
+
- [The page for agents](https://ryanjosephkamp.github.io/grooph/docs/agents/): the shortest path, every operation by example, what to do about each rule, and when no graph is the right answer.
|
|
56
|
+
- [From a chat](https://ryanjosephkamp.github.io/grooph/docs/chat/): what works in Claude's desktop app, in claude.ai and in ChatGPT.
|
|
57
|
+
- [Every rule by its code](https://ryanjosephkamp.github.io/grooph/docs/rules/), and [the graph document](https://ryanjosephkamp.github.io/grooph/docs/graph-ir/).
|
|
58
|
+
|
|
59
|
+
## What it does not do
|
|
60
|
+
|
|
61
|
+
It runs no agent, calls no model and needs no hosted service, and it uploads nothing unless you ask: `grooph events push`, or the hook installed with `--push`, sends what the hook recorded to a branch of its own on the project's own remote, which is public when the repository is. `grooph export` places files and prints a kickoff prompt; pasting that prompt into your harness is your decision. `grooph hooks install` adds an event hook that records which sessions and subagents ran, for `grooph watch` to show; the hook appends one line per event, its script returns no decision to the harness, and an agent can read what it wrote through grooph's own tool.
|
|
62
|
+
|
|
63
|
+
Source, issues and the templates' recorded runs: [github.com/ryanjosephkamp/grooph](https://github.com/ryanjosephkamp/grooph). MIT. The app this package serves holds other people's code; their names and licenses are in `THIRD-PARTY-NOTICES.md`, beside this file.
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
grooph 0.4.1 is under the MIT license (`LICENSE`). Two of its files are built files that hold other people's code, and this page carries those people's notices, as their licenses ask. It is written by the build from what the builds themselves say went into each file, not from a list kept by hand.
|
|
4
|
+
|
|
5
|
+
## In the app (`dist/app/`), which `grooph watch` serves
|
|
6
|
+
|
|
7
|
+
18 packages, each with the license text its own package carries:
|
|
8
|
+
|
|
9
|
+
### @xyflow/react 12.11.6
|
|
10
|
+
|
|
11
|
+
License: MIT · https://reactflow.dev
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
MIT License
|
|
15
|
+
|
|
16
|
+
Copyright (c) 2019-2025 webkid GmbH
|
|
17
|
+
|
|
18
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
20
|
+
in the Software without restriction, including without limitation the rights
|
|
21
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
22
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
23
|
+
furnished to do so, subject to the following conditions:
|
|
24
|
+
|
|
25
|
+
The above copyright notice and this permission notice shall be included in all
|
|
26
|
+
copies or substantial portions of the Software.
|
|
27
|
+
|
|
28
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
29
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
31
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
32
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
34
|
+
SOFTWARE.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### @xyflow/system 0.0.82
|
|
38
|
+
|
|
39
|
+
License: MIT · https://github.com/xyflow/xyflow
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
MIT License
|
|
43
|
+
|
|
44
|
+
Copyright (c) 2019-2025 webkid GmbH
|
|
45
|
+
|
|
46
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
47
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
48
|
+
in the Software without restriction, including without limitation the rights
|
|
49
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
50
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
51
|
+
furnished to do so, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
The above copyright notice and this permission notice shall be included in all
|
|
54
|
+
copies or substantial portions of the Software.
|
|
55
|
+
|
|
56
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
57
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
58
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
59
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
60
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
61
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
62
|
+
SOFTWARE.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### classcat 5.0.5
|
|
66
|
+
|
|
67
|
+
License: MIT · jorgebucaran/classcat
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
Copyright © Jorge Bucaran <<https://jorgebucaran.com>>
|
|
71
|
+
|
|
72
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
73
|
+
|
|
74
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
75
|
+
|
|
76
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### d3-color 3.1.0
|
|
80
|
+
|
|
81
|
+
License: ISC · https://d3js.org/d3-color/
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
Copyright 2010-2022 Mike Bostock
|
|
85
|
+
|
|
86
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
87
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
88
|
+
and this permission notice appear in all copies.
|
|
89
|
+
|
|
90
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
91
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
92
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
93
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
94
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
95
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
96
|
+
THIS SOFTWARE.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### d3-dispatch 3.0.1
|
|
100
|
+
|
|
101
|
+
License: ISC · https://d3js.org/d3-dispatch/
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
Copyright 2010-2021 Mike Bostock
|
|
105
|
+
|
|
106
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
107
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
108
|
+
and this permission notice appear in all copies.
|
|
109
|
+
|
|
110
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
111
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
112
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
113
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
114
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
115
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
116
|
+
THIS SOFTWARE.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### d3-drag 3.0.0
|
|
120
|
+
|
|
121
|
+
License: ISC · https://d3js.org/d3-drag/
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
Copyright 2010-2021 Mike Bostock
|
|
125
|
+
|
|
126
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
127
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
128
|
+
and this permission notice appear in all copies.
|
|
129
|
+
|
|
130
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
131
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
132
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
133
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
134
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
135
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
136
|
+
THIS SOFTWARE.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### d3-ease 3.0.1
|
|
140
|
+
|
|
141
|
+
License: BSD-3-Clause · https://d3js.org/d3-ease/
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
Copyright 2010-2021 Mike Bostock
|
|
145
|
+
Copyright 2001 Robert Penner
|
|
146
|
+
All rights reserved.
|
|
147
|
+
|
|
148
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
149
|
+
are permitted provided that the following conditions are met:
|
|
150
|
+
|
|
151
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
152
|
+
list of conditions and the following disclaimer.
|
|
153
|
+
|
|
154
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
155
|
+
this list of conditions and the following disclaimer in the documentation
|
|
156
|
+
and/or other materials provided with the distribution.
|
|
157
|
+
|
|
158
|
+
* Neither the name of the author nor the names of contributors may be used to
|
|
159
|
+
endorse or promote products derived from this software without specific prior
|
|
160
|
+
written permission.
|
|
161
|
+
|
|
162
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
163
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
164
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
165
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
166
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
167
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
168
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
169
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
170
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
171
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### d3-interpolate 3.0.1
|
|
175
|
+
|
|
176
|
+
License: ISC · https://d3js.org/d3-interpolate/
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
Copyright 2010-2021 Mike Bostock
|
|
180
|
+
|
|
181
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
182
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
183
|
+
and this permission notice appear in all copies.
|
|
184
|
+
|
|
185
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
186
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
187
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
188
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
189
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
190
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
191
|
+
THIS SOFTWARE.
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### d3-selection 3.0.0
|
|
195
|
+
|
|
196
|
+
License: ISC · https://d3js.org/d3-selection/
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
Copyright 2010-2021 Mike Bostock
|
|
200
|
+
|
|
201
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
202
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
203
|
+
and this permission notice appear in all copies.
|
|
204
|
+
|
|
205
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
206
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
207
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
208
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
209
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
210
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
211
|
+
THIS SOFTWARE.
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### d3-timer 3.0.1
|
|
215
|
+
|
|
216
|
+
License: ISC · https://d3js.org/d3-timer/
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
Copyright 2010-2021 Mike Bostock
|
|
220
|
+
|
|
221
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
222
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
223
|
+
and this permission notice appear in all copies.
|
|
224
|
+
|
|
225
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
226
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
227
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
228
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
229
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
230
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
231
|
+
THIS SOFTWARE.
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### d3-transition 3.0.1
|
|
235
|
+
|
|
236
|
+
License: ISC · https://d3js.org/d3-transition/
|
|
237
|
+
|
|
238
|
+
```text
|
|
239
|
+
Copyright 2010-2021 Mike Bostock
|
|
240
|
+
|
|
241
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
242
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
243
|
+
and this permission notice appear in all copies.
|
|
244
|
+
|
|
245
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
246
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
247
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
248
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
249
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
250
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
251
|
+
THIS SOFTWARE.
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### d3-zoom 3.0.0
|
|
255
|
+
|
|
256
|
+
License: ISC · https://d3js.org/d3-zoom/
|
|
257
|
+
|
|
258
|
+
```text
|
|
259
|
+
Copyright 2010-2021 Mike Bostock
|
|
260
|
+
|
|
261
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
262
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
263
|
+
and this permission notice appear in all copies.
|
|
264
|
+
|
|
265
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
266
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
267
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
268
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
269
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
270
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
271
|
+
THIS SOFTWARE.
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### fflate 0.8.3
|
|
275
|
+
|
|
276
|
+
License: MIT · https://101arrowz.github.io/fflate
|
|
277
|
+
|
|
278
|
+
```text
|
|
279
|
+
MIT License
|
|
280
|
+
|
|
281
|
+
Copyright (c) 2026 Arjun Barrett
|
|
282
|
+
|
|
283
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
284
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
285
|
+
in the Software without restriction, including without limitation the rights
|
|
286
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
287
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
288
|
+
furnished to do so, subject to the following conditions:
|
|
289
|
+
|
|
290
|
+
The above copyright notice and this permission notice shall be included in all
|
|
291
|
+
copies or substantial portions of the Software.
|
|
292
|
+
|
|
293
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
294
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
295
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
296
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
297
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
298
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
299
|
+
SOFTWARE.
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### react 19.3.0
|
|
303
|
+
|
|
304
|
+
License: MIT · https://react.dev/
|
|
305
|
+
|
|
306
|
+
```text
|
|
307
|
+
MIT License
|
|
308
|
+
|
|
309
|
+
Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
310
|
+
|
|
311
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
312
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
313
|
+
in the Software without restriction, including without limitation the rights
|
|
314
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
315
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
316
|
+
furnished to do so, subject to the following conditions:
|
|
317
|
+
|
|
318
|
+
The above copyright notice and this permission notice shall be included in all
|
|
319
|
+
copies or substantial portions of the Software.
|
|
320
|
+
|
|
321
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
322
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
323
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
324
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
325
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
326
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
327
|
+
SOFTWARE.
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### react-dom 19.3.0
|
|
331
|
+
|
|
332
|
+
License: MIT · https://react.dev/
|
|
333
|
+
|
|
334
|
+
```text
|
|
335
|
+
MIT License
|
|
336
|
+
|
|
337
|
+
Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
338
|
+
|
|
339
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
340
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
341
|
+
in the Software without restriction, including without limitation the rights
|
|
342
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
343
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
344
|
+
furnished to do so, subject to the following conditions:
|
|
345
|
+
|
|
346
|
+
The above copyright notice and this permission notice shall be included in all
|
|
347
|
+
copies or substantial portions of the Software.
|
|
348
|
+
|
|
349
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
350
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
351
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
352
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
353
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
354
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
355
|
+
SOFTWARE.
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### scheduler 0.28.0
|
|
359
|
+
|
|
360
|
+
License: MIT · https://react.dev/
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
MIT License
|
|
364
|
+
|
|
365
|
+
Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
366
|
+
|
|
367
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
368
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
369
|
+
in the Software without restriction, including without limitation the rights
|
|
370
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
371
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
372
|
+
furnished to do so, subject to the following conditions:
|
|
373
|
+
|
|
374
|
+
The above copyright notice and this permission notice shall be included in all
|
|
375
|
+
copies or substantial portions of the Software.
|
|
376
|
+
|
|
377
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
378
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
379
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
380
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
381
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
382
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
383
|
+
SOFTWARE.
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### use-sync-external-store 1.7.0
|
|
387
|
+
|
|
388
|
+
License: MIT · https://github.com/react/react
|
|
389
|
+
|
|
390
|
+
```text
|
|
391
|
+
MIT License
|
|
392
|
+
|
|
393
|
+
Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
394
|
+
|
|
395
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
396
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
397
|
+
in the Software without restriction, including without limitation the rights
|
|
398
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
399
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
400
|
+
furnished to do so, subject to the following conditions:
|
|
401
|
+
|
|
402
|
+
The above copyright notice and this permission notice shall be included in all
|
|
403
|
+
copies or substantial portions of the Software.
|
|
404
|
+
|
|
405
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
406
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
407
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
408
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
409
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
410
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
411
|
+
SOFTWARE.
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### zustand 4.5.7
|
|
415
|
+
|
|
416
|
+
License: MIT · https://github.com/pmndrs/zustand
|
|
417
|
+
|
|
418
|
+
```text
|
|
419
|
+
MIT License
|
|
420
|
+
|
|
421
|
+
Copyright (c) 2019 Paul Henschel
|
|
422
|
+
|
|
423
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
424
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
425
|
+
in the Software without restriction, including without limitation the rights
|
|
426
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
427
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
428
|
+
furnished to do so, subject to the following conditions:
|
|
429
|
+
|
|
430
|
+
The above copyright notice and this permission notice shall be included in all
|
|
431
|
+
copies or substantial portions of the Software.
|
|
432
|
+
|
|
433
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
434
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
435
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
436
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
437
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
438
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
439
|
+
SOFTWARE.
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
The app's fonts, Atkinson Hyperlegible Next and Atkinson Hyperlegible Mono, are under the SIL Open Font License 1.1. Their license texts are beside them, in `dist/app/assets/fonts/`.
|
|
443
|
+
|
|
444
|
+
## In the command (`dist/bundle/grooph.js`)
|
|
445
|
+
|
|
446
|
+
grooph's own code and no other package's.
|
|
447
|
+
|
|
448
|
+
## Installed beside it, and not in this package
|
|
449
|
+
|
|
450
|
+
- `@resvg/resvg-js` (^2.6.2), an optional dependency npm installs from its own package, under that package's own license (MPL-2.0). grooph copies none of its code.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/compile-BAvi-rd0.js","assets/share-BzIzB4EY.js","assets/groups-CjEPiwfv.js","assets/Import-ByMI7Uz9.js","assets/index-CeaKwKuU.js","assets/templates-CoNTzuuz.js","assets/runs-DcjRi7S6.js","assets/EmbedApp-390Z2d4x.js","assets/EmbedApp-CWb_HGpW.css","assets/screens-aIjMSzZg.js","assets/screens-DWbqIw6l.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{a as e,c as t,n,r,s as i,t as a}from"./index-CeaKwKuU.js";import{D as o,F as s,I as c,Rt as l,Tt as u,b as d,cn as f,fn as p,i as m,n as h,r as g,rn as _,sn as v,tt as y}from"./share-BzIzB4EY.js";import{d as b,i as x,l as S,m as C,n as w,o as T,p as E,r as D,t as ee,u as te}from"./templates-CoNTzuuz.js";import{A as ne,S as re,c as ie,f as ae,j as O,l as oe,m as se,r as ce,s as le,u as ue}from"./runs-DcjRi7S6.js";var k=t(e(),1),de=String.raw`^(?!#\/(?:run\?live$|live$|run\/[^?]+$|templates$|embed(?:\?|$)|templates\/(?:built-in|yours|plan)\/[^/?]+(?:\/use)?$|g\/[^/?]+(?:\?new)?$|open\?))`,fe=String.raw`^#\/templates(?:$|\/built-in\/[^/?]+(?:\/use)?$)`,pe=`grooph.persistence`;function me(){try{let e=localStorage.getItem(pe);return e?JSON.parse(e):null}catch{return null}}function A(e){try{localStorage.setItem(pe,JSON.stringify(e))}catch{}j=e;for(let e of N)e()}var j=me(),M=!1,N=new Set;async function he(){if(!(j!==null||M)){M=!0;try{let e=typeof navigator<`u`?navigator.storage:void 0;if(!e||typeof e.persist!=`function`){A({result:`unsupported`,seen:!1});return}A({result:typeof e.persisted==`function`&&await e.persisted()||await e.persist()?`granted`:`denied`,seen:!1})}catch{A({result:`denied`,seen:!1})}finally{M=!1}}}function ge(){j&&A({...j,seen:!0})}var _e=e=>(N.add(e),()=>N.delete(e));function ve(){let e=(0,k.useSyncExternalStore)(_e,()=>j);return e&&!e.seen?e:null}ne(()=>void he());var P;function ye(){return n(`compile`,()=>r(()=>import(`./compile-BAvi-rd0.js`),__vite__mapDeps([0,1,2]))).then(e=>P=e)}var be=()=>P!==void 0;function xe(e){let t=e.target?.harness,n=t!==void 0&&_.includes(t)?t:`claude-code`,r=f(e);if(!r.doc)return{ok:!1,target:t??`(none)`,reason:`schema`,issues:r.issues};let i=y(r.doc,{forExport:!0});if(i.some(e=>e.severity===`error`))return{ok:!1,target:t??`(none)`,reason:`rules`,issues:i};if(!P)return;let a=P.keptFolder(r.doc.id);if(a!==void 0)return{ok:!1,target:n,reason:`id`,issues:[],said:a};let o=P.tryCompile(r.doc,n);return o.ok?{ok:!0,target:n,result:o.result}:{ok:!1,target:t??`(none)`,reason:`rules`,issues:o.issues}}function Se(e){let t={};for(let[n,r]of Object.entries(e))t[n]=g(r);return new Uint8Array(m(t,{level:6}))}var Ce=e=>v(e),we=e=>`${e.id||`graph`}.grooph.json`,Te=(e,t)=>`${e.id||`graph`}-${t}.zip`;function Ee(e,t,n){let r=URL.createObjectURL(new Blob([t],{type:n})),i=document.createElement(`a`);i.href=r,i.download=e,i.rel=`noopener`,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),1e4)}async function De(e){try{return await navigator.clipboard.writeText(e),!0}catch{let t=document.createElement(`textarea`);t.value=e,t.setAttribute(`readonly`,``),t.style.position=`fixed`,t.style.opacity=`0`,document.body.append(t),t.select();let n=document.execCommand(`copy`);return t.remove(),n}}var F=a(),Oe=300,ke=new WeakMap;function Ae(e){let t=ke.get(e);if(!t){let n=d(e);t={svg:n,long:Number(/viewBox="\S+ \S+ (\S+) \S+"/.exec(n)?.[1]??0)>Oe},ke.set(e,t)}return t}var je=e=>Ae(e).long;function I({doc:e,className:t,decorative:n=!1}){return(0,F.jsx)(Me,{...Ae(e),className:t,decorative:n})}function Me({svg:e,long:t,className:n,decorative:r=!1}){return(0,F.jsx)(`span`,{className:`glyph${n?` ${n}`:``}${t?` is-long`:``}`,"aria-hidden":r||void 0,dangerouslySetInnerHTML:{__html:e}})}var L={q:``,kind:[],cost:[],speed:[],rigor:[],tags:[],sort:`name`,open:!1},R={name:`Name`,cost:`Cost, low first`,speed:`Speed, fast first`,rigor:`Rigor, high first`},Ne=e=>e.kind.length+e.cost.length+e.speed.length+e.rigor.length+e.tags.length,Pe=e=>e.q.trim()===``&&Ne(e)===0&&e.sort===`name`,Fe=e=>e.toLowerCase().split(/\s+/).filter(e=>e!==``),Ie=e=>{let t=e.template;return[t.title,t.summary,t.whenToUse,...t.tags??[],e.id].join(`
|
|
3
|
+
`).toLowerCase()};function Le(e,t){let n=e.template;if(t.kind.length>0&&!t.kind.includes(n.kind)||t.cost.length>0&&!t.cost.includes(n.profile.cost)||t.speed.length>0&&!t.speed.includes(n.profile.speed)||t.rigor.length>0&&!t.rigor.includes(n.profile.rigor)||t.tags.length>0&&!t.tags.every(e=>(n.tags??[]).includes(e)))return!1;let r=Fe(t.q);if(r.length===0)return!0;let i=Ie(e);return r.every(e=>i.includes(e))}function Re(e,t,n){let r=e.template,i=t.template,a=r.title.localeCompare(i.title);if(n===`name`)return a;let o=e=>w[n][e.profile[n]],s=n===`cost`?1:-1;return(o(r)-o(i))*s||a}function ze(e,t){return e.filter(e=>Le(e,t)).sort((e,n)=>Re(e,n,t.sort))}function Be(e){let t=new Map;for(let n of e)for(let e of n.template?.tags??[])t.set(e,(t.get(e)??0)+1);return[...t].sort((e,t)=>t[1]-e[1]||e[0].localeCompare(t[0])).map(([e])=>e)}var z=(e,t)=>e.includes(t)?e.filter(e=>e!==t):[...e,t],B=`grooph.templates.browse`,Ve=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`);function He(){try{let e=localStorage.getItem(B);if(e===null)return L;let t=JSON.parse(e),n=(e,t)=>Ve(e)?e.filter(e=>t===void 0||t.includes(e)):[];return{q:typeof t.q==`string`?t.q:``,kind:n(t.kind,[`graph`,`fragment`]),cost:n(t.cost,[`low`,`medium`,`high`]),speed:n(t.speed,[`fast`,`medium`,`slow`]),rigor:n(t.rigor,[`light`,`standard`,`high`]),tags:n(t.tags),sort:typeof t.sort==`string`&&t.sort in R?t.sort:`name`,open:t.open===!0}}catch{return L}}function Ue(e){try{Pe(e)&&!e.open?localStorage.removeItem(B):localStorage.setItem(B,JSON.stringify(e))}catch{}}async function We(){let e=await O();return E((await e.templates.list()).map(e=>e.doc))}async function Ge(e){return(await(await O()).templates.get(e))?.doc}async function Ke(e,t={}){if(!e.template)throw Error(`"${e.id}" has no template block`);if(C(e))throw Error(`"${e.id}" carries errors; Yours keeps only templates that validate`);let n=await O(),r=await n.templates.get(e.id);if(r&&!t.replace)return{exists:r.doc};let i=r?Math.max(r.doc.version,e.version)+1:e.version,a={id:e.id,doc:{...structuredClone(e),version:i},savedAt:Date.now()};return await n.templates.put(a),{saved:a,replaced:r!==void 0}}async function qe(e){await(await O()).templates.delete(e)}var Je=e=>`${e.id}.grooph.json`,Ye=e=>v(e),V=(e,t,n=!1)=>`#/templates/${e}/${encodeURIComponent(t)}${n?`/use`:``}`,Xe=[];function Ze(){let[e,t]=(0,k.useState)(T);return(0,k.useEffect)(()=>{if(e!==void 0)return;let n=!0;return S().then(e=>n&&t(e),()=>n&&t(null)),()=>{n=!1}},[]),e}function Qe(){let[e,t]=(0,k.useState)(null),[n,r]=(0,k.useState)(He);(0,k.useEffect)(()=>Ue(n),[n]),(0,k.useEffect)(()=>{let e=!0;return We().then(n=>e&&t(n)),()=>{e=!1}},[]);let i=Ze(),a=i??Xe,o=(0,k.useMemo)(()=>[...e??[],...a],[e,a]),s=(0,k.useMemo)(()=>Be(o),[o]),c=(0,k.useMemo)(()=>ze(e??[],n),[e,n]),l=(0,k.useMemo)(()=>ze(a,n),[a,n]),u=c.length+l.length,[d,f]=(0,k.useState)(b),p=(0,k.useRef)(null),m=()=>{f(`asking`),te().then(f,()=>f(null)).then(()=>setTimeout(()=>p.current?.focus()))},h=o.length,g=Ne(n),[_,v]=(0,k.useState)(!1),y=_?s:s.filter((e,t)=>t<$e||n.tags.includes(e)),S=(e,t)=>r(n=>({...n,[e]:t}));return i===void 0?(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`}):(0,F.jsxs)(`div`,{className:`library templates`,children:[(0,F.jsxs)(`header`,{className:`screen-head`,children:[(0,F.jsx)(`a`,{className:`icon-btn`,href:`#/`,"aria-label":`All graphs`,children:(0,F.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M15 5 8 12l7 7`})})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h1`,{children:`Templates`}),(0,F.jsx)(`p`,{className:`muted`,children:`Start a graph from one, or insert one into a graph you have open.`})]})]}),(0,F.jsxs)(`div`,{className:`browse`,role:`search`,children:[(0,F.jsxs)(`div`,{className:`browse-row`,children:[(0,F.jsx)(`input`,{type:`search`,className:`input browse-q`,placeholder:`Search templates`,"aria-label":`Search templates`,value:n.q,onChange:e=>S(`q`,e.target.value),autoComplete:`off`,enterKeyHint:`search`}),(0,F.jsxs)(`button`,{type:`button`,className:`btn browse-toggle${g>0?` is-on`:``}`,"aria-expanded":n.open,"aria-controls":`browse-filters`,onClick:()=>S(`open`,!n.open),children:[`Filters`,g>0?(0,F.jsx)(`span`,{className:`browse-count`,children:g}):null]})]}),(0,F.jsxs)(`div`,{className:`browse-row browse-meta`,children:[(0,F.jsx)(`span`,{className:`muted browse-shown`,role:`status`,"aria-live":`polite`,children:u===h?`${h} templates`:`${u} of ${h}`}),(0,F.jsxs)(`label`,{className:`browse-sort`,children:[(0,F.jsx)(`span`,{className:`muted`,children:`Sort`}),(0,F.jsx)(`select`,{className:`input`,"aria-label":`Sort by`,value:n.sort,onChange:e=>S(`sort`,e.target.value),children:Object.keys(R).map(e=>(0,F.jsx)(`option`,{value:e,children:R[e]},e))})]}),Pe(n)?null:(0,F.jsx)(`button`,{type:`button`,className:`link browse-clear`,onClick:()=>r({...L,open:n.open}),children:`Clear`})]}),n.open?(0,F.jsxs)(`div`,{className:`browse-filters`,id:`browse-filters`,children:[(0,F.jsx)(H,{label:`Kind`,options:[`graph`,`fragment`],text:e=>e===`graph`?`Whole graph`:`Fragment`,on:n.kind,onToggle:e=>S(`kind`,z(n.kind,e))}),[`cost`,`speed`,`rigor`].map(e=>(0,F.jsx)(H,{label:e[0].toUpperCase()+e.slice(1),options:D[e],text:e=>e[0].toUpperCase()+e.slice(1),title:t=>x[e][t],level:t=>w[e][t],on:n[e],onToggle:t=>S(e,z(n[e],t))},e)),s.length>0?(0,F.jsx)(H,{label:`Tags`,options:y,text:e=>e,on:n.tags,onToggle:e=>S(`tags`,z(n.tags,e)),more:s.length>$e?(0,F.jsx)(`button`,{type:`button`,className:`chip chip-small chip-more`,"aria-expanded":_,onClick:()=>v(e=>!e),children:_?`Fewer tags`:`All ${s.length} tags`}):null}):null]}):null]}),e&&e.length>0&&c.length>0?(0,F.jsxs)(`section`,{"aria-labelledby":`yours-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`yours-title`,children:`Yours`}),(0,F.jsx)(U,{source:`yours`,docs:c})]}):null,l.length>0?(0,F.jsxs)(`section`,{"aria-labelledby":`builtin-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`builtin-title`,children:`Built-in`}),(0,F.jsx)(U,{source:`built-in`,docs:l})]}):null,i===null?(0,F.jsx)(`p`,{className:`muted templates-hint`,role:`status`,children:`The built-in templates could not be fetched. They need a connection the first time. Yours are listed.`}):null,u===0?(0,F.jsxs)(`p`,{className:`muted templates-hint browse-none`,role:`status`,children:[`No template matches.`,` `,(0,F.jsx)(`button`,{type:`button`,className:`link`,onClick:()=>r({...L,open:n.open}),children:`Clear the search and filters`})]}):null,(0,F.jsxs)(`section`,{"aria-labelledby":`plans-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`plans-title`,children:`Plans`}),(0,F.jsx)(`p`,{className:`muted templates-hint`,children:ee}),(0,F.jsx)(`p`,{className:`muted templates-hint`,role:`status`,tabIndex:-1,ref:p,children:d&&d!==`asking`?`${d.length} plans, listed whole: the search and filters above are for the templates.`:(0,F.jsxs)(F.Fragment,{children:[d===null?`The plans could not be fetched. They need a connection the first time. `:null,(0,F.jsx)(`button`,{type:`button`,className:`btn`,disabled:d===`asking`,onClick:m,children:d===null?`Try again`:d===`asking`?`Fetching the plans…`:`Show the plans`})]})}),d&&d!==`asking`?(0,F.jsx)(U,{source:`plan`,docs:d}):null]}),e&&e.length===0?(0,F.jsxs)(`p`,{className:`muted templates-hint`,children:[(0,F.jsx)(`strong`,{children:`Yours`}),` is empty. Save a graph, or some of its nodes, as a template from the Graph panel of the editor, or import a template file from the graph list.`]}):null]})}var $e=8;function H({label:e,options:t,text:n,title:r,level:i,on:a,onToggle:o,more:s}){return(0,F.jsxs)(`div`,{className:`browse-group`,role:`group`,"aria-label":e,children:[(0,F.jsx)(`span`,{className:`browse-group-label`,children:e}),(0,F.jsxs)(`div`,{className:`chips browse-chips`,children:[t.map(e=>(0,F.jsxs)(`button`,{type:`button`,className:`chip chip-small${a.includes(e)?` chip-on`:``}`,"aria-pressed":a.includes(e),"aria-label":r?r(e):void 0,onClick:()=>o(e),children:[i?(0,F.jsxs)(`span`,{className:`meter`,"aria-hidden":`true`,"data-level":i(e),children:[(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{})]}):null,n(e)]},e)),s]})]})}function U({source:e,docs:t}){return(0,F.jsx)(`ul`,{className:`template-list`,"aria-label":e===`yours`?`Your templates`:e===`plan`?`Plan templates`:`Built-in templates`,children:t.map(t=>{let n=t.template;return(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`template-row${je(t)?` has-long-glyph`:``}`,href:V(e,t.id),"data-template":t.id,children:[(0,F.jsx)(I,{doc:t,className:`template-glyph`,decorative:!0}),(0,F.jsxs)(`span`,{className:`template-text`,children:[(0,F.jsxs)(`span`,{className:`template-title`,children:[n.title,n.kind===`fragment`?(0,F.jsx)(`span`,{className:`badge badge-quiet`,children:`fragment`}):null,e===`plan`?(0,F.jsx)(`span`,{className:`badge badge-quiet`,children:`plan`}):null]}),(0,F.jsxs)(`span`,{className:`template-when`,children:[(0,F.jsx)(`span`,{className:`template-label`,children:`Use when`}),` `,n.whenToUse]}),e===`plan`?null:(0,F.jsx)(et,{profile:n.profile})]})]})},t.id)})})}function et({profile:e}){return(0,F.jsx)(`ul`,{className:`template-meters`,"aria-label":`Profile`,children:[`cost`,`speed`,`rigor`].map(t=>(0,F.jsxs)(`li`,{className:`template-meter`,"aria-label":x[t][e[t]],title:x[t][e[t]],children:[(0,F.jsxs)(`span`,{className:`meter`,"aria-hidden":`true`,"data-level":w[t][e[t]],children:[(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{})]}),(0,F.jsx)(`span`,{className:`template-meter-word`,"aria-hidden":`true`,children:t})]},t))})}var W=`https://github.com/ryanjosephkamp/grooph`,G=`/grooph/docs/`,K=[{id:`grooph`,label:`Grooph`,dot:`oklch(0.85 0.14 165)`},{id:`meteor`,label:`Meteor`,dot:`oklch(0.9 0.2 124)`}],tt=`groophTheme`,nt=()=>K.find(e=>e.id===document.documentElement.dataset.theme)?.id??K[0].id;function rt(){return(0,F.jsxs)(`svg`,{viewBox:`0 0 32 32`,"aria-hidden":`true`,children:[(0,F.jsx)(`rect`,{width:`32`,height:`32`,rx:`8.5`}),(0,F.jsx)(`path`,{d:`M13.5 12.5 19 21M18.5 12.5 13 21M14 11h4`}),(0,F.jsx)(`circle`,{cx:`10`,cy:`11`,r:`4`}),(0,F.jsx)(`circle`,{cx:`22`,cy:`11`,r:`4`}),(0,F.jsx)(`circle`,{cx:`16`,cy:`23`,r:`4`})]})}var it=()=>(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`m4.5 10.5 3.5 3.5 7.5-8`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})});function at(){let[e,t]=(0,k.useState)(!1),[n,r]=(0,k.useState)(nt),i=(0,k.useRef)(null),a=(0,k.useRef)(null),o=()=>{e&&(t(!1),a.current?.focus())};return(0,k.useEffect)(()=>{let e=Array.from(document.querySelectorAll(`meta[name="theme-color"]`)),t=e.map(e=>e.content),n=i.current?getComputedStyle(i.current).backgroundColor:``;if(n)for(let t of e)t.content=n;return()=>e.forEach((e,n)=>e.content=t[n])},[n]),(0,F.jsx)(`header`,{className:`site-header has-menu`,ref:i,onKeyDown:e=>e.key===`Escape`&&o(),children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`a`,{className:`site-logo`,href:`#/`,children:[(0,F.jsx)(rt,{}),(0,F.jsx)(`span`,{children:`grooph`})]}),(0,F.jsxs)(`button`,{className:`site-menu-toggle`,type:`button`,ref:a,"aria-expanded":e,"aria-controls":`site-nav`,onClick:()=>t(!e),children:[(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M3.5 6h13M3.5 10h13M3.5 14h13`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`})}),`Menu`]}),(0,F.jsx)(`nav`,{className:`site-nav land-nav${e?` is-open`:``}`,id:`site-nav`,"aria-label":`grooph`,onClick:()=>t(!1),children:(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`#/templates`,children:`Templates`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:G,children:`Docs`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`Field guide`})}),(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{href:W,rel:`noopener`,children:[`Source`,(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M11.5 3.5h5v5M16.5 3.5l-7 7M14.5 12v3.5a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1H8`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,F.jsx)(`span`,{className:`sr-only`,children:` (GitHub)`})]})})]})}),(0,F.jsx)(ot,{theme:n,onTheme:r})]})})}function ot({theme:e,onTheme:t}){let[n,r]=(0,k.useState)(!1),i=(0,k.useRef)(null),a=(0,k.useRef)(null),o=(0,k.useRef)([]),s=K.findIndex(t=>t.id===e);(0,k.useEffect)(()=>{if(!n)return;o.current[s]?.focus();let e=e=>{i.current?.contains(e.target)||r(!1)};return document.addEventListener(`pointerdown`,e),()=>document.removeEventListener(`pointerdown`,e)},[n,s]);let c=()=>{r(!1),a.current?.focus()},l=e=>{e===K[0].id?delete document.documentElement.dataset.theme:document.documentElement.dataset.theme=e;try{localStorage.setItem(tt,e)}catch{}let n=new URL(location.href);n.searchParams.has(`theme`)&&(n.searchParams.delete(`theme`),history.replaceState(history.state,``,n)),t(e),c()};return(0,F.jsxs)(`div`,{className:`site-theme`,ref:i,children:[(0,F.jsxs)(`button`,{className:`site-theme-toggle`,type:`button`,ref:a,"aria-label":`Theme: ${K[s].label}`,"aria-haspopup":`menu`,"aria-expanded":n,"aria-controls":`site-theme-list`,onClick:()=>r(!n),onKeyDown:e=>{(e.key===`ArrowDown`||e.key===`ArrowUp`)&&(e.preventDefault(),r(!0))},children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,"aria-hidden":`true`}),(0,F.jsx)(`span`,{className:`site-theme-label`,children:`Theme`})]}),(0,F.jsxs)(`ul`,{className:`site-theme-list`,id:`site-theme-list`,role:`menu`,"aria-label":`Theme`,hidden:!n,onKeyDown:e=>{let t=o.current.indexOf(document.activeElement),n=e.key===`ArrowDown`?(t+1)%q:e.key===`ArrowUp`?(t-1+q)%q:e.key===`Home`?0:e.key===`End`?q-1:-1;n>=0?(e.preventDefault(),o.current[n]?.focus()):e.key===`Escape`?(e.stopPropagation(),c()):e.key===`Tab`&&r(!1)},children:[K.map((t,n)=>(0,F.jsx)(`li`,{role:`none`,children:(0,F.jsxs)(`button`,{type:`button`,role:`menuitemradio`,"aria-checked":t.id===e,tabIndex:-1,ref:e=>void(o.current[n]=e),onClick:()=>l(t.id),children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,style:{"--dot":t.dot},"aria-hidden":`true`}),t.label,(0,F.jsx)(it,{})]})},t.id)),(0,F.jsx)(`li`,{role:`none`,children:(0,F.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`menu`,tabIndex:-1,"data-pictures":``,ref:e=>void(o.current[K.length]=e),onClick:e=>{e.currentTarget.dataset.pressed=``,r(!1)},children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,style:{"--dot":`#0000`},"aria-hidden":`true`}),`Picture theme`]})})]})]})}var q=K.length+1,st=`/grooph/assets/site-icons.v1.svg`,ct=[{href:`https://ryanjosephkamp.github.io/`,name:`Ryan Kamp’s website`,title:`Website`,icon:`globe`},{href:`https://github.com/ryanjosephkamp/`,name:`Ryan Kamp on GitHub`,title:`GitHub`,icon:`github`},{href:`https://www.linkedin.com/in/rjk1999`,name:`Ryan Kamp on LinkedIn`,title:`LinkedIn`,icon:`linkedin`},{href:`https://x.com/ryanjosephkamp`,name:`Ryan Kamp on X`,title:`X`,icon:`x`},{href:`https://m.youtube.com/@RyanJosephKamp`,name:`Ryan Kamp on YouTube`,title:`YouTube`,icon:`youtube`}];function lt(){return(0,F.jsx)(`footer`,{className:`site-footer land-foot`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`div`,{children:[(0,F.jsxs)(`a`,{className:`site-logo`,href:`#/`,children:[(0,F.jsx)(rt,{}),(0,F.jsx)(`span`,{children:`grooph`})]}),(0,F.jsx)(`p`,{children:`Loop graphs for coding agents. Graphs live in this browser on this device. Nothing is sent anywhere.`})]}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h2`,{children:`Use it`}),(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`#/templates`,children:`Templates`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}quickstart/`,children:`Quickstart`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`Field guide`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:G,children:`Docs`})})]})]}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h2`,{children:`Help and contact`}),(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${W}/issues`,rel:`noopener`,children:`Report a bug or suggest a feature`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}community/`,children:`Community loops`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:W,rel:`noopener`,children:`Source on GitHub`})})]})]}),(0,F.jsxs)(`div`,{className:`site-credit`,children:[(0,F.jsxs)(`p`,{className:`site-made`,children:[`Made by `,(0,F.jsx)(`a`,{href:`https://ryanjosephkamp.github.io/`,children:`Ryan Kamp`})]}),(0,F.jsx)(`ul`,{className:`site-social`,"aria-label":`Ryan Kamp online`,children:ct.map(e=>(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:e.href,"aria-label":e.name,title:e.title,children:(0,F.jsx)(`svg`,{"aria-hidden":`true`,children:(0,F.jsx)(`use`,{href:`${st}#${e.icon}`})})})},e.href))}),(0,F.jsxs)(`a`,{className:`site-sponsor`,href:`https://github.com/sponsors/ryanjosephkamp`,children:[(0,F.jsx)(`svg`,{"aria-hidden":`true`,children:(0,F.jsx)(`use`,{href:`${st}#heart`})}),`Sponsor on GitHub`]})]}),(0,F.jsxs)(`p`,{className:`site-fine`,children:[`Every feature is free; sponsorship is optional and never unlocks anything. MIT license, © 2026 Ryan Kamp. This site uses no cookies, analytics or third-party requests. Fonts: Atkinson Hyperlegible Next and Mono, SIL Open Font License.`,` `,(0,F.jsx)(`a`,{href:`${W}#license-and-author`,rel:`noopener`,children:`Credits`})]})]})})}function ut({children:e}){let[t,n]=(0,k.useState)(`idle`),[r,i]=(0,k.useState)(null),[a,o]=(0,k.useState)(680),s=(0,k.useRef)(null);return(0,k.useEffect)(()=>{if(r===null)return;let e=e=>{let t=e.data;e.origin===location.origin&&e.source===s.current?.contentWindow&&t?.grooph===`embed-height`&&Number(t.height)>0&&o(Math.min(Number(t.height),4e3))};return addEventListener(`message`,e),()=>removeEventListener(`message`,e)},[r]),r===null?(0,F.jsxs)(F.Fragment,{children:[e,(0,F.jsxs)(`p`,{className:`land-play`,children:[(0,F.jsxs)(`button`,{type:`button`,className:`btn`,disabled:t===`loading`,onClick:async()=>{n(`loading`);try{let e=await fetch(`/grooph/demo/run.txt`);if(!e.ok)throw Error(String(e.status));i((await e.text()).trim()),n(`idle`)}catch{n(`failed`)}},children:[(0,F.jsx)(`span`,{"aria-hidden":`true`,children:`▶`}),` Watch a recorded run`]}),(0,F.jsx)(`span`,{className:`muted`,role:`status`,children:t===`loading`?`Fetching the run…`:t===`failed`?`The run could not be fetched. It needs a network the first time.`:``})]})]}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`iframe`,{ref:s,className:`land-run-frame`,title:`A recorded run of the heterogeneous critic template, played step by step`,src:`/grooph/#/embed?d=${r}&play=1`,style:{height:a}}),(0,F.jsxs)(`figcaption`,{className:`muted`,children:[`A run Claude Code made on 20 September, replayed from its own notes. The critic fails the first round, the builder goes again, and the run halts at the human gate.`,` `,(0,F.jsx)(`button`,{type:`button`,className:`link-button`,onClick:()=>i(null),children:`Back to the picture`})]})]})}var J=`review-gate`,dt=`/grooph-design a builder and a critic that loop until the checkout tests pass, and ask me before merging`,ft,Y=()=>n(`front`,()=>r(()=>import(`./front-BRl7rl-u.js`),[])).then(e=>ft=e),pt=600;function mt(){let[e,t]=(0,k.useState)(ft),[n,r]=(0,k.useState)(!1);return(0,k.useEffect)(()=>{if(e)return;let n=!0,i=setTimeout(()=>n&&r(!0),pt);return Y().then(e=>n&&t(e),()=>n&&r(!0)),()=>{n=!1,clearTimeout(i)}},[]),e??(n?null:void 0)}var ht=[`No account`,`Built for a phone's screen`,`Opens offline after a first visit`,`Graphs stay on your device`],X=`${G}field-guide/poster.svg`;function gt({device:e}){let[t,n]=(0,k.useState)(!0),r=mt();return r===void 0?(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`}):(0,F.jsxs)(`div`,{className:`land`,children:[(0,F.jsx)(at,{}),(0,F.jsxs)(`main`,{children:[(0,F.jsx)(`section`,{className:`land-hero`,"aria-label":`What grooph is`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`div`,{className:`land-hero-title`,children:[(0,F.jsx)(`p`,{className:`land-chip`,children:`Free and open source`}),(0,F.jsxs)(`h1`,{className:`land-headline`,children:[`Loop graphs `,(0,F.jsx)(`span`,{children:`for coding agents.`})]})]}),(0,F.jsxs)(`div`,{className:`land-hero-text`,children:[(0,F.jsx)(`p`,{className:`land-lede`,children:`Draw who builds, who checks, where a person decides and when the work stops. grooph checks that every loop names a stop, then compiles the graph into a package a Claude Code session runs. Your harness runs it; grooph never does.`}),(0,F.jsxs)(`div`,{className:`land-cta`,children:[(0,F.jsx)(`a`,{className:`btn btn-primary`,href:V(`built-in`,J),children:`Open the template`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/templates`,children:`See all twenty`})]}),(0,F.jsx)(`ul`,{className:`land-promise`,"aria-label":`About the app`,children:ht.map(e=>(0,F.jsxs)(`li`,{children:[(0,F.jsx)(it,{}),e]},e))})]}),r?(0,F.jsx)(`figure`,{className:`land-figure`,children:(0,F.jsxs)(ut,{children:[(0,F.jsx)(`div`,{className:`land-picture`,role:`img`,"aria-label":`The review gate template as a graph: a builder, a critic, a human merge approval and a stop, in one loop of at most four rounds`,dangerouslySetInnerHTML:{__html:r.HERO_SVG}}),(0,F.jsxs)(`figcaption`,{className:`muted`,children:[`The `,(0,F.jsx)(`a`,{href:V(`built-in`,J),children:`review gate`}),` template, drawn by grooph.`]})]})}):null]})}),(0,F.jsx)(`section`,{className:`land-section`,children:(0,F.jsx)(`div`,{className:`site-wrap`,children:(0,F.jsxs)(`ul`,{className:`land-claims`,"aria-label":`What grooph does`,children:[(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`Every loop names its stop.`}),` The validator refuses a loop without one, and warns when a loop has no budget and either no cap or a cap above five rounds. Where a graph asks for it, it refuses a critic that shares the builder’s context, and it refuses a step marked irreversible with no human gate before it.`]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`The graph is the contract.`}),` The package tells the session to run it as drawn: named subagents, stops in order, a halt at every human gate. grooph does not enforce it while it runs; eighteen of the twenty runs counted pass the checks of it, and two say why they do not.`]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`Every run is asked for a record.`}),` Notes, rounds and why it stopped, in a folder a monitor reads. To go on, a halted run is resumed in the same session with the person’s answer and its run id.`]})]})})}),(0,F.jsx)(`section`,{className:`land-section land-alt land-start`,"aria-labelledby":`land-start-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-start-title`,className:`land-h2`,children:`Two ways to start`}),(0,F.jsxs)(`div`,{className:`land-ways`,children:[(0,F.jsxs)(`div`,{className:`land-way`,children:[(0,F.jsx)(`h3`,{children:`Ask your agent`}),(0,F.jsxs)(`p`,{children:[`In Claude Code, with grooph `,(0,F.jsx)(`a`,{href:`${G}quickstart/`,children:`installed`}),`, describe the work. The session proposes one to three graphs, sends a link to compare them on your phone, and places the package you pick.`]}),(0,F.jsx)(vt,{text:dt})]}),(0,F.jsxs)(`div`,{className:`land-way`,children:[(0,F.jsx)(`h3`,{children:`Open a template`}),(0,F.jsx)(`p`,{children:`Twenty templates, each with a recorded run of its own. Open one, fill in its blanks, and export the package or the graph.`}),(0,F.jsxs)(`div`,{className:`land-way-actions`,children:[(0,F.jsx)(`a`,{className:`btn btn-primary`,href:V(`built-in`,J),children:`Open the review gate`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/templates`,children:`Browse all`})]})]})]}),(0,F.jsx)(`div`,{className:`land-device`,children:e??(0,F.jsx)(_t,{})})]})}),(0,F.jsx)(`section`,{className:`land-section land-strip`,"aria-labelledby":`land-strip-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-strip-title`,className:`land-h2`,children:`Loop shapes`}),r?(0,F.jsx)(`ul`,{className:`land-strip-list`,"aria-label":`Templates`,children:r.TILES.map(e=>(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`land-tile`,href:V(`built-in`,e.id),children:[(0,F.jsx)(Me,{svg:e.glyph,long:e.long,className:`land-tile-glyph${e.long?` is-wide`:``}`,decorative:!0}),(0,F.jsx)(`span`,{className:`land-tile-title`,children:e.title})]})},e.id))}):null,(0,F.jsxs)(`div`,{className:`land-poster`,children:[t?(0,F.jsx)(`a`,{href:X,"aria-label":`Open the poster of the twenty loop shapes`,children:(0,F.jsx)(`img`,{src:X,width:`1200`,height:`800`,loading:`lazy`,decoding:`async`,alt:`The poster: twenty loop shapes, each drawn with its name and when to reach for it`,onError:()=>n(!1)})}):null,(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h3`,{children:`Twenty shapes on one page`}),(0,F.jsxs)(`p`,{className:`land-guide-line`,children:[`All twenty, with what each one’s recorded run showed: `,(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`the field guide`}),`, and`,` `,(0,F.jsx)(`a`,{href:X,children:`a poster of the shapes`}),`.`]})]})]})]})}),(0,F.jsx)(`section`,{className:`land-section land-alt land-more`,"aria-labelledby":`land-more-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-more-title`,className:`land-h2`,children:`More than a drawing`}),(0,F.jsxs)(`ul`,{className:`land-more-list`,children:[(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`Put a graph on any page`}),(0,F.jsxs)(`p`,{children:[`One line of HTML shows a live graph a reader can pan, zoom and tap, or a recorded run that plays. `,(0,F.jsx)(`a`,{href:`${G}exports/`,children:`How to embed`}),`.`]})]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`See what is running`}),(0,F.jsxs)(`p`,{children:[`A hook records when each session and subagent starts and stops, and nothing they say. A screen shows it live.`,` `,(0,F.jsx)(`a`,{href:`${G}subagents/`,children:`How it works`}),`.`]})]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`Map work across sessions`}),(0,F.jsxs)(`p`,{children:[`Sessions, the people they work with, and what carries work between them, drawn and checked.`,` `,(0,F.jsx)(`a`,{href:`${G}operation-map/`,children:`Operation maps`}),`.`]})]})]})]})}),(0,F.jsx)(`section`,{className:`land-section land-honest`,"aria-labelledby":`land-honest-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`h2`,{id:`land-honest-title`,className:`land-h2`,children:[`What is shown, `,(0,F.jsx)(`mark`,{children:`and what is not`})]}),(0,F.jsxs)(`p`,{children:[`The latest kept run of each of the twenty templates is counted: in those a session stopped where its graph said, at a passed bar or a human gate, and left a record; eighteen of the twenty pass the project’s checks. No round cap or budget is on record as firing. In a paired comparison on four small tasks the package showed no quality advantage over a prompt derived from it. grooph runs no agent, calls no model and needs no hosted service.`,` `,(0,F.jsx)(`a`,{href:`${G}claims/`,children:`Every claim and its evidence`}),`.`]})]})})]}),(0,F.jsx)(lt,{})]})}function _t(){return(0,F.jsx)(`p`,{className:`land-device-line`,children:(0,F.jsx)(`a`,{className:`btn`,href:`#/`,children:`Your graphs`})})}function vt({text:e}){let[t,n]=(0,k.useState)(null);return(0,F.jsxs)(`div`,{className:`copy-line`,children:[(0,F.jsx)(`code`,{className:`copy-line-text`,children:e}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,"aria-label":`Copy the line for Claude Code`,onClick:async()=>n(await De(e)?`Copied. Paste it into Claude Code.`:`Could not copy. Select the line and copy it.`),children:`Copy`}),(0,F.jsx)(`span`,{className:`copy-line-said muted`,role:`status`,children:t})]})}function yt({className:e=``}){let t=ve();if(!t)return null;let n=t.result===`granted`;return(0,F.jsxs)(`div`,{className:`persist-notice ${n?`is-granted`:`is-denied`} ${e}`,role:`status`,children:[(0,F.jsx)(`p`,{children:n?(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`strong`,{children:`Storage kept.`}),` This browser agreed not to clear grooph’s data to free space.`]}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`strong`,{children:`Storage not guaranteed.`}),` This browser may clear grooph’s data when space runs low. Keep backups: Export, then Download graph.`]})}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:ge,children:`Got it`})]})}function bt({toast:e,onDone:t}){return(0,k.useEffect)(()=>{if(!e)return;let n=window.setTimeout(t,6e3);return()=>window.clearTimeout(n)},[e,t]),e?(0,F.jsxs)(`div`,{className:`toast`,role:`status`,children:[(0,F.jsx)(`span`,{children:e.text}),e.undo?(0,F.jsx)(`button`,{type:`button`,className:`toast-action`,onClick:()=>{e.undo(),t()},children:`Undo`}):null]},e.id):null}var xt=e=>{let t=Date.now()-e;return t<6e4?`just now`:t<36e5?`${Math.floor(t/6e4)} min ago`:t<864e5?`${Math.floor(t/36e5)} h ago`:new Date(e).toLocaleDateString()},St=()=>n(`Import`,()=>r(()=>import(`./Import-ByMI7Uz9.js`),__vite__mapDeps([3,4,1,5,6]))),Ct=e=>e?.scrollIntoView({block:`nearest`});function wt({runs:e}){return(0,F.jsx)(`ul`,{className:`run-rows`,"aria-label":`Runs`,children:e.map(e=>{let t=c(e.bundle.notes,e.bundle.working);return(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`run-row`,href:re(e.key),children:[(0,F.jsxs)(`span`,{className:`run-row-name`,children:[`Run `,(0,F.jsx)(`span`,{className:`mono`,children:e.run})]}),(0,F.jsx)(`span`,{className:`run-row-meta`,children:s(t)})]})},e.key)})})}function Tt({open:e}){let[t,n]=(0,k.useState)(null),[r,i]=(0,k.useState)([]),[a,o]=(0,k.useState)(!0),[s,c]=(0,k.useState)(null),[l,u]=(0,k.useState)(null),[d,f]=(0,k.useState)(null),[m,g]=(0,k.useState)(null),[_,v]=(0,k.useState)(null),y=(0,k.useRef)(null),[b,x]=(0,k.useState)(null),S=(0,k.useCallback)(async()=>{n(await ae()),i(await ce()),o((await O()).persistent)},[]);(0,k.useEffect)(()=>void S(),[S]);let C={open:e,route:h,problem:c,offer:v,close:()=>x(null)},w=(e,t)=>void St().then(t,()=>c({name:e,issues:[],what:`The part of grooph that opens it could not be fetched. It needs a connection the first time: try again when you have one.`})),T=e=>{e&&w(e.name,async t=>t.importText(await e.text(),e,C))};(0,k.useEffect)(()=>{let e=e=>{let t=e.clipboardData?.getData(`text/plain`);t&&e.target instanceof Element&&!e.target.closest(`input, textarea, select`)&&St().then(e=>e.openPasted(t,C,!0),()=>void 0)};return window.addEventListener(`paste`,e),()=>window.removeEventListener(`paste`,e)});let E=async(e,t)=>{let n=await Ke(e,{replace:t});if(`exists`in n){v(e=>e&&{...e,exists:n.exists});return}v(null),location.hash=V(`yours`,n.saved.id)},D=(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`library-actions`,children:[(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-large`,onClick:async()=>{e((await le()).key,!0)},children:`New graph`}),(0,F.jsx)(`a`,{className:`btn btn-large`,href:`#/templates`,children:`Templates`}),(0,F.jsxs)(`label`,{className:`btn btn-large file-btn`,children:[`Import .grooph.json`,(0,F.jsx)(`input`,{ref:y,type:`file`,accept:`.json,application/json`,onChange:e=>{T(e.target.files?.[0]),e.target.value=``}})]}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-large`,onClick:()=>w(`what you paste`,e=>x(t=>t?null:e.PasteBox)),children:`Paste a document`})]}),b?(0,F.jsx)(b,{host:C}):null,a?null:(0,F.jsx)(`p`,{className:`notice`,role:`status`,children:`This browser is not letting grooph store anything, so graphs last until the tab closes. Download them from Export to keep them.`}),(0,F.jsx)(yt,{}),_?(0,F.jsxs)(`div`,{className:`offer`,role:`alert`,ref:Ct,children:[(0,F.jsxs)(`p`,{children:[(0,F.jsxs)(`strong`,{children:[_.name,` is a template:`]}),` `,_.doc.template.title,_.doc.template.kind===`fragment`?` (a fragment)`:``,`.`,` `,_.refusal?`It carries errors, so it cannot go into Yours; grooph template add refuses it too. Open it as a graph to fix it.`:`Add it to Yours to use it from Templates.`]}),_.refusal?(0,F.jsx)(`pre`,{className:`issue-lines`,children:_.refusal.issues.map(p).join(`
|
|
4
|
+
`)}):null,_.exists?(0,F.jsxs)(`p`,{className:`field-hint`,children:[`Yours already has a template with the id `,(0,F.jsx)(`span`,{className:`mono`,children:_.doc.id}),` (version `,_.exists.version,`). Replacing it makes version `,Math.max(_.exists.version,_.doc.version)+1,`.`]}):null,(0,F.jsxs)(`div`,{className:`offer-actions`,children:[_.refusal?null:_.exists?(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>void E(_.doc,!0),children:`Replace yours`}):(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>void E(_.doc,!1),children:`Add to Yours`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:async()=>{let t=await ue(_.doc);v(null),e(t.key)},children:`Open it as a graph`}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-quiet`,onClick:()=>v(null),children:`Cancel`})]})]}):null,s?(0,F.jsxs)(`div`,{className:`refusal`,role:`alert`,ref:Ct,children:[(0,F.jsxs)(`p`,{children:[(0,F.jsxs)(`strong`,{children:[`Could not import `,s.name,`.`]}),` `,s.what??`It is not a graph document grooph can open.`]}),(0,F.jsx)(`pre`,{className:`issue-lines`,children:s.issues.map(p).join(`
|
|
5
|
+
`)}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>c(null),children:`Dismiss`})]}):null]});return t===null?null:t.length===0&&r.length===0?(0,F.jsx)(gt,{device:(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`library-empty land-empty`,children:[(0,F.jsx)(`p`,{children:`No graphs on this device yet.`}),(0,F.jsxs)(`p`,{className:`muted`,children:[`Start one here, or import a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph.json`}),` graph, a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-proposals.json`}),` set, a`,` `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-run.json`}),` run or a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-map.json`}),` operation map.`]})]}),D]})}):(0,F.jsxs)(`div`,{className:`library`,children:[(0,F.jsxs)(`header`,{className:`library-head`,children:[(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h1`,{className:`wordmark`,children:`grooph`}),(0,F.jsx)(`p`,{className:`muted`,children:`Loop graphs for coding agents. Draw, validate, export.`})]}),(0,F.jsx)(`a`,{className:`library-about`,href:`#/about`,children:`What is grooph?`})]}),D,t.length===0?(0,F.jsxs)(`div`,{className:`library-empty`,children:[(0,F.jsx)(`p`,{children:`No graphs on this device yet.`}),(0,F.jsxs)(`p`,{className:`muted`,children:[`Start a new one, or import a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph.json`}),` graph, a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-proposals.json`}),` set, a`,` `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-run.json`}),` run or a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-map.json`}),` operation map.`]})]}):(0,F.jsx)(`ul`,{className:`graph-list`,"aria-label":`Graphs on this device`,children:t.map(t=>(0,F.jsxs)(`li`,{className:`graph-row`,children:[d?.key===t.key?(0,F.jsx)(Et,{record:t,name:d.name,onName:e=>f({key:t.key,name:e}),onCancel:()=>f(null),onSave:async e=>{await se(t.key,d.name,{keepId:e}),f(null),await S()}}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`button`,{type:`button`,className:`graph-open${je(t.doc)?` has-long-glyph`:``}`,onClick:()=>e(t.key),children:[(0,F.jsx)(I,{doc:t.doc,className:`graph-glyph`,decorative:!0}),(0,F.jsxs)(`span`,{className:`graph-text`,children:[(0,F.jsx)(`span`,{className:`graph-name`,children:t.doc.name||`Untitled`}),(0,F.jsxs)(`span`,{className:`graph-meta`,children:[(0,F.jsx)(`span`,{className:`mono`,children:t.doc.id}),` · `,t.doc.nodes.length,` node`,t.doc.nodes.length===1?``:`s`,` ·`,` `,t.doc.loops.length,` loop`,t.doc.loops.length===1?``:`s`,` · `,xt(t.updatedAt)]})]})]}),(0,F.jsx)(`button`,{type:`button`,className:`icon-btn`,"aria-label":`Actions for ${t.doc.name}`,"aria-expanded":l===t.key,onClick:()=>{u(l===t.key?null:t.key),g(null)},children:(0,F.jsxs)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:[(0,F.jsx)(`circle`,{cx:`5`,cy:`12`,r:`1.6`}),(0,F.jsx)(`circle`,{cx:`12`,cy:`12`,r:`1.6`}),(0,F.jsx)(`circle`,{cx:`19`,cy:`12`,r:`1.6`})]})})]}),r.some(e=>e.graphId===t.doc.id)?(0,F.jsx)(wt,{runs:r.filter(e=>e.graphId===t.doc.id)}):null,l===t.key&&d?.key!==t.key?(0,F.jsxs)(`div`,{className:`row-actions`,children:[(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:()=>{f({key:t.key,name:t.doc.name}),u(null)},children:`Rename`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:async()=>{await oe(t.key),u(null),await S()},children:`Duplicate`}),m===t.key?(0,F.jsx)(`button`,{type:`button`,className:`btn btn-danger`,onClick:async()=>{await ie(t.key),u(null),g(null),await S()},children:`Delete for good`}):(0,F.jsx)(`button`,{type:`button`,className:`btn btn-danger-text`,onClick:()=>g(t.key),children:`Delete`})]}):null]},t.key))}),r.some(e=>!t.some(t=>t.doc.id===e.graphId))?(0,F.jsxs)(`section`,{className:`orphan-runs`,"aria-label":`Runs of graphs not on this device`,children:[(0,F.jsx)(`h2`,{className:`list-title`,children:`Runs of graphs not on this device`}),(0,F.jsx)(wt,{runs:r.filter(e=>!t.some(t=>t.doc.id===e.graphId))})]}):null,(0,F.jsxs)(`footer`,{className:`library-foot muted`,children:[`Graphs live in this browser on this device. Nothing is sent anywhere.`,` `,(0,F.jsx)(`a`,{href:`https://github.com/ryanjosephkamp/grooph`,rel:`noopener`,children:`Source`})]})]})}function Et(e){let{record:t}=e,n=u(t.doc,e.name).id,r=t.exported?.id,i=r!==void 0&&n!==r&&l(n,e.name);return(0,F.jsxs)(`form`,{className:`rename`,onSubmit:t=>{t.preventDefault(),e.onSave()},children:[(0,F.jsxs)(`div`,{className:`rename-row`,children:[(0,F.jsx)(`input`,{className:`input`,"aria-label":`Graph name`,value:e.name,autoFocus:!0,onChange:t=>e.onName(t.target.value)}),(0,F.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,children:`Save`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:e.onCancel,children:`Cancel`})]}),i?(0,F.jsx)(Dt,{exportedAs:r,nextId:n,onKeep:()=>e.onSave(r)}):null]})}function Dt({exportedAs:e,nextId:t,onKeep:n}){return(0,F.jsxs)(`div`,{className:`rename-warning`,role:`alert`,children:[(0,F.jsxs)(`p`,{children:[`This graph was exported from this device as `,(0,F.jsxs)(`span`,{className:`mono`,children:[`.grooph/`,e,`/`]}),`. With this name its id becomes`,` `,(0,F.jsx)(`span`,{className:`mono`,children:t}),`, so the next export writes a new package folder, `,(0,F.jsxs)(`span`,{className:`mono`,children:[`.grooph/`,t,`/`]}),`, beside the old one.`]}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:n,children:`Keep the old id`})]})}var Ot=i({App:()=>Lt,loadScreens:()=>Q,ready:()=>Pt}),kt=(0,k.lazy)(()=>n(`EmbedApp`,()=>r(()=>import(`./EmbedApp-390Z2d4x.js`),__vite__mapDeps([7,4,1,8]))).then(e=>({default:e.EmbedApp}))),Z;function Q(){return n(`screens`,()=>r(()=>import(`./screens-aIjMSzZg.js`),__vite__mapDeps([9,4,1,5,6,10]))).then(e=>Z=e)}function At(e){return!jt.has(Ft(e).name)}var jt=new Set([`library`,`about`,`templates`,`embed`]),Mt=e=>e.name===`template`&&e.source===`built-in`,Nt=300;function Pt(e){let t=[];return At(e)&&t.push(Q()),new RegExp(fe).test(e)&&t.push(S()),new RegExp(de).test(e)&&t.push(Promise.race([Y(),new Promise(e=>setTimeout(e,Nt))])),Promise.all(t.map(e=>e.catch(()=>void 0)))}function $(e){try{return decodeURIComponent(e)}catch{return e}}function Ft(e){if(e===`#/run?live`)return{name:`live-run`};if(e===`#/live`)return{name:`live`};let t=/^#\/run\/([^?]+)$/.exec(e);if(t)return{name:`run`,key:$(t[1])};if(e===`#/about`)return{name:`about`};if(e===`#/templates`)return{name:`templates`};if(e===`#/embed`||e.startsWith(`#/embed?`))return{name:`embed`};let n=/^#\/templates\/(built-in|yours|plan)\/([^/?]+)(\/use)?$/.exec(e);if(n)return{name:`template`,source:n[1],id:$(n[2]),use:n[3]!==void 0};let r=/^#\/g\/([^/?]+)(\?new)?$/.exec(e);if(r)return{name:`graph`,key:$(r[1]),fresh:r[2]!==void 0};if(e.startsWith(`#/open?`)){let t=/[?&]c=([^&]*)/.exec(e)?.[1];return{name:`open`,payload:o(e)??``,...t?{candidate:$(t)}:{}}}return{name:`library`}}function It(e,t,n){let[r,i]=(0,k.useState)(()=>e()?`yes`:`no`),[a,o]=(0,k.useState)(null),s=(0,k.useRef)(n);return s.current=n,(0,k.useEffect)(()=>{if(r!==`no`)return;let e=!1;return t().then(()=>!e&&i(`yes`),()=>{e||(o(s.current),i(`failed`))}),()=>{e=!0}},[r]),(0,k.useEffect)(()=>{r===`failed`&&a!==n&&i(`no`)},[n]),r===`failed`&&a!==n?`no`:r}function Lt(){let[e,t]=(0,k.useState)(()=>Ft(location.hash));(0,k.useEffect)(()=>{let e=()=>{t(Ft(location.hash)),window.scrollTo(0,0)};return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]);let n=It(()=>Z!==void 0,Q,e),r=It(()=>T()!==void 0,S,e);(0,k.useEffect)(()=>void Y().catch(()=>void 0),[]);let i=e=>e===`failed`?(0,F.jsxs)(`div`,{className:`notfound`,children:[(0,F.jsx)(`p`,{children:`This screen could not be fetched. It needs a connection the first time.`}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>location.reload(),children:`Load the page again`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/`,children:`Back to the library`})]}):(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`});if(e.name===`about`)return(0,F.jsx)(gt,{});if(Mt(e)&&r!==`yes`)return i(r);if(e.name===`templates`)return(0,F.jsx)(Qe,{});if(e.name===`library`)return(0,F.jsx)(Tt,{open:(e,t)=>{location.hash=`#/g/${encodeURIComponent(e)}${t?`?new`:``}`}});if(e.name===`embed`)return(0,F.jsx)(k.Suspense,{fallback:null,children:(0,F.jsx)(kt,{})});if(!Z)return i(n);let{EditorScreen:a,LiveRun:o,LiveSessions:s,OpenScreen:c,StoredRun:l,TemplateView:u,UseTemplate:d}=Z;if(e.name===`graph`)return(0,F.jsx)(a,{graphKey:e.key,fresh:e.fresh},e.key);if(e.name===`open`)return(0,F.jsx)(c,{payload:e.payload,candidate:e.candidate});if(e.name===`live-run`)return(0,F.jsx)(o,{});if(e.name===`live`)return(0,F.jsx)(s,{});if(e.name===`run`)return(0,F.jsx)(l,{runKey:e.key},e.key);let f=`${e.source}/${e.id}`;return e.use?(0,F.jsx)(d,{source:e.source,id:e.id},f):(0,F.jsx)(u,{source:e.source,id:e.id},f)}export{Lt as App,Se as S,Ee as _,V as a,ye as b,Ge as c,Je as d,Ye as f,De as g,be as h,bt as i,We as l,Q as loadScreens,xe as m,Dt as n,Ze as o,I as p,yt as r,Pt as ready,qe as s,Ot as t,Ke as u,we as v,Te as x,Ce as y};
|