@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.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +510 -2
  3. package/cli/templates/add-draft.md +22 -0
  4. package/cli/templates/add-error.md +5 -0
  5. package/cli/templates/add-result.md +11 -0
  6. package/cli/templates/edit-draft.md +24 -0
  7. package/cli/templates/edit-error.md +3 -0
  8. package/cli/templates/edit-path.md +3 -0
  9. package/cli/templates/edit-result.md +7 -0
  10. package/cli/templates/edit-unchanged.md +3 -0
  11. package/cli/templates/editor.html +338 -0
  12. package/cli/templates/explain-ambiguous.md +5 -0
  13. package/cli/templates/explain-error.md +5 -0
  14. package/cli/templates/explain-result.md +5 -0
  15. package/cli/templates/export-error.md +3 -0
  16. package/cli/templates/export-result.md +8 -0
  17. package/cli/templates/get-ambiguous.md +5 -0
  18. package/cli/templates/get-cancelled.md +5 -0
  19. package/cli/templates/get-candidates.md +5 -0
  20. package/cli/templates/get-error.md +5 -0
  21. package/cli/templates/get-home-dependencies.md +1 -0
  22. package/cli/templates/get-no-match.md +3 -0
  23. package/cli/templates/get-search-empty.md +3 -0
  24. package/cli/templates/get-search.md +5 -0
  25. package/cli/templates/import-backup.md +7 -0
  26. package/cli/templates/import-choice-rejected.md +1 -0
  27. package/cli/templates/import-decision.md +18 -0
  28. package/cli/templates/import-error.md +3 -0
  29. package/cli/templates/import-finding-incomplete.md +1 -0
  30. package/cli/templates/import-finding-unreadable.md +1 -0
  31. package/cli/templates/import-findings-configuration.md +3 -0
  32. package/cli/templates/import-findings.md +3 -0
  33. package/cli/templates/import-imported.md +3 -0
  34. package/cli/templates/import-private.md +6 -0
  35. package/cli/templates/import-rechecked.md +1 -0
  36. package/cli/templates/import-rechecks.md +1 -0
  37. package/cli/templates/import-report.md +1 -0
  38. package/cli/templates/import-reusable.md +2 -0
  39. package/cli/templates/import-unchanged.md +1 -0
  40. package/cli/templates/import-validation-findings.md +1 -0
  41. package/cli/templates/init-error.md +3 -0
  42. package/cli/templates/init-home.md +7 -0
  43. package/cli/templates/init-location.md +7 -0
  44. package/cli/templates/init-registered.md +5 -0
  45. package/cli/templates/init-repository.md +5 -0
  46. package/cli/templates/init-target.md +11 -0
  47. package/cli/templates/invocation-error.md +5 -0
  48. package/cli/templates/migration-notice.md +1 -0
  49. package/cli/templates/private-value.md +1 -0
  50. package/cli/templates/private-warning.md +1 -0
  51. package/cli/templates/projects-error.md +3 -0
  52. package/cli/templates/projects-result.md +3 -0
  53. package/cli/templates/readme-error.md +5 -0
  54. package/cli/templates/skill-missing.md +10 -0
  55. package/cli/templates/skill-outdated.md +7 -0
  56. package/cli/templates/validate-ambiguous.md +5 -0
  57. package/cli/templates/validate-error.md +5 -0
  58. package/cli/templates/validate-result.md +3 -0
  59. package/cli/woof.bundle.mjs +246 -0
  60. package/package.json +73 -4
  61. 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,5 @@
