orbitmap 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +60 -13
  2. package/dist/adapters/cloud.d.ts +53 -21
  3. package/dist/adapters/cloud.js +95 -29
  4. package/dist/adapters/cloud.js.map +1 -1
  5. package/dist/adapters/factory.d.ts +3 -0
  6. package/dist/adapters/factory.js +8 -1
  7. package/dist/adapters/factory.js.map +1 -1
  8. package/dist/adapters/local/adapter.d.ts +0 -20
  9. package/dist/adapters/local/adapter.js +0 -18
  10. package/dist/adapters/local/adapter.js.map +1 -1
  11. package/dist/adapters/local/context.d.ts +1 -1
  12. package/dist/adapters/local/context.js +10 -2
  13. package/dist/adapters/local/context.js.map +1 -1
  14. package/dist/adapters/local/entities/tasks.d.ts +9 -1
  15. package/dist/adapters/local/entities/tasks.js +47 -5
  16. package/dist/adapters/local/entities/tasks.js.map +1 -1
  17. package/dist/adapters/local/entities/work-items.d.ts +14 -30
  18. package/dist/adapters/local/entities/work-items.js +63 -47
  19. package/dist/adapters/local/entities/work-items.js.map +1 -1
  20. package/dist/adapters/local/rules.d.ts +4 -4
  21. package/dist/adapters/local/rules.js +4 -19
  22. package/dist/adapters/local/rules.js.map +1 -1
  23. package/dist/adapters/local/shapes.d.ts +27 -7
  24. package/dist/adapters/local/shapes.js +41 -5
  25. package/dist/adapters/local/shapes.js.map +1 -1
  26. package/dist/adapters/local/store.d.ts +55 -6
  27. package/dist/adapters/local/store.js +122 -8
  28. package/dist/adapters/local/store.js.map +1 -1
  29. package/dist/adapters/local/types.d.ts +9 -2
  30. package/dist/adapters/local/types.js +9 -2
  31. package/dist/adapters/local/types.js.map +1 -1
  32. package/dist/adapters/types.d.ts +7 -20
  33. package/dist/agent-instructions.d.ts +21 -8
  34. package/dist/agent-instructions.js +91 -35
  35. package/dist/agent-instructions.js.map +1 -1
  36. package/dist/area-directories.d.ts +75 -0
  37. package/dist/area-directories.js +162 -0
  38. package/dist/area-directories.js.map +1 -0
  39. package/dist/area-grouping.d.ts +55 -0
  40. package/dist/area-grouping.js +72 -0
  41. package/dist/area-grouping.js.map +1 -0
  42. package/dist/commands/areas.js +30 -2
  43. package/dist/commands/areas.js.map +1 -1
  44. package/dist/commands/assign.d.ts +1 -0
  45. package/dist/commands/assign.js +2 -0
  46. package/dist/commands/assign.js.map +1 -1
  47. package/dist/commands/context.d.ts +95 -0
  48. package/dist/commands/context.js +104 -2
  49. package/dist/commands/context.js.map +1 -1
  50. package/dist/commands/create.d.ts +1 -0
  51. package/dist/commands/create.js +19 -14
  52. package/dist/commands/create.js.map +1 -1
  53. package/dist/commands/dep.js +5 -8
  54. package/dist/commands/dep.js.map +1 -1
  55. package/dist/commands/doc-import.d.ts +1 -0
  56. package/dist/commands/doc-import.js +8 -26
  57. package/dist/commands/doc-import.js.map +1 -1
  58. package/dist/commands/doc-patch.js +16 -52
  59. package/dist/commands/doc-patch.js.map +1 -1
  60. package/dist/commands/doc-share.js +4 -0
  61. package/dist/commands/doc-share.js.map +1 -1
  62. package/dist/commands/doc-update.js +4 -8
  63. package/dist/commands/doc-update.js.map +1 -1
  64. package/dist/commands/doc.js +7 -12
  65. package/dist/commands/doc.js.map +1 -1
  66. package/dist/commands/docs-cache.js +23 -10
  67. package/dist/commands/docs-cache.js.map +1 -1
  68. package/dist/commands/docs.js +29 -10
  69. package/dist/commands/docs.js.map +1 -1
  70. package/dist/commands/get.js +4 -10
  71. package/dist/commands/get.js.map +1 -1
  72. package/dist/commands/ideas.d.ts +3 -1
  73. package/dist/commands/ideas.js +26 -49
  74. package/dist/commands/ideas.js.map +1 -1
  75. package/dist/commands/init.d.ts +24 -1
  76. package/dist/commands/init.js +0 -0
  77. package/dist/commands/init.js.map +1 -1
  78. package/dist/commands/intent.js +10 -14
  79. package/dist/commands/intent.js.map +1 -1
  80. package/dist/commands/issues.d.ts +3 -1
  81. package/dist/commands/issues.js +47 -72
  82. package/dist/commands/issues.js.map +1 -1
  83. package/dist/commands/log.d.ts +1 -0
  84. package/dist/commands/log.js +18 -17
  85. package/dist/commands/log.js.map +1 -1
  86. package/dist/commands/mission.js +3 -12
  87. package/dist/commands/mission.js.map +1 -1
  88. package/dist/commands/orbit.d.ts +7 -1
  89. package/dist/commands/orbit.js +13 -24
  90. package/dist/commands/orbit.js.map +1 -1
  91. package/dist/commands/setup-agent.d.ts +97 -4
  92. package/dist/commands/setup-agent.js +265 -38
  93. package/dist/commands/setup-agent.js.map +1 -1
  94. package/dist/commands/setup-mcp.d.ts +2 -0
  95. package/dist/commands/setup-mcp.js +17 -40
  96. package/dist/commands/setup-mcp.js.map +1 -1
  97. package/dist/commands/start.d.ts +43 -0
  98. package/dist/commands/start.js +158 -3
  99. package/dist/commands/start.js.map +1 -1
  100. package/dist/commands/status.d.ts +1 -0
  101. package/dist/commands/status.js +5 -15
  102. package/dist/commands/status.js.map +1 -1
  103. package/dist/commands/subtask.d.ts +1 -0
  104. package/dist/commands/subtask.js +9 -2
  105. package/dist/commands/subtask.js.map +1 -1
  106. package/dist/commands/task-edit-content.js +4 -8
  107. package/dist/commands/task-edit-content.js.map +1 -1
  108. package/dist/commands/task.d.ts +7 -0
  109. package/dist/commands/task.js +5 -2
  110. package/dist/commands/task.js.map +1 -1
  111. package/dist/commands/tasks.d.ts +35 -0
  112. package/dist/commands/tasks.js +45 -9
  113. package/dist/commands/tasks.js.map +1 -1
  114. package/dist/commands/vibes.d.ts +3 -1
  115. package/dist/commands/vibes.js +41 -31
  116. package/dist/commands/vibes.js.map +1 -1
  117. package/dist/config.d.ts +11 -0
  118. package/dist/config.js +14 -1
  119. package/dist/config.js.map +1 -1
  120. package/dist/doc-cache.d.ts +74 -5
  121. package/dist/doc-cache.js +106 -22
  122. package/dist/doc-cache.js.map +1 -1
  123. package/dist/enums.d.ts +26 -0
  124. package/dist/enums.js +53 -0
  125. package/dist/enums.js.map +1 -0
  126. package/dist/errors.d.ts +67 -0
  127. package/dist/errors.js +82 -0
  128. package/dist/errors.js.map +1 -1
  129. package/dist/index.js +134 -56
  130. package/dist/index.js.map +1 -1
  131. package/dist/mcp-config.d.ts +42 -1
  132. package/dist/mcp-config.js +82 -2
  133. package/dist/mcp-config.js.map +1 -1
  134. package/dist/oauth.js +10 -10
  135. package/dist/output.d.ts +12 -0
  136. package/dist/output.js +39 -1
  137. package/dist/output.js.map +1 -1
  138. package/dist/paths.d.ts +40 -0
  139. package/dist/paths.js +174 -9
  140. package/dist/paths.js.map +1 -1
  141. package/dist/project-config.d.ts +42 -1
  142. package/dist/project-config.js +51 -0
  143. package/dist/project-config.js.map +1 -1
  144. package/dist/workspace-resolve.d.ts +179 -9
  145. package/dist/workspace-resolve.js +288 -20
  146. package/dist/workspace-resolve.js.map +1 -1
  147. package/dist/write-target.d.ts +56 -0
  148. package/dist/write-target.js +170 -0
  149. package/dist/write-target.js.map +1 -0
  150. package/package.json +1 -1
  151. package/dist/commands/create-project.d.ts +0 -6
  152. package/dist/commands/create-project.js +0 -28
  153. package/dist/commands/create-project.js.map +0 -1
  154. package/dist/commands/projects.d.ts +0 -3
  155. package/dist/commands/projects.js +0 -28
  156. package/dist/commands/projects.js.map +0 -1
