@mnbny/woof 0.0.0-stage → 0.1.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 +510 -2
- package/cli/templates/add-draft.md +22 -0
- package/cli/templates/add-error.md +5 -0
- package/cli/templates/add-result.md +11 -0
- package/cli/templates/edit-draft.md +24 -0
- package/cli/templates/edit-error.md +3 -0
- package/cli/templates/edit-path.md +3 -0
- package/cli/templates/edit-result.md +7 -0
- package/cli/templates/edit-unchanged.md +3 -0
- package/cli/templates/editor.html +338 -0
- package/cli/templates/explain-ambiguous.md +5 -0
- package/cli/templates/explain-error.md +5 -0
- package/cli/templates/explain-result.md +5 -0
- package/cli/templates/export-error.md +3 -0
- package/cli/templates/export-result.md +8 -0
- package/cli/templates/get-ambiguous.md +5 -0
- package/cli/templates/get-cancelled.md +5 -0
- package/cli/templates/get-candidates.md +5 -0
- package/cli/templates/get-error.md +5 -0
- package/cli/templates/get-home-dependencies.md +1 -0
- package/cli/templates/get-no-match.md +3 -0
- package/cli/templates/get-search-empty.md +3 -0
- package/cli/templates/get-search.md +5 -0
- package/cli/templates/import-backup.md +7 -0
- package/cli/templates/import-choice-rejected.md +1 -0
- package/cli/templates/import-decision.md +18 -0
- package/cli/templates/import-error.md +3 -0
- package/cli/templates/import-finding-incomplete.md +1 -0
- package/cli/templates/import-finding-unreadable.md +1 -0
- package/cli/templates/import-findings-configuration.md +3 -0
- package/cli/templates/import-findings.md +3 -0
- package/cli/templates/import-imported.md +3 -0
- package/cli/templates/import-private.md +6 -0
- package/cli/templates/import-rechecked.md +1 -0
- package/cli/templates/import-rechecks.md +1 -0
- package/cli/templates/import-report.md +1 -0
- package/cli/templates/import-reusable.md +2 -0
- package/cli/templates/import-unchanged.md +1 -0
- package/cli/templates/import-validation-findings.md +1 -0
- package/cli/templates/init-error.md +3 -0
- package/cli/templates/init-home.md +7 -0
- package/cli/templates/init-location.md +7 -0
- package/cli/templates/init-registered.md +5 -0
- package/cli/templates/init-repository.md +5 -0
- package/cli/templates/init-target.md +11 -0
- package/cli/templates/invocation-error.md +5 -0
- package/cli/templates/migration-notice.md +1 -0
- package/cli/templates/private-value.md +1 -0
- package/cli/templates/private-warning.md +1 -0
- package/cli/templates/projects-error.md +3 -0
- package/cli/templates/projects-result.md +3 -0
- package/cli/templates/readme-error.md +5 -0
- package/cli/templates/skill-missing.md +10 -0
- package/cli/templates/skill-outdated.md +7 -0
- package/cli/templates/validate-ambiguous.md +5 -0
- package/cli/templates/validate-error.md +5 -0
- package/cli/templates/validate-result.md +3 -0
- package/cli/woof.bundle.mjs +246 -0
- package/package.json +73 -4
- package/skills/woof-execution/SKILL.md +84 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-theme="coffee">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>woof · Edit token</title>
|
|
7
|
+
<link
|
|
8
|
+
rel="stylesheet"
|
|
9
|
+
href="https://cdn.jsdelivr.net/npm/daisyui@5.7.50/daisyui.css"
|
|
10
|
+
integrity="sha384-UwBu1IAWgb8nYSKlFTAgsMdqElJVcwjO1O31z47tHuvyhJ4rgjfif927I0JH2zI1"
|
|
11
|
+
crossorigin="anonymous" />
|
|
12
|
+
<link
|
|
13
|
+
rel="stylesheet"
|
|
14
|
+
href="https://cdn.jsdelivr.net/npm/daisyui@5.7.50/theme/coffee.css"
|
|
15
|
+
integrity="sha384-qqdGitAgWSmI3kzDMAvw+yitfgYGWMosprlOArCcH00rMG+2PN6XI5fljOEgkaW4"
|
|
16
|
+
crossorigin="anonymous" />
|
|
17
|
+
<style nonce="{{nonce}}">
|
|
18
|
+
/* The prebuilt daisyUI file has no Tailwind utilities. These are the few that the daisyUI patterns below use,
|
|
19
|
+
with Tailwind's values. */
|
|
20
|
+
.flex {
|
|
21
|
+
display: flex;
|
|
22
|
+
}
|
|
23
|
+
.flex-col {
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
}
|
|
26
|
+
.flex-wrap {
|
|
27
|
+
flex-wrap: wrap;
|
|
28
|
+
}
|
|
29
|
+
.items-center {
|
|
30
|
+
align-items: center;
|
|
31
|
+
}
|
|
32
|
+
.justify-end {
|
|
33
|
+
justify-content: flex-end;
|
|
34
|
+
}
|
|
35
|
+
.gap-2 {
|
|
36
|
+
gap: 0.5rem;
|
|
37
|
+
}
|
|
38
|
+
.gap-4 {
|
|
39
|
+
gap: 1rem;
|
|
40
|
+
}
|
|
41
|
+
.gap-6 {
|
|
42
|
+
gap: 1.5rem;
|
|
43
|
+
}
|
|
44
|
+
.w-full {
|
|
45
|
+
width: 100%;
|
|
46
|
+
}
|
|
47
|
+
.flex-1 {
|
|
48
|
+
flex: 1 1 0%;
|
|
49
|
+
}
|
|
50
|
+
.h-full {
|
|
51
|
+
height: 100%;
|
|
52
|
+
}
|
|
53
|
+
.min-h-96 {
|
|
54
|
+
min-height: 24rem;
|
|
55
|
+
}
|
|
56
|
+
.min-h-screen {
|
|
57
|
+
min-height: 100vh;
|
|
58
|
+
}
|
|
59
|
+
.max-w-5xl {
|
|
60
|
+
max-width: 64rem;
|
|
61
|
+
}
|
|
62
|
+
.mx-auto {
|
|
63
|
+
margin-inline: auto;
|
|
64
|
+
}
|
|
65
|
+
.mt-auto {
|
|
66
|
+
margin-top: auto;
|
|
67
|
+
}
|
|
68
|
+
.p-6 {
|
|
69
|
+
padding: 1.5rem;
|
|
70
|
+
}
|
|
71
|
+
.font-mono {
|
|
72
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
73
|
+
}
|
|
74
|
+
.text-sm {
|
|
75
|
+
font-size: 0.875rem;
|
|
76
|
+
line-height: 1.25rem;
|
|
77
|
+
}
|
|
78
|
+
[hidden] {
|
|
79
|
+
display: none !important;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* daisyUI sizes a tab panel from a fixed tabs height. A grid lets the open panel take the height that the card
|
|
83
|
+
leaves, so the editor fills the page. */
|
|
84
|
+
.tabs-fill {
|
|
85
|
+
display: grid;
|
|
86
|
+
grid-template-columns: repeat(2, max-content) 1fr;
|
|
87
|
+
grid-template-rows: auto 1fr;
|
|
88
|
+
}
|
|
89
|
+
.tabs-fill > .tab-content {
|
|
90
|
+
grid-column: 1 / -1;
|
|
91
|
+
grid-row: 2;
|
|
92
|
+
height: auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* daisyUI has no typography styles, so rendered Markdown gets a minimal set. */
|
|
96
|
+
.markdown > * + * {
|
|
97
|
+
margin-top: 0.75em;
|
|
98
|
+
}
|
|
99
|
+
.markdown h1 {
|
|
100
|
+
font-size: 1.5rem;
|
|
101
|
+
font-weight: 700;
|
|
102
|
+
}
|
|
103
|
+
.markdown h2 {
|
|
104
|
+
font-size: 1.25rem;
|
|
105
|
+
font-weight: 700;
|
|
106
|
+
}
|
|
107
|
+
.markdown h3 {
|
|
108
|
+
font-weight: 700;
|
|
109
|
+
}
|
|
110
|
+
.markdown ul {
|
|
111
|
+
list-style: disc;
|
|
112
|
+
padding-left: 1.5em;
|
|
113
|
+
}
|
|
114
|
+
.markdown ol {
|
|
115
|
+
list-style: decimal;
|
|
116
|
+
padding-left: 1.5em;
|
|
117
|
+
}
|
|
118
|
+
.markdown a {
|
|
119
|
+
text-decoration: underline;
|
|
120
|
+
}
|
|
121
|
+
.markdown blockquote {
|
|
122
|
+
padding-left: 1em;
|
|
123
|
+
border-left: 4px solid var(--color-base-300);
|
|
124
|
+
}
|
|
125
|
+
.markdown code,
|
|
126
|
+
.markdown pre {
|
|
127
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
128
|
+
background: var(--color-base-200);
|
|
129
|
+
border-radius: var(--radius-field);
|
|
130
|
+
}
|
|
131
|
+
.markdown code {
|
|
132
|
+
padding: 0.1em 0.3em;
|
|
133
|
+
}
|
|
134
|
+
.markdown pre {
|
|
135
|
+
padding: 1em;
|
|
136
|
+
overflow: auto;
|
|
137
|
+
}
|
|
138
|
+
.markdown pre code {
|
|
139
|
+
padding: 0;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
</head>
|
|
143
|
+
<body class="bg-base-200">
|
|
144
|
+
<main class="min-h-screen max-w-5xl mx-auto p-6 flex flex-col gap-6">
|
|
145
|
+
<span id="loading" class="loading loading-dots loading-lg"></span>
|
|
146
|
+
|
|
147
|
+
<form id="form" class="card card-border bg-base-100 flex-1" hidden>
|
|
148
|
+
<div class="card-body gap-4">
|
|
149
|
+
<div class="breadcrumbs text-sm"><ul id="crumbs"></ul></div>
|
|
150
|
+
<h1 class="card-title font-mono" id="path"></h1>
|
|
151
|
+
<div class="flex flex-wrap gap-2" id="badges"></div>
|
|
152
|
+
|
|
153
|
+
<div id="workspace" class="tabs tabs-lift tabs-fill flex-1">
|
|
154
|
+
<input type="radio" name="view" class="tab" aria-label="Write" checked />
|
|
155
|
+
<div class="tab-content bg-base-100 border-base-300 p-6">
|
|
156
|
+
<div class="flex flex-col gap-2 h-full">
|
|
157
|
+
<textarea id="content" class="textarea w-full flex-1 min-h-96 font-mono" spellcheck="false"></textarea>
|
|
158
|
+
<span class="label" id="count"></span>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
<input type="radio" name="view" class="tab" aria-label="Preview" />
|
|
162
|
+
<div class="tab-content bg-base-100 border-base-300 p-6">
|
|
163
|
+
<article class="markdown" id="preview"></article>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div id="error" role="alert" class="alert alert-error alert-soft" hidden><span id="error-text"></span></div>
|
|
168
|
+
|
|
169
|
+
<div class="card-actions items-center justify-end mt-auto">
|
|
170
|
+
<span id="dirty" class="badge badge-warning badge-soft" hidden>Unsaved changes</span>
|
|
171
|
+
<span id="shortcut" hidden
|
|
172
|
+
><kbd class="kbd kbd-sm" id="modifier">Ctrl</kbd> <kbd class="kbd kbd-sm">S</kbd></span
|
|
173
|
+
>
|
|
174
|
+
<button type="button" id="cancel" class="btn btn-ghost">Cancel</button>
|
|
175
|
+
<button type="submit" id="save" class="btn btn-primary">Save</button>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</form>
|
|
179
|
+
|
|
180
|
+
<div id="done" role="status" class="alert" hidden><span id="done-text"></span></div>
|
|
181
|
+
|
|
182
|
+
<div class="toast toast-top toast-end" id="toast" hidden>
|
|
183
|
+
<div class="alert alert-error"><span>woof could not save the content.</span></div>
|
|
184
|
+
</div>
|
|
185
|
+
</main>
|
|
186
|
+
|
|
187
|
+
<script nonce="{{nonce}}">
|
|
188
|
+
const $ = id => document.getElementById(id)
|
|
189
|
+
const REFERENCE = /\{\{([A-Za-z0-9_.-]+)\}\}/g
|
|
190
|
+
let state
|
|
191
|
+
let saved
|
|
192
|
+
let timer
|
|
193
|
+
let busy = false
|
|
194
|
+
|
|
195
|
+
const post = async (route, body) => {
|
|
196
|
+
const response = await fetch(location.pathname + route, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers: { 'content-type': 'application/json' },
|
|
199
|
+
body: JSON.stringify(body ?? {}),
|
|
200
|
+
})
|
|
201
|
+
return { ok: response.ok, data: await response.json() }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const element = (tag, className, text) => {
|
|
205
|
+
const node = document.createElement(tag)
|
|
206
|
+
if (className) node.className = className
|
|
207
|
+
if (text !== undefined) node.textContent = text
|
|
208
|
+
return node
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const snapshot = () => $('content').value
|
|
212
|
+
|
|
213
|
+
const refreshDirty = () => {
|
|
214
|
+
const dirty = Boolean(state) && snapshot() !== saved
|
|
215
|
+
$('dirty').hidden = !dirty
|
|
216
|
+
return dirty
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// References are plain text in the rendered preview, so they become badges without parsing markup.
|
|
220
|
+
const markReferences = root => {
|
|
221
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT)
|
|
222
|
+
const nodes = []
|
|
223
|
+
while (walker.nextNode()) if (walker.currentNode.nodeValue.match(REFERENCE)) nodes.push(walker.currentNode)
|
|
224
|
+
for (const node of nodes) {
|
|
225
|
+
const parts = []
|
|
226
|
+
let last = 0
|
|
227
|
+
for (const match of node.nodeValue.matchAll(REFERENCE)) {
|
|
228
|
+
parts.push(document.createTextNode(node.nodeValue.slice(last, match.index)))
|
|
229
|
+
parts.push(element('span', 'badge badge-sm badge-primary badge-outline font-mono', match[1]))
|
|
230
|
+
last = match.index + match[0].length
|
|
231
|
+
}
|
|
232
|
+
parts.push(document.createTextNode(node.nodeValue.slice(last)))
|
|
233
|
+
node.replaceWith(...parts)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const preview = async () => {
|
|
238
|
+
const content = $('content').value
|
|
239
|
+
const lines = content.split('\n').length
|
|
240
|
+
$('count').textContent =
|
|
241
|
+
`${lines} ${lines === 1 ? 'line' : 'lines'}, ${content.length} ${content.length === 1 ? 'character' : 'characters'}`
|
|
242
|
+
const { data } = await post('preview', { content })
|
|
243
|
+
$('preview').innerHTML = data.html ?? ''
|
|
244
|
+
markReferences($('preview'))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Errors mark code with backticks, so each code span becomes a code element.
|
|
248
|
+
const showError = text => {
|
|
249
|
+
$('error-text').replaceChildren(
|
|
250
|
+
...text
|
|
251
|
+
.split('`')
|
|
252
|
+
.map((part, index) => (index % 2 ? element('code', '', part) : document.createTextNode(part))),
|
|
253
|
+
)
|
|
254
|
+
$('error').hidden = !text
|
|
255
|
+
$('content').classList.toggle('textarea-error', Boolean(text))
|
|
256
|
+
if (!text) return
|
|
257
|
+
$('toast').hidden = false
|
|
258
|
+
setTimeout(() => ($('toast').hidden = true), 2400)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const finish = (kind, text) => {
|
|
262
|
+
busy = true
|
|
263
|
+
state = undefined
|
|
264
|
+
$('form').hidden = true
|
|
265
|
+
$('dirty').hidden = true
|
|
266
|
+
$('shortcut').hidden = true
|
|
267
|
+
$('done').className = `alert alert-${kind}`
|
|
268
|
+
$('done-text').textContent = text
|
|
269
|
+
$('done').hidden = false
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const load = async () => {
|
|
273
|
+
const { ok, data } = await post('state')
|
|
274
|
+
$('loading').hidden = true
|
|
275
|
+
if (!ok) return finish('error', data.error)
|
|
276
|
+
state = data
|
|
277
|
+
const segments = state.path.split('.')
|
|
278
|
+
$('crumbs').replaceChildren(...segments.map(segment => element('li', '', segment)))
|
|
279
|
+
$('path').textContent = state.path
|
|
280
|
+
$('badges').replaceChildren(
|
|
281
|
+
element('span', 'badge badge-primary', state.type),
|
|
282
|
+
element('span', 'badge badge-outline', state.where),
|
|
283
|
+
...(state.kind === 'file' ? [element('span', 'badge badge-ghost font-mono', state.files[0])] : []),
|
|
284
|
+
)
|
|
285
|
+
$('content').value = state.content
|
|
286
|
+
await preview()
|
|
287
|
+
saved = snapshot()
|
|
288
|
+
$('form').hidden = false
|
|
289
|
+
$('modifier').textContent = /Mac|iPhone|iPad/.test(navigator.platform) ? '⌘' : 'Ctrl'
|
|
290
|
+
$('shortcut').hidden = false
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const save = async () => {
|
|
294
|
+
if (!state || busy) return
|
|
295
|
+
busy = true
|
|
296
|
+
$('save').replaceChildren(element('span', 'loading loading-spinner'), 'Saving')
|
|
297
|
+
showError('')
|
|
298
|
+
const { ok, data } = await post('save', { content: $('content').value })
|
|
299
|
+
busy = false
|
|
300
|
+
$('save').replaceChildren('Save')
|
|
301
|
+
if (!ok) return showError(data.error)
|
|
302
|
+
finish('success', 'Content saved. Continue in the terminal. You can close this tab.')
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
$('content').addEventListener('input', () => {
|
|
306
|
+
refreshDirty()
|
|
307
|
+
clearTimeout(timer)
|
|
308
|
+
timer = setTimeout(preview, 180)
|
|
309
|
+
})
|
|
310
|
+
$('content').addEventListener('keydown', event => {
|
|
311
|
+
if (event.key !== 'Tab') return
|
|
312
|
+
event.preventDefault()
|
|
313
|
+
event.target.setRangeText(' ', event.target.selectionStart, event.target.selectionEnd, 'end')
|
|
314
|
+
event.target.dispatchEvent(new Event('input'))
|
|
315
|
+
})
|
|
316
|
+
$('form').addEventListener('submit', event => {
|
|
317
|
+
event.preventDefault()
|
|
318
|
+
save()
|
|
319
|
+
})
|
|
320
|
+
document.addEventListener('keydown', event => {
|
|
321
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 's') {
|
|
322
|
+
event.preventDefault()
|
|
323
|
+
save()
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
$('cancel').addEventListener('click', async () => {
|
|
327
|
+
if (refreshDirty() && !confirm('Discard your changes?')) return
|
|
328
|
+
await post('cancel')
|
|
329
|
+
finish('warning', 'Edit cancelled. Nothing was changed. You can close this tab.')
|
|
330
|
+
})
|
|
331
|
+
addEventListener('beforeunload', event => {
|
|
332
|
+
if (state && refreshDirty()) event.preventDefault()
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
load()
|
|
336
|
+
</script>
|
|
337
|
+
</body>
|
|
338
|
+
</html>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Exported {{project}}.
|
|
2
|
+
|
|
3
|
+
Archive: {{archive}}
|
|
4
|
+
Files: {{files}}
|
|
5
|
+
|
|
6
|
+
The archive contains the project's tokens and only their required dependencies after applying project overrides. Tokens marked private contain placeholders.
|
|
7
|
+
|
|
8
|
+
Import it with woof import {{archiveArgument}} --agent.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Warning: Repository resources depend on woof home tokens or files; keep those shared dependencies available when moving this checkout.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Backup of woof home before this import: {{backup}}
|
|
2
|
+
|
|
3
|
+
The backup holds the root configuration, each file that it referenced, and each file that the import replaced. Its paths are relative to woof home. If the user wants to undo the import, or if the report lists incomplete recovery, offer to restore the backup:
|
|
4
|
+
|
|
5
|
+
unzip -o {{backupArgument}} -d {{homeArgument}}
|
|
6
|
+
|
|
7
|
+
Restore only after the user approves. The backup does not hold the files that the import created. After a restore, the configuration no longer references them.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Warning: {{details}}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Review {{kind}} {{path}}
|
|
2
|
+
|
|
3
|
+
{{diff}}{{notice}}{{reusable}}{{rechecks}}
|
|
4
|
+
|
|
5
|
+
Import needs the user's decision for this item. No import files change until every item has a decision.
|
|
6
|
+
|
|
7
|
+
{{document}}
|
|
8
|
+
|
|
9
|
+
Set choices[next.id] to the choice that the user makes:
|
|
10
|
+
|
|
11
|
+
- "take": use the archive's version. Add it if missing, or replace the local item.
|
|
12
|
+
- "keep": keep the local item and skip the archive's version.
|
|
13
|
+
- {"action":"add","address":"..."}: import it at a new address or path, and keep the local item.
|
|
14
|
+
- {"action":"reuse","address":"..."}: use an identical local item instead of importing it.
|
|
15
|
+
|
|
16
|
+
For token renames or reuse, avoid addresses such as -draft- whose references use the reserved {{-...-}} marker syntax.
|
|
17
|
+
|
|
18
|
+
Save the file and run woof import {{archive}} --decisions {{decisions}} --agent.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Validation could not finish: {{details}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Could not read {{file}}: {{details}}. Repair this configuration before running woof again.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Warning: This archive contains private placeholders for these tokens:
|
|
2
|
+
{{tokens}}
|
|
3
|
+
|
|
4
|
+
Their values were omitted during export. Import can continue. After import, ask the user for the missing values and replace the placeholders with woof edit.
|
|
5
|
+
|
|
6
|
+
A placeholder that differs from a local value in the same layer needs normal conflict review. A shared token with the same name does not by itself cause a conflict with a new project token.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Rechecked decisions that no longer required a choice: {{items}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Earlier decisions need review: {{items}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{{fields}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Nothing was imported. Each item already matched or was kept.{{rechecked}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Import completed. Review the separate validation findings; do not repeat the import.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Choose a name for the registered project.
|
|
2
|
+
|
|
3
|
+
{{command}}
|
|
4
|
+
|
|
5
|
+
Ask the user for the project name, and replace NAME with it. Base paths and worktree paths are optional, and --base-path and --worktree-path can repeat. Without paths, woof selects a registered project only with --project.
|
|
6
|
+
|
|
7
|
+
Retry with the exact command.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Choose where to create the project configuration.
|
|
2
|
+
|
|
3
|
+
In this repo (shared with the team): {{checkout}}. It has no name:
|
|
4
|
+
{{repository}}
|
|
5
|
+
|
|
6
|
+
In woof home (only you): {{rootFile}}. It needs a name. Its base paths and worktree paths are optional, and --base-path and --worktree-path can repeat:
|
|
7
|
+
{{home}}
|
|
8
|
+
|
|
9
|
+
Ask the user which configuration to create, and replace NAME with the name that the user chooses. Without paths, woof selects a registered project only with --project. Do not choose for the user.
|
|
10
|
+
|
|
11
|
+
Replace LOCATION with one of the locations.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Migrated configuration {{file}}: {{from}} -> {{to}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Token "{{path}}" needs a value because its private content was omitted during export. Ask the user to provide it, then update the token with woof edit.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Warning: {{message}}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
woof execution skill: not installed
|
|
2
|
+
|
|
3
|
+
Tell the user that the woof-execution skill is not installed, and recommend that they install it. The skill shows agents how to use woof: lookups and discovery, project selection and setup, adding and editing tokens, checks, and export and import reviews. Install it only after the user approves.
|
|
4
|
+
|
|
5
|
+
To install, copy this directory:
|
|
6
|
+
{{source}}
|
|
7
|
+
|
|
8
|
+
Copy it to one of these locations:
|
|
9
|
+
- {{claude}} (Claude Code)
|
|
10
|
+
- {{agents}} (agents that read ~/.agents, such as Codex)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
woof execution skill: update available
|
|
2
|
+
|
|
3
|
+
Tell the user that their woof-execution skill is out of date, and recommend that they update it. This woof includes version {{bundled}}. These installed copies are older:
|
|
4
|
+
{{copies}}
|
|
5
|
+
|
|
6
|
+
Update only after the user approves. To update, replace each older copy with this directory:
|
|
7
|
+
{{source}}
|