1
+ Several projects match this directory:
2
+
3
+ {{projects}}
4
+
5
+ Ask the user which project to use, unless the conversation names one. Then run {{command}}, with NAME replaced by the project name. No selection was saved.
@@ -0,0 +1,5 @@
1
+ woof could not explain the resolution.
2
+
3
+ {{details}}
4
+
5
+ Search the tokens with woof get 'TERMS' --search --agent.
@@ -0,0 +1,5 @@
1
+ Resolution for {{requested}}
2
+
3
+ Project: {{project}}
4
+
5
+ {{tokens}}
@@ -0,0 +1,3 @@
1
+ woof could not export the project.
2
+
3
+ {{details}}
@@ -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,5 @@
1
+ Several projects match this directory:
2
+
3
+ {{projects}}
4
+
5
+ Ask the user which project to use, unless the conversation names one. Then run {{command}}, with NAME replaced by the project name. No selection was saved.
@@ -0,0 +1,5 @@
1
+ woof lookup was cancelled.
2
+
3
+ {{details}}
4
+
5
+ Earlier completed effects are not rolled back.
@@ -0,0 +1,5 @@
1
+ No token has this exact address. These resources match:
2
+
3
+ {{candidates}}
4
+
5
+ Choose the resource that matches the conversation. If the choice is unclear, ask the user. To resolve it, run {{command}}, with PATH replaced by its path.
@@ -0,0 +1,5 @@
1
+ woof could not complete the lookup.
2
+
3
+ {{details}}
4
+
5
+ Search the tokens with woof get 'TERMS' --search --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,3 @@
1
+ No resources matched this lookup.
2
+
3
+ Search with other terms: {{search}}, with TERMS replaced by the new terms.
@@ -0,0 +1,3 @@
1
+ No resources matched this lookup.
2
+
3
+ Search with other terms: {{search}}, with TERMS replaced by the new terms.
@@ -0,0 +1,5 @@
1
+ Matching resources
2
+
3
+ {{candidates}}
4
+
5
+ Choose the resource that matches the conversation. If the choice is unclear, ask the user. To resolve it, run {{command}}, with PATH replaced by its path. Discovery alone never runs a resource.
@@ -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,3 @@
1
+ woof could not complete the import.
2
+
3
+ {{details}}{{report}}
@@ -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,3 @@
1
+ Warning: Import completed, but validation found:
2
+ {{findings}}
3
+ Repair the configuration files named above before running woof again.
@@ -0,0 +1,3 @@
1
+ Warning: Import completed, but validation found:
2
+ {{findings}}
3
+ Review the reported tokens or run woof validate --project {{project}}.
@@ -0,0 +1,3 @@
1
+ Imported {{project}}.
2
+
3
+ {{report}}{{rechecked}}{{validation}}
@@ -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,2 @@
1
+ These local items have the same content. Reusing one keeps its description and tags:
2
+ {{candidates}}
@@ -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,3 @@
1
+ woof could not create the project configuration.
2
+
3
+ {{details}}
@@ -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,7 @@
1
+ Choose the location of the repository configuration in {{checkout}}.
2
+
3
+ {{commands}}
4
+
5
+ Ask the user which location to use. woof reads each location in the same way.
6
+
7
+ Replace LOCATION with one of the locations.
@@ -0,0 +1,5 @@
1
+ Registered project {{name}}.
2
+
3
+ {{fields}}
4
+
5
+ woof selects the project in directories that match its paths. Without paths, select it with --project {{name}}. To add a token, run {{add}}.
@@ -0,0 +1,5 @@
1
+ Created a repository configuration.
2
+
3
+ File: {{file}}
4
+
5
+ To add a token, run {{add}}.
@@ -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,5 @@
1
+ woof could not prepare the invocation.
2
+
3
+ {{details}}
4
+
5
+ Review the arguments and {{configuration}}. If woof reports a pending migration, retry with --migrate.
@@ -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,3 @@
1
+ woof could not list projects.
2
+
3
+ {{details}}
@@ -0,0 +1,3 @@
1
+ {{summary}}
2
+
3
+ {{list}}
@@ -0,0 +1,5 @@
1
+ woof could not print its user guide.
2
+
3
+ {{details}}
4
+
5
+ Run woof from its checkout or an installed package; a standalone bundle copied elsewhere has no guide.
@@ -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}}
@@ -0,0 +1,5 @@
1
+ Several projects match this directory:
2
+
3
+ {{projects}}
4
+
5
+ Ask the user which project to use, unless the conversation names one. Then run {{command}}, with NAME replaced by the project name. No selection was saved.
@@ -0,0 +1,5 @@
1
+ {{summary}}
2
+
3
+ {{details}}
4
+
5
+ Fix {{fix}}, then run woof validate --agent again.
@@ -0,0 +1,3 @@
1
+ {{summary}}
2
+
3
+ Project: {{project}}