fix(linkedin-studio): Oppgave 1 fix-pass — clipboard heredoc + report refs + calendar queue-felter [skip-docs]

Primær-sti-fixer fra cold-review:
- clipboard (10 cmds): printf '%s' '<text>' → quoted heredoc (apostrof/%/$/backtick
  korrumperte stdin); «Copied» betinget på COPIED, FAILED → be om manuell kopi
- report.md: heatmap-gren pekte til ikke-eksisterende «Step 6c» → «Step 2c»;
  Step 8b export skriver .md → la til Write i allowed-tools
- calendar.md: Step 1 emitter ENTRY RECORDS (id/draft_path/character_count) fra
  returnerte entry-objekter; publish + reschedule resolver id derfra
  (queueFormatSummary droppet feltene → handlingene var brutt)

test-runner: 138 passed / 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GqEHp4uDiivfrAUjw4BdE
This commit is contained in:
Kjell Tore Guttormsen 2026-06-30 13:35:17 +02:00
commit 882f6eee5e
12 changed files with 51 additions and 23 deletions

View file

@ -39,8 +39,15 @@ console.log('=== OVERDUE ===');
console.log(queueFormatSummary(queueOverdue())); console.log(queueFormatSummary(queueOverdue()));
console.log('=== COUNTS ==='); console.log('=== COUNTS ===');
console.log(JSON.stringify(queueCount(), null, 2)); console.log(JSON.stringify(queueCount(), null, 2));
console.log('=== ENTRY RECORDS (internal — id / draft_path / character_count etc. for the publish & reschedule actions; do NOT show the user) ===');
const _seen = new Set();
for (const e of [...queueToday(), ...queueOverdue(), ...queueUpcoming(14)]) {
if (_seen.has(e.id)) continue; _seen.add(e.id);
console.log(JSON.stringify({ id: e.id, draft_path: e.draft_path, scheduled_date: e.scheduled_date, scheduled_time: e.scheduled_time, hook_preview: e.hook_preview, pillar: e.pillar, format: e.format, character_count: e.character_count }));
}
" "
``` ```
The `queueFormatSummary` blocks are the human-readable overview; the **ENTRY RECORDS** block is the agent's lookup table for the `id`, `draft_path`, and `character_count` that the action steps need (these fields are not in the readable summary).
Also read state for context: Also read state for context:
- `~/.claude/linkedin-studio.local.md` for weekly goal and current progress - `~/.claude/linkedin-studio.local.md` for weekly goal and current progress
@ -110,7 +117,7 @@ No posts scheduled for today.
- Run /linkedin:quick for an unplanned quick post - Run /linkedin:quick for an unplanned quick post
``` ```
**3b. Pick a post.** Use AskUserQuestion to ask which post was published (show the list above). **3b. Pick a post.** Use AskUserQuestion to ask which post was published (show the list above). Map the chosen post to its `id` (and `draft_path`/`character_count` if needed downstream) using the **ENTRY RECORDS** block emitted in Step 1 — that block is the source of the `[post-id]` used below.
**3c. Update queue status:** **3c. Update queue status:**
```bash ```bash
@ -168,8 +175,8 @@ If they choose to reschedule:
2. Ask for the new date and time 2. Ask for the new date and time
3. Re-add the entry with the **same id** and new date/time — `queueAdd` replaces any 3. Re-add the entry with the **same id** and new date/time — `queueAdd` replaces any
existing entry with that id, so the post moves in place (no duplicate). Carry the existing entry with that id, so the post moves in place (no duplicate). Carry the
unchanged fields (draft_path, pillar, format, hook preview, char count) from the unchanged fields (id, draft_path, pillar, format, hook preview, char count) from the
entry shown in Step 2: **ENTRY RECORDS** block emitted in Step 1:
```bash ```bash
node --input-type=module -e "import { queueAdd } from '${CLAUDE_PLUGIN_ROOT}/hooks/scripts/queue-manager.mjs'; console.log(queueAdd('[post-id]', '[draft_path]', '[new-YYYY-MM-DD]', '[new-HH:MM]', '[pillar]', '[format]', '[hook preview]', [charCount]));" node --input-type=module -e "import { queueAdd } from '${CLAUDE_PLUGIN_ROOT}/hooks/scripts/queue-manager.mjs'; console.log(queueAdd('[post-id]', '[draft_path]', '[new-YYYY-MM-DD]', '[new-HH:MM]', '[pillar]', '[format]', '[hook preview]', [charCount]));"
``` ```