@@ -3,13 +3,13 @@ export declare const MARKER_END = "<!-- ORBITMAP_END -->";
3
3
  /** The core skill name (entry point). Kept for backwards compatibility. */
4
4
  export declare const SKILL_NAME = "orbitmap";
5
5
  export declare const SKILL_ORBITMAP_FRONTMATTER = "---\nname: orbitmap\ndescription: >\n OrbitMap project management via the orbitmap CLI. Use when the user mentions OrbitMap,\n orbit, tasks, backlog, missions, intents, ideas, issues, vibes, or asks to track,\n plan, or log work. Entry point: object model, context resolution, command reference.\n---";
6
- export declare const SKILL_ORBITMAP_BODY = "# OrbitMap CLI \u2014 core\n\nOrbitMap is an agentic project management platform. You interact with it exclusively\nthrough the `orbitmap` CLI (run with `npx orbitmap \u2026` if not on PATH). The CLI works\nidentically in cloud mode and local-files mode \u2014 never assume which one is active, and\nnever read or write the workspace's data files directly. The CLI is the only interface.\n\n## General behaviour\n- Always prioritise the user's direct request. If the user asks you to do something\n (read a file, write code, answer a question), handle that first.\n- Only interact with OrbitMap when the user explicitly asks you to (e.g. \"check my\n tasks\", \"start a task\", \"what's on my backlog\", \"log this idea\").\n- When the user mentions OrbitMap, orbit, task, backlog, or project-management concepts\n in the context of tracking work, use `orbitmap` commands to handle the request.\n\n## Object model\n- Workspace = team level. Area = repo-level scope (formerly Project) \u2014 tasks, vibes and\n most issues live in an area. Mission (MS-) = time-boxed workspace focus; at most one\n active. Intent (IN-) = workspace-level goal grouping tasks/issues. Idea (ID-) = future\n possibility, not a problem. Issue (IS-) = problem/bug. Vibe (VB-) = ad-hoc work log\n outside a task. Task (TS-) = unit of work.\n- Entity numbers (TS-xxxxxx etc.) are accepted by every command that takes an id.\n\n## Context\n- Area resolves automatically (config/env). Override per call with `--area <slug>`.\n- If a command fails asking for area context, run `orbitmap areas` to list areas, then\n retry with `--area`.\n- `orbitmap context` shows who you are, the workspace, and the active area. Run it when\n unsure.\n\n## Task statuses\nbacklog, todo, in_progress, in_review, review_changes, done, blocked.\n`orbitmap tasks` defaults to todo,in_progress. Ask for others explicitly, e.g.\n`orbitmap tasks --status backlog` when the user asks about the backlog.\n\n## Command reference (all commands accept --json)\n- Context: `orbitmap context`, `orbitmap areas`, `orbitmap overview`\n- Tasks: `orbitmap tasks [--status s1,s2]`, `orbitmap task TS-x`, `orbitmap get <ID>`,\n `orbitmap start [TS-x]`, `orbitmap status TS-x <status> [--delivery <d>]`,\n `orbitmap create \"title\" [--intent IN-x|--mission MS-x] [--priority p]`,\n `orbitmap subtask TS-parent \"title\"`, `orbitmap assign TS-x [agent]`,\n `orbitmap dep add|remove TS-a TS-b`, `orbitmap log TS-x \"msg\" --type <t>`\n- Issues: `orbitmap issue register|list|show|status|resolve`\n- Ideas: `orbitmap idea add|list|show|status`\n- Vibes: `orbitmap vibe log|list|show`\n- Missions: `orbitmap mission list|show|create|update|status|link|unlink`\n- Intents: `orbitmap intent list|show|create|update|link|unlink`\n- Documents: `orbitmap docs`, `orbitmap doc <slug> [--section \"## H\"|--full]`,\n `orbitmap doc-import`, `orbitmap doc-update`\n\n## Error handling\n- If OrbitMap is unreachable (network down / workspace directory unavailable), inform\n the user and continue the primary work without logging. Do NOT retry failed orbitmap\n calls in a loop \u2014 report the issue and proceed with the task.";
6
+ export declare const SKILL_ORBITMAP_BODY = "# OrbitMap CLI \u2014 core\n\nOrbitMap is an agentic project management platform. You interact with it exclusively\nthrough the `orbitmap` CLI (run with `npx orbitmap \u2026` if not on PATH). The CLI works\nidentically in cloud mode and local-files mode \u2014 never assume which one is active, and\nnever read or write the workspace's data files directly. The CLI is the only interface.\n\n## General behaviour\n- Always prioritise the user's direct request. If the user asks you to do something\n (read a file, write code, answer a question), handle that first.\n- Only interact with OrbitMap when the user explicitly asks you to (e.g. \"check my\n tasks\", \"start a task\", \"what's on my backlog\", \"log this idea\").\n- When the user mentions OrbitMap, orbit, task, backlog, or project-management concepts\n in the context of tracking work, use `orbitmap` commands to handle the request.\n\n## Object model\n- Workspace = team level. Area = repo-level scope (formerly Project) \u2014 tasks, vibes and\n most issues live in an area. Mission (MS-) = time-boxed workspace focus; at most one\n active. Intent (IN-) = workspace-level goal grouping tasks/issues. Idea (ID-) = future\n possibility, not a problem. Issue (IS-) = problem/bug. Vibe (VB-) = ad-hoc work log\n outside a task. Task (TS-) = unit of work.\n- Entity numbers (TS-xxxxxx etc.) are accepted by every command that takes an id.\n\n## Context\n- START HERE, always: `orbitmap context`. `orbitmap context` is authoritative and returns\n in ONE call everything a session needs \u2014 the agent, the workspace, the areas you work in,\n the active mission, open intents, your tasks and the documents. Never list areas and never\n ask the user \"which area?\" before you have read it.\n- You work in a WORKSPACE, not inside a single area. Missions, intents\n and documents are workspace-level and take no area \u2014 a document is exactly ONE copy,\n global to the workspace, never per-area. Tasks, vibes, issues and ideas are\n AREA-scoped.\n- Missions and intents outrank individual tasks. Asked to work on \"what matters\", take the\n active mission and open intents from context and pick work that serves them.\n- The area follows from the directory, never from a question to the user:\n `.orbitmap/config.json` maps directories \u2192 area slugs at the workspace root, and each\n area directory carries its own `.orbitmap/config.json` marker naming its area. That\n config is the only source of truth \u2014 never hard-code area names anywhere.\n So: do area-scoped work from the directory it belongs to and let the CLI resolve it.\n- `--area <slug>` is an OVERRIDE for a single call, not part of normal usage \u2014 reach for it\n only to read or write outside the area the current directory resolves to.\n- If a command fails with `AREA_CONTEXT_REQUIRED`, its details list the mapped\n directories: cd into the right one, or retry with `--area <slug>`.\n- WRITES: the resolved area is a default for *reading*, never a statement of where the\n work belongs. Before creating anything area-scoped (task, subtask, issue, vibe),\n derive the target area from the work itself (which repo/package it lives in) and pass\n `--area <slug>` if that differs from the area the CLI echoes. If the work itself is\n genuinely ambiguous, ASK THE USER; do not guess. There is no\n `move` command: a write in the wrong area has to be recreated.\n- Every write echoes its scope on stderr: `creates in area <slug> (source: \u2026)` when it\n creates an object, `scoped to area <slug> (source: \u2026)` when it changes one by id. A\n `source` of `global ~/.orbitmap/config.json` is a machine-wide leftover that nothing\n here chose \u2014 treat it as unconfirmed and pass `--area` explicitly.\n\n## Task statuses\nbacklog, todo, in_progress, in_review, review_changes, done, blocked.\n`orbitmap tasks` defaults to todo,in_progress. Ask for others explicitly, e.g.\n`orbitmap tasks --status backlog` when the user asks about the backlog.\n\n## Command reference (all commands accept --json)\n- Context: `orbitmap context` (start here), `orbitmap overview`, `orbitmap areas`\n (rarely needed \u2014 context already lists the areas you work in)\n- Tasks: `orbitmap tasks [--status s1,s2]`, `orbitmap task TS-x`, `orbitmap get <ID>`,\n `orbitmap start [TS-x]`, `orbitmap status TS-x <status> [--delivery <d>]`,\n `orbitmap create \"title\" [--intent IN-x|--mission MS-x] [--priority p]`,\n `orbitmap subtask TS-parent \"title\"`, `orbitmap assign TS-x [agent]`,\n `orbitmap dep add|remove TS-a TS-b`, `orbitmap log TS-x \"msg\" --type <t>`\n- Issues: `orbitmap issue register|list|show|status|resolve`\n- Ideas: `orbitmap idea add|list|show|status`\n- Vibes: `orbitmap vibe log|list|show`\n- Missions: `orbitmap mission list|show|create|update|status|link|unlink`\n- Intents: `orbitmap intent list|show|create|update|link|unlink`\n- Documents: `orbitmap docs`, `orbitmap doc <slug> [--section \"## H\"|--full]`,\n `orbitmap doc-import`, `orbitmap doc-update`\n\n## Error handling\n- If OrbitMap is unreachable (network down / workspace directory unavailable), inform\n the user and continue the primary work without logging. Do NOT retry failed orbitmap\n calls in a loop \u2014 report the issue and proceed with the task.";
7
7
  export declare const SKILL_WORKING_FRONTMATTER = "---\nname: orbitmap-working\ndescription: >\n Working on OrbitMap tasks: starting/resuming, logging work, decisions and blockers,\n finishing with the correct status, git branches and delivery status. Use whenever\n implementing, resuming, or finishing a tracked task.\n---";
