domain/architecture/system/release/plugin/claude/ops.bend
near-v-framework@0.6.0.0 · 191 lines · 0 definitions
1import Base
2import bend-net-json@0.3.0.0/json.bend as Json
3import near-v-framework@0.6.0.0/domain/architecture/system/release/plugin/json.bend as J
4import near-v-framework@0.6.0.0/domain/architecture/system/release/plugin/claude/type.bend as Pl
5
6# Claude Code's part of a plugin, as the keys it adds to .claude-plugin/plugin.json.
7
8# ---- userConfig ----
9def kind_keys(k: Pl.Input) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
10 match k:
11 case Pl.Text{sensitive, d}:
12 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, [("type", Json.Str{"string"})],
13 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, J.when_true("sensitive", sensitive), J.opt("default", J.text(d))))
14 case Pl.Choice{os, d}:
15 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, [("type", Json.Str{"string"}), ("options", J.texts(os))], J.opt("default", J.text(d)))
16 case Pl.Texts{d}:
17 [("type", Json.Str{"string"}), ("multiple", Json.Flag{True{}}), ("default", J.texts(d))]
18 case Pl.Number{lo, hi, d}:
19 List.concat(&2, Sigma<&2, &2, String, _ => Json.Val>, [[("type", Json.Str{"number"})], J.opt("min", J.number(lo)), J.opt("max", J.number(hi)), J.opt("default", J.number(d))])
20 case Pl.Boolean{d}:
21 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, [("type", Json.Str{"boolean"})], J.opt("default", J.flag(d)))
22 case Pl.Folder{d}:
23 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, [("type", Json.Str{"directory"})], J.opt("default", J.text(d)))
24 case Pl.Path{d}:
25 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, [("type", Json.Str{"file"})], J.opt("default", J.text(d)))
26
27def field(f: Pl.Field) -> Sigma<&2, &2, String, _ => Json.Val>:
28 match f:
29 case Pl.Field{key, title, description, required, k}:
30 (key, J.cat([[("title", Json.Str{title}), ("description", Json.Str{description})], J.when_true("required", required), kind_keys(k)]))
31
32def fields(fs: List<&2, Pl.Field>) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
33 match fs:
34 case []:
35 []
36 case f <> rest:
37 field(f) <> fields(rest)
38
39# ---- hooks ----
40def event_name(e: Pl.HookEvent) -> String:
41 match e:
42 case Pl.SessionStart{}:
43 "SessionStart"
44 case Pl.Setup{}:
45 "Setup"
46 case Pl.UserPromptSubmit{}:
47 "UserPromptSubmit"
48 case Pl.UserPromptExpansion{}:
49 "UserPromptExpansion"
50 case Pl.PreToolUse{}:
51 "PreToolUse"
52 case Pl.PermissionRequest{}:
53 "PermissionRequest"
54 case Pl.PermissionDenied{}:
55 "PermissionDenied"
56 case Pl.PostToolUse{}:
57 "PostToolUse"
58 case Pl.PostToolUseFailure{}:
59 "PostToolUseFailure"
60 case Pl.PostToolBatch{}:
61 "PostToolBatch"
62 case Pl.Notification{}:
63 "Notification"
64 case Pl.MessageDisplay{}:
65 "MessageDisplay"
66 case Pl.SubagentStart{}:
67 "SubagentStart"
68 case Pl.SubagentStop{}:
69 "SubagentStop"
70 case Pl.TaskCreated{}:
71 "TaskCreated"
72 case Pl.TaskCompleted{}:
73 "TaskCompleted"
74 case Pl.Stop{}:
75 "Stop"
76 case Pl.StopFailure{}:
77 "StopFailure"
78 case Pl.TeammateIdle{}:
79 "TeammateIdle"
80 case Pl.InstructionsLoaded{}:
81 "InstructionsLoaded"
82 case Pl.ConfigChange{}:
83 "ConfigChange"
84 case Pl.CwdChanged{}:
85 "CwdChanged"
86 case Pl.DirectoryAdded{}:
87 "DirectoryAdded"
88 case Pl.FileChanged{}:
89 "FileChanged"
90 case Pl.WorktreeCreate{}:
91 "WorktreeCreate"
92 case Pl.WorktreeRemove{}:
93 "WorktreeRemove"
94 case Pl.PreCompact{}:
95 "PreCompact"
96 case Pl.PostCompact{}:
97 "PostCompact"
98 case Pl.PreModelSwitch{}:
99 "PreModelSwitch"
100 case Pl.PostModelSwitch{}:
101 "PostModelSwitch"
102 case Pl.Elicitation{}:
103 "Elicitation"
104 case Pl.ElicitationResult{}:
105 "ElicitationResult"
106 case Pl.SessionEnd{}:
107 "SessionEnd"
108
109def shell_name(m: Maybe<&2, Pl.Shell>) -> Maybe<&2, Json.Val>:
110 match m:
111 case Some{Pl.Bash{}}:
112 Some{Json.Str{"bash"}}
113 case Some{Pl.PowerShell{}}:
114 Some{Json.Str{"powershell"}}
115 case None{}:
116 None{}
117
118def form_keys(f: Pl.Form) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
119 match f:
120 case Pl.Exec{command, args}:
121 [("command", Json.Str{command}), ("args", J.texts(args))]
122 case Pl.ShellForm{command, sh}:
123 List.append(&2, Sigma<&2, &2, String, _ => Json.Val>, [("command", Json.Str{command})], J.opt("shell", shell_name(sh)))
124
125def run_keys(r: Pl.Run) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
126 match r:
127 case Pl.Blocking{}:
128 []
129 case Pl.Async{}:
130 [("async", Json.Flag{True{}})]
131 case Pl.AsyncRewake{}:
132 [("asyncRewake", Json.Flag{True{}})]
133
134def handler(h: Pl.Handler) -> Json.Val:
135 match h:
136 case Pl.Command{f, r, w, t, s}:
137 J.cat([[("type", Json.Str{"command"})], form_keys(f), run_keys(r), J.opt("if", J.text(w)), J.opt("timeout", J.number(t)), J.opt("statusMessage", J.text(s))])
138
139def handlers(hs: List<&2, Pl.Handler>) -> List<&2, Json.Val>:
140 match hs:
141 case []:
142 []
143 case h <> rest:
144 handler(h) <> handlers(rest)
145
146def group(g: Pl.Group) -> Json.Val:
147 match g:
148 case Pl.Group{m, hs}:
149 J.cat([J.opt("matcher", J.text(m)), [("hooks", Json.Arr{handlers(hs)})]])
150
151def groups(gs: List<&2, Pl.Group>) -> List<&2, Json.Val>:
152 match gs:
153 case []:
154 []
155 case g <> rest:
156 group(g) <> groups(rest)
157
158def hooks(hs: List<&2, Pl.Hook>) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
159 match hs:
160 case []:
161 []
162 case Pl.Hook{e, gs} <> rest:
163 (event_name(e), Json.Arr{groups(gs)}) <> hooks(rest)
164
165# ---- Claude Code's part of .claude-plugin/plugin.json ----
166def config(fs: List<&2, Pl.Field>) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
167 match fs:
168 case []:
169 []
170 case f <> rest:
171 [("userConfig", J.obj(fields(f <> rest)))]
172
173def hooks_key(hs: List<&2, Pl.Hook>) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
174 match hs:
175 case []:
176 []
177 case h <> rest:
178 [("hooks", J.obj(hooks(h <> rest)))]
179
180# Enabled is Claude Code's default, so only a plugin that starts disabled says so.
181def enabled_key(b: Bool) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
182 match b:
183 case True{}:
184 []
185 case False{}:
186 [("defaultEnabled", Json.Flag{False{}})]
187
188def keys(c: Pl.Claude) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:
189 match c:
190 case Pl.Claude{display, enabled, fs, hs}:
191 List.concat(&2, Sigma<&2, &2, String, _ => Json.Val>, [J.opt("displayName", J.text(display)), enabled_key(enabled), config(fs), hooks_key(hs)])