@llodev/pm-tasks-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # @llodev/pm-tasks-core
2
+
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [`a571ab1`](https://github.com/llodev/skills/commit/a571ab1537ea7d3fe61c7b89c5be0f08d01f3838) - First stable release of the pm-tasks-\* family.
8
+
9
+ - `@llodev/pm-tasks-core` — Phases 1–3 extraction pipeline (input → sections → generic card), 6 CRUD verbs (`task.create`, `checklist.check`, `task.close`, `task.due-date.set`, `task.assignee.add`, `task.comment.add`), autonomous-mode contract (allowlist + scope + rate-limit + audit log), shared init UX library.
10
+ - `@llodev/pm-tasks-trello` — Trello adapter on the canonical generic card. Paste-friendly output, MCP-driven publish, autonomous mode against a board allowlist.
11
+ - `@llodev/pm-tasks-asana` — Asana adapter with workspace/project/section + custom-field + subtask-inheritance support. Paste, MCP-driven publish, autonomous mode.
12
+
13
+ Architecture, contract, and CRUD vocabulary documented in `docs/specs/2026-06-11-pm-tasks-design.md` and `docs/plans/2026-06-11-pm-tasks-v1.md`.
14
+
15
+ ## 0.1.0 (unreleased)
16
+
17
+ - Initial extraction from `plan-to-task-cards` v0.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LLDev Information Solutions
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @llodev/pm-tasks-core
2
+
3
+ Core skill shared by every `@llodev/pm-tasks-<tool>` adapter (Trello, Asana, Jira, Linear, Notion, ClickUp, Monday, Bitrix24, Todoist).
4
+
5
+ This package alone is not useful. Install at least one adapter:
6
+
7
+ ```
8
+ npm i @llodev/pm-tasks-core @llodev/pm-tasks-trello
9
+ # or
10
+ npx skills add llodev/skills/pm-tasks-core llodev/skills/pm-tasks-trello
11
+ ```
12
+
13
+ ## What lives here
14
+
15
+ - The extraction phases (plan → generic card).
16
+ - The canonical CRUD vocabulary every adapter implements.
17
+ - The autonomous-mode contract (sentinels, allowlist, guardrails).
18
+ - The init UX shared by all adapter `init` commands.
19
+ - The audit log format.
20
+
21
+ ## Optional cron — rotate audit log
22
+
23
+ ```cron
24
+ # Daily at 04:00, keep 90 days of audit log for Trello + Asana
25
+ 0 4 * * * /path/to/pm-tasks-core/scripts/rotate-audit.sh trello
26
+ 0 4 * * * /path/to/pm-tasks-core/scripts/rotate-audit.sh asana
27
+ ```
28
+
29
+ ## License
30
+
31
+ MIT — see [LICENSE](./LICENSE).
package/SKILL.md ADDED
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: pm-tasks-core
3
+ description: >-
4
+ Core extraction + vocabulary for the @llodev/pm-tasks-* family. Use when
5
+ working with any pm-tasks-<tool> adapter (Trello, Asana, etc.) — provides
6
+ Phases 1–3 (identify input, extract structure, build the generic card) plus
7
+ the canonical CRUD vocabulary (task.create, checklist.check, task.close,
8
+ task.due-date.set, task.assignee.add, task.comment.add) consumed by adapters.
9
+ Also defines autonomous-mode contract (sentinels, allowlist, scope, audit log)
10
+ and the shared init UX. Triggered indirectly by any prompt that an adapter
11
+ handles (e.g. "create Trello card", "publish plan to Asana", "[autonomous]
12
+ create task"). Do NOT activate alone — it has no tool-specific formatting.
13
+ license: MIT
14
+ metadata:
15
+ version: 1.0.0
16
+ tags:
17
+ - agent-skill
18
+ - plan-to-tasks
19
+ - pm-tools
20
+ family: pm-tasks
21
+ role: core
22
+ compatibility:
23
+ agents:
24
+ - claude-code
25
+ - cursor
26
+ - codex
27
+ - windsurf
28
+ - cline
29
+ - roo-code
30
+ ---
31
+
32
+ # pm-tasks-core
33
+
34
+ Shared core for all `pm-tasks-<tool>` adapters. Defines the extraction phases, the generic-card structure, the CRUD vocabulary, the autonomous-mode contract, the configuration lookup rules, and the audit-log format. Adapters reference this skill by path — no formal dependency mechanism in the spec.
35
+
36
+ ## Routing
37
+
38
+ Adapters invoke this skill BEFORE applying their tool-specific formatting. The exact pointer is documented in [`references/contract.md`](references/contract.md).
39
+
40
+ ## Phases
41
+
42
+ | Phase | Purpose | Reference |
43
+ | ----- | ------------------------------------------------------------ | ---------------------------------------------------------- |
44
+ | 1 | Identify the input (plan file vs inline paste vs implicit) | [`references/contract.md`](references/contract.md) § 1 |
45
+ | 2 | Extract sections by intent (goal, prereqs, tasks, done-when) | [`references/contract.md`](references/contract.md) § 2 |
46
+ | 2.5 | Anti-patterns gate | [`anti-patterns/core.md`](anti-patterns/core.md) |
47
+ | 3 | Build the generic card | [`references/generic-card.md`](references/generic-card.md) |
48
+
49
+ Adapters then execute Phases 4+ per their own SKILL.md.
50
+
51
+ ## CRUD vocabulary (verbs adapters implement)
52
+
53
+ See [`references/crud-vocabulary.md`](references/crud-vocabulary.md). Six verbs, all idempotent (with `clientToken` rules for non-natural cases).
54
+
55
+ ## Autonomous mode
56
+
57
+ See [`references/autonomous-mode.md`](references/autonomous-mode.md). Activated only by sentinel `[autonomous]` / `--auto` / env `LLODEV_PM_TASKS_AUTONOMOUS=1`. Requires explicit allowlist + scope + rate limit in the tool's config. Never inferred.
58
+
59
+ ## Configuration
60
+
61
+ Lookup order: `<git-root>/.<tool>.json` → `~/.config/llodev/pm-tasks/<tool>.json` → abort. Secrets NEVER in JSON (env vars / OS keychain only).
62
+
63
+ ## Audit log
64
+
65
+ Append-only JSONL at `~/.local/share/llodev/pm-tasks/<tool>/audit.log`. Schema in [`references/audit-log-format.md`](references/audit-log-format.md). Doubles as the lookup index for `<task-ref>` resolution.
66
+
67
+ ## Init helper
68
+
69
+ Adapters expose `npx @llodev/pm-tasks-<tool> init`. Shared UX in [`references/init-ux.md`](references/init-ux.md). Implementation library at `./scripts/init-lib.mjs`.
70
+
71
+ ## Standalone fallback
72
+
73
+ This skill is not useful without an adapter. If activated alone, tell the user to install at least one `pm-tasks-<tool>` package.
@@ -0,0 +1,55 @@
1
+ # Card & workflow anti-patterns (core)
2
+
3
+ Expert guardrails — violating these wastes board space, breaks paste targets, or misleads reviewers.
4
+
5
+ ---
6
+
7
+ ## Structure & granularity
8
+
9
+ **NEVER** create one checklist item per micro-step from the plan (e.g. "open file", "run linter", "save"). **Why:** the card mirrors **tasks/outcomes**, not every keystroke; noise hides real progress.
10
+
11
+ **NEVER** duplicate the entire plan verbatim into description or checklist. **Why:** defeats the purpose of a summary; links to plan/spec suffice.
12
+
13
+ **NEVER** merge multiple phases into a single card without explicit user consent. **Why:** timelines, ownership, and "done" blur; violates one-card-one-phase default.
14
+
15
+ **NEVER** bury **Pre-flight / prerequisites** inside a random block. **Why:** skipped baselines cause false "blocked" churn; baseline always tops the checklist.
16
+
17
+ ---
18
+
19
+ ## Honesty about sources
20
+
21
+ **NEVER** present **inferred** goals, prerequisites, verification, or out-of-scope as if they appeared in the plan. **Why:** teammates act on fiction. Tag with `(inferred)` or state in conversational wrapper: "Plan had no Done when — verification derived from tasks."
22
+
23
+ **NEVER** invent file paths or spec links not present in the plan. **Why:** stale links wreck trust; use placeholders only if unavoidable: `[link TBD]` and say why.
24
+
25
+ ---
26
+
27
+ ## Paste-ready output
28
+
29
+ **NEVER** put meta-commentary (**"I'll now…"**, rationale paragraphs) **inside** the titled blocks (`TITLE`, `DESCRIPTION`, checklist sections meant for paste). **Why:** pollutes tooling fields. Keep prose **before or after** the paste blocks only.
30
+
31
+ **NEVER** use vague verification lines like `"tests pass"` without naming **which** command or scope. **Why:** unmeasurable; use concrete commands (`pnpm test`, `pytest apps/api/...`) from the plan or mark `(add command)`.
32
+
33
+ ---
34
+
35
+ ## Estimates & sizing
36
+
37
+ **NEVER** report a single point estimate as certainty (e.g. "4h exactly"). **Why:** AI-assisted variance is wide; stick to optimistic — realistic range and optional buffer narrative.
38
+
39
+ **NEVER** apply the tier table blindly to spikes, migrations, or "unknown-unknown" chunks. **Why:** those need **XL** or explicit `"too uncertain — spike first"` flag in timeline notes.
40
+
41
+ ---
42
+
43
+ ## Scale
44
+
45
+ **NEVER** put **100+** checkbox items on one card when blocks exist. **Why:** defeats tracking; split by block per SKILL.md parent/child guidance.
46
+
47
+ ---
48
+
49
+ ## Conflicting or missing input
50
+
51
+ **NEVER** silently pick a phase when multiple plan files apply. **Why:** wrong scope. Prefer: list candidates, recommend one default, confirm.
52
+
53
+ **NEVER** output an empty checklist because the plan "reads like prose". **Why:** salvage with inferred task bullets or ask one clarifying question before shipping empty.
54
+
55
+ **NEVER** invent a **Goal** or **Done when** for task-only plans (no Goal / verification section) without tagging **`(inferred)`** in the conversational wrapper. **Why:** prose-only plans look complete but aren't; teammates treat invented goals as authoritative. Derive from dominant theme / last tasks and say so explicitly.
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@llodev/pm-tasks-core",
3
+ "version": "1.0.0",
4
+ "description": "Core skill for the pm-tasks-* family: extracts implementation plans into structured task content, defines the CRUD vocabulary (task.create, checklist.check, task.close, task.due-date.set, task.assignee.add, task.comment.add), specifies the autonomous-mode contract, and provides the shared init UX library for tool adapters. Use when an adapter (pm-tasks-trello, pm-tasks-asana, etc.) needs the canonical generic-card structure or when running the init helper for any tool.",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/llodev/skills/tree/main/pm-tasks/pm-tasks-core",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/llodev/skills.git",
10
+ "directory": "pm-tasks/pm-tasks-core"
11
+ },
12
+ "files": [
13
+ "SKILL.md",
14
+ "references",
15
+ "anti-patterns",
16
+ "scripts",
17
+ "LICENSE",
18
+ "README.md",
19
+ "CHANGELOG.md"
20
+ ],
21
+ "keywords": [
22
+ "agent-skill",
23
+ "claude-code",
24
+ "cursor",
25
+ "codex",
26
+ "windsurf",
27
+ "plan-to-tasks",
28
+ "pm-tools"
29
+ ],
30
+ "type": "module",
31
+ "exports": {
32
+ "./init-lib": "./scripts/init-lib.mjs"
33
+ },
34
+ "engines": {
35
+ "node": ">=20"
36
+ },
37
+ "dependencies": {
38
+ "ajv": "^8.17.1",
39
+ "ajv-formats": "^3.0.1"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ # Audit log format
2
+
3
+ Append-only JSONL at `~/.local/share/llodev/pm-tasks/<tool>/audit.log` (configurable via `autonomous.auditLog`).
4
+
5
+ ## Required fields (every entry)
6
+
7
+ | Field | Type | Notes |
8
+ | --------- | ------- | ----------------------------------------------------------------------- |
9
+ | `ts` | string | ISO 8601 with timezone |
10
+ | `verb` | string | one of the 6 CRUD verbs |
11
+ | `tool` | string | `trello`, `asana`, etc. |
12
+ | `ok` | boolean | success of the operation |
13
+ | `session` | string | caller-provided session id (defaults to a random short id when missing) |
14
+
15
+ ## Verb-dependent fields
16
+
17
+ | Verb | Additional |
18
+ | ------------------- | --------------------------------------------------------- |
19
+ | `task.create` | `id`, `url`, `name`, `clientToken?`, `scope.{board,list}` |
20
+ | `checklist.check` | `id`, `item` |
21
+ | `task.close` | `id` |
22
+ | `task.due-date.set` | `id`, `due` |
23
+ | `task.assignee.add` | `id`, `userAlias` |
24
+ | `task.comment.add` | `id`, `commentId`, `clientToken?` |
25
+
26
+ ## Example
27
+
28
+ ```jsonl
29
+ {"ts":"2026-06-11T18:00:00Z","verb":"task.create","tool":"trello","ok":true,"id":"abc123","url":"https://trello.com/c/abc123/...","name":"Implementar feature X","clientToken":"ct-xyz","scope":{"board":"proj-x","list":"backlog"},"session":"sess-001"}
30
+ {"ts":"2026-06-11T18:05:00Z","verb":"checklist.check","tool":"trello","ok":true,"id":"abc123","item":"build endpoint","session":"sess-001"}
31
+ {"ts":"2026-06-11T18:10:00Z","verb":"task.close","tool":"trello","ok":true,"id":"abc123","session":"sess-001"}
32
+ ```
33
+
34
+ ## Concurrency
35
+
36
+ Single-line JSON writes < 4KB are atomic at OS level on Linux/macOS. Multiple agents in parallel do not corrupt. No locks.
37
+
38
+ ## Rotation
39
+
40
+ `pm-tasks/pm-tasks-core/scripts/rotate-audit.sh` purges entries older than 90 days. Suggested cron entry in this file's README.
41
+
42
+ ## Lookup usage
43
+
44
+ The log doubles as the lookup index for `<task-ref>` resolution steps 4–5. Adapter implementations scan from newest to oldest, filter by `scope.boards`, match `clientToken` or name partial.
@@ -0,0 +1,61 @@
1
+ # Autonomous mode
2
+
3
+ Operations executed without a human reviewing each step. Designed for invocation by AI agents during task execution.
4
+
5
+ ## Activation (three signals)
6
+
7
+ 1. **Prompt sentinel** — caller includes `[autonomous]` or `--auto` literally.
8
+ 2. **Env var** — `LLODEV_PM_TASKS_AUTONOMOUS=1` (for CI / cron).
9
+ 3. **Never inferred.** Without sentinel or env, preview + human approval is mandatory.
10
+
11
+ ## Allowlist gate (in tool config)
12
+
13
+ Autonomous mode requires an `autonomous` block in `.<tool>.json` (or its global counterpart):
14
+
15
+ ```json
16
+ {
17
+ "autonomous": {
18
+ "enabled": true,
19
+ "allow": ["task.create", "checklist.check", "task.close", "task.due-date.set", "task.assignee.add", "task.comment.add"],
20
+ "scope": {
21
+ "boards": ["<board-or-project-id>"],
22
+ "lists": ["<list-or-section-id>"]
23
+ },
24
+ "rateLimit": { "writesPerMinute": 30, "commentsPerMinute": 10 },
25
+ "auditLog": "~/.local/share/llodev/pm-tasks/<tool>/audit.log"
26
+ }
27
+ }
28
+ ```
29
+
30
+ Block missing OR `enabled: false` → autonomous aborts with `{ ok: false, code: "INVALID_CONFIG" }`.
31
+ Verb not in `allow` → `{ code: "ALLOWLIST_VIOLATION" }`.
32
+ Target outside `scope` → `{ code: "OUT_OF_SCOPE" }`.
33
+ Rate exceeded → `{ code: "RATE_LIMITED" }`.
34
+
35
+ ## Hard-coded forbidden verbs (v1)
36
+
37
+ Regardless of allowlist:
38
+
39
+ - `task.delete`, `task.archive`
40
+ - `task.rename`
41
+ - `task.description.replace`
42
+ - `task.assignee.remove`, any `member.remove`
43
+ - Any operation outside `scope`
44
+
45
+ Returns `{ code: "FORBIDDEN_VERB" }` without touching MCP.
46
+
47
+ ## Write-through flow
48
+
49
+ - Skip Phase 5.x preview & approval.
50
+ - Run allowlist + scope + rate-limit checks.
51
+ - Call MCP write tool.
52
+ - Emit structured envelope to caller (JSON, not human-formatted).
53
+ - Append entry to audit log per [`audit-log-format.md`](audit-log-format.md).
54
+
55
+ ## Failure handling
56
+
57
+ Any failure → structured envelope. Skill does NOT auto-retry. Caller decides retry/abort/escalate. If the verb supports `clientToken`, caller can safely retry the exact same call (will be deduped).
58
+
59
+ ## Forensics
60
+
61
+ The audit log is the source of truth for "what happened in this autonomous session". Also serves as the lookup index for `taskRef` step 4–5 in [`crud-vocabulary.md`](crud-vocabulary.md).
@@ -0,0 +1,90 @@
1
+ # pm-tasks-core ↔ adapter contract
2
+
3
+ > **Versioning:** Renaming or removing a field below is a **MAJOR** bump for `@llodev/pm-tasks-core`. Adding optional fields is a minor bump. CI `contract-check.yml` enforces this.
4
+
5
+ This document is the single source of truth that every `pm-tasks-<tool>` adapter consumes. Adapters MUST execute Phases 1–3 (defined here) before applying their tool-specific formatting.
6
+
7
+ ## Phase 1 — Identify the input
8
+
9
+ Resolve which plan text to analyze:
10
+
11
+ 1. `@path` in the prompt → read that file (full file, no range limits).
12
+ 2. Inline pasted text → use as-is.
13
+ 3. "this plan" / implicit → most recently opened plan file in the workspace.
14
+
15
+ Multiple plausible candidates → list them, recommend one default, confirm before proceeding.
16
+
17
+ ## Phase 2 — Extract sections by intent
18
+
19
+ Map sections by intent (labels vary across languages and authoring styles):
20
+
21
+ | Concept | Common labels |
22
+ | ------------- | ---------------------------------------------------------- |
23
+ | Goal | `Goal`, `Objective`, `Purpose` |
24
+ | Spec refs | `Spec:`, `Design doc`, links to spec files |
25
+ | Prerequisites | `Pre-flight`, `Requirements`, `Baseline check` |
26
+ | File map | `File map`, `Files created/modified`, `Deliverables` |
27
+ | Tasks | `## Task N`, `### Task N`, numbered blocks |
28
+ | Task groups | `## Block A`, thematic headers grouping tasks |
29
+ | Done criteria | `Done when`, `Self-review checklist`, `Final verification` |
30
+ | Out of scope | `Out of scope`, `What comes after` |
31
+ | Next step | `What comes after`, `Phase N+1`, `Next phase` |
32
+
33
+ Implicit sections → infer from structure. Tasks-only inputs → derive goal from first block, derive verification from last tasks, tag everything inferred with `(inferred)`.
34
+
35
+ ## Phase 3 — Build the generic card
36
+
37
+ Produce blocks in the order defined in [`generic-card.md`](generic-card.md):
38
+
39
+ 1. `title` — single line, ≤120 chars by default
40
+ 2. `description` — goal + context + spec ref
41
+ 3. `implementationChecklist` — task-line verbatim or compressed per `fidelity` decision
42
+ 4. `verificationChecklist` — derived from done-when or last tasks
43
+ 5. `timeline` — AI-assisted estimate
44
+ 6. `labels` — derived from tags in the plan
45
+
46
+ ## Decisions emitted by the core
47
+
48
+ The core resolves and exposes these decisions before Phase 4 begins. Adapters reference them by name:
49
+
50
+ | Decision | Values | Default |
51
+ | ---------- | ------------------------------------------------------ | -------------------- |
52
+ | `scope` | `one-card-per-phase`, `parent+children`, `single-card` | `one-card-per-phase` |
53
+ | `audience` | `solo`, `squad`, `dense-board` | `solo` |
54
+ | `fidelity` | `verbatim`, `compressed` | `compressed` |
55
+ | `language` | `pt`, `en`, `mixed` | detected from plan |
56
+
57
+ ## CRUD verb vocabulary
58
+
59
+ The 6 verbs of v1, with their semantic invariants and idempotency rules, live in [`crud-vocabulary.md`](crud-vocabulary.md). Adapters map each verb to one or more MCP tool calls.
60
+
61
+ ## Result envelope
62
+
63
+ Every CRUD operation returns:
64
+
65
+ ```json
66
+ {
67
+ "ok": true,
68
+ "verb": "<verb>",
69
+ "tool": "<tool>",
70
+ "ref": { "id": "<native-id>", "url": "<full-url>", "alias": "<alias-or-null>" },
71
+ "details": { /* verb-specific */ }
72
+ }
73
+ ```
74
+
75
+ Failures:
76
+
77
+ ```json
78
+ { "ok": false, "code": "<CODE>", "verb": "<verb>", "message": "<human>", "details": { } }
79
+ ```
80
+
81
+ Stable error codes: `FORBIDDEN_VERB`, `OUT_OF_SCOPE`, `ALLOWLIST_VIOLATION`, `RATE_LIMITED`, `REF_NOT_RESOLVED`, `MCP_ERROR`, `INVALID_CONFIG`.
82
+
83
+ ## Standalone fallback
84
+
85
+ Adapters MUST include a short fallback section in their own `SKILL.md` (~10 lines) for when this core is not installed: ask user for minimum input (title + checklist), skip extraction.
86
+
87
+ ## Compatibility notes for adapters
88
+
89
+ - Reference this file by relative path: `pm-tasks/pm-tasks-core/references/contract.md`.
90
+ - Declare `"@llodev/pm-tasks-core"` in `dependencies` for skillpm + Claude Code marketplace cascade. Vercel CLI users must install core manually — note this in the adapter description.
@@ -0,0 +1,63 @@
1
+ # CRUD vocabulary (v1)
2
+
3
+ Six verbs. Each adapter maps every verb to one or more MCP tool calls.
4
+
5
+ ## task.create
6
+
7
+ Create a new task/card/issue from a generic-card spec.
8
+
9
+ - **Inputs:** `genericCard` (per `generic-card.md`), `targetList` (alias from config), `clientToken?` (opaque idempotency key).
10
+ - **Idempotency:** Before creating, search the target scope for any task with matching `clientToken`. If found, return existing ref. Token persistence per tool documented in adapter `operations.md`.
11
+ - **Returns:** envelope with `ref.{id,url}`.
12
+
13
+ ## checklist.check
14
+
15
+ Mark a checklist item / subtask as complete.
16
+
17
+ - **Inputs:** `taskRef`, `item` (text or index), `checklistName?` (when task has multiple).
18
+ - **Idempotency:** natural (no-op if already checked).
19
+ - **Returns:** envelope.
20
+
21
+ ## task.close
22
+
23
+ Close / move to done.
24
+
25
+ - **Inputs:** `taskRef`.
26
+ - **Adapter semantics:** Trello → move to `closeListAlias`. Asana → `completed: true`. Linear → state `completed`. Notion → status `Done`. Bitrix24 → status `5`. Todoist → `close`.
27
+ - **Idempotency:** natural.
28
+
29
+ ## task.due-date.set
30
+
31
+ Set or change due date.
32
+
33
+ - **Inputs:** `taskRef`, `due` (ISO 8601 date or `null` to clear).
34
+ - **Idempotency:** no-op if value matches.
35
+
36
+ ## task.assignee.add
37
+
38
+ Add an assignee/member to a task. v1 NEVER removes.
39
+
40
+ - **Inputs:** `taskRef`, `userAlias` (from config `members`).
41
+ - **Idempotency:** adapter checks current assignees before MCP call.
42
+
43
+ ## task.comment.add
44
+
45
+ Post a comment / note / story.
46
+
47
+ - **Inputs:** `taskRef`, `body`, `clientToken?`.
48
+ - **Idempotency:** body is prefixed with `[ct:<clientToken>]` if provided. Adapter scans recent comments for matching token before posting.
49
+
50
+ ## Verbs forbidden in autonomous mode (v1, hard-coded)
51
+
52
+ `task.delete`, `task.archive`, `task.rename`, `task.description.replace`, `task.assignee.remove`, any `member.remove`, and any operation targeting a board/project outside the declared autonomous `scope`.
53
+
54
+ ## `<task-ref>` resolution order
55
+
56
+ Adapters resolve `taskRef` in this order, stopping at first success:
57
+
58
+ 1. Full task URL.
59
+ 2. Native ID.
60
+ 3. Alias in config `taskAliases`.
61
+ 4. `clientToken` match in audit log (most recent).
62
+ 5. Name partial match in audit log scoped to `autonomous.scope` (most recent).
63
+ 6. Otherwise → `{ ok: false, code: "REF_NOT_RESOLVED", candidates: [...] }`.
@@ -0,0 +1,143 @@
1
+ ---
2
+ description: Tool-agnostic card blocks (title, description, checklists, timeline, labels) for pm-tasks-core Phase 3. Read entire file before building paste blocks.
3
+ ---
4
+
5
+ # Generic card blocks (Phase 3)
6
+
7
+ > This file is referenced by every `pm-tasks-<tool>` adapter. Changes here may affect all adapters — coordinate via Changesets.
8
+
9
+ Produce the following blocks **in order**. Adapt section names in Phase 4 per tool (see the adapter's `references/format.md`).
10
+
11
+ For **paste/rendering** when a named tool is chosen, apply the adapter's paste-health rules during Phase 4 — not while drafting generic blocks.
12
+
13
+ ---
14
+
15
+ ## Title
16
+
17
+ Pattern: `[System/Area] — [Phase N] ([short summary of what's built])`
18
+
19
+ Max 80 characters. Examples:
20
+
21
+ - `API Scaffold — Phase 1 (NestJS + shared wiring)`
22
+ - `Celebrations BC — Phase 3 (domain + contracts + HTTP)`
23
+
24
+ ---
25
+
26
+ ## Description
27
+
28
+ ```
29
+ **Goal:** [one sentence from the plan's goal, translated to plain language]
30
+
31
+ **Spec:** [file or document reference]
32
+ **Plan:** [file or document reference]
33
+ **Prerequisite:** [phase or condition that must be true before starting]
34
+
35
+ ---
36
+
37
+ **Deliverables**
38
+ • [artifact 1]
39
+ • [artifact 2]
40
+ (group by layer/area if more than 7 items)
41
+
42
+ ---
43
+
44
+ **Out of scope**
45
+ • [explicitly deferred item 1]
46
+ • [item 2]
47
+
48
+ **Next step**
49
+ **[Phase N+1 or follow-up name]** — [one sentence]
50
+ ```
51
+
52
+ - Use `**Section**` labels (not `##`) when formatting for tools that flatten Markdown headings on paste.
53
+ - **Publish flows (Phase 5+):** the adapter decides whether to omit **Out of scope** / **Next step** from `desc` / `html_notes` — see the adapter's `references/format.md`.
54
+ - **Generic paste:** include Out of scope and Next step unless the user asks to drop them.
55
+
56
+ ---
57
+
58
+ ## Implementation checklist
59
+
60
+ Structure:
61
+
62
+ ```
63
+ ### Pre-flight
64
+ - [ ] [prerequisite check 1]
65
+ - [ ] [prerequisite check 2]
66
+
67
+ ### [Block or Group name] (Tasks N–M)
68
+ - [ ] Task N — [action verb] + [artifact] [(skill or note if relevant)]
69
+ - [ ] Task N+1 — ...
70
+
71
+ ### [Next block]
72
+ ...
73
+ ```
74
+
75
+ Rules:
76
+
77
+ - One checkbox per task, not per step. Steps live inside the plan, not the card.
78
+ - If a task includes a skill invocation, note it: `(skill: ts-ddd-entity)`
79
+ - If a plan has no explicit blocks, group tasks by layer: setup, domain, application, infra, http, docs.
80
+ - Pre-flight (baseline verification) always comes first.
81
+
82
+ ---
83
+
84
+ ## Verification checklist
85
+
86
+ Draw from the plan's `Done when` / `Self-review checklist` / `Final verification` section.
87
+
88
+ ```
89
+ ### Verification
90
+
91
+ - [ ] [test command] — passes
92
+ - [ ] [build command] — exits 0
93
+ - [ ] [runtime check] (e.g. curl localhost:3001/health returns expected payload)
94
+ - [ ] [security/quality check] (e.g. no secrets staged, no forbidden imports)
95
+ - [ ] [git hygiene check] (e.g. N commits, one per task)
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Timeline estimate
101
+
102
+ Estimate calendar time for a developer using AI assistance (Claude, Cursor, Copilot, etc.).
103
+
104
+ **Complexity tiers per task:**
105
+
106
+ | Tier | Description | AI-assisted estimate |
107
+ | ------------------ | -------------------------------------------- | -------------------- |
108
+ | S — Setup/config | Files, manifests, workspace wiring | 10–20 min |
109
+ | M — Standard TDD | Write test → implement → pass | 20–45 min |
110
+ | L — Complex domain | Entity/aggregate with invariants, many tests | 45–90 min |
111
+ | XL — Large block | 4+ related tasks sharing the same fixture | 1.5–3 h |
112
+ | Docs | README, inline docs, layout updates | 10–20 min |
113
+
114
+ **Estimation formula:**
115
+
116
+ 1. Classify each task by tier.
117
+ 2. Sum the estimates.
118
+ 3. Add 20% buffer for integration, context-switching, and debugging.
119
+ 4. Round to a practical unit (hours or days).
120
+ 5. Present a range: `optimistic — realistic`.
121
+
122
+ **Format:**
123
+
124
+ ```
125
+ ### Estimated timeline (AI-assisted)
126
+
127
+ | Scope | Estimate |
128
+ | ------------------------------------------- | ----------------------- |
129
+ | Optimistic (focused session, no blockers) | Xh |
130
+ | Realistic (normal day, some back-and-forth) | Xh / X days |
131
+ | Task count | N tasks across N blocks |
132
+
133
+ > Timeline assumes a developer with AI assistance (Claude/Cursor/Copilot).
134
+ > Solo (no AI): multiply by 3–5×.
135
+ ```
136
+
137
+ Generic output may keep the timeline **as Markdown table**. Adapters may flatten or relocate the table during Phase 4 per their paste-health rules in the adapter's `references/format.md`.
138
+
139
+ ---
140
+
141
+ ## Labels / Tags
142
+
143
+ Suggest **3–6** from plan context: phase, domain/layer (`api`, `web`, …), status, size tier from timeline tiers. Apply the adapter's label palette and caps (defined in the adapter's `references/format.md`).
@@ -0,0 +1,62 @@
1
+ # Init UX (shared across pm-tasks-<tool> adapters)
2
+
3
+ Every `pm-tasks-<tool>` adapter exposes `npx @llodev/pm-tasks-<tool> init` and follows this four-step flow. Implementation library at `pm-tasks/pm-tasks-core/scripts/init-lib.mjs`.
4
+
5
+ ## Step 1 — Scope prompt
6
+
7
+ ```
8
+ Where should the config live?
9
+ > local → ./.{tool}.json (per-repo override)
10
+ global → ~/.config/llodev/pm-tasks/{tool}.json
11
+ ```
12
+
13
+ Default highlight: `local` if inside a git repo, `global` otherwise.
14
+
15
+ ## Step 2 — MCP auto-detect
16
+
17
+ Adapter probes the tool's MCP with the lightest read operation:
18
+
19
+ - Trello → `list_boards`
20
+ - Asana → `list_workspaces`
21
+ - Linear → `viewer`
22
+ - Notion → `users.me`
23
+ - ...
24
+
25
+ Three outcomes:
26
+
27
+ | Outcome | Action |
28
+ | ------------------------------ | ------------------------------------------------------------------------- |
29
+ | MCP responded | Go to Step 3A (MCP-assisted). |
30
+ | MCP exists but unauthenticated | Print exact env var names (`LLODEV_PM_TASKS_<TOOL>_<NAME>`) to set, exit. |
31
+ | MCP not configured | Print MCP setup instructions for the adapter, go to Step 3B (scaffold). |
32
+
33
+ ## Step 3A — MCP-assisted (happy path)
34
+
35
+ Read-only MCP calls enumerate workspace → boards/projects → lists/sections → labels → members. User picks via interactive prompts (multi-select for arrays).
36
+
37
+ Final prompt: *"Enable autonomous mode? (adds an `autonomous` block with conservative defaults: 6 verbs, rate 30/min, no hard-coded scope — you add it afterwards)"* — default `n`.
38
+
39
+ Write the config; validate against `schemas/config.json`; exit.
40
+
41
+ ## Step 3B — Scaffold (fallback)
42
+
43
+ Write `.{tool}.json` with placeholders and inline `// comments` showing where to find each ID. Print MCP setup instructions referencing the adapter's `references/mcp-config.md`. Exit.
44
+
45
+ ## Step 4 — Confirmation
46
+
47
+ Print:
48
+
49
+ - Path written
50
+ - Schema validation result
51
+ - Sample trigger prompt the user can paste (`"create a card on <tool> from this plan"`)
52
+ - Reminder: secrets go in env vars or OS keychain, NEVER in this JSON.
53
+
54
+ ## Implementation API (consumed by adapters)
55
+
56
+ Adapter `scripts/init.mjs` imports from `@llodev/pm-tasks-core/init-lib`:
57
+
58
+ ```javascript
59
+ import { promptScope, promptYesNo, multiSelect, writeConfig, validateConfig, probeMCP, printInstructions } from "@llodev/pm-tasks-core/init-lib";
60
+ ```
61
+
62
+ Each adapter implements its own MCP-probing logic and field-mapping; UX primitives are shared.
@@ -0,0 +1,88 @@
1
+ // @llodev/pm-tasks-core/init-lib
2
+ // Shared init primitives. Node 20+ built-ins + Ajv for schema validation.
3
+ import { createInterface } from "node:readline/promises";
4
+ import { stdin as input, stdout as output } from "node:process";
5
+ import { mkdir, writeFile, access, readFile } from "node:fs/promises";
6
+ import { homedir } from "node:os";
7
+ import path from "node:path";
8
+
9
+ const rl = () => createInterface({ input, output });
10
+
11
+ export async function promptScope(toolName) {
12
+ const r = rl();
13
+ try {
14
+ console.log(`\nWhere should the ${toolName} config live?\n 1) local → ./.${toolName}.json\n 2) global → ~/.config/llodev/pm-tasks/${toolName}.json`);
15
+ const a = (await r.question("Choose [1/2] (default 1): ")).trim() || "1";
16
+ if (a === "1") return { scope: "local", path: path.resolve(`.${toolName}.json`) };
17
+ if (a === "2") return { scope: "global", path: path.join(homedir(), ".config", "llodev", "pm-tasks", `${toolName}.json`) };
18
+ throw new Error(`invalid choice: ${a}`);
19
+ } finally { r.close(); }
20
+ }
21
+
22
+ export async function promptYesNo(question, defaultNo = true) {
23
+ const r = rl();
24
+ try {
25
+ const a = (await r.question(`${question} [y/N]: `)).trim().toLowerCase();
26
+ if (a === "y" || a === "yes") return true;
27
+ return false;
28
+ } finally { r.close(); }
29
+ }
30
+
31
+ export async function multiSelect(label, choices) {
32
+ const r = rl();
33
+ try {
34
+ console.log(`\n${label}`);
35
+ choices.forEach((c, i) => console.log(` ${i + 1}) ${c.label}`));
36
+ const a = (await r.question("Select (comma-separated, e.g. 1,3,5): ")).trim();
37
+ const picks = a.split(",").map((x) => parseInt(x.trim(), 10) - 1).filter((i) => i >= 0 && i < choices.length);
38
+ return picks.map((i) => choices[i].value);
39
+ } finally { r.close(); }
40
+ }
41
+
42
+ export async function writeConfig(targetPath, data) {
43
+ await mkdir(path.dirname(targetPath), { recursive: true });
44
+ try { await access(targetPath); throw new Error(`config already exists at ${targetPath}, aborting`); } catch (e) {
45
+ if (e.code !== "ENOENT") throw e;
46
+ }
47
+ await writeFile(targetPath, JSON.stringify(data, null, 2) + "\n");
48
+ }
49
+
50
+ export async function validateConfig(data, schema) {
51
+ // Adapter loads its own schemas/config.json and passes it here for validation.
52
+ const { default: Ajv2020 } = await import("ajv/dist/2020.js");
53
+ const { default: addFormats } = await import("ajv-formats");
54
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
55
+ addFormats(ajv);
56
+ const validate = ajv.compile(schema);
57
+ if (!validate(data)) {
58
+ return { ok: false, errors: validate.errors };
59
+ }
60
+ return { ok: true };
61
+ }
62
+
63
+ export async function probeMCP({ tool, probeCommand }) {
64
+ // Caller-supplied async probe function; library only sequences UX.
65
+ try {
66
+ const result = await probeCommand();
67
+ return { mcpAvailable: true, result };
68
+ } catch (e) {
69
+ if (/^auth\b|\b(unauthorized|forbidden)\b|\b40[13]\b/i.test(e.message)) {
70
+ return { mcpAvailable: true, unauthenticated: true, error: e.message };
71
+ }
72
+ return { mcpAvailable: false, error: e.message };
73
+ }
74
+ }
75
+
76
+ export function printInstructions(lines) {
77
+ console.log(`\n${lines.join("\n")}\n`);
78
+ }
79
+
80
+ export async function readJsonIfExists(p) {
81
+ try {
82
+ const src = await readFile(p, "utf8");
83
+ return JSON.parse(src);
84
+ } catch (e) {
85
+ if (e.code === "ENOENT") return null;
86
+ throw e;
87
+ }
88
+ }
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ # Rotate audit log for a given tool. Keeps last 90 days.
3
+ set -euo pipefail
4
+
5
+ TOOL="${1:-}"
6
+ if [[ -z "$TOOL" ]]; then
7
+ echo "usage: rotate-audit.sh <tool>"
8
+ echo "example: rotate-audit.sh trello"
9
+ exit 2
10
+ fi
11
+
12
+ LOG_DIR="${LLODEV_PM_TASKS_LOG_DIR:-$HOME/.local/share/llodev/pm-tasks}/$TOOL"
13
+ LOG="$LOG_DIR/audit.log"
14
+ KEEP_DAYS="${KEEP_DAYS:-90}"
15
+
16
+ [[ ! -f "$LOG" ]] && { echo "(no log at $LOG, nothing to rotate)"; exit 0; }
17
+
18
+ CUTOFF=$(date -u -v -"${KEEP_DAYS}"d +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d "${KEEP_DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)
19
+ TMP="$(mktemp)"
20
+
21
+ awk -v cutoff="$CUTOFF" 'match($0, /"ts":"([^"]+)"/, m) { if (m[1] >= cutoff) print }' "$LOG" > "$TMP"
22
+
23
+ mv "$TMP" "$LOG"
24
+ echo "rotated $LOG (kept entries >= $CUTOFF)"