8
- export declare const SKILL_WORKING_BODY = "# Working on OrbitMap tasks\n\n## Task workflow (on user request)\nWhen the user asks you to work on tasks:\n1. `orbitmap tasks --status in_progress` \u2014 check for unfinished work.\n2. If found \u2192 `orbitmap task TS-x` \u2192 read the work log \u2192 resume from the resume point.\n3. If not \u2192 `orbitmap start` \u2014 auto-picks the first todo task, sets it in_progress and\n prints full context (description, agent_instructions, logs).\n4. If no tasks \u2192 inform the user.\nUse `orbitmap start TS-x` to begin a specific task; `orbitmap task TS-x` only inspects.\n\n## Rules\n- Work on ONE task at a time.\n- Always read agent_instructions from the task before implementing. Task-level\n agent_instructions take precedence over area-level instructions.\n- Only work on subtasks assigned to you; do not pick up other agents' subtasks.\n- Do NOT mark a parent task done while it has unfinished subtasks, unless the user\n explicitly asks.\n\n## Logging\n- `orbitmap log TS-x \"\u2026\" --type note|code_change|decision|blocker` \u2014 work WITHIN a task.\n- `orbitmap vibe log \"\u2026\" --type discovery|exploration|fix` \u2014 ad-hoc work outside a task.\n- Use `--type decision` when you pick between approaches, reject an alternative, or lock\n in a non-obvious assumption \u2014 record the choice AND the why, not just the outcome.\n- `orbitmap idea add` \u2014 future possibilities, NOT problems (problems \u2192\n `orbitmap issue register`).\n- Keep log content concrete, concise, and useful for someone resuming work later.\n\n## End of session or task \u2014 MANDATORY\n- Task finished \u2192 default to **in_review** so a human verifies before closing:\n `orbitmap log TS-x \"Ready for review: \u2026\" --type note` then\n `orbitmap status TS-x in_review`.\n- Task finished AND the user's prompt or the task's agent_instructions explicitly say to\n close without review \u2192 `orbitmap log TS-x \"Summary: \u2026\" --type note` then\n `orbitmap status TS-x done`.\n- Blocked by an external dependency you cannot resolve (waiting on another task, missing\n access/credentials, unclear requirements, failing external service) \u2192\n `orbitmap log TS-x \"Blocked: <reason>\" --type blocker` then\n `orbitmap status TS-x blocked`.\n- Session ending, task not done but NOT blocked \u2192 `orbitmap log TS-x \"Resume point: \u2026\"\n --type note` \u2014 leave status in_progress.\n- NEVER leave a task without a final log entry.\n\n### Status decision guide\n- **in_review**: work is finished. THE DEFAULT for completed work. The requester should\n verify before closing.\n- **done**: only when the prompt or task agent_instructions explicitly allow closing\n without review (\"auto-close\", \"mark as done\", \"no review needed\"). A user saying \"do\n this task\" is NOT permission to auto-close.\n- **blocked**: an external factor outside your control stops you. Always log the\n specific blocker.\n- **in_progress** (keep): session ends but you can resume autonomously next time.\n\n## Git workflow\n- When the task context contains a branch_name, create or switch to it:\n `git checkout -b <branch_name>` (or `git checkout <branch_name>` if it exists).\n- If the task has NO branch_name, work on the current branch \u2014 do not create one.\n- Do NOT work directly on main/master/develop unless the task has no branch_name and you\n are already on a feature branch.\n\n## Delivery flow\n- Commit messages: prefix the entity number with its type tag \u2014\n `[TS-r5d8zf] Add delivery status field` (also `[IS-\u2026]`, `[ID-\u2026]`, `[VB-\u2026]`).\n- When you committed/pushed code during the task, finish with\n `orbitmap status TS-x <status> --delivery on_branch`.\n- When the user asks what's in a branch/PR: `git log target..source --oneline`, parse\n `[TS-\u2026]`/`[IS-\u2026]` tags, report the matched entities.\n- When the user reports a merge or release: update the relevant tasks with\n `--delivery merged` or `--delivery released`.\n\n## Planning mode (agents with a plan mode)\nWhen you create an implementation plan for a tracked task, you MUST include OrbitMap\nlifecycle steps as explicit plan items:\n- First step: reference the OrbitMap task number and title.\n- Last steps, always: (1) `orbitmap log` with a summary of all changes; (2)\n `orbitmap status` set per the status decision guide (or a resume-point log if\n incomplete).\n\n## Example: completing a task (default \u2192 in_review)\n1. `orbitmap tasks --status in_progress` \u2192 empty\n2. `orbitmap start` \u2192 task context\n3. read agent_instructions; implement; run tests; commit with `[TS-x]` prefix\n4. `orbitmap log TS-x \"Implemented X by doing Y\" --type code_change`\n5. `orbitmap log TS-x \"Ready for review: all tests pass.\" --type note`\n6. `orbitmap status TS-x in_review --delivery on_branch`";
8
+ export declare const SKILL_WORKING_BODY = "# Working on OrbitMap tasks\n\n## Task workflow (on user request)\nWhen the user asks you to work on tasks \u2014 including a vague \"work on what's important\":\n1. `orbitmap context` \u2014 the workspace, your areas, the active mission, open intents and\n your tasks in one call. Do not ask which area and do not list areas first.\n2. Unfinished work in context (or `orbitmap tasks --status in_progress`) \u2192\n `orbitmap task TS-x` \u2192 read the work log \u2192 resume from the resume point.\n3. Otherwise pick work that serves the active mission / open intents, or `orbitmap start`\n \u2014 auto-picks the first todo task, sets it in_progress and prints full context\n (description, agent_instructions, logs).\n4. If there is nothing to pick up \u2192 inform the user.\nUse `orbitmap start TS-x` to begin a specific task; `orbitmap task TS-x` only inspects.\n\n## Rules\n- Work on ONE task at a time.\n- Always read agent_instructions from the task before implementing. Task-level\n agent_instructions take precedence over area-level instructions.\n- Subtasks never show up in a task list (`orbitmap context`, `orbitmap tasks`,\n `orbitmap start`) \u2014 only inside the parent task you opened with `orbitmap task TS-x`.\n- Only work on subtasks assigned to you; do not pick up other agents' subtasks.\n- Do NOT mark a parent task done while it has unfinished subtasks, unless the user\n explicitly asks.\n\n## Logging\n- `orbitmap log TS-x \"\u2026\" --type note|code_change|decision|blocker` \u2014 work WITHIN a task.\n- `orbitmap vibe log \"\u2026\" --type discovery|exploration|fix` \u2014 ad-hoc work outside a task.\n- Use `--type decision` when you pick between approaches, reject an alternative, or lock\n in a non-obvious assumption \u2014 record the choice AND the why, not just the outcome.\n- `orbitmap idea add` \u2014 future possibilities, NOT problems (problems \u2192\n `orbitmap issue register`).\n- Keep log content concrete, concise, and useful for someone resuming work later.\n\n## End of session or task \u2014 MANDATORY\n- Task finished \u2192 default to **in_review** so a human verifies before closing:\n `orbitmap log TS-x \"Ready for review: \u2026\" --type note` then\n `orbitmap status TS-x in_review`.\n- Task finished AND the user's prompt or the task's agent_instructions explicitly say to\n close without review \u2192 `orbitmap log TS-x \"Summary: \u2026\" --type note` then\n `orbitmap status TS-x done`.\n- Blocked by an external dependency you cannot resolve (waiting on another task, missing\n access/credentials, unclear requirements, failing external service) \u2192\n `orbitmap log TS-x \"Blocked: <reason>\" --type blocker` then\n `orbitmap status TS-x blocked`.\n- Session ending, task not done but NOT blocked \u2192 `orbitmap log TS-x \"Resume point: \u2026\"\n --type note` \u2014 leave status in_progress.\n- NEVER leave a task without a final log entry.\n\n### Status decision guide\n- **in_review**: work is finished. THE DEFAULT for completed work. The requester should\n verify before closing.\n- **done**: only when the prompt or task agent_instructions explicitly allow closing\n without review (\"auto-close\", \"mark as done\", \"no review needed\"). A user saying \"do\n this task\" is NOT permission to auto-close.\n- **blocked**: an external factor outside your control stops you. Always log the\n specific blocker.\n- **in_progress** (keep): session ends but you can resume autonomously next time.\n\n## Git workflow\n- When the task context contains a branch_name, create or switch to it:\n `git checkout -b <branch_name>` (or `git checkout <branch_name>` if it exists).\n- If the task has NO branch_name, work on the current branch \u2014 do not create one.\n- Do NOT work directly on main/master/develop unless the task has no branch_name and you\n are already on a feature branch.\n\n## Delivery flow\n- Commit messages: prefix the entity number with its type tag \u2014\n `[TS-r5d8zf] Add delivery status field` (also `[IS-\u2026]`, `[ID-\u2026]`, `[VB-\u2026]`).\n- When you committed/pushed code during the task, finish with\n `orbitmap status TS-x <status> --delivery on_branch`.\n- When the user asks what's in a branch/PR: `git log target..source --oneline`, parse\n `[TS-\u2026]`/`[IS-\u2026]` tags, report the matched entities.\n- When the user reports a merge or release: update the relevant tasks with\n `--delivery merged` or `--delivery released`.\n\n## Planning mode (agents with a plan mode)\nWhen you create an implementation plan for a tracked task, you MUST include OrbitMap\nlifecycle steps as explicit plan items:\n- First step: reference the OrbitMap task number and title.\n- Last steps, always: (1) `orbitmap log` with a summary of all changes; (2)\n `orbitmap status` set per the status decision guide (or a resume-point log if\n incomplete).\n\n## Example: completing a task (default \u2192 in_review)\n1. `orbitmap context` \u2192 workspace, mission, intents, tasks; nothing in_progress\n2. `orbitmap start` \u2192 task context\n3. read agent_instructions; implement; run tests; commit with `[TS-x]` prefix\n4. `orbitmap log TS-x \"Implemented X by doing Y\" --type code_change`\n5. `orbitmap log TS-x \"Ready for review: all tests pass.\" --type note`\n6. `orbitmap status TS-x in_review --delivery on_branch`";
9
9
  export declare const SKILL_PLANNING_FRONTMATTER = "---\nname: orbitmap-planning\ndescription: >\n Planning with OrbitMap: missions (time-boxed focus), intents (goals grouping work),\n promoting ideas to tasks, triaging issues, decomposing work into tasks and subtasks.\n Use for \"plan\", \"roadmap\", \"mission\", \"intent\", \"break this down\", idea or issue\n triage requests.\n---";