View file

@ -208,9 +208,11 @@ CAPTION
Then auto-copy the full deck to clipboard silently: Then auto-copy the full deck to clipboard silently:
```bash ```bash
printf '%s' '<FULL_DECK_PAYLOAD>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<FULL_DECK_PAYLOAD>
__LINKEDIN_CLIP_EOF__
``` ```
Substitute `<FULL_DECK_PAYLOAD>` with the assembled deck above — all slides' copy + the caption. Then confirm: "Full deck — [N] slides + caption — copied to clipboard." Substitute `<FULL_DECK_PAYLOAD>` between the heredoc markers with the assembled deck above — all slides' copy + the caption (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, confirm: "Full deck — [N] slides + caption — copied to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the deck above manually — do not claim it was copied.
Offer refinement options as text (no interactive prompt): Offer refinement options as text (no interactive prompt):
"Want to refine? Options: adjust slide text / change visual style / regenerate specific slide / different hook / ready for publishing." "Want to refine? Options: adjust slide text / change visual style / regenerate specific slide / different hook / ready for publishing."

View file

@ -138,10 +138,12 @@ Show the post with:
Auto-copy the post text to clipboard silently: Auto-copy the post text to clipboard silently:
```bash ```bash
printf '%s' '<POST_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<POST_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Then present: "Post copied to clipboard. Go to linkedin.com, click 'Start a post', paste it, and hit Post." Substitute `<POST_TEXT>` with the exact post text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, present: "Post copied to clipboard. Go to linkedin.com, click 'Start a post', paste it, and hit Post." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
## Step 7: State Update ## Step 7: State Update

View file

@ -69,10 +69,12 @@ Show, in this order:
Auto-copy the self-comments + draft replies to clipboard silently (so they're one paste away): Auto-copy the self-comments + draft replies to clipboard silently (so they're one paste away):
```bash ```bash
printf '%s' '<DRAFT_COMMENTS_BLOCK>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<DRAFT_COMMENTS_BLOCK>
__LINKEDIN_CLIP_EOF__
``` ```
Then confirm: "Copied your draft comments to clipboard." Substitute `<DRAFT_COMMENTS_BLOCK>` with the exact comments block between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, confirm: "Copied your draft comments to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
## Step 4: Persist the Plan to State ## Step 4: Persist the Plan to State

View file

@ -118,9 +118,11 @@ After creating the adaptation:
- Save to `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/drafts/multiplatform/[platform]-[slug].md` - Save to `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/drafts/multiplatform/[platform]-[slug].md`
- Auto-copy the adapted content to clipboard silently: - Auto-copy the adapted content to clipboard silently:
```bash ```bash
printf '%s' '<ADAPTED_CONTENT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<ADAPTED_CONTENT>
__LINKEDIN_CLIP_EOF__
``` ```
- Present the content and confirm: "Copied to clipboard." - Substitute `<ADAPTED_CONTENT>` with the exact adapted text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Present the content, and only if the helper prints `COPIED`, confirm: "Copied to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
- Note platform-specific publishing tips - Note platform-specific publishing tips
## Reference Files ## Reference Files

View file

@ -218,9 +218,11 @@ Fix any miss before showing it.
Show the post with its character count, the hook highlighted, and one alternative hook. Auto-copy the post text to clipboard silently: Show the post with its character count, the hook highlighted, and one alternative hook. Auto-copy the post text to clipboard silently:
```bash ```bash
printf '%s' '<POST_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<POST_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Then say: "Post copied to clipboard. Go to linkedin.com, click 'Start a post', paste it, and hit Post." Substitute `<POST_TEXT>` with the exact post text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, say: "Post copied to clipboard. Go to linkedin.com, click 'Start a post', paste it, and hit Post." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
### 3.5 — Record it ### 3.5 — Record it

View file

@ -136,7 +136,9 @@ Offer to help identify target profiles and draft comments.
Auto-copy the final post text to clipboard silently before presenting: Auto-copy the final post text to clipboard silently before presenting:
```bash ```bash
printf '%s' '<FINAL_POST_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<FINAL_POST_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Present the final post as copy-paste ready content: Present the final post as copy-paste ready content:

View file

@ -150,9 +150,11 @@ Present ONE draft with:
Auto-copy the final post text to clipboard silently: Auto-copy the final post text to clipboard silently:
```bash ```bash
printf '%s' '<FINAL_POST_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<FINAL_POST_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Then confirm: "Copied to clipboard." Substitute `<FINAL_POST_TEXT>` with the exact post text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, confirm: "Copied to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
Do NOT proactively offer alternative versions. Only generate alternatives if the user asks for them. Do NOT proactively offer alternative versions. Only generate alternatives if the user asks for them.

View file

@ -159,9 +159,11 @@ Show the post with:
Auto-copy the final post text to clipboard silently: Auto-copy the final post text to clipboard silently:
```bash ```bash
printf '%s' '<FINAL_POST_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<FINAL_POST_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Then confirm: "Copied to clipboard." Substitute `<FINAL_POST_TEXT>` with the exact post text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, confirm: "Copied to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
Do NOT proactively offer alternative versions. Only generate alternatives if the user asks. Do NOT proactively offer alternative versions. Only generate alternatives if the user asks.

View file

@ -146,9 +146,11 @@ Show:
Auto-copy the main draft text to clipboard silently: Auto-copy the main draft text to clipboard silently:
```bash ```bash
printf '%s' '<MAIN_DRAFT_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<MAIN_DRAFT_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Then confirm: "Copied to clipboard." Substitute `<MAIN_DRAFT_TEXT>` with the exact draft text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, confirm: "Copied to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
Do NOT use AskUserQuestion for refinement. Simply state: Do NOT use AskUserQuestion for refinement. Simply state:

View file

@ -10,6 +10,7 @@ allowed-tools:
- Bash - Bash
- Read - Read
- Glob - Glob
- Write
- AskUserQuestion - AskUserQuestion
- Task - Task
--- ---
@ -69,7 +70,7 @@ Enter your choice:
``` ```
**If monthly (option 2):** Ask for month (YYYY-MM format, default to current month), then jump to **Step 2b**. **If monthly (option 2):** Ask for month (YYYY-MM format, default to current month), then jump to **Step 2b**.
**If heatmap (option 3):** Run the heatmap CLI command and jump to **Step 6c**. **If heatmap (option 3):** Run the heatmap CLI command and jump to **Step 2c**.
**If weekly (option 1 or default):** Continue below. **If weekly (option 1 or default):** Continue below.
### Weekly: Determine Week ### Weekly: Determine Week

View file

@ -172,9 +172,11 @@ Style: [minimal / branded / text-heavy]
Auto-copy the POST CAPTION text to clipboard silently: Auto-copy the POST CAPTION text to clipboard silently:
```bash ```bash
printf '%s' '<POST_CAPTION_TEXT>' | node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/clipboard-helper.mjs <<'__LINKEDIN_CLIP_EOF__'
<POST_CAPTION_TEXT>
__LINKEDIN_CLIP_EOF__
``` ```
Then confirm: "Post caption copied to clipboard." Substitute `<POST_CAPTION_TEXT>` with the exact caption text between the heredoc markers (a quoted heredoc keeps apostrophes, `%`, `$`, and backticks literal). Only if the helper prints `COPIED`, confirm: "Post caption copied to clipboard." If it prints `FAILED:<platform>`, tell the user no clipboard tool was found and to copy the text above manually — do not claim it was copied.
## Step 7: Refinement Cycle ## Step 7: Refinement Cycle