@aholbreich/agent-skills 0.7.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 - 2026-05-07
4
+
5
+ Added:
6
+
7
+ - `confluence-update` now supports `--labels "a,b,c"` to assign Confluence page labels during an update.
8
+ - `confluence-update` now supports `--wrap-macro NAME` (e.g., `page-properties`) to automatically wrap the output HTML in a Confluence `<ac:structured-macro>` element.
9
+
3
10
  ## 0.7.0 - 2026-05-07
4
11
 
5
12
  Added:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aholbreich/agent-skills",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Handcrafted Agent Skills for browser-authenticated Jira and Confluence ingestion, LLM wiki workflows, and developer automation.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -11,6 +11,7 @@ const {
11
11
  safeName,
12
12
  extractPageId,
13
13
  renderContent,
14
+ wrapMacro,
14
15
  replaceMarkedBlock,
15
16
  } = lib;
16
17
 
@@ -33,6 +34,8 @@ Common options:
33
34
  --representation REP storage | markdown (default: storage)
34
35
  --raw-dir DIR Output/audit dir (default: CONFLUENCE_UPDATE_RAW_DIR, CONFLUENCE_RAW_DIR, or ./raw)
35
36
  --message TEXT Version message (default: Updated by confluence-update)
37
+ --labels LIST Comma-separated labels to add/set on the page
38
+ --wrap-macro NAME Wrap the generated storage in a macro (e.g. page-properties)
36
39
  --minor-edit Mark update as minor edit (default)
37
40
  --major-edit Do not mark update as minor edit
38
41
  --expected-version N|auto Fail if current page version is not N. Use 'auto' to always overwrite (default: null)
@@ -78,7 +81,9 @@ const opts = {
78
81
  representation: 'storage',
79
82
  title: '',
80
83
  message: 'Updated by confluence-update',
84
+ wrapMacro: '',
81
85
  minorEdit: true,
86
+ labels: [],
82
87
  expectedVersion: null,
83
88
  apply: false,
84
89
  marker: '',
@@ -107,6 +112,8 @@ for (let i = 0; i < args.length; i++) {
107
112
  else if (a === '--representation') opts.representation = args[++i];
108
113
  else if (a === '--title') opts.title = args[++i];
109
114
  else if (a === '--message') opts.message = args[++i];
115
+ else if (a === '--labels') opts.labels = args[++i].split(',').map(s => s.trim()).filter(Boolean);
116
+ else if (a === '--wrap-macro') opts.wrapMacro = args[++i];
110
117
  else if (a === '--minor-edit') opts.minorEdit = true;
111
118
  else if (a === '--major-edit') opts.minorEdit = false;
112
119
  else if (a === '--expected-version') opts.expectedVersion = args[++i] === 'auto' ? 'auto' : Number(args[i]);
@@ -404,7 +411,7 @@ function currentStorage(page) {
404
411
  }
405
412
 
406
413
  function updatePayload(page, storage) {
407
- return {
414
+ const payload = {
408
415
  id: String(page.id),
409
416
  type: page.type || 'page',
410
417
  title: opts.title || page.title,
@@ -416,6 +423,12 @@ function updatePayload(page, storage) {
416
423
  message: opts.message,
417
424
  },
418
425
  };
426
+ if (opts.labels.length > 0) {
427
+ payload.metadata = {
428
+ labels: opts.labels.map(name => ({ prefix: 'global', name }))
429
+ };
430
+ }
431
+ return payload;
419
432
  }
420
433
 
421
434
  function createPayload(storage) {
@@ -426,6 +439,11 @@ function createPayload(storage) {
426
439
  body: { storage: { value: storage, representation: 'storage' } },
427
440
  };
428
441
  if (opts.parentId) payload.ancestors = [{ id: String(opts.parentId) }];
442
+ if (opts.labels.length > 0) {
443
+ payload.metadata = {
444
+ labels: opts.labels.map(name => ({ prefix: 'global', name }))
445
+ };
446
+ }
429
447
  return payload;
430
448
  }
431
449
 
@@ -526,7 +544,9 @@ async function runCreate(cookie, inputStorage) {
526
544
 
527
545
  async function main() {
528
546
  const rawInput = await fsp.readFile(path.resolve(opts.file), 'utf8');
529
- const inputStorage = renderContent(rawInput, opts.representation);
547
+ let inputStorage = renderContent(rawInput, opts.representation);
548
+ if (opts.wrapMacro) inputStorage = wrapMacro(inputStorage, opts.wrapMacro);
549
+
530
550
  const pageId = opts.command === 'create' ? '' : extractPageId(opts.pageInput);
531
551
  if (opts.command !== 'create' && !pageId) throw new Error(`Could not extract page id from: ${opts.pageInput}`);
532
552
  const openUrl = opts.command === 'create' ? wikiBase : pageUrl(pageId);
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { randomUUID } = require('crypto');
4
+
3
5
  function escapeHtml(s) {
4
6
  return String(s ?? '')
5
7
  .replace(/&/g, '&amp;')
@@ -183,12 +185,26 @@ function generateSimpleDiff(oldText, newText) {
183
185
  return diff.join('\n');
184
186
  }
185
187
 
188
+ function wrapMacro(storage, macroType) {
189
+ if (!macroType) return storage;
190
+ const name = String(macroType).toLowerCase();
191
+
192
+ // Page Properties macro is internally called "details"
193
+ if (name === 'page-properties' || name === 'details') {
194
+ return `<ac:structured-macro ac:name="details" ac:schema-version="1" ac:macro-id="${randomUUID()}"><ac:rich-text-body>${storage}</ac:rich-text-body></ac:structured-macro>`;
195
+ }
196
+
197
+ // Generic wrapper for other rich-text body macros
198
+ return `<ac:structured-macro ac:name="${escapeHtml(name)}" ac:schema-version="1" ac:macro-id="${randomUUID()}"><ac:rich-text-body>${storage}</ac:rich-text-body></ac:structured-macro>`;
199
+ }
200
+
186
201
  module.exports = {
187
202
  escapeHtml,
188
203
  safeName,
189
204
  extractPageId,
190
205
  markdownToStorage,
191
206
  renderContent,
207
+ wrapMacro,
192
208
  blockMarkers,
193
209
  replaceMarkedBlock,
194
210
  replaceTextMatch,