10
- export declare const SKILL_PLANNING_BODY = "# Planning in OrbitMap\n\n## Hierarchy\nMission (MS-) \u2192 Intent (IN-) \u2192 Task (TS-) / Issue (IS-). Missions and intents are\nworkspace-level; tasks live in areas. An intent groups the tasks/issues that realise one\ngoal; a mission time-boxes a set of intents (and directly-attached items) toward an\noutcome. At most ONE mission is active at a time.\n\n## Missions\n- `orbitmap mission list` / `orbitmap mission show MS-x`\n- `orbitmap mission create \"name\" [--outcome \"\u2026\"] [--start d] [--end d]`\n- `orbitmap mission status MS-x active|completed|cancelled` \u2014 activating fails while\n another mission is active; complete or cancel it first.\n- `orbitmap mission link MS-x IN-y|TS-y|IS-y|ID-y` / `mission unlink` \u2014 attach items.\n\n## Intents\n- `orbitmap intent create \"name\" [--mission MS-x]`, statuses:\n new \u2192 design \u2192 plan \u2192 build \u2192 done (or cancelled); update with\n `orbitmap intent update IN-x --status build`.\n- `orbitmap intent link IN-x TS-y|IS-y` attaches work items to the intent.\n- RULE (intent-exclusive): an item linked to an intent gets its mission THROUGH the\n intent \u2014 never set a direct mission on a task/issue that has an intent. The CLI\n enforces this; do not fight it.\n\n## Planning workflow (recommended when the user asks to plan a body of work)\n1. Clarify the outcome \u2192 `orbitmap mission create` (or pick the active mission).\n2. Split into goals \u2192 `orbitmap intent create` per goal, `mission link` them.\n3. Decompose each intent into concrete tasks \u2192\n `orbitmap create \"title\" --intent IN-x [--priority p]`, subtasks via\n `orbitmap subtask`.\n4. Wire ordering constraints \u2192 `orbitmap dep add TS-a TS-b` (a depends on b).\n5. Review: `orbitmap mission show MS-x` and `orbitmap overview`.\n\n## Ideas (opportunities, not problems)\n- Capture: `orbitmap idea add \"\u2026\" [--priority p]`.\n- Review: `orbitmap idea list` (default pending).\n- Promote to work: analyse the codebase first, then `orbitmap create \"task title\"\n --intent \u2026` referencing the idea in the description, then\n `orbitmap idea status ID-x used`. Reject with `\u2026 rejected`.\n\n## Issues (problems)\n- Report: `orbitmap issue register \"title\" --severity critical|high|medium|low\n [--description \"\u2026\"]`.\n- Start investigating: `orbitmap issue status IS-x investigating`.\n- Convert to work: `orbitmap create` a fix task, link it, and resolve with\n `orbitmap issue resolve IS-x --task TS-y --resolution \"\u2026\"` (or status wont_fix /\n duplicate with a reason).";
10
+ export declare const SKILL_PLANNING_BODY = "# Planning in OrbitMap\n\n## Hierarchy\nMission (MS-) \u2192 Intent (IN-) \u2192 Task (TS-) / Issue (IS-). Missions and intents are\nworkspace-level and never take an area \u2014 plan from anywhere in the workspace, and never\nask which area to plan in. Tasks and issues are area-scoped. An intent groups the\ntasks/issues that realise one goal; a mission time-boxes a set of intents (and\ndirectly-attached items) toward an outcome. At most ONE mission is active at a time.\n`orbitmap context` already gives you the active mission and the open intents \u2014 read it\nbefore planning instead of listing anything.\n\n## Missions\n- `orbitmap mission list` / `orbitmap mission show MS-x`\n- `orbitmap mission create \"name\" [--outcome \"\u2026\"] [--start d] [--end d]`\n- `orbitmap mission status MS-x active|completed|cancelled` \u2014 activating fails while\n another mission is active; complete or cancel it first.\n- `orbitmap mission link MS-x IN-y|TS-y|IS-y|ID-y` / `mission unlink` \u2014 attach items.\n\n## Intents\n- `orbitmap intent create \"name\" [--mission MS-x]`, statuses:\n new \u2192 design \u2192 plan \u2192 build \u2192 done (or cancelled); update with\n `orbitmap intent update IN-x --status build`.\n- `orbitmap intent link IN-x TS-y|IS-y` attaches work items to the intent.\n- RULE (intent-exclusive): an item linked to an intent gets its mission THROUGH the\n intent \u2014 never set a direct mission on a task/issue that has an intent. The CLI\n enforces this; do not fight it.\n\n## Planning workflow (recommended when the user asks to plan a body of work)\n1. Clarify the outcome \u2192 `orbitmap mission create` (or pick the active mission).\n2. Split into goals \u2192 `orbitmap intent create` per goal, `mission link` them.\n3. Decompose each intent into concrete tasks \u2192\n `orbitmap create \"title\" --intent IN-x [--priority p]`, subtasks via\n `orbitmap subtask`.\n4. Wire ordering constraints \u2192 `orbitmap dep add TS-a TS-b` (a depends on b).\n5. Review: `orbitmap mission show MS-x` and `orbitmap overview`.\n\n## Ideas (opportunities, not problems)\n- Capture: `orbitmap idea add \"\u2026\" [--priority p]`.\n- Review: `orbitmap idea list` (default pending).\n- Promote to work: analyse the codebase first, then `orbitmap create \"task title\"\n --intent \u2026` referencing the idea in the description, then\n `orbitmap idea status ID-x used`. Reject with `\u2026 rejected`.\n\n## Issues (problems)\n- Report: `orbitmap issue register \"title\" --severity critical|high|medium|low\n [--description \"\u2026\"]`.\n- Start investigating: `orbitmap issue status IS-x investigating`.\n- Convert to work: `orbitmap create` a fix task, link it, and resolve with\n `orbitmap issue resolve IS-x --task TS-y --resolution \"\u2026\"` (or status wont_fix /\n duplicate with a reason).";
11
11
  export declare const SKILL_DOCS_FRONTMATTER = "---\nname: orbitmap-docs\ndescription: >\n Reading and updating OrbitMap documents (specs, architecture, guides, decisions).\n Use when the user asks to read, import, or update project documentation tracked in\n OrbitMap.\n---";
