@aitne-sh/aitne 0.1.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/LICENSE +21 -0
- package/README.md +464 -0
- package/agent-assets/agent-profiles/_safety.md +26 -0
- package/agent-assets/agent-profiles/conversational.md +33 -0
- package/agent-assets/agent-profiles/docs-qa.md +24 -0
- package/agent-assets/agent-profiles/observer.md +28 -0
- package/agent-assets/agent-profiles/profile-importer.md +63 -0
- package/agent-assets/agent-profiles/proxy.md +28 -0
- package/agent-assets/agent-profiles/routine.md +16 -0
- package/agent-assets/agent-profiles/task.md +18 -0
- package/agent-assets/docs/concepts/agent-day.md +88 -0
- package/agent-assets/docs/concepts/auth-health.md +75 -0
- package/agent-assets/docs/concepts/backends-and-tiers.md +126 -0
- package/agent-assets/docs/concepts/costs-and-quotas.md +103 -0
- package/agent-assets/docs/concepts/delegated-mode.md +223 -0
- package/agent-assets/docs/concepts/memory-model.md +118 -0
- package/agent-assets/docs/concepts/observations.md +80 -0
- package/agent-assets/docs/concepts/process-keys.md +89 -0
- package/agent-assets/docs/concepts/routines.md +108 -0
- package/agent-assets/docs/concepts/safety-and-execution.md +109 -0
- package/agent-assets/docs/concepts/safety-model.md +279 -0
- package/agent-assets/docs/concepts/skills.md +100 -0
- package/agent-assets/docs/features/integrations/calendar.md +92 -0
- package/agent-assets/docs/features/integrations/git.md +95 -0
- package/agent-assets/docs/features/integrations/github.md +170 -0
- package/agent-assets/docs/features/integrations/mail.md +106 -0
- package/agent-assets/docs/features/integrations/notion.md +69 -0
- package/agent-assets/docs/features/integrations/obsidian.md +71 -0
- package/agent-assets/docs/features/lifestyle/git.md +178 -0
- package/agent-assets/docs/features/lifestyle/reading.md +93 -0
- package/agent-assets/docs/features/lifestyle/receipts.md +71 -0
- package/agent-assets/docs/features/lifestyle/travel-bookings.md +44 -0
- package/agent-assets/docs/features/lifestyle/travel-time.md +52 -0
- package/agent-assets/docs/features/memory-files/agent-journal.md +105 -0
- package/agent-assets/docs/features/memory-files/projects.md +56 -0
- package/agent-assets/docs/features/memory-files/roadmap.md +61 -0
- package/agent-assets/docs/features/memory-files/schedule.md +112 -0
- package/agent-assets/docs/features/memory-files/today.md +73 -0
- package/agent-assets/docs/features/memory-files/user-profile.md +81 -0
- package/agent-assets/docs/features/messaging/dashboard-chat.md +93 -0
- package/agent-assets/docs/features/messaging/discord.md +50 -0
- package/agent-assets/docs/features/messaging/overview.md +111 -0
- package/agent-assets/docs/features/messaging/pairing-and-magic-phrase.md +69 -0
- package/agent-assets/docs/features/messaging/slack.md +51 -0
- package/agent-assets/docs/features/messaging/telegram.md +63 -0
- package/agent-assets/docs/features/messaging/whatsapp.md +48 -0
- package/agent-assets/docs/features/operations/activity-and-conversations.md +105 -0
- package/agent-assets/docs/features/operations/approvals.md +58 -0
- package/agent-assets/docs/features/operations/backend-routing.md +62 -0
- package/agent-assets/docs/features/operations/cost-tracking.md +59 -0
- package/agent-assets/docs/features/operations/notifications.md +69 -0
- package/agent-assets/docs/features/operations/quiet-hours.md +106 -0
- package/agent-assets/docs/features/operations/schedule-approaching.md +60 -0
- package/agent-assets/docs/features/routines/custom-routines.md +101 -0
- package/agent-assets/docs/features/routines/evening-review.md +81 -0
- package/agent-assets/docs/features/routines/hourly-check.md +85 -0
- package/agent-assets/docs/features/routines/monthly-review.md +65 -0
- package/agent-assets/docs/features/routines/morning-routine.md +123 -0
- package/agent-assets/docs/features/routines/weekly-review.md +70 -0
- package/agent-assets/docs/getting-started/01-what-is-this.md +192 -0
- package/agent-assets/docs/getting-started/02-first-steps.md +80 -0
- package/agent-assets/docs/getting-started/03-what-can-this-do.md +110 -0
- package/agent-assets/docs/getting-started/04-first-day.md +287 -0
- package/agent-assets/docs/glossary.md +116 -0
- package/agent-assets/docs/guides/add-a-custom-routine.md +71 -0
- package/agent-assets/docs/guides/backup-and-restore.md +54 -0
- package/agent-assets/docs/guides/change-which-model-handles-x.md +47 -0
- package/agent-assets/docs/guides/connect-a-new-mail-account.md +59 -0
- package/agent-assets/docs/guides/import-knowledge-file.md +275 -0
- package/agent-assets/docs/guides/install-and-run.md +72 -0
- package/agent-assets/docs/guides/migrate-machines.md +52 -0
- package/agent-assets/docs/guides/pause-the-agent.md +65 -0
- package/agent-assets/docs/guides/reinstall-cleanly.md +52 -0
- package/agent-assets/docs/guides/setup-wizard.md +107 -0
- package/agent-assets/docs/guides/switch-default-backend.md +60 -0
- package/agent-assets/docs/reference/api.md +51 -0
- package/agent-assets/docs/reference/cli-commands.md +121 -0
- package/agent-assets/docs/reference/config.md +74 -0
- package/agent-assets/docs/reference/disallowed-tools.md +76 -0
- package/agent-assets/docs/reference/keyboard-shortcuts.md +39 -0
- package/agent-assets/docs/reference/process-keys.md +59 -0
- package/agent-assets/docs/reference/skills.md +50 -0
- package/agent-assets/docs/troubleshooting/auth-failed.md +57 -0
- package/agent-assets/docs/troubleshooting/dashboard-shows-degraded.md +55 -0
- package/agent-assets/docs/troubleshooting/fallback-keeps-firing.md +54 -0
- package/agent-assets/docs/troubleshooting/messaging-not-pairing.md +53 -0
- package/agent-assets/docs/troubleshooting/morning-routine-didnt-run.md +75 -0
- package/agent-assets/docs/troubleshooting/observation-not-detected.md +57 -0
- package/agent-assets/docs/troubleshooting/quota-exhausted.md +57 -0
- package/agent-assets/optimizer-skills/drift-analysis/SKILL.md +75 -0
- package/agent-assets/optimizer-skills/knowledge-map/SKILL.md +71 -0
- package/agent-assets/optimizer-skills/skill-curation/SKILL.md +108 -0
- package/agent-assets/project-doc-templates/git-repo.md +21 -0
- package/agent-assets/project-doc-templates/project.md +38 -0
- package/agent-assets/skills/attach/SKILL.md +104 -0
- package/agent-assets/skills/context/SKILL.md +257 -0
- package/agent-assets/skills/context/curation.json +37 -0
- package/agent-assets/skills/context/seeds/file-responsibilities.seed.json +13 -0
- package/agent-assets/skills/context/seeds/frontmatter-requirements.seed.json +40 -0
- package/agent-assets/skills/docs-search/SKILL.md +176 -0
- package/agent-assets/skills/external-services/SKILL.delegated.claude.md +369 -0
- package/agent-assets/skills/external-services/SKILL.delegated.codex.md +349 -0
- package/agent-assets/skills/external-services/SKILL.delegated.gemini.md +347 -0
- package/agent-assets/skills/external-services/SKILL.md +371 -0
- package/agent-assets/skills/mail/SKILL.delegated.claude.md +284 -0
- package/agent-assets/skills/mail/SKILL.delegated.codex.md +261 -0
- package/agent-assets/skills/mail/SKILL.delegated.gemini.md +255 -0
- package/agent-assets/skills/mail/SKILL.md +313 -0
- package/agent-assets/skills/mail/references/errors.md +17 -0
- package/agent-assets/skills/mail/references/providers.md +40 -0
- package/agent-assets/skills/mail/references/query-grammar.md +24 -0
- package/agent-assets/skills/management-policy/SKILL.md +307 -0
- package/agent-assets/skills/management-policy/curation.json +13 -0
- package/agent-assets/skills/management-policy/seeds/policy-file-shape.seed.json +16 -0
- package/agent-assets/skills/management-task-modify/SKILL.md +202 -0
- package/agent-assets/skills/management-task-register/SKILL.md +330 -0
- package/agent-assets/skills/management-task-stop/SKILL.md +166 -0
- package/agent-assets/skills/notify/SKILL.md +196 -0
- package/agent-assets/skills/notion/SKILL.delegated.claude.md +254 -0
- package/agent-assets/skills/notion/SKILL.delegated.codex.md +195 -0
- package/agent-assets/skills/notion/SKILL.delegated.gemini.md +194 -0
- package/agent-assets/skills/notion/SKILL.md +86 -0
- package/agent-assets/skills/observations/SKILL.md +234 -0
- package/agent-assets/skills/observations/curation.json +13 -0
- package/agent-assets/skills/observations/seeds/source-namespacing.seed.json +20 -0
- package/agent-assets/skills/project-doc/SKILL.md +86 -0
- package/agent-assets/skills/project-doc/curation.json +21 -0
- package/agent-assets/skills/project-doc/seeds/project-shape.seed.json +25 -0
- package/agent-assets/skills/project-doc/seeds/slug-grammar.seed.json +20 -0
- package/agent-assets/skills/reading/SKILL.md +198 -0
- package/agent-assets/skills/reading/references/reading-taste.md +197 -0
- package/agent-assets/skills/receipts/SKILL.md +134 -0
- package/agent-assets/skills/roadmap/SKILL.md +276 -0
- package/agent-assets/skills/roadmap/curation.json +13 -0
- package/agent-assets/skills/roadmap/references/horizon-tags.md +40 -0
- package/agent-assets/skills/roadmap/references/preparation-timeline.md +47 -0
- package/agent-assets/skills/roadmap/seeds/entry-types.seed.json +16 -0
- package/agent-assets/skills/schedule/SKILL.md +228 -0
- package/agent-assets/skills/scheduled-managed-task/SKILL.md +392 -0
- package/agent-assets/skills/today/SKILL.md +198 -0
- package/agent-assets/skills/today/curation.json +21 -0
- package/agent-assets/skills/today/seeds/agent-notes-flavors.seed.json +17 -0
- package/agent-assets/skills/today/seeds/section-shape.seed.json +17 -0
- package/agent-assets/skills/travel/SKILL.md +132 -0
- package/agent-assets/skills/travel-time/SKILL.md +149 -0
- package/agent-assets/skills/user-interview/SKILL.md +323 -0
- package/agent-assets/skills/user-interview/references/sweep-and-fallback.md +94 -0
- package/agent-assets/skills/user-profile/SKILL.md +210 -0
- package/agent-assets/skills/user-profile/curation.json +29 -0
- package/agent-assets/skills/user-profile/seeds/learned-context-format.seed.json +14 -0
- package/agent-assets/skills/user-profile/seeds/routing-table.seed.json +53 -0
- package/agent-assets/skills/user-profile/seeds/topic-files.seed.json +27 -0
- package/agent-assets/task-flows/dashboard.docs_qa.md +43 -0
- package/agent-assets/task-flows/default.md +11 -0
- package/agent-assets/task-flows/git.branch.created.md +25 -0
- package/agent-assets/task-flows/git.lifecycle.poll.md +52 -0
- package/agent-assets/task-flows/git.local_ahead.stale.md +34 -0
- package/agent-assets/task-flows/git.merge_to_default.md +30 -0
- package/agent-assets/task-flows/git.project.refresh_architecture.md +100 -0
- package/agent-assets/task-flows/git.project.retemplate.md +73 -0
- package/agent-assets/task-flows/git.push.detected.md +32 -0
- package/agent-assets/task-flows/git.push.force_pushed.md +36 -0
- package/agent-assets/task-flows/git.tag.created.md +24 -0
- package/agent-assets/task-flows/github.assigned.md +43 -0
- package/agent-assets/task-flows/github.pull_request.review_requested.md +57 -0
- package/agent-assets/task-flows/github.security_alert.md +45 -0
- package/agent-assets/task-flows/github.workflow_run.failed.md +57 -0
- package/agent-assets/task-flows/knowledge.import.md +161 -0
- package/agent-assets/task-flows/message.received.dm.md +142 -0
- package/agent-assets/task-flows/message.received.dm_first.md +117 -0
- package/agent-assets/task-flows/message.received.md +14 -0
- package/agent-assets/task-flows/routine.custom.md +38 -0
- package/agent-assets/task-flows/routine.evening_review.md +323 -0
- package/agent-assets/task-flows/routine.hourly_check.delegated.claude.md +405 -0
- package/agent-assets/task-flows/routine.hourly_check.delegated.codex.md +400 -0
- package/agent-assets/task-flows/routine.hourly_check.delegated.gemini.md +404 -0
- package/agent-assets/task-flows/routine.hourly_check.md +184 -0
- package/agent-assets/task-flows/routine.hourly_check.triage.md +93 -0
- package/agent-assets/task-flows/routine.monthly_review.md +250 -0
- package/agent-assets/task-flows/routine.morning_routine.md +300 -0
- package/agent-assets/task-flows/routine.morning_routine_initial.md +184 -0
- package/agent-assets/task-flows/routine.roadmap_refresh.md +275 -0
- package/agent-assets/task-flows/routine.today_refresh.md +172 -0
- package/agent-assets/task-flows/routine.user_profile_sweep.md +242 -0
- package/agent-assets/task-flows/routine.weekly_review.md +247 -0
- package/agent-assets/task-flows/schedule.approaching.md +124 -0
- package/agent-assets/task-flows/scheduled.dm.md +391 -0
- package/agent-assets/task-flows/scheduled.task.md +141 -0
- package/agent-assets/task-flows/setup.initial.md +277 -0
- package/agent-assets/task-flows/setup.update.md +53 -0
- package/agent-assets/templates/README.md +85 -0
- package/agent-assets/templates/_index.md +39 -0
- package/agent-assets/templates/_manifest.json +103 -0
- package/agent-assets/templates/agent/journal.md +10 -0
- package/agent-assets/templates/agent/profile-questions.md +74 -0
- package/agent-assets/templates/context-index.md +42 -0
- package/agent-assets/templates/dossiers/_index.md +22 -0
- package/agent-assets/templates/dossiers/evening.md +23 -0
- package/agent-assets/templates/dossiers/hourly.md +23 -0
- package/agent-assets/templates/dossiers/monthly.md +23 -0
- package/agent-assets/templates/dossiers/morning.md +23 -0
- package/agent-assets/templates/dossiers/roadmap.md +23 -0
- package/agent-assets/templates/dossiers/weekly.md +23 -0
- package/agent-assets/templates/projects/_active.base +14 -0
- package/agent-assets/templates/projects/_index.md +29 -0
- package/agent-assets/templates/roadmap.md +15 -0
- package/agent-assets/templates/routines/_index.md +20 -0
- package/agent-assets/templates/routines/evening.md +22 -0
- package/agent-assets/templates/routines/hourly.md +30 -0
- package/agent-assets/templates/routines/monthly.md +25 -0
- package/agent-assets/templates/routines/morning.md +26 -0
- package/agent-assets/templates/routines/weekly.md +23 -0
- package/agent-assets/templates/rules/_index.md +19 -0
- package/agent-assets/templates/rules/journal-export.md +41 -0
- package/agent-assets/templates/rules/journal-format.md +61 -0
- package/agent-assets/templates/rules/management.md +48 -0
- package/agent-assets/templates/rules/mcp.md +40 -0
- package/agent-assets/templates/rules/policies/_index.md +22 -0
- package/agent-assets/templates/rules/redaction.md +30 -0
- package/agent-assets/templates/today.md +13 -0
- package/agent-assets/templates/user/_index.md +16 -0
- package/agent-assets/templates/user/expertise.md +7 -0
- package/agent-assets/templates/user/goals.md +7 -0
- package/agent-assets/templates/user/people.md +7 -0
- package/agent-assets/templates/user/personal.md +7 -0
- package/agent-assets/templates/user/profile.md +28 -0
- package/agent-assets/templates/user/work.md +7 -0
- package/bin/aitne.mjs +1096 -0
- package/package.json +78 -0
- package/personal-agent.mjs +39 -0
- package/scripts/browser.mjs +99 -0
- package/scripts/check-redaction-coverage.mjs +109 -0
- package/scripts/commands/audit.mjs +309 -0
- package/scripts/commands/doctor.mjs +437 -0
- package/scripts/commands/open.mjs +40 -0
- package/scripts/commands/setup.mjs +21 -0
- package/scripts/commands/uninstall.mjs +114 -0
- package/scripts/commands/update.mjs +96 -0
- package/scripts/commands/version.mjs +62 -0
- package/scripts/commands.md +0 -0
- package/scripts/lib/sqlite-loader.mjs +49 -0
- package/scripts/message-discipline-digest.mjs +535 -0
- package/scripts/poc/google-connector-inheritance/REPORT.md +197 -0
- package/scripts/poc/google-connector-inheritance/claude-sdk-probe.mjs +79 -0
- package/scripts/remint-roadmap-ids.mjs +257 -0
- package/scripts/rm-paths.mjs +22 -0
- package/scripts/run-node.mjs +223 -0
- package/scripts/smoke-obsidian-api.mjs +166 -0
- package/scripts/start.mjs +160 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# POC Report — Google Connector Inheritance
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-04-19
|
|
4
|
+
**Environment**: Darwin 25.4.0 (macOS), Node 25.8.0
|
|
5
|
+
**Goal**: Verify that headless Claude Code (via `@anthropic-ai/claude-agent-sdk`) and Codex CLI (`codex exec`) subprocesses inherit the user's installed Gmail / Calendar plugins and can actually invoke them.
|
|
6
|
+
|
|
7
|
+
**Verdict**: ✅ **PASS for both Claude Code and Codex.** The proposed delegated-mode design is technically viable.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Claude Code — Agent SDK (`query()`)
|
|
12
|
+
|
|
13
|
+
**SDK version**: `@anthropic-ai/claude-agent-sdk@0.2.98`
|
|
14
|
+
**Transport**: SDK spawns a Claude Code CLI subprocess; inherits user config at `~/.claude/`.
|
|
15
|
+
|
|
16
|
+
### 1.1 Tool manifest inheritance
|
|
17
|
+
|
|
18
|
+
Probe script: `packages/daemon/scripts/poc/claude-sdk-probe.mjs`
|
|
19
|
+
|
|
20
|
+
Captured from the `system { subtype: "init" }` message emitted at the start of every SDK session:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Total tools exposed: 238
|
|
24
|
+
MCP servers inherited: 12
|
|
25
|
+
- plugin:discord:discord
|
|
26
|
+
- github
|
|
27
|
+
- google-workspace ← local stdio MCP (not claude.ai hosted)
|
|
28
|
+
- claude.ai Indeed
|
|
29
|
+
- claude.ai Canva
|
|
30
|
+
- claude.ai Figma
|
|
31
|
+
- claude.ai Slack
|
|
32
|
+
- claude.ai Notion
|
|
33
|
+
- claude.ai Hugging Face
|
|
34
|
+
- claude.ai Gmail ← hosted connector (OAuth'd via claude.ai)
|
|
35
|
+
- claude.ai Google Drive
|
|
36
|
+
- claude.ai Google Calendar ← hosted connector
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Gmail/Calendar tool counts inherited:
|
|
40
|
+
|
|
41
|
+
- `mcp__claude_ai_Gmail__*` — **10** tools (create_draft, search_threads, get_thread, list_labels, label_message, label_thread, list_drafts, create_label, unlabel_message, unlabel_thread)
|
|
42
|
+
- `mcp__claude_ai_Google_Calendar__*` — **8** tools (create_event, delete_event, get_event, list_calendars, list_events, respond_to_event, suggest_time, update_event)
|
|
43
|
+
- `mcp__google-workspace__*` — **96** tools (gcal_*, gmail_*)
|
|
44
|
+
|
|
45
|
+
**Conclusion**: Zero config passed to `query()`. The subprocess automatically picks up every MCP the user has configured in Claude Code. Matches the `claude -p` CLI output exactly.
|
|
46
|
+
|
|
47
|
+
### 1.2 Live invocation
|
|
48
|
+
|
|
49
|
+
Probe script: `packages/daemon/scripts/poc/claude-sdk-invoke.mjs`
|
|
50
|
+
|
|
51
|
+
Prompt: *"Call `mcp__claude_ai_Gmail__search_threads` with `newer_than:30d`, pageSize=3. Report whether it succeeded, thread count, first subject."*
|
|
52
|
+
|
|
53
|
+
Result:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"toolUses": [
|
|
58
|
+
{ "name": "mcp__claude_ai_Gmail__search_threads",
|
|
59
|
+
"input": { "query": "newer_than:30d", "pageSize": 3 } }
|
|
60
|
+
],
|
|
61
|
+
"toolResultsSummary": [ { "is_error": false, "previewLen": 500 } ],
|
|
62
|
+
"assistantText": "(a) Succeeded: Yes. (b) Threads returned: 3. (c) First thread subject: \"Security alert\"",
|
|
63
|
+
"result": { "subtype": "success", "durationMs": 10518, "costUsd": 0.115, "numTurns": 3 }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Conclusion**: The SDK's `query()` subprocess can not only *see* the Gmail connector but *invoke* it and receive real user-account data. Auth is already attached (no reauth prompt).
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 2. Codex CLI (`codex exec`)
|
|
72
|
+
|
|
73
|
+
**CLI version**: `codex-cli 0.121.0`
|
|
74
|
+
**Transport**: Daemon spawns `codex exec --json --skip-git-repo-check --model <id> ...` subprocess (see `packages/daemon/src/core/backends/codex-core.ts:617-631`).
|
|
75
|
+
**Registered MCP servers** (`codex mcp list`):
|
|
76
|
+
```
|
|
77
|
+
google-workspace /opt/homebrew/bin/node .../google_workspace/dist/src/index.js enabled
|
|
78
|
+
```
|
|
79
|
+
Plus Codex's own built-in `codex_apps` namespace (ChatGPT-style app connectors, bundled with the `codex@openai-codex` plugin).
|
|
80
|
+
|
|
81
|
+
### 2.1 Tool manifest inheritance
|
|
82
|
+
|
|
83
|
+
Prompt: *"List every tool name containing gmail/calendar/google-workspace."*
|
|
84
|
+
|
|
85
|
+
Captured tools (truncated for brevity):
|
|
86
|
+
|
|
87
|
+
- `mcp__codex_apps__gmail._*` — **21** tools (`_search_emails`, `_read_email`, `_send_email`, `_create_draft`, `_apply_labels_to_emails`, `_archive_emails`, `_forward_emails`, `_get_profile`, etc.)
|
|
88
|
+
- `mcp__codex_apps__google_calendar._*` — **11** tools (`_search_events`, `_create_event`, `_update_event`, `_respond_event`, `_get_availability`, etc.)
|
|
89
|
+
- `mcp__google_workspace__.*` — ~100 tools (same local MCP as Claude Code)
|
|
90
|
+
|
|
91
|
+
**Conclusion**: `codex exec` non-interactive mode inherits both the plugin-provided `codex_apps` connectors AND the user's configured `google-workspace` MCP.
|
|
92
|
+
|
|
93
|
+
### 2.2 Live invocation
|
|
94
|
+
|
|
95
|
+
Prompt: *"Call `mcp__codex_apps__gmail._search_emails` with `newer_than:30d`, max_results=3. Report success/count/first subject."*
|
|
96
|
+
|
|
97
|
+
Result (trimmed from JSON stream):
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
mcp: codex_apps/gmail_search_emails started
|
|
101
|
+
mcp: codex_apps/gmail_search_emails (completed)
|
|
102
|
+
(a) succeeded: yes
|
|
103
|
+
(b) emails returned: 3
|
|
104
|
+
(c) first email subject: Security alert
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Conclusion**: Codex's native `codex_apps` Gmail connector is invocable from non-interactive `codex exec`, returns real user data. Same inbox state as Claude Code, confirming both are hitting the same underlying Google account.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 3. Cross-backend summary
|
|
112
|
+
|
|
113
|
+
| Property | Claude Code SDK | Codex CLI |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| CLI subprocess inherits user plugins | ✅ | ✅ |
|
|
116
|
+
| Hosted Gmail connector available | ✅ `mcp__claude_ai_Gmail__*` (10) | ✅ `mcp__codex_apps__gmail._*` (21) |
|
|
117
|
+
| Hosted Calendar connector available | ✅ `mcp__claude_ai_Google_Calendar__*` (8) | ✅ `mcp__codex_apps__google_calendar._*` (11) |
|
|
118
|
+
| Local `google-workspace` MCP available | ✅ | ✅ |
|
|
119
|
+
| Invocation returns real user data | ✅ | ✅ |
|
|
120
|
+
| Auth prompt during invocation | ❌ (none) | ❌ (none) |
|
|
121
|
+
| First-call latency | ~10 s (Claude) | ~5 s (Codex) |
|
|
122
|
+
| Test cost | $0.12 | included in ChatGPT plan |
|
|
123
|
+
|
|
124
|
+
**Both backends independently satisfy the Phase 0 success criterion** defined in `GOOGLE_AUTH_DELEGATION_DESIGN.md`.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 4. Implications for the design
|
|
129
|
+
|
|
130
|
+
### Confirmed assumptions
|
|
131
|
+
|
|
132
|
+
1. **Daemon can spawn either backend headlessly and reach Gmail/Calendar without owning any OAuth tokens.** This is the foundational assumption of the delegated mode.
|
|
133
|
+
2. **No GCP project, no OAuth JSON, no daemon-side credential management is required** for the delegated path.
|
|
134
|
+
3. **Multi-backend compatibility is symmetric** between Claude Code and Codex for the core Gmail/Calendar use cases. Gemini CLI still needs verification but is not a blocker.
|
|
135
|
+
4. **Each backend uses a different tool namespace** (`mcp__claude_ai_Gmail__*` vs `mcp__codex_apps__gmail._*`). Skills must be compiled per-backend.
|
|
136
|
+
|
|
137
|
+
### Revised scope
|
|
138
|
+
|
|
139
|
+
- **Initial delegated-mode support can span Claude Code AND Codex** (not Claude-only as hedged in the draft design). This simplifies fallback routing: `BackendRouter` may fall over main → fallback freely in delegated mode as long as both backends have a Google connector configured.
|
|
140
|
+
- **Skill templates must be namespace-aware per backend**, not just mode-aware. The `SkillsCompiler` change from a `(backend, mode)` matrix remains, but the delegated-mode skill body for Claude Code vs Codex will reference different tool names.
|
|
141
|
+
|
|
142
|
+
### New concerns surfaced by the POC
|
|
143
|
+
|
|
144
|
+
1. **Feature parity gap between connectors**. Claude's 10 Gmail tools vs Codex's 21 — Codex exposes attachment reading, batch operations, forwarding, archiving; Claude's hosted connector is thinner. Design must degrade gracefully when a task-flow instruction isn't supported by the active backend.
|
|
145
|
+
2. **`google-workspace` local MCP is the lowest common denominator**. If the user has it installed on both backends, the skill can target it uniformly (~100 tools covering nearly the full API). This may be the cleanest skill-writing target, with `mcp__claude_ai_*` / `mcp__codex_apps__*` as optional shortcuts.
|
|
146
|
+
3. **Invocation cost is non-trivial** ($0.12 for a 3-turn Claude exec on Opus). At hourly-check cadence across multiple accounts, this adds real spend. The design's "single-account only in delegated mode" restriction should stay.
|
|
147
|
+
4. **Tool-name drift risk**. `mcp__claude_ai_Gmail__*` namespace could change if Anthropic renames connectors. Skill prompts that hardcode tool names may break. Mitigation: instruct the agent with role descriptions rather than exact tool names ("use your Gmail search tool") and let the agent discover names at runtime.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 5. Recommended next step
|
|
152
|
+
|
|
153
|
+
The design doc's Phase 0 is **unblocked**. Proceed to Phase 1 (config plumbing + mode toggle), with one amendment:
|
|
154
|
+
|
|
155
|
+
- Update `GOOGLE_AUTH_DELEGATION_DESIGN.md` §4.4 to reflect that Claude Code + Codex both qualify as "Google-capable backends" from day one.
|
|
156
|
+
- Defer Gemini CLI verification to a separate task; it does not block initial shipping.
|
|
157
|
+
|
|
158
|
+
Artifacts:
|
|
159
|
+
|
|
160
|
+
- `packages/daemon/scripts/poc/claude-sdk-probe.mjs` — SDK tool manifest probe
|
|
161
|
+
- `packages/daemon/scripts/poc/claude-sdk-invoke.mjs` — SDK live invocation probe
|
|
162
|
+
- This report (`scripts/poc/google-connector-inheritance/REPORT.md`)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Appendix — Raw excerpts
|
|
167
|
+
|
|
168
|
+
### A. SDK init message key fields
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"systemInit": {
|
|
173
|
+
"model": "claude-opus-4-6[1m]",
|
|
174
|
+
"toolCount": 238,
|
|
175
|
+
"mcpServerCount": 12,
|
|
176
|
+
"mcpServerNames": [
|
|
177
|
+
"plugin:discord:discord", "github", "google-workspace",
|
|
178
|
+
"claude.ai Indeed", "claude.ai Canva", "claude.ai Figma",
|
|
179
|
+
"claude.ai Slack", "claude.ai Notion", "claude.ai Hugging Face",
|
|
180
|
+
"claude.ai Gmail", "claude.ai Google Drive", "claude.ai Google Calendar"
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### B. Codex config snippet
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
~/.codex/config.toml
|
|
190
|
+
model = "gpt-5.4"
|
|
191
|
+
|
|
192
|
+
codex mcp list
|
|
193
|
+
Name Command Args Status
|
|
194
|
+
google-workspace /opt/homebrew/bin/node /Users/shuto/Projects/mcp_server/google_workspace/dist/... enabled
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Codex `codex_apps` connectors are bundled with the `codex@openai-codex` Claude Code plugin (per `~/.claude/plugins/installed_plugins.json`); no separate registration is needed.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// POC: Verify whether @anthropic-ai/claude-agent-sdk subprocess
|
|
3
|
+
// inherits the user's installed Gmail / Calendar / google-workspace plugins.
|
|
4
|
+
//
|
|
5
|
+
// Mirrors the invocation style used by packages/daemon/src/core/backends/claude-code-core.ts.
|
|
6
|
+
// Run from repo root: node scripts/poc/google-connector-inheritance/claude-sdk-probe.mjs
|
|
7
|
+
|
|
8
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
9
|
+
|
|
10
|
+
const prompt =
|
|
11
|
+
'Print every tool name you have access to whose name contains "gmail", "calendar", or "google-workspace" (case-insensitive). ' +
|
|
12
|
+
'One tool name per line. No prose, no markdown fences. If none, print "NONE". Do not call the tools.';
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
const toolNames = new Set();
|
|
16
|
+
let finalText = "";
|
|
17
|
+
let systemInit = null;
|
|
18
|
+
let result = null;
|
|
19
|
+
|
|
20
|
+
const iter = query({
|
|
21
|
+
prompt,
|
|
22
|
+
options: {
|
|
23
|
+
// Do NOT set mcpServers — we are testing default inheritance.
|
|
24
|
+
// Do NOT pass cwd — let it default so user-level ~/.claude/ config applies.
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
for await (const msg of iter) {
|
|
29
|
+
if (msg.type === "system" && msg.subtype === "init") {
|
|
30
|
+
systemInit = {
|
|
31
|
+
model: msg.model,
|
|
32
|
+
tools: Array.isArray(msg.tools) ? msg.tools : [],
|
|
33
|
+
mcpServers: Array.isArray(msg.mcp_servers) ? msg.mcp_servers : [],
|
|
34
|
+
};
|
|
35
|
+
for (const t of systemInit.tools) toolNames.add(t);
|
|
36
|
+
} else if (msg.type === "assistant" && msg.message?.content) {
|
|
37
|
+
for (const block of msg.message.content) {
|
|
38
|
+
if (block.type === "text") finalText += block.text;
|
|
39
|
+
}
|
|
40
|
+
} else if (msg.type === "result") {
|
|
41
|
+
result = {
|
|
42
|
+
subtype: msg.subtype,
|
|
43
|
+
durationMs: msg.duration_ms,
|
|
44
|
+
costUsd: msg.total_cost_usd,
|
|
45
|
+
numTurns: msg.num_turns,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const googleToolsInInit = [...toolNames].filter((t) =>
|
|
51
|
+
/gmail|calendar|google-workspace/i.test(t),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const report = {
|
|
55
|
+
sdkVersion: (await import("@anthropic-ai/claude-agent-sdk/package.json", { with: { type: "json" } })).default.version,
|
|
56
|
+
systemInit: systemInit
|
|
57
|
+
? {
|
|
58
|
+
model: systemInit.model,
|
|
59
|
+
toolCount: systemInit.tools.length,
|
|
60
|
+
mcpServerCount: systemInit.mcpServers.length,
|
|
61
|
+
mcpServerNames: systemInit.mcpServers.map((s) => s.name ?? s),
|
|
62
|
+
}
|
|
63
|
+
: null,
|
|
64
|
+
googleToolsInInit,
|
|
65
|
+
assistantTextGoogleTools: finalText
|
|
66
|
+
.split(/\r?\n/)
|
|
67
|
+
.map((l) => l.trim())
|
|
68
|
+
.filter((l) => /gmail|calendar|google-workspace/i.test(l)),
|
|
69
|
+
result,
|
|
70
|
+
rawAssistantText: finalText.slice(0, 2000),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
console.log(JSON.stringify(report, null, 2));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
main().catch((err) => {
|
|
77
|
+
console.error("POC failed:", err);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
});
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Re-mint fabricated roadmap-entry IDs in roadmap.md.
|
|
3
|
+
//
|
|
4
|
+
// Background: when `POST /api/context/roadmap/id` is misclassified
|
|
5
|
+
// (e.g. the 2026-04-28 incident where it landed in the default-Approve
|
|
6
|
+
// fail-closed bucket), the agent's `roadmap_refresh` task-flow falls
|
|
7
|
+
// through to inventing IDs inline. Sonnet's typical fabrications follow
|
|
8
|
+
// an obvious `[0-9][a-f][0-9][a-f][0-9][a-f]` alternation pattern
|
|
9
|
+
// (`1a2b3c`, `4d5e6f`, `0d1e2f`, …) instead of the daemon's randomly
|
|
10
|
+
// distributed `[a-f0-9]{6}`. Even after the underlying classifier bug
|
|
11
|
+
// is patched, those fabricated IDs persist in roadmap.md because the
|
|
12
|
+
// task-flow's "merge-by-id" rule preserves existing entries verbatim.
|
|
13
|
+
//
|
|
14
|
+
// This script:
|
|
15
|
+
// 1. Reads the active vault's `roadmap.md` via the daemon API.
|
|
16
|
+
// 2. Detects fabricated IDs by the alternation heuristic (or all
|
|
17
|
+
// IDs when `--all` is set).
|
|
18
|
+
// 3. Mints a fresh daemon-owned ID for each via
|
|
19
|
+
// `POST /api/context/roadmap/id`.
|
|
20
|
+
// 4. Rewrites the file via `PUT /api/context/roadmap`.
|
|
21
|
+
//
|
|
22
|
+
// The mint endpoint (now Autonomous) does not require auth, but PUT
|
|
23
|
+
// does — the script reads the bearer token from the macOS keychain
|
|
24
|
+
// the same way the daemon stores it.
|
|
25
|
+
//
|
|
26
|
+
// Usage:
|
|
27
|
+
// node scripts/remint-roadmap-ids.mjs # detect + remint
|
|
28
|
+
// node scripts/remint-roadmap-ids.mjs --dry-run # print plan only
|
|
29
|
+
// node scripts/remint-roadmap-ids.mjs --all # remint every id
|
|
30
|
+
// node scripts/remint-roadmap-ids.mjs --port 8321 # override port
|
|
31
|
+
//
|
|
32
|
+
// Other vault files (agent-journal.md, dossiers/roadmap.md, project
|
|
33
|
+
// notes) are NOT rewritten — the script logs every replacement so the
|
|
34
|
+
// operator can grep their vault for stale references.
|
|
35
|
+
//
|
|
36
|
+
// IMPORTANT: the live mint+PUT path has only been exercised via
|
|
37
|
+
// `--dry-run` — back up the vault (or rely on the daemon's snapshot
|
|
38
|
+
// table) before running without `--dry-run`. Live execution requires
|
|
39
|
+
// `--yes` to avoid accidental writes.
|
|
40
|
+
|
|
41
|
+
import { execFileSync } from "node:child_process";
|
|
42
|
+
import { argv, exit } from "node:process";
|
|
43
|
+
|
|
44
|
+
// Heuristic mirror of `looksFabricatedRoadmapId` in
|
|
45
|
+
// packages/daemon/src/core/roadmap-ids.ts (kept inline so the script
|
|
46
|
+
// has no dist dependency). Unit-tested in roadmap-ids.test.ts; if you
|
|
47
|
+
// change the regex below, update both sites.
|
|
48
|
+
const ROADMAP_ID_RE = /^rm-\d{8}-[a-f0-9]{6}$/;
|
|
49
|
+
const ROADMAP_ID_COMMENT_RE = /<!--\s*id:\s*(rm-\d{8}-[a-f0-9]{6})\s*-->/g;
|
|
50
|
+
const FABRICATED_SUFFIX_RE = /^[0-9][a-f][0-9][a-f][0-9][a-f]$/;
|
|
51
|
+
|
|
52
|
+
function parseArgs(args) {
|
|
53
|
+
const opts = { dryRun: false, all: false, port: 8321, yes: false };
|
|
54
|
+
for (let i = 0; i < args.length; i++) {
|
|
55
|
+
const a = args[i];
|
|
56
|
+
if (a === "--dry-run") opts.dryRun = true;
|
|
57
|
+
else if (a === "--all") opts.all = true;
|
|
58
|
+
else if (a === "--yes") opts.yes = true;
|
|
59
|
+
else if (a === "--port") opts.port = Number(args[++i]);
|
|
60
|
+
else if (a === "--help" || a === "-h") {
|
|
61
|
+
process.stdout.write(
|
|
62
|
+
"Usage: remint-roadmap-ids.mjs [--dry-run] [--all] [--yes] [--port N]\n"
|
|
63
|
+
+ " --dry-run print plan, do not write\n"
|
|
64
|
+
+ " --all remint every id (default: only fabricated-looking ones)\n"
|
|
65
|
+
+ " --yes required to perform live writes (omit for dry-run safety)\n"
|
|
66
|
+
+ " --port N override daemon port (default 8321)\n",
|
|
67
|
+
);
|
|
68
|
+
exit(0);
|
|
69
|
+
} else {
|
|
70
|
+
process.stderr.write(`Unknown argument: ${a}\n`);
|
|
71
|
+
exit(2);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return opts;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function readApiToken() {
|
|
78
|
+
try {
|
|
79
|
+
return execFileSync(
|
|
80
|
+
"security",
|
|
81
|
+
[
|
|
82
|
+
"find-generic-password",
|
|
83
|
+
"-s",
|
|
84
|
+
"com.personal-agent.secret.apiToken",
|
|
85
|
+
"-w",
|
|
86
|
+
],
|
|
87
|
+
{ encoding: "utf-8" },
|
|
88
|
+
).trim();
|
|
89
|
+
} catch (err) {
|
|
90
|
+
process.stderr.write(
|
|
91
|
+
`Failed to read API token from macOS keychain: ${err.message}\n`,
|
|
92
|
+
);
|
|
93
|
+
process.stderr.write(
|
|
94
|
+
"(The script needs the daemon's apiToken to PUT the rewritten roadmap.)\n",
|
|
95
|
+
);
|
|
96
|
+
exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function fetchJson(url, init = {}) {
|
|
101
|
+
const res = await fetch(url, init);
|
|
102
|
+
const text = await res.text();
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
throw new Error(`${init.method ?? "GET"} ${url} → ${res.status}: ${text}`);
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
return JSON.parse(text);
|
|
108
|
+
} catch {
|
|
109
|
+
return text;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function suffixOf(id) {
|
|
114
|
+
// `rm-YYYYMMDD-xxxxxx` → `xxxxxx`
|
|
115
|
+
const dash = id.lastIndexOf("-");
|
|
116
|
+
return dash >= 0 ? id.slice(dash + 1) : id;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function looksFabricated(id) {
|
|
120
|
+
return FABRICATED_SUFFIX_RE.test(suffixOf(id));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function findIdsInBody(body) {
|
|
124
|
+
const ids = new Set();
|
|
125
|
+
for (const m of body.matchAll(ROADMAP_ID_COMMENT_RE)) ids.add(m[1]);
|
|
126
|
+
return [...ids];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function main() {
|
|
130
|
+
const opts = parseArgs(argv.slice(2));
|
|
131
|
+
if (!opts.dryRun && !opts.yes) {
|
|
132
|
+
process.stderr.write(
|
|
133
|
+
"Live execution requires --yes (or use --dry-run to preview). Refusing to write.\n",
|
|
134
|
+
);
|
|
135
|
+
exit(2);
|
|
136
|
+
}
|
|
137
|
+
const base = `http://127.0.0.1:${opts.port}`;
|
|
138
|
+
const token = readApiToken();
|
|
139
|
+
|
|
140
|
+
// 1. Read current roadmap.md (Bearer covers both ReadSensitive and
|
|
141
|
+
// Approve tiers, so we always send it).
|
|
142
|
+
const authHeaders = { Authorization: `Bearer ${token}` };
|
|
143
|
+
const roadmap = await fetchJson(`${base}/api/context/roadmap`, {
|
|
144
|
+
headers: authHeaders,
|
|
145
|
+
}).catch((err) => {
|
|
146
|
+
process.stderr.write(`Failed to read roadmap.md: ${err.message}\n`);
|
|
147
|
+
exit(1);
|
|
148
|
+
});
|
|
149
|
+
const body =
|
|
150
|
+
typeof roadmap === "object" && roadmap !== null && "content" in roadmap
|
|
151
|
+
? String(roadmap.content)
|
|
152
|
+
: String(roadmap);
|
|
153
|
+
|
|
154
|
+
const allIds = findIdsInBody(body);
|
|
155
|
+
if (allIds.length === 0) {
|
|
156
|
+
process.stdout.write("No roadmap IDs found in roadmap.md — nothing to do.\n");
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const targets = opts.all
|
|
161
|
+
? allIds.filter((id) => ROADMAP_ID_RE.test(id))
|
|
162
|
+
: allIds.filter(looksFabricated);
|
|
163
|
+
|
|
164
|
+
if (targets.length === 0) {
|
|
165
|
+
process.stdout.write(
|
|
166
|
+
`Scanned ${allIds.length} ID(s). None match the fabrication heuristic. Use --all to force re-mint.\n`,
|
|
167
|
+
);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
process.stdout.write(
|
|
172
|
+
opts.all
|
|
173
|
+
? `Re-minting all ${targets.length} ID(s) (--all flag set):\n`
|
|
174
|
+
: `Found ${targets.length} fabricated-looking ID(s) (of ${allIds.length} total):\n`,
|
|
175
|
+
);
|
|
176
|
+
for (const id of targets) process.stdout.write(` - ${id}\n`);
|
|
177
|
+
|
|
178
|
+
// 2. Mint replacements (daemon refuses to mint a duplicate against
|
|
179
|
+
// the live file, so we feed it the IDs already in flight to
|
|
180
|
+
// avoid collisions when it scans).
|
|
181
|
+
const mapping = new Map();
|
|
182
|
+
for (const oldId of targets) {
|
|
183
|
+
if (opts.dryRun) {
|
|
184
|
+
mapping.set(oldId, "<would mint>");
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const minted = await fetchJson(`${base}/api/context/roadmap/id`, {
|
|
188
|
+
method: "POST",
|
|
189
|
+
headers: { "Content-Type": "application/json" },
|
|
190
|
+
// Body is intentionally empty — the mint endpoint defaults
|
|
191
|
+
// creationDate to today, which is what we want for a re-mint.
|
|
192
|
+
body: "{}",
|
|
193
|
+
}).catch((err) => {
|
|
194
|
+
process.stderr.write(`Mint failed for ${oldId}: ${err.message}\n`);
|
|
195
|
+
exit(1);
|
|
196
|
+
});
|
|
197
|
+
if (!minted || typeof minted.id !== "string" || !ROADMAP_ID_RE.test(minted.id)) {
|
|
198
|
+
process.stderr.write(`Mint returned malformed response for ${oldId}\n`);
|
|
199
|
+
exit(1);
|
|
200
|
+
}
|
|
201
|
+
if ([...mapping.values()].includes(minted.id)) {
|
|
202
|
+
// The daemon-side existingIds dedup only sees what's in the
|
|
203
|
+
// file; back-to-back mint calls within the same script run
|
|
204
|
+
// could collide. Retry once.
|
|
205
|
+
process.stderr.write(`Mint collision on ${minted.id}, retrying…\n`);
|
|
206
|
+
const retry = await fetchJson(`${base}/api/context/roadmap/id`, {
|
|
207
|
+
method: "POST",
|
|
208
|
+
headers: { "Content-Type": "application/json" },
|
|
209
|
+
body: "{}",
|
|
210
|
+
});
|
|
211
|
+
mapping.set(oldId, retry.id);
|
|
212
|
+
} else {
|
|
213
|
+
mapping.set(oldId, minted.id);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
process.stdout.write("\nPlanned replacements:\n");
|
|
218
|
+
for (const [oldId, newId] of mapping)
|
|
219
|
+
process.stdout.write(` ${oldId} → ${newId}\n`);
|
|
220
|
+
|
|
221
|
+
if (opts.dryRun) {
|
|
222
|
+
process.stdout.write("\n[--dry-run] No file written.\n");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 3. Substitute IDs in the body. Use a literal regex per ID so a
|
|
227
|
+
// fabricated ID that happens to be a substring of another ID
|
|
228
|
+
// (extremely unlikely given the date prefix but cheap to guard)
|
|
229
|
+
// can't double-replace.
|
|
230
|
+
let updated = body;
|
|
231
|
+
for (const [oldId, newId] of mapping) {
|
|
232
|
+
const escaped = oldId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
233
|
+
updated = updated.replace(new RegExp(escaped, "g"), newId);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 4. PUT the rewritten roadmap.
|
|
237
|
+
await fetchJson(`${base}/api/context/roadmap`, {
|
|
238
|
+
method: "PUT",
|
|
239
|
+
headers: {
|
|
240
|
+
"Content-Type": "application/json",
|
|
241
|
+
Authorization: `Bearer ${token}`,
|
|
242
|
+
},
|
|
243
|
+
body: JSON.stringify({ content: updated }),
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
process.stdout.write(
|
|
247
|
+
`\nRewrote roadmap.md with ${mapping.size} re-minted ID(s).\n`,
|
|
248
|
+
);
|
|
249
|
+
process.stdout.write(
|
|
250
|
+
"If other vault files (agent-journal.md, dossiers/, projects/) reference the old IDs above, grep + update them manually.\n",
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
main().catch((err) => {
|
|
255
|
+
process.stderr.write(`Unhandled error: ${err.stack ?? err.message}\n`);
|
|
256
|
+
exit(1);
|
|
257
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { rm } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cross-platform rm -rf for build artifacts. Each path is resolved
|
|
7
|
+
* relative to the caller's CWD so per-package `clean` scripts can call
|
|
8
|
+
* `node ../../scripts/rm-paths.mjs dist` without juggling absolute paths.
|
|
9
|
+
*
|
|
10
|
+
* `recursive: true, force: true` matches the `rm -rf` semantics:
|
|
11
|
+
* non-existent paths are ignored, directories are removed recursively.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const targets = process.argv.slice(2);
|
|
15
|
+
if (targets.length === 0) {
|
|
16
|
+
console.error("Usage: rm-paths.mjs <path>...");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (const target of targets) {
|
|
21
|
+
await rm(path.resolve(target), { recursive: true, force: true });
|
|
22
|
+
}
|