@aitne-sh/aitne 0.1.8 → 0.1.9
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/README.md +218 -161
- package/agent-assets/agent-profiles/_safety.md +3 -3
- package/agent-assets/agent-profiles/browser-task.md +108 -0
- package/agent-assets/agent-profiles/conversational.md +3 -3
- package/agent-assets/agent-profiles/profile-importer.md +2 -2
- package/agent-assets/agent-profiles/routine-fetch-window.md +30 -19
- package/agent-assets/agents/context-index-reconcile/agent.md +52 -0
- package/agent-assets/agents/evening-review/agent.md +53 -0
- package/agent-assets/agents/hourly-check/agent.md +62 -0
- package/agent-assets/agents/monthly-review/agent.md +55 -0
- package/agent-assets/agents/morning-routine/agent.md +78 -0
- package/agent-assets/agents/roadmap-maintenance/agent.md +52 -0
- package/agent-assets/agents/skill-curation/agent.md +52 -0
- package/agent-assets/agents/user-profile-sweep-evening/agent.md +48 -0
- package/agent-assets/agents/user-profile-sweep-morning/agent.md +53 -0
- package/agent-assets/agents/weekly-review/agent.md +51 -0
- package/agent-assets/docs/concepts/agent-day.md +13 -11
- package/agent-assets/docs/concepts/auth-health.md +47 -10
- package/agent-assets/docs/concepts/backends-and-tiers.md +66 -31
- package/agent-assets/docs/concepts/costs-and-quotas.md +50 -15
- package/agent-assets/docs/concepts/delegated-mode.md +52 -13
- package/agent-assets/docs/concepts/memory-model.md +72 -32
- package/agent-assets/docs/concepts/observations.md +49 -11
- package/agent-assets/docs/concepts/process-keys.md +56 -22
- package/agent-assets/docs/concepts/routines.md +60 -33
- package/agent-assets/docs/concepts/safety-and-execution.md +50 -21
- package/agent-assets/docs/concepts/safety-model.md +42 -34
- package/agent-assets/docs/concepts/skills.md +33 -17
- package/agent-assets/docs/features/integrations/browser-history.md +195 -0
- package/agent-assets/docs/features/integrations/calendar.md +39 -29
- package/agent-assets/docs/features/integrations/git.md +18 -7
- package/agent-assets/docs/features/integrations/github.md +84 -33
- package/agent-assets/docs/features/integrations/mail.md +59 -16
- package/agent-assets/docs/features/integrations/notion.md +18 -6
- package/agent-assets/docs/features/integrations/obsidian.md +28 -5
- package/agent-assets/docs/features/lifestyle/git.md +42 -38
- package/agent-assets/docs/features/lifestyle/reading.md +50 -22
- package/agent-assets/docs/features/lifestyle/receipts.md +51 -21
- package/agent-assets/docs/features/lifestyle/travel-bookings.md +76 -14
- package/agent-assets/docs/features/memory-files/agent-journal.md +111 -50
- package/agent-assets/docs/features/memory-files/projects.md +71 -17
- package/agent-assets/docs/features/memory-files/roadmap.md +50 -10
- package/agent-assets/docs/features/memory-files/schedule.md +113 -70
- package/agent-assets/docs/features/memory-files/today.md +46 -21
- package/agent-assets/docs/features/memory-files/user-profile.md +63 -33
- package/agent-assets/docs/features/messaging/bang-commands.md +113 -36
- package/agent-assets/docs/features/messaging/dashboard-chat.md +43 -21
- package/agent-assets/docs/features/messaging/discord.md +35 -4
- package/agent-assets/docs/features/messaging/overview.md +37 -19
- package/agent-assets/docs/features/messaging/pairing-and-magic-phrase.md +94 -27
- package/agent-assets/docs/features/messaging/slack.md +67 -14
- package/agent-assets/docs/features/messaging/telegram.md +18 -5
- package/agent-assets/docs/features/messaging/whatsapp.md +71 -17
- package/agent-assets/docs/features/operations/activity-and-conversations.md +44 -15
- package/agent-assets/docs/features/operations/approvals.md +48 -16
- package/agent-assets/docs/features/operations/backend-routing.md +68 -16
- package/agent-assets/docs/features/operations/cost-tracking.md +84 -17
- package/agent-assets/docs/features/operations/managed-chromium.md +221 -0
- package/agent-assets/docs/features/operations/notifications.md +52 -11
- package/agent-assets/docs/features/operations/quiet-hours.md +63 -40
- package/agent-assets/docs/features/operations/schedule-approaching.md +54 -24
- package/agent-assets/docs/features/routines/custom-routines.md +88 -20
- package/agent-assets/docs/features/routines/evening-review.md +74 -21
- package/agent-assets/docs/features/routines/hourly-check.md +149 -29
- package/agent-assets/docs/features/routines/morning-routine.md +53 -35
- package/agent-assets/docs/features/routines/weekly-review.md +40 -21
- package/agent-assets/docs/features/wiki/commands.md +26 -16
- package/agent-assets/docs/features/wiki/cost-and-approval.md +240 -0
- package/agent-assets/docs/features/wiki/dashboard.md +255 -0
- package/agent-assets/docs/features/wiki/overview.md +68 -10
- package/agent-assets/docs/features/wiki/search.md +248 -0
- package/agent-assets/docs/features/wiki/workspaces.md +254 -0
- package/agent-assets/docs/getting-started/01-what-is-this.md +34 -23
- package/agent-assets/docs/getting-started/02-first-steps.md +13 -8
- package/agent-assets/docs/getting-started/03-what-can-this-do.md +25 -14
- package/agent-assets/docs/getting-started/04-first-day.md +38 -20
- package/agent-assets/docs/glossary.md +235 -24
- package/agent-assets/docs/guides/add-a-custom-routine.md +63 -23
- package/agent-assets/docs/guides/backup-and-restore.md +80 -16
- package/agent-assets/docs/guides/budget-and-cost-for-wiki.md +56 -25
- package/agent-assets/docs/guides/build-your-wiki.md +22 -9
- package/agent-assets/docs/guides/change-which-model-handles-x.md +64 -10
- package/agent-assets/docs/guides/connect-a-new-mail-account.md +64 -15
- package/agent-assets/docs/guides/explore-with-trace-and-connect.md +28 -11
- package/agent-assets/docs/guides/import-knowledge-file.md +50 -40
- package/agent-assets/docs/guides/install-and-run.md +48 -19
- package/agent-assets/docs/guides/maintain-wiki-health.md +35 -10
- package/agent-assets/docs/guides/migrate-machines.md +74 -18
- package/agent-assets/docs/guides/multiple-wikis-for-multiple-domains.md +111 -60
- package/agent-assets/docs/guides/pause-the-agent.md +65 -24
- package/agent-assets/docs/guides/reinstall-cleanly.md +88 -18
- package/agent-assets/docs/guides/setup-wizard.md +113 -54
- package/agent-assets/docs/guides/switch-default-backend.md +62 -16
- package/agent-assets/docs/guides/use-an-existing-obsidian-vault.md +26 -10
- package/agent-assets/docs/reference/api.md +143 -32
- package/agent-assets/docs/reference/cli-commands.md +38 -17
- package/agent-assets/docs/reference/config.md +224 -49
- package/agent-assets/docs/reference/disallowed-tools.md +29 -10
- package/agent-assets/docs/reference/keyboard-shortcuts.md +34 -10
- package/agent-assets/docs/reference/knowledge-layout.md +620 -0
- package/agent-assets/docs/reference/process-keys.md +61 -5
- package/agent-assets/docs/reference/skills.md +38 -12
- package/agent-assets/docs/troubleshooting/auth-failed.md +48 -19
- package/agent-assets/docs/troubleshooting/dashboard-shows-degraded.md +90 -28
- package/agent-assets/docs/troubleshooting/fallback-keeps-firing.md +86 -22
- package/agent-assets/docs/troubleshooting/messaging-not-pairing.md +68 -24
- package/agent-assets/docs/troubleshooting/morning-routine-didnt-run.md +80 -20
- package/agent-assets/docs/troubleshooting/observation-not-detected.md +73 -21
- package/agent-assets/docs/troubleshooting/quota-exhausted.md +29 -5
- package/agent-assets/docs/troubleshooting/wiki-ingest-full-blocked.md +126 -54
- package/agent-assets/docs/troubleshooting/wiki-write-failed.md +29 -12
- package/agent-assets/optimizer-skills/drift-analysis/SKILL.md +1 -1
- package/agent-assets/optimizer-skills/knowledge-map/SKILL.md +1 -1
- package/agent-assets/optimizer-skills/skill-curation/SKILL.md +1 -1
- package/agent-assets/sandbox/linux/aitne-chromium.apparmor +91 -0
- package/agent-assets/sandbox/macos/aitne-chromium.sb +156 -0
- package/agent-assets/skills/agent-actions/SKILL.md +2 -2
- package/agent-assets/skills/agent-create/SKILL.md +149 -0
- package/agent-assets/skills/attach/SKILL.md +2 -2
- package/agent-assets/skills/browser-history/SKILL.md +198 -0
- package/agent-assets/skills/browser-history-respond/SKILL.md +106 -0
- package/agent-assets/skills/browser-task/SKILL.md +169 -0
- package/agent-assets/skills/context/SKILL.md +12 -12
- package/agent-assets/skills/context/curation.json +2 -2
- package/agent-assets/skills/context/references/api.md +43 -31
- package/agent-assets/skills/context/references/required-frontmatter.md +3 -3
- package/agent-assets/skills/context/references/snapshot-files.md +6 -6
- package/agent-assets/skills/context/seeds/file-responsibilities.seed.json +3 -3
- package/agent-assets/skills/docs-search/SKILL.md +4 -3
- package/agent-assets/skills/external-services/SKILL.delegated.claude.md +11 -21
- package/agent-assets/skills/external-services/SKILL.delegated.codex.md +11 -21
- package/agent-assets/skills/external-services/SKILL.delegated.gemini.md +11 -21
- package/agent-assets/skills/external-services/SKILL.md +3 -3
- package/agent-assets/skills/external-services/SKILL.native.claude.md +5 -5
- package/agent-assets/skills/external-services/SKILL.native.codex.md +7 -7
- package/agent-assets/skills/external-services/SKILL.native.gemini.md +4 -4
- package/agent-assets/skills/external-services/references/calendar-apple.md +2 -2
- package/agent-assets/skills/external-services/references/calendar-outlook.md +1 -1
- package/agent-assets/skills/external-services/references/obsidian.md +2 -2
- package/agent-assets/skills/gmail-lifestyle/SKILL.md +9 -82
- package/agent-assets/skills/mail/SKILL.delegated.claude.md +14 -5
- package/agent-assets/skills/mail/SKILL.delegated.codex.md +8 -4
- package/agent-assets/skills/mail/SKILL.delegated.gemini.md +8 -4
- package/agent-assets/skills/mail/references/api.md +4 -2
- package/agent-assets/skills/mail/references/providers.md +1 -1
- package/agent-assets/skills/managed-tasks/SKILL.md +9 -9
- package/agent-assets/skills/managed-tasks/references/errors.md +9 -6
- package/agent-assets/skills/managed-tasks/references/recurrence-rule.md +1 -1
- package/agent-assets/skills/management-policy/SKILL.md +32 -31
- package/agent-assets/skills/management-policy/curation.json +1 -1
- package/agent-assets/skills/management-policy/references/policy-workflow.md +9 -9
- package/agent-assets/skills/management-policy/seeds/policy-file-shape.seed.json +1 -1
- package/agent-assets/skills/notify/SKILL.md +4 -4
- package/agent-assets/skills/notify/references/priority.md +9 -4
- package/agent-assets/skills/notion/SKILL.delegated.claude.md +1 -1
- package/agent-assets/skills/notion/SKILL.delegated.codex.md +1 -1
- package/agent-assets/skills/notion/SKILL.delegated.gemini.md +1 -1
- package/agent-assets/skills/notion/SKILL.native.claude.md +10 -6
- package/agent-assets/skills/notion/SKILL.native.codex.md +9 -4
- package/agent-assets/skills/notion/SKILL.native.gemini.md +9 -4
- package/agent-assets/skills/observations/SKILL.md +24 -8
- package/agent-assets/skills/project-doc/SKILL.md +1 -1
- package/agent-assets/skills/project-doc/curation.json +3 -3
- package/agent-assets/skills/project-doc/seeds/project-shape.seed.json +7 -4
- package/agent-assets/skills/project-doc/seeds/slug-grammar.seed.json +3 -3
- package/agent-assets/skills/reading/SKILL.md +10 -0
- package/agent-assets/skills/reading/references/reading-taste.md +2 -2
- package/agent-assets/skills/roadmap/SKILL.md +5 -5
- package/agent-assets/skills/roadmap/curation.json +1 -1
- package/agent-assets/skills/roadmap/references/api.md +7 -7
- package/agent-assets/skills/roadmap/references/cross-check.md +15 -8
- package/agent-assets/skills/roadmap/references/migration.md +4 -4
- package/agent-assets/skills/roadmap/seeds/entry-types.seed.json +1 -1
- package/agent-assets/skills/schedule/SKILL.md +42 -34
- package/agent-assets/skills/schedule/references/batch.md +2 -2
- package/agent-assets/skills/schedule/references/errors.md +7 -4
- package/agent-assets/skills/schedule/references/model-selection.md +3 -3
- package/agent-assets/skills/schedule/references/recurrence-rule.md +1 -1
- package/agent-assets/skills/scheduled-managed-task/SKILL.md +46 -36
- package/agent-assets/skills/today/SKILL.md +9 -9
- package/agent-assets/skills/today/curation.json +3 -3
- package/agent-assets/skills/today/references/agent-plan-lifecycle.md +6 -5
- package/agent-assets/skills/today/seeds/section-shape.seed.json +1 -1
- package/agent-assets/skills/user-interview/SKILL.md +12 -9
- package/agent-assets/skills/user-interview/references/op-briefing.md +2 -2
- package/agent-assets/skills/user-interview/references/sweep-and-fallback.md +8 -0
- package/agent-assets/skills/user-profile/SKILL.md +17 -17
- package/agent-assets/skills/user-profile/curation.json +2 -2
- package/agent-assets/skills/user-profile/references/character-preferences.md +2 -2
- package/agent-assets/skills/user-profile/seeds/routing-table.seed.json +8 -8
- package/agent-assets/skills/user-profile/seeds/topic-files.seed.json +6 -6
- package/agent-assets/skills/wiki/wiki-compile/SKILL.md +4 -4
- package/agent-assets/system-prompts/routine-fetch-window.md +22 -12
- package/agent-assets/task-flows/_partials/calendar-acquire.google_calendar.md +4 -2
- package/agent-assets/task-flows/_partials/calendar-acquire.outlook_calendar.md +4 -2
- package/agent-assets/task-flows/_partials/capture-user-info.md +2 -2
- package/agent-assets/task-flows/_partials/dm-intent.long-horizon.md +1 -1
- package/agent-assets/task-flows/_partials/dm-intent.project.md +9 -9
- package/agent-assets/task-flows/_partials/mail-acquire.outlook_mail.md +3 -2
- package/agent-assets/task-flows/_partials/notion-acquire.notion.md +10 -5
- package/agent-assets/task-flows/browser_task.md +84 -0
- package/agent-assets/task-flows/github.assigned.md +1 -1
- package/agent-assets/task-flows/github.pull_request.review_requested.md +2 -2
- package/agent-assets/task-flows/github.workflow_run.failed.md +2 -2
- package/agent-assets/task-flows/knowledge.import.md +14 -14
- package/agent-assets/task-flows/message.received.dm.md +9 -4
- package/agent-assets/task-flows/message.received.dm_first.md +3 -3
- package/agent-assets/task-flows/routine.custom.md +3 -3
- package/agent-assets/task-flows/routine.evening_review.md +8 -8
- package/agent-assets/task-flows/routine.fetch_window.md +2 -2
- package/agent-assets/task-flows/routine.hourly_check.md +16 -12
- package/agent-assets/task-flows/routine.monthly_review.md +21 -21
- package/agent-assets/task-flows/routine.morning_routine_journal.md +119 -97
- package/agent-assets/task-flows/routine.morning_routine_today.md +43 -43
- package/agent-assets/task-flows/routine.research_cluster_update.md +35 -0
- package/agent-assets/task-flows/routine.research_dispatch.md +38 -0
- package/agent-assets/task-flows/routine.research_offer_dm.md +125 -0
- package/agent-assets/task-flows/routine.research_wiki_summary.md +53 -0
- package/agent-assets/task-flows/routine.roadmap_refresh.md +10 -10
- package/agent-assets/task-flows/routine.today_refresh.md +4 -4
- package/agent-assets/task-flows/routine.user_profile_sweep.md +10 -10
- package/agent-assets/task-flows/routine.weekly_review.md +93 -24
- package/agent-assets/task-flows/schedule.approaching.md +0 -1
- package/agent-assets/task-flows/scheduled.dm.md +5 -5
- package/agent-assets/task-flows/scheduled.task.md +4 -4
- package/agent-assets/task-flows/setup.initial.md +21 -21
- package/agent-assets/task-flows/setup.update.md +2 -2
- package/agent-assets/templates/README.md +27 -20
- package/agent-assets/templates/_index.md +42 -26
- package/agent-assets/templates/_manifest.json +34 -99
- package/agent-assets/templates/{user → identity}/_index.md +1 -1
- package/agent-assets/templates/{user → identity}/profile.md +2 -2
- package/agent-assets/templates/{dossiers → knowledge/dossiers}/_index.md +1 -1
- package/agent-assets/templates/{projects → plans/projects}/_active.base +1 -1
- package/agent-assets/templates/policies/_index.md +21 -0
- package/agent-assets/templates/{rules → policies}/journal-export.md +1 -1
- package/agent-assets/templates/{rules → policies}/journal-format.md +5 -5
- package/agent-assets/templates/{rules/policies → policies/management-captures}/_index.md +2 -2
- package/agent-assets/templates/{rules → policies}/management.md +3 -3
- package/agent-assets/templates/{rules → policies}/mcp.md +1 -1
- package/agent-assets/templates/{rules → policies}/redaction.md +1 -1
- package/agent-assets/templates/{routines → policies/routines}/_index.md +1 -1
- package/agent-assets/templates/{routines → policies/routines}/evening.md +2 -2
- package/agent-assets/templates/{routines → policies/routines}/hourly.md +1 -1
- package/agent-assets/templates/{routines → policies/routines}/monthly.md +2 -2
- package/bin/aitne.mjs +13 -4
- package/package.json +5 -4
- package/scripts/commands/doctor.mjs +14 -8
- package/scripts/commands/run-now.mjs +6 -21
- package/scripts/lib/ports.d.mts +27 -0
- package/scripts/lib/ports.mjs +36 -0
- package/scripts/lib/read-api-token.mjs +176 -0
- package/scripts/start.mjs +2 -1
- package/agent-assets/docs/features/lifestyle/travel-time.md +0 -58
- package/agent-assets/skills/gmail-lifestyle/references/travel-time-api.md +0 -59
- package/agent-assets/skills/schedule/references/recurring.md +0 -185
- package/agent-assets/templates/context-index.md +0 -42
- package/agent-assets/templates/rules/_index.md +0 -19
- /package/agent-assets/templates/{user → identity}/expertise.md +0 -0
- /package/agent-assets/templates/{user → identity}/goals.md +0 -0
- /package/agent-assets/templates/{user → identity}/people.md +0 -0
- /package/agent-assets/templates/{user → identity}/personal.md +0 -0
- /package/agent-assets/templates/{user → identity}/work.md +0 -0
- /package/agent-assets/templates/{agent/journal.md → journal/agent.md} +0 -0
- /package/agent-assets/templates/{dossiers → knowledge/dossiers}/evening.md +0 -0
- /package/agent-assets/templates/{dossiers → knowledge/dossiers}/hourly.md +0 -0
- /package/agent-assets/templates/{dossiers → knowledge/dossiers}/monthly.md +0 -0
- /package/agent-assets/templates/{dossiers → knowledge/dossiers}/morning.md +0 -0
- /package/agent-assets/templates/{dossiers → knowledge/dossiers}/roadmap.md +0 -0
- /package/agent-assets/templates/{dossiers → knowledge/dossiers}/weekly.md +0 -0
- /package/agent-assets/templates/{projects → plans/projects}/_index.md +0 -0
- /package/agent-assets/templates/{roadmap.md → plans/roadmap.md} +0 -0
- /package/agent-assets/templates/{routines → policies/routines}/morning.md +0 -0
- /package/agent-assets/templates/{routines → policies/routines}/weekly.md +0 -0
- /package/agent-assets/templates/{agent → state}/profile-questions.md +0 -0
- /package/agent-assets/templates/{today.md → state/today.md} +0 -0
|
@@ -32,15 +32,15 @@ or the dashboard's Settings → Management page._
|
|
|
32
32
|
## C. Active Policies
|
|
33
33
|
|
|
34
34
|
Auto-maintained by the daemon (do not edit). Source files live under
|
|
35
|
-
`
|
|
36
|
-
`management-policy` skill. Full index: [[
|
|
35
|
+
`policies/management-captures/<slug>.md`; capture new policies via the
|
|
36
|
+
`management-policy` skill. Full index: [[policies/management-captures/_index.md]]
|
|
37
37
|
|
|
38
38
|
_No active policies yet._
|
|
39
39
|
|
|
40
40
|
## Notes
|
|
41
41
|
|
|
42
42
|
- The agent cannot use `Edit` / `Write` tools on this file — writes go
|
|
43
|
-
through `/api/context/
|
|
43
|
+
through `/api/context/policies/management` (locked + snapshotted) or the
|
|
44
44
|
managed-tasks / sot-bindings API surfaces.
|
|
45
45
|
- This file is injected into every flow via `policy-files.ts`. Keep it
|
|
46
46
|
concise so prompt assembly stays cheap.
|
|
@@ -16,7 +16,7 @@ This file governs how the agent uses attached Model Context Protocol
|
|
|
16
16
|
the target with me via DM when the change is visible to others (a new
|
|
17
17
|
issue, a posted message, an edited doc).
|
|
18
18
|
- Failures are loggable events. On repeated MCP call failures, the agent
|
|
19
|
-
appends to `agent
|
|
19
|
+
appends to `journal/agent.md` and surfaces the pattern at the next
|
|
20
20
|
hourly check.
|
|
21
21
|
- Scope to the active task. MCP calls unrelated to the current flow's
|
|
22
22
|
stated goal are skipped.
|
|
@@ -22,7 +22,7 @@ redaction is performed in code by `packages/shared/src/secret-redaction.ts`.
|
|
|
22
22
|
## Context-specific (journal export)
|
|
23
23
|
|
|
24
24
|
When exporting `daily/*.md` to an external vault (B-005), additional
|
|
25
|
-
user-defined rules in `
|
|
25
|
+
user-defined rules in `policies/journal-export.md` are applied on top.
|
|
26
26
|
|
|
27
27
|
## Appearance in logs
|
|
28
28
|
|
|
@@ -17,4 +17,4 @@ I've added later via DM). All checks are treated equally.
|
|
|
17
17
|
| `evening.md` | evening | `routine.evening_review` |
|
|
18
18
|
| `weekly.md` | Friday | `routine.weekly_review` |
|
|
19
19
|
| `monthly.md` | month-end | `routine.monthly_review` |
|
|
20
|
-
| custom/<slug>.md | user-defined cron in `routines/custom/` | `routine.custom.<slug>` |
|
|
20
|
+
| custom/<slug>.md | user-defined cron in `policies/routines/custom/` | `routine.custom.<slug>` |
|
|
@@ -10,7 +10,7 @@ template_version: 1
|
|
|
10
10
|
## Checks
|
|
11
11
|
|
|
12
12
|
### Today → Handoff
|
|
13
|
-
- **Action**: scan `today.md` for open items and summarize them into
|
|
13
|
+
- **Action**: scan `state/today.md` for open items and summarize them into
|
|
14
14
|
`## Handoff` so tomorrow's morning routine can pick them up
|
|
15
15
|
|
|
16
16
|
### Tomorrow preview
|
|
@@ -18,5 +18,5 @@ template_version: 1
|
|
|
18
18
|
deadlines into `## Handoff`
|
|
19
19
|
|
|
20
20
|
### Journal tail
|
|
21
|
-
- **Action**: append a 1–2 sentence note to `agent
|
|
21
|
+
- **Action**: append a 1–2 sentence note to `journal/agent.md` describing
|
|
22
22
|
anything surprising the agent observed today
|
|
@@ -21,7 +21,7 @@ skipping any whose preconditions are not met.
|
|
|
21
21
|
|
|
22
22
|
### Upcoming schedule
|
|
23
23
|
- **Precondition**: always
|
|
24
|
-
- **Action**: scan `today.md` `## Agent Plan` for items in the next 60
|
|
24
|
+
- **Action**: scan `state/today.md` `## Agent Plan` for items in the next 60
|
|
25
25
|
min; ensure each has a `scheduled.task` row.
|
|
26
26
|
|
|
27
27
|
## Skip conditions (applied before any check)
|
|
@@ -17,9 +17,9 @@ Fires on the last calendar day of the month. Output target:
|
|
|
17
17
|
`daily/*.md` items
|
|
18
18
|
|
|
19
19
|
### Roadmap delta
|
|
20
|
-
- **Action**: compare current `roadmap.md` against the month's progress;
|
|
20
|
+
- **Action**: compare current `plans/roadmap.md` against the month's progress;
|
|
21
21
|
highlight completed + delayed items
|
|
22
22
|
|
|
23
23
|
### Habit + health snapshot
|
|
24
|
-
- **Action**: if the user logged health/habit data in `
|
|
24
|
+
- **Action**: if the user logged health/habit data in `identity/personal.md`,
|
|
25
25
|
surface month-over-month changes (opt-in only)
|
package/bin/aitne.mjs
CHANGED
|
@@ -8,6 +8,15 @@ import process from "node:process";
|
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { ensureBuild } from "../scripts/run-node.mjs";
|
|
10
10
|
import { fetchHttpOk, openBrowser } from "../scripts/browser.mjs";
|
|
11
|
+
// Port defaults live in this plain-ESM module (NOT @aitne/shared, per the
|
|
12
|
+
// pre-build constraint noted below). scripts/lib/ ships in the published
|
|
13
|
+
// `files` list, so this import works in global installs too.
|
|
14
|
+
import {
|
|
15
|
+
DEFAULT_API_PORT,
|
|
16
|
+
DEFAULT_DASHBOARD_PORT,
|
|
17
|
+
resolveApiPort,
|
|
18
|
+
resolveDashboardPort,
|
|
19
|
+
} from "../scripts/lib/ports.mjs";
|
|
11
20
|
|
|
12
21
|
const IS_WINDOWS = process.platform === "win32";
|
|
13
22
|
|
|
@@ -55,8 +64,8 @@ const DAEMON_PID_FILE = path.join(PIDS_DIR, "daemon.pid");
|
|
|
55
64
|
const DASHBOARD_PID_FILE = path.join(PIDS_DIR, "dashboard.pid");
|
|
56
65
|
const DAEMON_LOG_FILE = path.join(DATA_DIR, "logs", "daemon.log");
|
|
57
66
|
const DASHBOARD_LOG_FILE = path.join(DATA_DIR, "logs", "dashboard.log");
|
|
58
|
-
const DAEMON_PORT =
|
|
59
|
-
const DASHBOARD_PORT =
|
|
67
|
+
const DAEMON_PORT = resolveApiPort();
|
|
68
|
+
const DASHBOARD_PORT = resolveDashboardPort();
|
|
60
69
|
|
|
61
70
|
const VERSION = JSON.parse(
|
|
62
71
|
fs.readFileSync(path.join(PROJECT_ROOT, "package.json"), "utf8"),
|
|
@@ -1004,8 +1013,8 @@ Options:
|
|
|
1004
1013
|
|
|
1005
1014
|
Environment:
|
|
1006
1015
|
PA_DATA_DIR Data directory (default: ~/.personal-agent)
|
|
1007
|
-
PA_API_PORT Daemon port (default:
|
|
1008
|
-
PA_DASHBOARD_PORT Dashboard port (default:
|
|
1016
|
+
PA_API_PORT Daemon port (default: ${DEFAULT_API_PORT})
|
|
1017
|
+
PA_DASHBOARD_PORT Dashboard port (default: ${DEFAULT_DASHBOARD_PORT})
|
|
1009
1018
|
|
|
1010
1019
|
Examples:
|
|
1011
1020
|
aitne start Launch in background
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aitne-sh/aitne",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Aitne — a local-first, proactive personal AI agent. A long-running TypeScript daemon is the nervous system; Claude Code (or Codex / Gemini CLI) is the brain. All persistent memory lives in local Markdown files.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"README.md"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@aitne/daemon": "0.1.
|
|
47
|
-
"@aitne/dashboard": "0.1.
|
|
48
|
-
"@aitne/shared": "0.1.
|
|
46
|
+
"@aitne/daemon": "0.1.9",
|
|
47
|
+
"@aitne/dashboard": "0.1.9",
|
|
48
|
+
"@aitne/shared": "0.1.9"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"test": "node scripts/check-redaction-coverage.mjs && vitest run --coverage",
|
|
76
76
|
"test:watch": "vitest",
|
|
77
77
|
"check:redaction": "node scripts/check-redaction-coverage.mjs",
|
|
78
|
+
"check:vault-paths": "node scripts/check-vault-path-drift.mjs",
|
|
78
79
|
"lint": "turbo run lint",
|
|
79
80
|
"typecheck:tests": "turbo run typecheck:tests",
|
|
80
81
|
"clean": "turbo run clean && node scripts/rm-paths.mjs node_modules .buildstamp"
|
|
@@ -38,7 +38,7 @@ Exit code:
|
|
|
38
38
|
await checkSecretStore(ctx),
|
|
39
39
|
await checkBackendCli(),
|
|
40
40
|
await checkProcessProbe(),
|
|
41
|
-
await checkBrowserOpener(),
|
|
41
|
+
await checkBrowserOpener(ctx.DASHBOARD_PORT),
|
|
42
42
|
await checkDataDirWritable(ctx.DATA_DIR),
|
|
43
43
|
await checkBetterSqlite3(ctx.PROJECT_ROOT),
|
|
44
44
|
await checkAgentAssets(ctx.PROJECT_ROOT),
|
|
@@ -127,8 +127,8 @@ async function checkPort(label, port, pidFile, getRunningPid) {
|
|
|
127
127
|
label,
|
|
128
128
|
detail: `${port} in use by another process`,
|
|
129
129
|
hint: label.startsWith("Daemon")
|
|
130
|
-
? `Set PA_API_PORT to an open port (e.g. PA_API_PORT=
|
|
131
|
-
: `Set PA_DASHBOARD_PORT to an open port (e.g. PA_DASHBOARD_PORT=
|
|
130
|
+
? `Set PA_API_PORT to an open port (e.g. PA_API_PORT=8331 aitne start), or stop the conflicting process.`
|
|
131
|
+
: `Set PA_DASHBOARD_PORT to an open port (e.g. PA_DASHBOARD_PORT=8333 aitne start), or stop the conflicting process.`,
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -182,11 +182,17 @@ async function checkSecretStore(ctx) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
if (platform === "win32") {
|
|
185
|
-
|
|
185
|
+
// Match the factory's terminal fallback (secret-client-factory.ts:37-41): prefer
|
|
186
|
+
// in-box powershell.exe, else pwsh.exe, else default to powershell.exe — the exact
|
|
187
|
+
// binary the daemon will exec — so a both-missing FAIL names the right binary.
|
|
188
|
+
const psBinary = whichSync("powershell.exe") ? "powershell.exe" : (whichSync("pwsh.exe") ? "pwsh.exe" : "powershell.exe");
|
|
186
189
|
try {
|
|
190
|
+
// Mirror WindowsDpapiSecretClient's real encrypt path: ConvertTo/From-SecureString
|
|
191
|
+
// (no -Key => DPAPI). Works on both powershell.exe (5.1) and pwsh.exe (7+); the prior
|
|
192
|
+
// [ProtectedData] type check false-fails on PowerShell-Core-only hosts that work fine.
|
|
187
193
|
execFileSync(psBinary, [
|
|
188
|
-
"-NoProfile", "-Command",
|
|
189
|
-
"
|
|
194
|
+
"-NoProfile", "-NonInteractive", "-Command",
|
|
195
|
+
"$s = ConvertTo-SecureString 'probe' -AsPlainText -Force; $e = ConvertFrom-SecureString $s; if (-not $e) { exit 1 }; exit 0",
|
|
190
196
|
], { stdio: "pipe", timeout: 5000 });
|
|
191
197
|
return { status: "pass", label: "Secret store", detail: `Windows DPAPI via ${psBinary} reachable` };
|
|
192
198
|
} catch (err) {
|
|
@@ -253,7 +259,7 @@ async function checkProcessProbe() {
|
|
|
253
259
|
* Warn-only: nothing in the daemon depends on this; users can navigate to
|
|
254
260
|
* the dashboard URL by hand if missing.
|
|
255
261
|
*/
|
|
256
|
-
async function checkBrowserOpener() {
|
|
262
|
+
async function checkBrowserOpener(dashboardPort) {
|
|
257
263
|
const platform = process.platform;
|
|
258
264
|
const tool =
|
|
259
265
|
platform === "darwin" ? "open"
|
|
@@ -268,7 +274,7 @@ async function checkBrowserOpener() {
|
|
|
268
274
|
detail: `${tool} not on PATH`,
|
|
269
275
|
hint:
|
|
270
276
|
platform === "linux"
|
|
271
|
-
?
|
|
277
|
+
? `apt install xdg-utils · or open http://localhost:${dashboardPort} manually after \`aitne start\`.`
|
|
272
278
|
: "Auto-open is a convenience; the dashboard URL works in any browser.",
|
|
273
279
|
};
|
|
274
280
|
}
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* `docs/design/appendices/evening-review-slimdown.md` §2.2.
|
|
10
10
|
*
|
|
11
11
|
* Implementation:
|
|
12
|
-
* - Reads the daemon's apiToken from the
|
|
13
|
-
*
|
|
12
|
+
* - Reads the daemon's apiToken from the OS secret store (macOS
|
|
13
|
+
* Keychain, Windows DPAPI, Linux libsecret, or the encrypted file
|
|
14
|
+
* fallback) via the shared cross-platform reader — the same entry
|
|
15
|
+
* the dashboard proxy uses. Bearer-auth required because
|
|
14
16
|
* `POST /api/agent/run-now/*` routes are Approve-tier in the
|
|
15
17
|
* `risk-classifier`.
|
|
16
18
|
* - POSTs to `http://127.0.0.1:<PA_API_PORT>/api/agent/run-now/<job>`.
|
|
@@ -23,7 +25,7 @@
|
|
|
23
25
|
* - 3 daemon not running, not reachable, or 5xx
|
|
24
26
|
* - 4 result.status === "failed" — the job reported errors[]
|
|
25
27
|
*/
|
|
26
|
-
import {
|
|
28
|
+
import { readApiToken } from "../lib/read-api-token.mjs";
|
|
27
29
|
|
|
28
30
|
const SUPPORTED_JOBS = new Set(["roadmap_maintenance"]);
|
|
29
31
|
|
|
@@ -53,7 +55,7 @@ export async function run(args, ctx) {
|
|
|
53
55
|
const token = readApiToken();
|
|
54
56
|
if (!token) {
|
|
55
57
|
process.stderr.write(
|
|
56
|
-
"Failed to read daemon API token from the
|
|
58
|
+
"Failed to read the daemon API token from the OS secret store.\n" +
|
|
57
59
|
"Is the daemon initialized? Run `aitne start` once first.\n",
|
|
58
60
|
);
|
|
59
61
|
process.exit(3);
|
|
@@ -125,23 +127,6 @@ function parseArgs(args) {
|
|
|
125
127
|
return opts;
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
function readApiToken() {
|
|
129
|
-
try {
|
|
130
|
-
return execFileSync(
|
|
131
|
-
"security",
|
|
132
|
-
[
|
|
133
|
-
"find-generic-password",
|
|
134
|
-
"-s",
|
|
135
|
-
"com.personal-agent.secret.apiToken",
|
|
136
|
-
"-w",
|
|
137
|
-
],
|
|
138
|
-
{ encoding: "utf-8" },
|
|
139
|
-
).trim();
|
|
140
|
-
} catch {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
130
|
function printSummary(job, result) {
|
|
146
131
|
if (job === "roadmap_maintenance") {
|
|
147
132
|
if (!result || typeof result !== "object") {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for the plain-ESM launcher mirror `ports.mjs`.
|
|
3
|
+
*
|
|
4
|
+
* `ports.mjs` is hand-written JavaScript (it must run before the TypeScript
|
|
5
|
+
* build), so it carries no inferred types. This sidecar lets TypeScript
|
|
6
|
+
* consumers — notably the `packages/shared/src/ports.test.ts` drift guard,
|
|
7
|
+
* which imports this module to assert it stays in lockstep with the TS
|
|
8
|
+
* source-of-truth `packages/shared/src/ports.ts` — typecheck the import under
|
|
9
|
+
* `strict`. Keep these signatures identical to `ports.ts`'s exports (minus
|
|
10
|
+
* `loopbackOrigins`, which is TS-only and not mirrored here).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Daemon HTTP API port. Overridable via `PA_API_PORT`. */
|
|
14
|
+
export const DEFAULT_API_PORT: number;
|
|
15
|
+
|
|
16
|
+
/** Dashboard (Next.js) port. Overridable via `PA_DASHBOARD_PORT`. */
|
|
17
|
+
export const DEFAULT_DASHBOARD_PORT: number;
|
|
18
|
+
|
|
19
|
+
/** Resolve the daemon API port from env, falling back to DEFAULT_API_PORT. */
|
|
20
|
+
export function resolveApiPort(
|
|
21
|
+
env?: Record<string, string | undefined>,
|
|
22
|
+
): number;
|
|
23
|
+
|
|
24
|
+
/** Resolve the dashboard port from env, falling back to DEFAULT_DASHBOARD_PORT. */
|
|
25
|
+
export function resolveDashboardPort(
|
|
26
|
+
env?: Record<string, string | undefined>,
|
|
27
|
+
): number;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default network ports for the Aitne daemon API and dashboard.
|
|
3
|
+
*
|
|
4
|
+
* SINGLE SOURCE OF TRUTH (launcher / plain-ESM side). `bin/aitne.mjs` and the
|
|
5
|
+
* `scripts/**` launchers cannot import `@aitne/shared`: they run *before* the
|
|
6
|
+
* TypeScript build that produces it (running `aitne start` is what triggers
|
|
7
|
+
* that build), and the published package ships only `bin` + `scripts/*.mjs` +
|
|
8
|
+
* `agent-assets`, never `packages/`. So the defaults are mirrored here in a
|
|
9
|
+
* build-independent module that lives under the published `scripts/lib/`.
|
|
10
|
+
*
|
|
11
|
+
* The TypeScript mirror lives in `packages/shared/src/ports.ts`. The two are
|
|
12
|
+
* pinned together by `packages/shared/src/ports.test.ts`, which fails CI if
|
|
13
|
+
* the values ever drift. Change a default in BOTH or the test goes red.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Daemon HTTP API port. Overridable via `PA_API_PORT`. */
|
|
17
|
+
export const DEFAULT_API_PORT = 8321;
|
|
18
|
+
|
|
19
|
+
/** Dashboard (Next.js) port. Overridable via `PA_DASHBOARD_PORT`. Not 3000 — that collides with most dev servers. */
|
|
20
|
+
export const DEFAULT_DASHBOARD_PORT = 8322;
|
|
21
|
+
|
|
22
|
+
function parsePort(raw) {
|
|
23
|
+
if (raw == null || raw === "") return null;
|
|
24
|
+
const n = Number.parseInt(raw, 10);
|
|
25
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Resolve the daemon API port from env, falling back to DEFAULT_API_PORT. */
|
|
29
|
+
export function resolveApiPort(env = process.env) {
|
|
30
|
+
return parsePort(env.PA_API_PORT) ?? DEFAULT_API_PORT;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Resolve the dashboard port from env, falling back to DEFAULT_DASHBOARD_PORT. */
|
|
34
|
+
export function resolveDashboardPort(env = process.env) {
|
|
35
|
+
return parsePort(env.PA_DASHBOARD_PORT) ?? DEFAULT_DASHBOARD_PORT;
|
|
36
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform reader for the daemon's `apiToken` secret.
|
|
3
|
+
*
|
|
4
|
+
* CLI scripts (`run-now`, `remint-roadmap-ids`) need the daemon's apiToken to
|
|
5
|
+
* call Approve-tier `/api/...` routes, but they intentionally must run WITHOUT
|
|
6
|
+
* a successful `@aitne/shared` build (which only ships `./dist/*.js`). So this
|
|
7
|
+
* helper re-implements the per-OS read inline, mirroring the secret clients in
|
|
8
|
+
* `packages/shared/src/`:
|
|
9
|
+
*
|
|
10
|
+
* - darwin → macOS Keychain via `security` (service com.personal-agent.secret.apiToken)
|
|
11
|
+
* - win32 → DPAPI: decrypt ~/.personal-agent/secrets/apiToken.dpapi via PowerShell
|
|
12
|
+
* - linux → libsecret (`secret-tool lookup`), else the AES-256-GCM file store
|
|
13
|
+
* - WSL / other → the AES-256-GCM file store
|
|
14
|
+
*
|
|
15
|
+
* The file-store format/params and the DPAPI script are copied verbatim from
|
|
16
|
+
* `secret-client-file.ts` / `secret-client-windows.ts` — keep them in sync if
|
|
17
|
+
* those change. The secret clients hardcode `~/.personal-agent/secrets` (they
|
|
18
|
+
* do NOT honor PA_DATA_DIR), so this helper uses the same homedir-relative
|
|
19
|
+
* location to find what the daemon actually wrote.
|
|
20
|
+
*
|
|
21
|
+
* Returns the token string, or null when it cannot be read; the caller decides
|
|
22
|
+
* how to message the failure. Best-effort: never throws (so a CLI never dies
|
|
23
|
+
* with a raw stack trace on a misconfigured secret store).
|
|
24
|
+
*/
|
|
25
|
+
import { execFileSync } from "node:child_process";
|
|
26
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
27
|
+
import { homedir } from "node:os";
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
import { createDecipheriv, scryptSync } from "node:crypto";
|
|
30
|
+
|
|
31
|
+
const SECRET_NAME = "apiToken";
|
|
32
|
+
const KEYCHAIN_SERVICE = "com.personal-agent.secret.apiToken";
|
|
33
|
+
|
|
34
|
+
function secretsDir() {
|
|
35
|
+
return join(homedir(), ".personal-agent", "secrets");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** @returns {string | null} the daemon apiToken, or null if unreadable. */
|
|
39
|
+
export function readApiToken() {
|
|
40
|
+
const platform = process.platform;
|
|
41
|
+
if (platform === "darwin") return readDarwin();
|
|
42
|
+
if (platform === "win32") return readWindows();
|
|
43
|
+
if (platform === "linux") {
|
|
44
|
+
if (!isWsl() && whichSync("secret-tool")) {
|
|
45
|
+
const fromKeyring = readSecretTool();
|
|
46
|
+
if (fromKeyring) return fromKeyring;
|
|
47
|
+
}
|
|
48
|
+
return readFileStore();
|
|
49
|
+
}
|
|
50
|
+
return readFileStore();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function readDarwin() {
|
|
54
|
+
// Byte-identical to the historical `security` read so macOS cannot regress.
|
|
55
|
+
try {
|
|
56
|
+
return execFileSync(
|
|
57
|
+
"security",
|
|
58
|
+
["find-generic-password", "-s", KEYCHAIN_SERVICE, "-w"],
|
|
59
|
+
{ encoding: "utf-8" },
|
|
60
|
+
).trim();
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Cross-platform `which`, returning the resolved path or null. */
|
|
67
|
+
function whichSync(cmd) {
|
|
68
|
+
const tool = process.platform === "win32" ? "where" : "which";
|
|
69
|
+
try {
|
|
70
|
+
const out = execFileSync(tool, [cmd], {
|
|
71
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
72
|
+
timeout: 2_000,
|
|
73
|
+
});
|
|
74
|
+
return out.toString().split(/\r?\n/)[0]?.trim() || null;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function readWindows() {
|
|
81
|
+
const path = join(secretsDir(), `${SECRET_NAME}.dpapi`);
|
|
82
|
+
if (!existsSync(path)) return null;
|
|
83
|
+
const encrypted = readFileSync(path, "utf-8").trim();
|
|
84
|
+
// Prefer in-box Windows PowerShell 5.1, fall back to PowerShell 7+ (pwsh),
|
|
85
|
+
// matching the daemon's secret-client-factory resolution order.
|
|
86
|
+
const psBinary = whichSync("powershell.exe")
|
|
87
|
+
? "powershell.exe"
|
|
88
|
+
: whichSync("pwsh.exe")
|
|
89
|
+
? "pwsh.exe"
|
|
90
|
+
: "powershell.exe";
|
|
91
|
+
// Mirrors WindowsDpapiSecretClient.get(): DPAPI-decrypt via
|
|
92
|
+
// ConvertTo-SecureString and marshal back to plaintext. The ciphertext is
|
|
93
|
+
// passed via stdin, never interpolated into the script, to avoid injection.
|
|
94
|
+
const script = [
|
|
95
|
+
"$enc = [System.Console]::In.ReadToEnd().Trim()",
|
|
96
|
+
"$ss = ConvertTo-SecureString $enc",
|
|
97
|
+
"$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ss)",
|
|
98
|
+
"try { [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) }",
|
|
99
|
+
"finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) }",
|
|
100
|
+
].join("; ");
|
|
101
|
+
try {
|
|
102
|
+
const out = execFileSync(
|
|
103
|
+
psBinary,
|
|
104
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
105
|
+
{ input: encrypted, encoding: "utf-8", timeout: 10_000 },
|
|
106
|
+
);
|
|
107
|
+
return out.trimEnd() || null;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function readSecretTool() {
|
|
114
|
+
try {
|
|
115
|
+
const out = execFileSync(
|
|
116
|
+
"secret-tool",
|
|
117
|
+
["lookup", "service", "personal-agent", "key", SECRET_NAME],
|
|
118
|
+
{ encoding: "utf-8", timeout: 5_000 },
|
|
119
|
+
);
|
|
120
|
+
return out.replace(/\n$/, "") || null;
|
|
121
|
+
} catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Detect WSL. WSL reports platform "linux" but cannot use `secret-tool`
|
|
128
|
+
* (D-Bus / GNOME Keyring typically unavailable), so it uses the file store.
|
|
129
|
+
*/
|
|
130
|
+
function isWsl() {
|
|
131
|
+
try {
|
|
132
|
+
return /microsoft|wsl/i.test(readFileSync("/proc/version", "utf-8"));
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── AES-256-GCM file store (mirrors secret-client-file.ts) ────────────────
|
|
139
|
+
const FILE_ALGORITHM = "aes-256-gcm";
|
|
140
|
+
const FILE_KEY_LENGTH = 32; // 256 bits
|
|
141
|
+
const FILE_SCRYPT = { N: 16384, r: 8, p: 1 };
|
|
142
|
+
|
|
143
|
+
/** Resolve the file-store master password (env, then key file); null if none. */
|
|
144
|
+
function resolveMasterPassword() {
|
|
145
|
+
if (process.env.PA_MASTER_PASSWORD) return process.env.PA_MASTER_PASSWORD;
|
|
146
|
+
const keyFilePath = join(secretsDir(), ".master-key");
|
|
147
|
+
if (!existsSync(keyFilePath)) return null;
|
|
148
|
+
// Refuse to read a key file with insecure permissions (mirrors the daemon's
|
|
149
|
+
// 0600/0400 gate); degrade to null rather than risk exposing it.
|
|
150
|
+
const mode = statSync(keyFilePath).mode & 0o777;
|
|
151
|
+
if (mode !== 0o600 && mode !== 0o400) return null;
|
|
152
|
+
return readFileSync(keyFilePath, "utf-8").trim();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function readFileStore() {
|
|
156
|
+
const path = join(secretsDir(), `${SECRET_NAME}.enc`);
|
|
157
|
+
if (!existsSync(path)) return null;
|
|
158
|
+
try {
|
|
159
|
+
const password = resolveMasterPassword();
|
|
160
|
+
if (!password) return null;
|
|
161
|
+
const stored = JSON.parse(readFileSync(path, "utf-8"));
|
|
162
|
+
const salt = Buffer.from(stored.salt, "hex");
|
|
163
|
+
const iv = Buffer.from(stored.iv, "hex");
|
|
164
|
+
const authTag = Buffer.from(stored.authTag, "hex");
|
|
165
|
+
const ciphertext = Buffer.from(stored.ciphertext, "hex");
|
|
166
|
+
const key = scryptSync(password, salt, FILE_KEY_LENGTH, FILE_SCRYPT);
|
|
167
|
+
const decipher = createDecipheriv(FILE_ALGORITHM, key, iv);
|
|
168
|
+
decipher.setAuthTag(authTag);
|
|
169
|
+
return Buffer.concat([
|
|
170
|
+
decipher.update(ciphertext),
|
|
171
|
+
decipher.final(),
|
|
172
|
+
]).toString("utf-8");
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
package/scripts/start.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import process from "node:process";
|
|
7
7
|
import { ensureBuild, log } from "./run-node.mjs";
|
|
8
8
|
import { openBrowser, waitForHttpReady } from "./browser.mjs";
|
|
9
|
+
import { resolveDashboardPort } from "./lib/ports.mjs";
|
|
9
10
|
|
|
10
11
|
const IS_WINDOWS = process.platform === "win32";
|
|
11
12
|
const requireFromScript = createRequire(import.meta.url);
|
|
@@ -57,7 +58,7 @@ function nextSpawnArgs(dashboardDir, nextBin, userArgs) {
|
|
|
57
58
|
* 5. Ctrl+C stops both
|
|
58
59
|
*/
|
|
59
60
|
|
|
60
|
-
const DASHBOARD_PORT =
|
|
61
|
+
const DASHBOARD_PORT = resolveDashboardPort();
|
|
61
62
|
const noOpen = process.argv.slice(2).includes("--no-open");
|
|
62
63
|
const children = [];
|
|
63
64
|
let shuttingDown = false;
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
schema_version: 1
|
|
3
|
-
slug: features/lifestyle/travel-time
|
|
4
|
-
title: Travel Time
|
|
5
|
-
id: travel-time
|
|
6
|
-
aliases:
|
|
7
|
-
- door to door
|
|
8
|
-
- eta
|
|
9
|
-
category: features
|
|
10
|
-
summary: |
|
|
11
|
-
A skill that estimates door-to-door travel time given an origin
|
|
12
|
-
and destination — used by schedule-approaching reminders for
|
|
13
|
-
events with location.
|
|
14
|
-
section: lifestyle
|
|
15
|
-
tags:
|
|
16
|
-
- lifestyle
|
|
17
|
-
- travel
|
|
18
|
-
- skills
|
|
19
|
-
status: stable
|
|
20
|
-
ask_examples:
|
|
21
|
-
- How long will it take me to get to the airport?
|
|
22
|
-
- Does the agent know about traffic?
|
|
23
|
-
locale: en-US
|
|
24
|
-
created: 2026-04-25
|
|
25
|
-
updated: 2026-04-25
|
|
26
|
-
keywords:
|
|
27
|
-
- travel time
|
|
28
|
-
- departure time
|
|
29
|
-
- google maps
|
|
30
|
-
- commute
|
|
31
|
-
- ETA
|
|
32
|
-
related:
|
|
33
|
-
- features/lifestyle/travel-bookings
|
|
34
|
-
- features/operations/schedule-approaching
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
# Travel Time
|
|
38
|
-
|
|
39
|
-
## In One Sentence
|
|
40
|
-
|
|
41
|
-
A skill the agent calls to estimate door-to-door travel time before
|
|
42
|
-
a calendar event with a location.
|
|
43
|
-
|
|
44
|
-
## What It Does
|
|
45
|
-
|
|
46
|
-
- Reads origin (current location, configured home/work) and
|
|
47
|
-
destination (event location).
|
|
48
|
-
- Returns a typical-time estimate with mode (drive, transit, walk).
|
|
49
|
-
- Used by `schedule-approaching` reminders to lead-time the alert.
|
|
50
|
-
|
|
51
|
-
## Where in the Dashboard
|
|
52
|
-
|
|
53
|
-
There is no operator surface for the travel-time data itself; the
|
|
54
|
-
estimates appear inline in event reminders and morning routines.
|
|
55
|
-
|
|
56
|
-
## Related
|
|
57
|
-
|
|
58
|
-
- [Schedule Approaching](../operations/schedule-approaching.md)
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
kind: reference
|
|
3
|
-
name: travel-time-api
|
|
4
|
-
description: /api/travel-time reference — Google Maps Directions wrapper. Estimate door-to-door duration and compute departure time for a calendar event with location.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# `/api/travel-time` reference
|
|
8
|
-
|
|
9
|
-
Uses the Google Maps Directions API. Prerequisite: `googleMapsApiKey`
|
|
10
|
-
configured in the daemon's secret store, with the Directions API
|
|
11
|
-
enabled.
|
|
12
|
-
|
|
13
|
-
## GET /api/travel-time
|
|
14
|
-
|
|
15
|
-
Estimate travel time between two locations.
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# Transit (default)
|
|
19
|
-
curl -s "http://localhost:8321/api/travel-time?origin=Grand+Central&destination=Times+Square"
|
|
20
|
-
|
|
21
|
-
# Driving with arrival time
|
|
22
|
-
curl -s "http://localhost:8321/api/travel-time?origin=Brooklyn&destination=Newark&mode=driving&arrival=2026-04-12T14:00:00-04:00"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
| Param | Type | Default | Description |
|
|
26
|
-
|-------|------|---------|-------------|
|
|
27
|
-
| `origin` | string | (required) | Origin address or place name |
|
|
28
|
-
| `destination` | string | (required) | Destination address or place name |
|
|
29
|
-
| `mode` | string | transit | driving, transit, walking, bicycling |
|
|
30
|
-
| `arrival` | ISO 8601 | — | Desired arrival time (computes departure time) |
|
|
31
|
-
|
|
32
|
-
Response:
|
|
33
|
-
|
|
34
|
-
```json
|
|
35
|
-
{
|
|
36
|
-
"origin": "Grand Central Terminal, NY",
|
|
37
|
-
"destination": "Times Square, NY",
|
|
38
|
-
"mode": "transit",
|
|
39
|
-
"durationSeconds": 1380,
|
|
40
|
-
"durationText": "23 mins",
|
|
41
|
-
"distanceMeters": 8500,
|
|
42
|
-
"distanceText": "8.5 km",
|
|
43
|
-
"departBy": "2026-04-12T13:34:00.000Z"
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## GET /api/travel-time/for-event/:eventId
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
curl -s "http://localhost:8321/api/travel-time/for-event/abc123?origin=Home&mode=transit"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
| Param | Type | Default | Description |
|
|
54
|
-
|-------|------|---------|-------------|
|
|
55
|
-
| `origin` | string | (required) | Your starting location |
|
|
56
|
-
| `mode` | string | transit | Travel mode |
|
|
57
|
-
|
|
58
|
-
Response includes both `event` and `travelTime` blocks; see the route
|
|
59
|
-
implementation for full shape.
|