12
- export declare const SKILL_DOCS_BODY = "# OrbitMap documents\n\n## Choosing what to read\n`orbitmap docs` lists documents with their `context` (when the doc is relevant) and\n`sections_count`. Use context to pick the right document; use sections_count to decide\nwhether to fetch the TOC first (many sections) or go straight to full.\n\n## Token-efficient reading flow\n1. `orbitmap doc <slug>` \u2192 context + table of contents (cheap).\n2. `orbitmap doc <slug> --section \"## Auth\"` \u2192 just that section.\n3. `orbitmap doc <slug> --full` \u2192 full content (expensive \u2014 last resort).\nUse the lightest mode that answers your question. When the CLI reports a local file path\nfor the full content, read that file instead of printing the content into the\nconversation.\n\n## Editing\n- Import a new document: `orbitmap doc-import <file.md> --title \"\u2026\" --type\n spec|architecture|api|guide|decision|changelog|other [--context \"\u2026\"]`.\n- Update: `orbitmap doc-update <slug> --file <file.md>` (replaces content, bumps\n version).\n- To change an OrbitMap document, ALWAYS go through these commands \u2014 NEVER edit files\n inside the OrbitMap workspace/cache directories directly.";
12
+ export declare const SKILL_DOCS_BODY = "# OrbitMap documents\n\nDocuments are workspace-level: exactly ONE copy per workspace, never per-area. No document\ncommand takes an area, and `orbitmap context` already lists them.\n\n## Choosing what to read\n`orbitmap docs` lists documents with their `context` (when the doc is relevant) and\n`sections_count`. Use context to pick the right document; use sections_count to decide\nwhether to fetch the TOC first (many sections) or go straight to full.\n\n## Token-efficient reading flow\n1. `orbitmap doc <slug>` \u2192 context + table of contents (cheap).\n2. `orbitmap doc <slug> --section \"## Auth\"` \u2192 just that section.\n3. `orbitmap doc <slug> --full` \u2192 full content (expensive \u2014 last resort).\nUse the lightest mode that answers your question. When the CLI reports a local file path\nfor the full content, read that file instead of printing the content into the\nconversation.\n\n## Editing\n- Import a new document: `orbitmap doc-import <file.md> --title \"\u2026\" --type\n spec|architecture|api|guide|decision|changelog|other [--context \"\u2026\"]`.\n- Update: `orbitmap doc-update <slug> --file <file.md>` (replaces content, bumps\n version).\n- To change an OrbitMap document, ALWAYS go through these commands \u2014 NEVER edit files\n inside the OrbitMap workspace/cache directories directly.";
13
13
  export interface SkillDef {
14
14
  /** Skill name = directory name under `.claude/skills/`. */
15
15
  name: string;
@@ -19,12 +19,25 @@ export interface SkillDef {
19
19
  body: string;
20
20
  }
21
21
  export declare const SKILLS: readonly SkillDef[];
22
- export declare const THIN_HOOK_CLAUDE = "## OrbitMap\n\nThis project tracks work in OrbitMap via the `orbitmap` CLI (works the same whether data\nis in the cloud or in local files). When the user mentions tasks, backlog, missions,\nintents, ideas, issues, vibes, or asks you to work on / log / plan something, load the\nmatching skill: `orbitmap` (context & commands), `orbitmap-working` (doing tasks),\n`orbitmap-planning` (missions/intents/ideas/issues), `orbitmap-docs` (documents).\nGolden rules: work on ONE task at a time; NEVER finish a task session without a final\n`orbitmap log` entry and an `orbitmap status` update; finished work defaults to\n`in_review`, not `done`. NEVER edit files inside the OrbitMap workspace directory\ndirectly \u2014 always go through `orbitmap` commands.";
23
- export declare const THIN_HOOK_GENERIC = "## OrbitMap\n\nThis project tracks work in OrbitMap via the `orbitmap` CLI (works the same whether data\nis in the cloud or in local files). When the user mentions tasks, backlog, missions,\nintents, ideas, issues, vibes, or asks you to work on / log / plan something, follow the\nsections below: core (context & commands), working on tasks, planning\n(missions/intents/ideas/issues), and documents.\nGolden rules: work on ONE task at a time; NEVER finish a task session without a final\n`orbitmap log` entry and an `orbitmap status` update; finished work defaults to\n`in_review`, not `done`. NEVER edit files inside the OrbitMap workspace directory\ndirectly \u2014 always go through `orbitmap` commands.";
22
+ export declare const THIN_HOOK_CLAUDE = "## OrbitMap\n\nThis project tracks work in OrbitMap via the `orbitmap` CLI (cloud or local files alike).\nYou work in a WORKSPACE: run `orbitmap context` first \u2014 one call gives the workspace, your\nareas, the active mission, open intents, tasks and documents. Never ask which area \u2014 it\nfollows from the directory (map in `.orbitmap/config.json`); missions, intents and docs\nneed none. When the user mentions tasks, backlog, missions, intents, ideas, issues, vibes,\nor asks you to work on / log / plan something, load the matching skill: `orbitmap`\n(context & commands), `orbitmap-working` (doing tasks), `orbitmap-planning`\n(missions/intents/ideas/issues), `orbitmap-docs` (documents).\nGolden rules: ONE task at a time; NEVER finish a task session without a final\n`orbitmap log` entry and an `orbitmap status` update; finished work defaults to\n`in_review`, not `done`. NEVER edit workspace files directly \u2014 always use `orbitmap`.";
23
+ export declare const THIN_HOOK_GENERIC = "## OrbitMap\n\nThis project tracks work in OrbitMap via the `orbitmap` CLI (cloud or local files alike).\nYou work in a WORKSPACE: run `orbitmap context` first \u2014 one call gives the workspace, your\nareas, the active mission, open intents, tasks and documents. Never ask which area \u2014 it\nfollows from the directory (map in `.orbitmap/config.json`); missions, intents and docs\nneed none. When the user mentions tasks, backlog, missions, intents, ideas, issues, vibes,\nor asks you to work on / log / plan something, follow the sections below: core (context &\ncommands), working on tasks, planning (missions/intents/ideas/issues), and documents.\nGolden rules: ONE task at a time; NEVER finish a task session without a final\n`orbitmap log` entry and an `orbitmap status` update; finished work defaults to\n`in_review`, not `done`. NEVER edit workspace files directly \u2014 always use `orbitmap`.";
24
24
  /** Build one SKILL.md file (frontmatter + body) for Claude. */
25
25
  export declare function buildSkillFile(skill: SkillDef): string;
26
- /** Build the thin always-on block for a Claude config file (CLAUDE.md). */
27
- export declare function buildClaudeHook(): string;
26
+ /**
27
+ * One extra line appended to the Claude hook when the skills were installed at PROJECT
28
+ * scope. `CLAUDE.md` is inherited by every sub-directory, but a project-level
29
+ * `.claude/skills/` directory is not: a session started in a sibling or child repository
30
+ * reads this hook and cannot load the skills it names. The hook must therefore say where
31
+ * the skills actually are, and how to make them visible everywhere. At user scope the
32
+ * skills are visible wherever the hook is, so no caveat is needed.
33
+ */
34
+ export declare const SKILL_SCOPE_CAVEAT_PROJECT: string;
35
+ /**
36
+ * Build the thin always-on block for a Claude config file (CLAUDE.md).
37
+ * `scope` is where the accompanying skill files were installed — see
38
+ * {@link SKILL_SCOPE_CAVEAT_PROJECT}.
39
+ */
40
+ export declare function buildClaudeHook(scope?: 'user' | 'project'): string;
28
41
  /**
29
42
  * Build the markdown fallback block for non-Claude agents: the thin hook plus all four
30
43
  * skill bodies inlined (no skill ecosystem to lean on).
@@ -57,11 +57,35 @@ never read or write the workspace's data files directly. The CLI is the only int
57
57
  - Entity numbers (TS-xxxxxx etc.) are accepted by every command that takes an id.
58
58
 
59
59
  ## Context
60
- - Area resolves automatically (config/env). Override per call with \`--area <slug>\`.
61
- - If a command fails asking for area context, run \`orbitmap areas\` to list areas, then
62
- retry with \`--area\`.
63
- - \`orbitmap context\` shows who you are, the workspace, and the active area. Run it when
64
- unsure.
60
+ - START HERE, always: \`orbitmap context\`. \`orbitmap context\` is authoritative and returns
61
+ in ONE call everything a session needs the agent, the workspace, the areas you work in,
62
+ the active mission, open intents, your tasks and the documents. Never list areas and never
63
+ ask the user "which area?" before you have read it.
64
+ - You work in a WORKSPACE, not inside a single area. Missions, intents
65
+ and documents are workspace-level and take no area — a document is exactly ONE copy,
66
+ global to the workspace, never per-area. Tasks, vibes, issues and ideas are
67
+ AREA-scoped.
68
+ - Missions and intents outrank individual tasks. Asked to work on "what matters", take the
69
+ active mission and open intents from context and pick work that serves them.
70
+ - The area follows from the directory, never from a question to the user:
71
+ \`.orbitmap/config.json\` maps directories → area slugs at the workspace root, and each
72
+ area directory carries its own \`.orbitmap/config.json\` marker naming its area. That
73
+ config is the only source of truth — never hard-code area names anywhere.
74
+ So: do area-scoped work from the directory it belongs to and let the CLI resolve it.
75
+ - \`--area <slug>\` is an OVERRIDE for a single call, not part of normal usage — reach for it
76
+ only to read or write outside the area the current directory resolves to.
77
+ - If a command fails with \`AREA_CONTEXT_REQUIRED\`, its details list the mapped
78
+ directories: cd into the right one, or retry with \`--area <slug>\`.
79
+ - WRITES: the resolved area is a default for *reading*, never a statement of where the
80
+ work belongs. Before creating anything area-scoped (task, subtask, issue, vibe),
81
+ derive the target area from the work itself (which repo/package it lives in) and pass
82
+ \`--area <slug>\` if that differs from the area the CLI echoes. If the work itself is
83
+ genuinely ambiguous, ASK THE USER; do not guess. There is no
84
+ \`move\` command: a write in the wrong area has to be recreated.
85
+ - Every write echoes its scope on stderr: \`creates in area <slug> (source: …)\` when it
86
+ creates an object, \`scoped to area <slug> (source: …)\` when it changes one by id. A
87
+ \`source\` of \`global ~/.orbitmap/config.json\` is a machine-wide leftover that nothing
88
+ here chose — treat it as unconfirmed and pass \`--area\` explicitly.
65
89
 
66
90
  ## Task statuses
67
91
  backlog, todo, in_progress, in_review, review_changes, done, blocked.
@@ -69,7 +93,8 @@ backlog, todo, in_progress, in_review, review_changes, done, blocked.
69
93
  \`orbitmap tasks --status backlog\` when the user asks about the backlog.
70
94
 
71
95
  ## Command reference (all commands accept --json)
72
- - Context: \`orbitmap context\`, \`orbitmap areas\`, \`orbitmap overview\`
96
+ - Context: \`orbitmap context\` (start here), \`orbitmap overview\`, \`orbitmap areas\`
97
+ (rarely needed — context already lists the areas you work in)
73
98
  - Tasks: \`orbitmap tasks [--status s1,s2]\`, \`orbitmap task TS-x\`, \`orbitmap get <ID>\`,
74
99
  \`orbitmap start [TS-x]\`, \`orbitmap status TS-x <status> [--delivery <d>]\`,
75
100
  \`orbitmap create "title" [--intent IN-x|--mission MS-x] [--priority p]\`,
@@ -98,18 +123,23 @@ description: >
98
123
  export const SKILL_WORKING_BODY = `# Working on OrbitMap tasks
99
124
 
100
125
  ## Task workflow (on user request)
101
- When the user asks you to work on tasks:
102
- 1. \`orbitmap tasks --status in_progress\` — check for unfinished work.
103
- 2. If found \`orbitmap task TS-x\` read the work log resume from the resume point.
104
- 3. If not \`orbitmap start\` auto-picks the first todo task, sets it in_progress and
105
- prints full context (description, agent_instructions, logs).
106
- 4. If no tasks inform the user.
126
+ When the user asks you to work on tasks — including a vague "work on what's important":
127
+ 1. \`orbitmap context\` — the workspace, your areas, the active mission, open intents and
128
+ your tasks in one call. Do not ask which area and do not list areas first.
129
+ 2. Unfinished work in context (or \`orbitmap tasks --status in_progress\`)
130
+ \`orbitmap task TS-x\` read the work log → resume from the resume point.
131
+ 3. Otherwise pick work that serves the active mission / open intents, or \`orbitmap start\`
132
+ — auto-picks the first todo task, sets it in_progress and prints full context
133
+ (description, agent_instructions, logs).
134
+ 4. If there is nothing to pick up → inform the user.
107
135
  Use \`orbitmap start TS-x\` to begin a specific task; \`orbitmap task TS-x\` only inspects.
108
136
 
109
137
  ## Rules
110
138
  - Work on ONE task at a time.
111
139
  - Always read agent_instructions from the task before implementing. Task-level
112
140
  agent_instructions take precedence over area-level instructions.
141
+ - Subtasks never show up in a task list (\`orbitmap context\`, \`orbitmap tasks\`,
142
+ \`orbitmap start\`) — only inside the parent task you opened with \`orbitmap task TS-x\`.
113
143
  - Only work on subtasks assigned to you; do not pick up other agents' subtasks.
114
144
  - Do NOT mark a parent task done while it has unfinished subtasks, unless the user
115
145
  explicitly asks.
@@ -174,7 +204,7 @@ lifecycle steps as explicit plan items:
174
204
  incomplete).
175
205
 
176
206
  ## Example: completing a task (default → in_review)
177
- 1. \`orbitmap tasks --status in_progress\` → empty
207
+ 1. \`orbitmap context\` → workspace, mission, intents, tasks; nothing in_progress
178
208
  2. \`orbitmap start\` → task context
179
209
  3. read agent_instructions; implement; run tests; commit with \`[TS-x]\` prefix
180
210
  4. \`orbitmap log TS-x "Implemented X by doing Y" --type code_change\`
@@ -193,9 +223,12 @@ export const SKILL_PLANNING_BODY = `# Planning in OrbitMap
193
223
 
194
224
  ## Hierarchy
195
225
  Mission (MS-) → Intent (IN-) → Task (TS-) / Issue (IS-). Missions and intents are
196
- workspace-level; tasks live in areas. An intent groups the tasks/issues that realise one
197
- goal; a mission time-boxes a set of intents (and directly-attached items) toward an
198
- outcome. At most ONE mission is active at a time.
226
+ workspace-level and never take an area plan from anywhere in the workspace, and never
227
+ ask which area to plan in. Tasks and issues are area-scoped. An intent groups the
228
+ tasks/issues that realise one goal; a mission time-boxes a set of intents (and
229
+ directly-attached items) toward an outcome. At most ONE mission is active at a time.
230
+ \`orbitmap context\` already gives you the active mission and the open intents — read it
231
+ before planning instead of listing anything.
199
232
 
200
233
  ## Missions
201
234
  - \`orbitmap mission list\` / \`orbitmap mission show MS-x\`
@@ -246,6 +279,9 @@ description: >
246
279
  ---`;
247
280
  export const SKILL_DOCS_BODY = `# OrbitMap documents
248
281
 
282
+ Documents are workspace-level: exactly ONE copy per workspace, never per-area. No document
283
+ command takes an area, and \`orbitmap context\` already lists them.
284
+
249
285
  ## Choosing what to read
250
286
  \`orbitmap docs\` lists documents with their \`context\` (when the doc is relevant) and
251
287
  \`sections_count\`. Use context to pick the right document; use sections_count to decide
@@ -292,36 +328,56 @@ export const SKILLS = [
292
328
  // Claude variant — §8.2, verbatim (without the markers, which buildClaudeHook adds).
293
329
  export const THIN_HOOK_CLAUDE = `## OrbitMap
294
330
 
295
- This project tracks work in OrbitMap via the \`orbitmap\` CLI (works the same whether data
296
- is in the cloud or in local files). When the user mentions tasks, backlog, missions,
297
- intents, ideas, issues, vibes, or asks you to work on / log / plan something, load the
298
- matching skill: \`orbitmap\` (context & commands), \`orbitmap-working\` (doing tasks),
299
- \`orbitmap-planning\` (missions/intents/ideas/issues), \`orbitmap-docs\` (documents).
300
- Golden rules: work on ONE task at a time; NEVER finish a task session without a final
331
+ This project tracks work in OrbitMap via the \`orbitmap\` CLI (cloud or local files alike).
332
+ You work in a WORKSPACE: run \`orbitmap context\` first one call gives the workspace, your
333
+ areas, the active mission, open intents, tasks and documents. Never ask which area it
334
+ follows from the directory (map in \`.orbitmap/config.json\`); missions, intents and docs
335
+ need none. When the user mentions tasks, backlog, missions, intents, ideas, issues, vibes,
336
+ or asks you to work on / log / plan something, load the matching skill: \`orbitmap\`
337
+ (context & commands), \`orbitmap-working\` (doing tasks), \`orbitmap-planning\`
338
+ (missions/intents/ideas/issues), \`orbitmap-docs\` (documents).
339
+ Golden rules: ONE task at a time; NEVER finish a task session without a final
301
340
  \`orbitmap log\` entry and an \`orbitmap status\` update; finished work defaults to
302
- \`in_review\`, not \`done\`. NEVER edit files inside the OrbitMap workspace directory
303
- directly — always go through \`orbitmap\` commands.`;
341
+ \`in_review\`, not \`done\`. NEVER edit workspace files directly always use \`orbitmap\`.`;
304
342
  // Non-Claude variant: same rules, but points at the inlined sections below instead of
305
343
  // skills that these agents cannot load.
306
344
  export const THIN_HOOK_GENERIC = `## OrbitMap
307
345
 
308
- This project tracks work in OrbitMap via the \`orbitmap\` CLI (works the same whether data
309
- is in the cloud or in local files). When the user mentions tasks, backlog, missions,
310
- intents, ideas, issues, vibes, or asks you to work on / log / plan something, follow the
311
- sections below: core (context & commands), working on tasks, planning
312
- (missions/intents/ideas/issues), and documents.
313
- Golden rules: work on ONE task at a time; NEVER finish a task session without a final
346
+ This project tracks work in OrbitMap via the \`orbitmap\` CLI (cloud or local files alike).
347
+ You work in a WORKSPACE: run \`orbitmap context\` first one call gives the workspace, your
348
+ areas, the active mission, open intents, tasks and documents. Never ask which area it
349
+ follows from the directory (map in \`.orbitmap/config.json\`); missions, intents and docs
350
+ need none. When the user mentions tasks, backlog, missions, intents, ideas, issues, vibes,
351
+ or asks you to work on / log / plan something, follow the sections below: core (context &
352
+ commands), working on tasks, planning (missions/intents/ideas/issues), and documents.
353
+ Golden rules: ONE task at a time; NEVER finish a task session without a final
314
354
  \`orbitmap log\` entry and an \`orbitmap status\` update; finished work defaults to
315
- \`in_review\`, not \`done\`. NEVER edit files inside the OrbitMap workspace directory
316
- directly — always go through \`orbitmap\` commands.`;
355
+ \`in_review\`, not \`done\`. NEVER edit workspace files directly always use \`orbitmap\`.`;
317
356
  // ── Assembly helpers ───────────────────────────────────────────────────────────
318
357
  /** Build one SKILL.md file (frontmatter + body) for Claude. */
319
358
  export function buildSkillFile(skill) {
320
359
  return `${skill.frontmatter}\n\n${skill.body}\n`;
321
360
  }
322
- /** Build the thin always-on block for a Claude config file (CLAUDE.md). */
323
- export function buildClaudeHook() {
324
- return `${MARKER_START}\n${THIN_HOOK_CLAUDE}\n${MARKER_END}`;
361
+ /**
362
+ * One extra line appended to the Claude hook when the skills were installed at PROJECT
363
+ * scope. `CLAUDE.md` is inherited by every sub-directory, but a project-level
364
+ * `.claude/skills/` directory is not: a session started in a sibling or child repository
365
+ * reads this hook and cannot load the skills it names. The hook must therefore say where
366
+ * the skills actually are, and how to make them visible everywhere. At user scope the
367
+ * skills are visible wherever the hook is, so no caveat is needed.
368
+ */
369
+ export const SKILL_SCOPE_CAVEAT_PROJECT = 'These skills are installed at PROJECT scope, in this directory\'s `.claude/skills/`. ' +
370
+ 'If you cannot load them (e.g. this session started in a different directory), do not ' +
371
+ 'guess the workflow — ask the user to run `orbitmap setup-agent --scope user`, which ' +
372
+ 'installs them into `~/.claude/skills/` where every session can see them.';
373
+ /**
374
+ * Build the thin always-on block for a Claude config file (CLAUDE.md).
375
+ * `scope` is where the accompanying skill files were installed — see
376
+ * {@link SKILL_SCOPE_CAVEAT_PROJECT}.
377
+ */
378
+ export function buildClaudeHook(scope = 'user') {
379
+ const body = scope === 'project' ? `${THIN_HOOK_CLAUDE}\n${SKILL_SCOPE_CAVEAT_PROJECT}` : THIN_HOOK_CLAUDE;
380
+ return `${MARKER_START}\n${body}\n${MARKER_END}`;
325
381
  }
326
382
  /**
327
383
  * Build the markdown fallback block for non-Claude agents: the thin hook plus all four
@@ -1 +1 @@
1
- {"version":3,"file":"agent-instructions.js","sourceRoot":"","sources":["../src/agent-instructions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-instructions.js","sourceRoot":"","sources":["../src/agent-instructions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Which directory holds which area's code — the guessing half of the workspace-first
3
+ * `orbitmap init` (schema v2).
4
+ *
5
+ * A workspace groups several areas, and on this machine each of them is (usually) a
6
+ * directory: either a subdirectory of an umbrella checkout, or the repository the user is
7
+ * standing in. Nothing on the server records that mapping — it is per machine — so `init`
8
+ * has to infer it and then write it down (`config.json` `areas` for in-tree directories,
9
+ * `link.json` `areas` for the rest).
10
+ *
11
+ * Three signals, in decreasing order of confidence, all of them cheap and offline:
12
+ *
13
+ * 1. **`name`** — the directory is literally named after the area slug. Unambiguous.
14
+ * 2. **`git-remote`** — the directory's `origin` remote is the area's `git_url`. The
15
+ * strongest signal there is (an area *is* a repository in the data model), and the only
16
+ * one that survives a renamed checkout.
17
+ * 3. **`slugified-name`** — slugifying the directory name yields the slug (`My App` →
18
+ * `my-app`), i.e. the same rule the server used to make the slug in the first place.
19
+ *
20
+ * The git remote is read from `.git/config` rather than by spawning `git`: the CLI's tests
21
+ * are offline and process-free by policy, a subprocess per candidate directory is the
22
+ * slowest thing `init` could possibly do, and the file format has been stable for two
23
+ * decades. Anything not matched by these three is asked about (or skipped) — never guessed.
24
+ */
25
+ /** As much of an area as the mapping needs; satisfied by `GET /areas` entries. */
26
+ export interface AreaLike {
27
+ slug: string;
28
+ name?: string;
29
+ /** Repository URL recorded on the area, when the provider returns one. */
30
+ git_url?: string | null;
31
+ }
32
+ /** Which signal produced a directory ↔ area pairing. */
33
+ export type AreaMatchKind = 'name' | 'git-remote' | 'slugified-name';
34
+ /** One inferred pairing. */
35
+ export interface AreaDirectoryMatch<T extends AreaLike = AreaLike> {
36
+ area: T;
37
+ /** Absolute directory. */
38
+ dir: string;
39
+ how: AreaMatchKind;
40
+ }
41
+ /**
42
+ * Immediate subdirectories of `root` that could plausibly be an area checkout — absolute
43
+ * paths, sorted, dot-directories and the usual build/dependency noise removed.
44
+ *
45
+ * Deliberately one level deep: deeper nesting is a real layout but scanning for it turns a
46
+ * setup command into a filesystem crawl, and the manual answer covers it in one line.
47
+ */
48
+ export declare function listCandidateDirectories(root: string): string[];
49
+ /**
50
+ * Comparable form of a git URL: scheme, credentials, the `.git` suffix and the
51
+ * `git@host:path` / `https://host/path` spelling difference all removed, so the two ways of
52
+ * writing the same repository compare equal.
53
+ */
54
+ export declare function normalizeGitUrl(url: string): string;
55
+ /**
56
+ * The `origin` remote URL recorded in `dir`'s git config, or `undefined` when `dir` is not a
57
+ * checkout (or has no origin). Handles the `.git`-as-a-file form that worktrees and
58
+ * submodules use.
59
+ */
60
+ export declare function readGitRemoteUrl(dir: string): string | undefined;
61
+ /** True when `dir` is the checkout of `area`, by any of the three signals. */
62
+ export declare function matchDirectoryToArea(dir: string, area: AreaLike): AreaMatchKind | undefined;
63
+ /**
64
+ * Guess a directory under `root` for each area, and report which areas got none.
65
+ *
66
+ * One directory is never handed to two areas: the candidates are consumed as they match, in
67
+ * area order, so a `name` hit for one area cannot be stolen by a `slugified-name` hit for
68
+ * another.
69
+ */
70
+ export declare function detectAreaDirectories<T extends AreaLike>(root: string, areas: T[], candidates?: string[]): {
71
+ matched: Array<AreaDirectoryMatch<T>>;
72
+ unmatched: T[];
73
+ };
74
+ /** The inverse question: standing in `dir`, which of these areas is it? */
75
+ export declare function detectAreaForDirectory<T extends AreaLike>(dir: string, areas: T[]): AreaDirectoryMatch<T> | undefined;
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Which directory holds which area's code — the guessing half of the workspace-first
3
+ * `orbitmap init` (schema v2).
4
+ *
5
+ * A workspace groups several areas, and on this machine each of them is (usually) a
6
+ * directory: either a subdirectory of an umbrella checkout, or the repository the user is
7
+ * standing in. Nothing on the server records that mapping — it is per machine — so `init`
8
+ * has to infer it and then write it down (`config.json` `areas` for in-tree directories,
9
+ * `link.json` `areas` for the rest).
10
+ *
11
+ * Three signals, in decreasing order of confidence, all of them cheap and offline:
12
+ *
13
+ * 1. **`name`** — the directory is literally named after the area slug. Unambiguous.
14
+ * 2. **`git-remote`** — the directory's `origin` remote is the area's `git_url`. The
15
+ * strongest signal there is (an area *is* a repository in the data model), and the only
16
+ * one that survives a renamed checkout.
17
+ * 3. **`slugified-name`** — slugifying the directory name yields the slug (`My App` →
18
+ * `my-app`), i.e. the same rule the server used to make the slug in the first place.
19
+ *
20
+ * The git remote is read from `.git/config` rather than by spawning `git`: the CLI's tests
21
+ * are offline and process-free by policy, a subprocess per candidate directory is the
22
+ * slowest thing `init` could possibly do, and the file format has been stable for two
23
+ * decades. Anything not matched by these three is asked about (or skipped) — never guessed.
24
+ */
25
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
26
+ import { basename, isAbsolute, join, resolve } from 'node:path';
27
+ import { slugify } from './adapters/local/store.js';
28
+ /** Directory names never worth scanning as an area checkout. */
29
+ const SKIP_DIRS = new Set([
30
+ 'node_modules',
31
+ 'vendor',
32
+ 'dist',
33
+ 'build',
34
+ 'out',
35
+ 'target',
36
+ 'coverage',
37
+ 'tmp',
38
+ '__pycache__',
39
+ ]);
40
+ /**
41
+ * Immediate subdirectories of `root` that could plausibly be an area checkout — absolute
42
+ * paths, sorted, dot-directories and the usual build/dependency noise removed.
43
+ *
44
+ * Deliberately one level deep: deeper nesting is a real layout but scanning for it turns a
45
+ * setup command into a filesystem crawl, and the manual answer covers it in one line.
46
+ */
47
+ export function listCandidateDirectories(root) {
48
+ let entries;
49
+ try {
50
+ entries = readdirSync(resolve(root), { withFileTypes: true });
51
+ }
52
+ catch {
53
+ return [];
54
+ }
55
+ return entries
56
+ .filter((entry) => entry.isDirectory())
57
+ .map((entry) => entry.name)
58
+ .filter((name) => !name.startsWith('.') && !SKIP_DIRS.has(name.toLowerCase()))
59
+ .sort()
60
+ .map((name) => join(resolve(root), name));
61
+ }
62
+ /**
63
+ * Comparable form of a git URL: scheme, credentials, the `.git` suffix and the
64
+ * `git@host:path` / `https://host/path` spelling difference all removed, so the two ways of
65
+ * writing the same repository compare equal.
66
+ */
67
+ export function normalizeGitUrl(url) {
68
+ let out = url.trim().toLowerCase();
69
+ if (!out)
70
+ return '';
71
+ out = out.replace(/^git\+/, '');
72
+ out = out.replace(/^[a-z][a-z0-9+.-]*:\/\//, '');
73
+ out = out.replace(/^[^/@]+@/, '');
74
+ // scp-style `host:org/repo` → `host/org/repo`; a `:port` (digits) is left alone.
75
+ out = out.replace(/^([^/:]+):(?!\d)/, '$1/');
76
+ out = out.replace(/\.git$/, '');
77
+ return out.replace(/\/+$/, '');
78
+ }
79
+ /**
80
+ * The `origin` remote URL recorded in `dir`'s git config, or `undefined` when `dir` is not a
81
+ * checkout (or has no origin). Handles the `.git`-as-a-file form that worktrees and
82
+ * submodules use.
83
+ */
84
+ export function readGitRemoteUrl(dir) {
85
+ const gitPath = join(resolve(dir), '.git');
86
+ if (!existsSync(gitPath))
87
+ return undefined;
88
+ let configFile = join(gitPath, 'config');
89
+ try {
90
+ if (statSync(gitPath).isFile()) {
91
+ const pointer = readFileSync(gitPath, 'utf-8').match(/^gitdir:\s*(.+)$/m)?.[1]?.trim();
92
+ if (!pointer)
93
+ return undefined;
94
+ configFile = join(isAbsolute(pointer) ? pointer : resolve(dir, pointer), 'config');
95
+ }
96
+ if (!existsSync(configFile))
97
+ return undefined;
98
+ const contents = readFileSync(configFile, 'utf-8');
99
+ // Only the `[remote "origin"]` section: any other remote (a fork, a mirror) is a
100
+ // different repository as far as identifying an area goes.
101
+ const section = contents.split(/^\[/m).find((part) => /^remote\s+"origin"\]/.test(part));
102
+ return section?.match(/^\s*url\s*=\s*(.+)$/m)?.[1]?.trim() || undefined;
103
+ }
104
+ catch {
105
+ return undefined;
106
+ }
107
+ }
108
+ /** True when `dir` is the checkout of `area`, by any of the three signals. */
109
+ export function matchDirectoryToArea(dir, area) {
110
+ const name = basename(resolve(dir));
111
+ if (name === area.slug)
112
+ return 'name';
113
+ if (area.git_url) {
114
+ const remote = readGitRemoteUrl(dir);
115
+ if (remote && normalizeGitUrl(remote) === normalizeGitUrl(area.git_url))
116
+ return 'git-remote';
117
+ }
118
+ if (slugify(name) === area.slug)
119
+ return 'slugified-name';
120
+ return undefined;
121
+ }
122
+ /**
123
+ * Guess a directory under `root` for each area, and report which areas got none.
124
+ *
125
+ * One directory is never handed to two areas: the candidates are consumed as they match, in
126
+ * area order, so a `name` hit for one area cannot be stolen by a `slugified-name` hit for
127
+ * another.
128
+ */
129
+ export function detectAreaDirectories(root, areas, candidates = listCandidateDirectories(root)) {
130
+ const remaining = [...candidates];
131
+ const matched = [];
132
+ const unmatched = [];
133
+ for (const area of areas) {
134
+ // The signals are tried in confidence order across *all* remaining candidates, so a
135
+ // weak match on an early directory never beats a strong one further down the list.
136
+ let hit;
137
+ for (const how of ['name', 'git-remote', 'slugified-name']) {
138
+ const dir = remaining.find((candidate) => matchDirectoryToArea(candidate, area) === how);
139
+ if (dir) {
140
+ hit = { dir, how };
141
+ break;
142
+ }
143
+ }
144
+ if (!hit) {
145
+ unmatched.push(area);
146
+ continue;
147
+ }
148
+ remaining.splice(remaining.indexOf(hit.dir), 1);
149
+ matched.push({ area, dir: hit.dir, how: hit.how });
150
+ }
151
+ return { matched, unmatched };
152
+ }
153
+ /** The inverse question: standing in `dir`, which of these areas is it? */
154
+ export function detectAreaForDirectory(dir, areas) {
155
+ for (const how of ['name', 'git-remote', 'slugified-name']) {
156
+ const area = areas.find((candidate) => matchDirectoryToArea(dir, candidate) === how);
157
+ if (area)
158
+ return { area, dir: resolve(dir), how };
159
+ }
160
+ return undefined;
161
+ }
162
+ //# sourceMappingURL=area-directories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"area-directories.js","sourceRoot":"","sources":["../src/area-directories.ts"],"names":[],"mappings":"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"}