sdocs-dev 1.6.2 → 1.13.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/bin/sdocs-bridge.js +974 -0
- package/bin/sdocs-dev.js +152 -2102
- package/bin/sdocs-icon-names.js +1965 -0
- package/lib/agent-block.js +245 -0
- package/lib/agent-files.js +162 -0
- package/lib/bridge-commands.js +171 -0
- package/lib/cells-transclude.js +114 -0
- package/lib/cells-verify.js +165 -0
- package/lib/commands.js +291 -0
- package/lib/constants.js +283 -0
- package/lib/help-text.js +2759 -0
- package/lib/io.js +177 -0
- package/lib/library-autostart.js +145 -0
- package/lib/library-commands.js +307 -0
- package/lib/library-ephemeral.js +111 -0
- package/lib/library-index.js +285 -0
- package/lib/library-paths.js +20 -0
- package/lib/library-scan.js +258 -0
- package/lib/library-server.js +400 -0
- package/lib/library-store.js +141 -0
- package/lib/router.js +52 -0
- package/lib/safe.js +200 -0
- package/lib/setup.js +351 -0
- package/lib/short-link.js +105 -0
- package/lib/styles.js +91 -0
- package/lib/update-check.js +163 -0
- package/lib/url.js +111 -0
- package/package.json +5 -16
- package/shared/sdocs-cells-formula.js +485 -0
- package/shared/sdocs-cells.js +389 -0
- package/shared/sdocs-contrast.js +196 -0
- package/shared/sdocs-form-block.js +605 -0
- package/shared/sdocs-library-tags.js +41 -0
- package/{public → shared}/sdocs-styles.js +134 -5
- package/README.md +0 -149
- /package/{public → shared}/sdocs-slugify.js +0 -0
- /package/{public → shared}/sdocs-yaml.js +0 -0
package/lib/constants.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// Shared constants used across the CLI lib.
|
|
2
|
+
//
|
|
3
|
+
// VERSION resolves to the CLI's own package version (cli/package.json),
|
|
4
|
+
// not the server's root package.json.
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
exports.DEFAULT_URL = 'https://smalldocs.org';
|
|
10
|
+
exports.VERSION = require('../package.json').version;
|
|
11
|
+
exports.UPDATE_CACHE = path.join(os.homedir(), '.sdocs', 'update-check.json');
|
|
12
|
+
exports.SETUP_CACHE = path.join(os.homedir(), '.sdocs', 'setup.json');
|
|
13
|
+
exports.ONE_DAY = 86400000;
|
|
14
|
+
exports.AGENT_CHANGES_URL = 'https://smalldocs.org/agent-changes';
|
|
15
|
+
exports.INSTALL_SH_URL = exports.DEFAULT_URL + '/install';
|
|
16
|
+
exports.GITHUB_REPO_URL = 'https://github.com/espressoplease/SDocs';
|
|
17
|
+
|
|
18
|
+
// Printed by `sdoc feedback` with no args. Goal: an agent can read this
|
|
19
|
+
// once and write valid form blocks afterwards. Short, dense, and every
|
|
20
|
+
// supported field type appears in the example.
|
|
21
|
+
exports.FORM_DSL_REFERENCE = `\
|
|
22
|
+
sdoc feedback — interactive form DSL
|
|
23
|
+
====================================
|
|
24
|
+
|
|
25
|
+
Ask the user something structured. Write a fenced \`\`\`form block into a
|
|
26
|
+
markdown file, then run:
|
|
27
|
+
|
|
28
|
+
sdoc feedback file.md # opens the file, exits on first submit
|
|
29
|
+
|
|
30
|
+
That is the simplest, recommended shape: ONE submit button, single
|
|
31
|
+
process invocation. The user clicks, the file gets the answers, the
|
|
32
|
+
process prints one JSON line on stdout, and exits. You just spawn the
|
|
33
|
+
command, wait for it to finish, and read its stdout.
|
|
34
|
+
|
|
35
|
+
You only need the other modes when you genuinely want multiple submits
|
|
36
|
+
in one session:
|
|
37
|
+
|
|
38
|
+
sdoc feedback file.md --keep-open # bridge stays alive across many
|
|
39
|
+
# submits; you tail stdout to
|
|
40
|
+
# react per click
|
|
41
|
+
sdoc feedback file.md --keep-open \\
|
|
42
|
+
--log-file /tmp/sdoc.jsonl # also mirror events to a file
|
|
43
|
+
# (fallback for harnesses that
|
|
44
|
+
# can't tail a background process)
|
|
45
|
+
sdoc feedback file.md --message "Q" # show "Q" above the document
|
|
46
|
+
|
|
47
|
+
Strong default: write forms with ONE button. Reach for --keep-open + a
|
|
48
|
+
multi-button form only when "the user submits several things during one
|
|
49
|
+
session" is the actual goal.
|
|
50
|
+
|
|
51
|
+
A form block has four sections: id, fields, buttons, and (added by the
|
|
52
|
+
bridge on submit) answers + submissions. You author id, fields, buttons.
|
|
53
|
+
|
|
54
|
+
Full example
|
|
55
|
+
------------
|
|
56
|
+
|
|
57
|
+
\`\`\`form
|
|
58
|
+
id: q3-review
|
|
59
|
+
fields:
|
|
60
|
+
- name: ready
|
|
61
|
+
type: radio
|
|
62
|
+
label: "Are you ready to ship?"
|
|
63
|
+
options: [Yes, "Needs more time", Push out]
|
|
64
|
+
required: true
|
|
65
|
+
default: Yes
|
|
66
|
+
help: "All teams have signed off."
|
|
67
|
+
|
|
68
|
+
- name: notes
|
|
69
|
+
type: textarea
|
|
70
|
+
label: "Detailed thoughts"
|
|
71
|
+
rows: 5
|
|
72
|
+
placeholder: "Anything else?"
|
|
73
|
+
default: |
|
|
74
|
+
Pre-filled text the user can edit.
|
|
75
|
+
Spans multiple lines via the | scalar.
|
|
76
|
+
|
|
77
|
+
- name: name_field
|
|
78
|
+
type: text
|
|
79
|
+
label: "Your name"
|
|
80
|
+
default: "Jane" # pre-fills the input; user can edit to "Jane!"
|
|
81
|
+
|
|
82
|
+
- name: tags
|
|
83
|
+
type: checkbox
|
|
84
|
+
label: "Which areas?"
|
|
85
|
+
options: [api, web, docs, infra]
|
|
86
|
+
default: [api, docs]
|
|
87
|
+
|
|
88
|
+
- name: tier
|
|
89
|
+
type: select
|
|
90
|
+
label: "Pricing tier"
|
|
91
|
+
options: [free, pro, team, enterprise]
|
|
92
|
+
default: pro
|
|
93
|
+
|
|
94
|
+
- name: head_count
|
|
95
|
+
type: number
|
|
96
|
+
label: "How many people?"
|
|
97
|
+
min: 1
|
|
98
|
+
max: 500
|
|
99
|
+
default: 5
|
|
100
|
+
|
|
101
|
+
- name: target_date
|
|
102
|
+
type: date
|
|
103
|
+
label: "Target ship date"
|
|
104
|
+
default: "2026-06-01"
|
|
105
|
+
|
|
106
|
+
buttons:
|
|
107
|
+
- name: send_decision
|
|
108
|
+
label: "Send decision"
|
|
109
|
+
scope: [ready] # this button only submits the 'ready' field
|
|
110
|
+
after: ready # render this button inline, right under the
|
|
111
|
+
# 'ready' field, instead of in the footer row
|
|
112
|
+
|
|
113
|
+
- name: send_all
|
|
114
|
+
label: "Submit everything"
|
|
115
|
+
final: true # this button always ends the session
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
Field types
|
|
119
|
+
-----------
|
|
120
|
+
|
|
121
|
+
text single-line input. default, placeholder, required, maxlength
|
|
122
|
+
textarea multi-line. default (block-scalar OK), rows, placeholder, required, maxlength
|
|
123
|
+
radio one of N choices. options[] required. default selects one.
|
|
124
|
+
checkbox multi-select. options[] required. default is an array.
|
|
125
|
+
select dropdown. options[] required. default selects one.
|
|
126
|
+
number numeric input. min, max, step. default is a number.
|
|
127
|
+
date date picker (YYYY-MM-DD). min, max. default is the ISO date string.
|
|
128
|
+
|
|
129
|
+
Per-field keys
|
|
130
|
+
--------------
|
|
131
|
+
|
|
132
|
+
name required, [a-z0-9_-]{1,64}, unique per form
|
|
133
|
+
label shown above the control
|
|
134
|
+
help small grey description under the control
|
|
135
|
+
required true/false
|
|
136
|
+
default pre-fill value the user can edit (array for checkbox, number
|
|
137
|
+
for number, ISO date for date, string otherwise)
|
|
138
|
+
options radio / checkbox / select; array of strings
|
|
139
|
+
placeholder text / textarea / number; greyed-out hint that vanishes on type
|
|
140
|
+
rows textarea only
|
|
141
|
+
min/max number, date
|
|
142
|
+
step number only
|
|
143
|
+
|
|
144
|
+
Buttons
|
|
145
|
+
-------
|
|
146
|
+
|
|
147
|
+
name required, unique per form
|
|
148
|
+
label button text
|
|
149
|
+
scope optional list of field names. Defaults to all fields.
|
|
150
|
+
final optional bool. true means this submit ends the session even
|
|
151
|
+
when --keep-open was passed.
|
|
152
|
+
after optional field name. Renders the button inline right under
|
|
153
|
+
that field instead of in the bottom row. Combine with scope
|
|
154
|
+
for a "submit just this section" pattern.
|
|
155
|
+
help optional one-line override for the auto-generated hint
|
|
156
|
+
(see "Button hints" below). Only set this when your own
|
|
157
|
+
one-liner is clearly better than the default.
|
|
158
|
+
|
|
159
|
+
Button hints (automatic, you do not author these)
|
|
160
|
+
-------------------------------------------------
|
|
161
|
+
|
|
162
|
+
Every button gets a small grey line under it explaining what happens
|
|
163
|
+
when the user clicks. You do not write the hint; it is derived from the
|
|
164
|
+
button's shape:
|
|
165
|
+
|
|
166
|
+
final: true -> "Submitting hands off to the agent and ends
|
|
167
|
+
this session."
|
|
168
|
+
scope: [a, b] -> "Sends just these answers (a, b). You can
|
|
169
|
+
keep editing."
|
|
170
|
+
no scope (non-final) -> "Sends all answers. You can keep editing."
|
|
171
|
+
|
|
172
|
+
After a successful submit, a green italic line also appears under that
|
|
173
|
+
same button: "Saved to <filename> at HH:MM:SS". It updates in place on
|
|
174
|
+
each subsequent click of that button. You do not author this either.
|
|
175
|
+
|
|
176
|
+
Set the per-button \`help: "..."\` key only when your own copy is
|
|
177
|
+
genuinely more useful than the default (e.g. when the field semantics
|
|
178
|
+
are non-obvious and the auto hint would mislead).
|
|
179
|
+
|
|
180
|
+
Multi-round flow (with --keep-open)
|
|
181
|
+
-----------------------------------
|
|
182
|
+
|
|
183
|
+
1. Write a file with a form block, run \`sdoc feedback file.md --keep-open\`.
|
|
184
|
+
2. User edits, clicks a non-final submit. Bridge writes the file with
|
|
185
|
+
answers + a submission entry. The bridge stays alive.
|
|
186
|
+
3. Read the file. \`submissions[-1]\` has the user's latest answer.
|
|
187
|
+
4. Rewrite the file with the next question (keep the form id stable to
|
|
188
|
+
preserve answers + history; change fields or labels as needed).
|
|
189
|
+
5. The browser refreshes automatically. The user answers the new form.
|
|
190
|
+
6. Repeat until the user clicks a button with \`final: true\`, or closes
|
|
191
|
+
the tab.
|
|
192
|
+
|
|
193
|
+
How to know a submit happened (events)
|
|
194
|
+
--------------------------------------
|
|
195
|
+
|
|
196
|
+
Every successful submit emits one JSON line to stdout, e.g.
|
|
197
|
+
|
|
198
|
+
{"event":"submit","form_id":"q1","by":"send_decision",
|
|
199
|
+
"at":"2026-05-24T10:01:32.123Z","scope":["ready"],
|
|
200
|
+
"values":{"ready":"Yes"},"final":false}
|
|
201
|
+
|
|
202
|
+
Startup chatter is on stderr, so stdout is a clean event channel.
|
|
203
|
+
|
|
204
|
+
DO NOT fire-and-forget
|
|
205
|
+
----------------------
|
|
206
|
+
|
|
207
|
+
The submit JSON arrives WHEN the user clicks - which could be seconds
|
|
208
|
+
or minutes after you spawn the command. The whole protocol depends on
|
|
209
|
+
you (or your harness) noticing when the process exits.
|
|
210
|
+
|
|
211
|
+
Wrong:
|
|
212
|
+
|
|
213
|
+
bash -c 'sdoc feedback file.md > log.json 2>&1 &'
|
|
214
|
+
^^ ^^
|
|
215
|
+
starts shell backgrounding;
|
|
216
|
+
immediately parent NEVER notices exit
|
|
217
|
+
|
|
218
|
+
That looks like it worked. The user fills out the form, clicks submit,
|
|
219
|
+
the JSON lands in log.json, the process exits 0... and your agent
|
|
220
|
+
never knows. You just sit there.
|
|
221
|
+
|
|
222
|
+
Right (depends on your harness):
|
|
223
|
+
|
|
224
|
+
Claude Code Bash tool with run_in_background: true
|
|
225
|
+
(you get a notification when the process exits)
|
|
226
|
+
Codex Codex's background-task primitive, same shape
|
|
227
|
+
Plain shell Foreground: sdoc feedback file.md, then wait.
|
|
228
|
+
Or: sdoc feedback file.md & wait \$!
|
|
229
|
+
(the wait \$! is what was missing)
|
|
230
|
+
Make / script Run it foreground and capture stdout - no '&'
|
|
231
|
+
|
|
232
|
+
The CLI prints a stderr warning when stdout is not a TTY at startup,
|
|
233
|
+
so you get a hint if you set it up wrong.
|
|
234
|
+
|
|
235
|
+
Two reading patterns:
|
|
236
|
+
|
|
237
|
+
Single-shot sdoc feedback file.md
|
|
238
|
+
User clicks once, bridge writes the file, prints one
|
|
239
|
+
JSON line to stdout, exits 0. Agent runs the command,
|
|
240
|
+
waits for it to finish, reads stdout. No tailing. Works
|
|
241
|
+
in every harness that can run a child process.
|
|
242
|
+
|
|
243
|
+
Multi-click sdoc feedback file.md --keep-open
|
|
244
|
+
Bridge stays alive. Each click prints another JSON
|
|
245
|
+
line. Agent runs the command in the background and
|
|
246
|
+
reads new lines as they arrive (Claude Code, Codex,
|
|
247
|
+
opencode all support this).
|
|
248
|
+
|
|
249
|
+
Log fallback --log-file PATH
|
|
250
|
+
The same JSON lines, also appended to a file. Use this
|
|
251
|
+
when your harness can run a backgrounded process but
|
|
252
|
+
can't stream its stdout (Aider, older Cursor modes).
|
|
253
|
+
Agent reads the file periodically.
|
|
254
|
+
|
|
255
|
+
On submit, the form block grows two new sections:
|
|
256
|
+
|
|
257
|
+
\`\`\`yaml
|
|
258
|
+
answers:
|
|
259
|
+
ready: Yes
|
|
260
|
+
notes: |
|
|
261
|
+
Multi-line answer text the user kept or edited.
|
|
262
|
+
tags: [api, docs]
|
|
263
|
+
head_count: 5
|
|
264
|
+
target_date: "2026-06-01"
|
|
265
|
+
submissions:
|
|
266
|
+
- by: send_decision
|
|
267
|
+
at: "2026-05-23T10:01:32Z"
|
|
268
|
+
scope: [ready]
|
|
269
|
+
values:
|
|
270
|
+
ready: Yes
|
|
271
|
+
\`\`\`
|
|
272
|
+
|
|
273
|
+
Constraints
|
|
274
|
+
-----------
|
|
275
|
+
|
|
276
|
+
- 64KB max per form block source.
|
|
277
|
+
- Field and button names: [a-z0-9_-]{1,64}.
|
|
278
|
+
- Strings containing triple-backticks are rejected on submit.
|
|
279
|
+
- Markdown around the form block is preserved byte-for-byte.
|
|
280
|
+
|
|
281
|
+
End.
|
|
282
|
+
`;
|
|
283
|
+
|