@brainervirus/workit-core 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +180 -0
- package/commands/wk-changelog.md +2 -0
- package/commands/wk-commit.md +2 -0
- package/commands/wk-docs-refresh.md +2 -0
- package/commands/wk-handoff.md +2 -0
- package/commands/wk-implement.md +2 -0
- package/commands/wk-init.md +2 -0
- package/commands/wk-issue-update.md +2 -0
- package/commands/wk-meetings.md +2 -0
- package/commands/wk-pr.md +2 -0
- package/commands/wk-release-notes.md +2 -0
- package/commands/wk-status.md +2 -0
- package/commands/wk-verify.md +2 -0
- package/package.json +43 -0
- package/scripts/_shared/common.sh +158 -0
- package/scripts/changelog-context.sh +42 -0
- package/scripts/docs-refresh-context.sh +40 -0
- package/scripts/fixtures/sample-plan.md +15 -0
- package/scripts/fixtures/sample-sdd/progress.md +2 -0
- package/scripts/init/apply.sh +5 -0
- package/scripts/init/status.sh +5 -0
- package/scripts/init/toolkit-status.sh +5 -0
- package/scripts/install-cursor-plugin.sh +83 -0
- package/scripts/install-opencode-plugin.sh +76 -0
- package/scripts/pr-create.sh +5 -0
- package/scripts/pr-ready-context.sh +88 -0
- package/scripts/present/ascii-wireframe.sh +5 -0
- package/scripts/present/flow-diagram.sh +5 -0
- package/scripts/release-notes-context.sh +40 -0
- package/scripts/rewrite-workspace-deps.ts +17 -0
- package/scripts/run-cursor-mcp.sh +10 -0
- package/scripts/sync-runtime.sh +96 -0
- package/scripts/update-superpowers.sh +56 -0
- package/scripts/vcs/config.sh +5 -0
- package/scripts/vcs/merged-style.sh +5 -0
- package/scripts/vcs/token-create-urls.sh +5 -0
- package/scripts/vcs/verify-token.sh +5 -0
- package/scripts/verify-project.sh +140 -0
- package/scripts/youtrack/api.sh +5 -0
- package/scripts/youtrack/config.sh +5 -0
- package/scripts/youtrack/greeting.sh +5 -0
- package/scripts/youtrack/parse-duration.sh +5 -0
- package/scripts/youtrack/token-create-url.sh +5 -0
- package/scripts/youtrack/verify-token.sh +5 -0
- package/scripts/youtrack/work-date-ms.sh +5 -0
- package/skills/wk-changelog/SKILL.md +15 -0
- package/skills/wk-commit/SKILL.md +16 -0
- package/skills/wk-docs-refresh/SKILL.md +15 -0
- package/skills/wk-handoff/SKILL.md +17 -0
- package/skills/wk-implement/SKILL.md +41 -0
- package/skills/wk-init/SKILL.md +31 -0
- package/skills/wk-issue-update/SKILL.md +27 -0
- package/skills/wk-issue-update/references/youtrack-update-style.md +81 -0
- package/skills/wk-meetings/SKILL.md +17 -0
- package/skills/wk-pr/SKILL.md +27 -0
- package/skills/wk-release-notes/SKILL.md +15 -0
- package/skills/wk-status/SKILL.md +16 -0
- package/skills/wk-verify/SKILL.md +16 -0
- package/src/core/branch.ts +246 -0
- package/src/core/changelog.ts +312 -0
- package/src/core/config-guard.ts +26 -0
- package/src/core/config.ts +73 -0
- package/src/core/detector.ts +207 -0
- package/src/core/doc-render.ts +14 -0
- package/src/core/docs-repo.ts +196 -0
- package/src/core/docs-validate.ts +255 -0
- package/src/core/flow-state.ts +225 -0
- package/src/core/git.ts +56 -0
- package/src/core/gitignore.ts +43 -0
- package/src/core/handoff-context.ts +115 -0
- package/src/core/hygiene.ts +77 -0
- package/src/core/init.ts +443 -0
- package/src/core/parse-sections.ts +24 -0
- package/src/core/plan-tasks.ts +33 -0
- package/src/core/ports/init-apply.ts +15 -0
- package/src/core/ports/init-status.ts +4 -0
- package/src/core/ports/init-toolkit-status.ts +4 -0
- package/src/core/ports/pr-create.ts +22 -0
- package/src/core/ports/present-ascii.ts +10 -0
- package/src/core/ports/present-flow.ts +10 -0
- package/src/core/ports/vcs-config.ts +14 -0
- package/src/core/ports/vcs-merged-style.ts +5 -0
- package/src/core/ports/vcs-token-create-urls.ts +4 -0
- package/src/core/ports/vcs-verify-token.ts +4 -0
- package/src/core/ports/youtrack-api.ts +17 -0
- package/src/core/ports/youtrack-config.ts +23 -0
- package/src/core/ports/youtrack-greeting.ts +10 -0
- package/src/core/ports/youtrack-parse-duration.ts +14 -0
- package/src/core/ports/youtrack-token-create-url.ts +4 -0
- package/src/core/ports/youtrack-verify-token.ts +12 -0
- package/src/core/ports/youtrack-work-date-ms.ts +10 -0
- package/src/core/pr-create.ts +212 -0
- package/src/core/present.ts +100 -0
- package/src/core/reminder.ts +82 -0
- package/src/core/repo-tool.ts +9 -0
- package/src/core/rules.ts +122 -0
- package/src/core/scripts.ts +42 -0
- package/src/core/sdd.ts +188 -0
- package/src/core/templates.ts +37 -0
- package/src/core/vcs-config.ts +252 -0
- package/src/core/verify-parse.ts +27 -0
- package/src/core/workspaces.ts +81 -0
- package/src/core/youtrack.ts +488 -0
- package/src/core.ts +62 -0
- package/src/state.ts +22 -0
- package/src/tools/docs-repo.ts +42 -0
- package/src/tools/flow.ts +88 -0
- package/src/tools/handoff.ts +160 -0
- package/src/tools/index.ts +22 -0
- package/src/tools/present.ts +45 -0
- package/src/tools/repo.ts +357 -0
- package/src/tools/rules.ts +30 -0
- package/src/tools/sdd.ts +189 -0
- package/src/tools/templates.ts +27 -0
- package/src/tools/youtrack.ts +356 -0
- package/templates/execution-contract.md +56 -0
- package/templates/greeting.md +1 -0
- package/templates/headers.md +3 -0
- package/templates/hygiene/.editorconfig +8 -0
- package/templates/hygiene/.gitattributes +3 -0
- package/templates/hygiene/CHANGELOG.md +14 -0
- package/templates/hygiene/CONTRIBUTING.md +3 -0
- package/templates/hygiene/LICENSE +21 -0
- package/templates/hygiene/README.md +3 -0
- package/templates/issue-update.md +6 -0
- package/templates/plan-template.md +25 -0
- package/templates/spec-template.md +51 -0
- package/templates/superpowers-doc-contract.md +69 -0
- package/vendor/superpowers/skills/brainstorming/SKILL.md +159 -0
- package/vendor/superpowers/skills/brainstorming/scripts/frame-template.html +213 -0
- package/vendor/superpowers/skills/brainstorming/scripts/helper.js +167 -0
- package/vendor/superpowers/skills/brainstorming/scripts/server.cjs +723 -0
- package/vendor/superpowers/skills/brainstorming/scripts/start-server.sh +209 -0
- package/vendor/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -0
- package/vendor/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/vendor/superpowers/skills/brainstorming/visual-companion.md +291 -0
- package/vendor/superpowers/skills/dispatching-parallel-agents/SKILL.md +185 -0
- package/vendor/superpowers/skills/executing-plans/SKILL.md +70 -0
- package/vendor/superpowers/skills/finishing-a-development-branch/SKILL.md +241 -0
- package/vendor/superpowers/skills/receiving-code-review/SKILL.md +213 -0
- package/vendor/superpowers/skills/requesting-code-review/SKILL.md +103 -0
- package/vendor/superpowers/skills/requesting-code-review/code-reviewer.md +172 -0
- package/vendor/superpowers/skills/subagent-driven-development/SKILL.md +418 -0
- package/vendor/superpowers/skills/subagent-driven-development/implementer-prompt.md +139 -0
- package/vendor/superpowers/skills/subagent-driven-development/scripts/review-package +44 -0
- package/vendor/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +22 -0
- package/vendor/superpowers/skills/subagent-driven-development/scripts/task-brief +40 -0
- package/vendor/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +188 -0
- package/vendor/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/vendor/superpowers/skills/systematic-debugging/SKILL.md +296 -0
- package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/vendor/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/vendor/superpowers/skills/systematic-debugging/find-polluter.sh +63 -0
- package/vendor/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/vendor/superpowers/skills/systematic-debugging/test-academic.md +14 -0
- package/vendor/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/vendor/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/vendor/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/vendor/superpowers/skills/test-driven-development/SKILL.md +371 -0
- package/vendor/superpowers/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/vendor/superpowers/skills/using-git-worktrees/SKILL.md +202 -0
- package/vendor/superpowers/skills/using-superpowers/SKILL.md +62 -0
- package/vendor/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -0
- package/vendor/superpowers/skills/using-superpowers/references/codex-tools.md +39 -0
- package/vendor/superpowers/skills/using-superpowers/references/pi-tools.md +16 -0
- package/vendor/superpowers/skills/verification-before-completion/SKILL.md +139 -0
- package/vendor/superpowers/skills/writing-plans/SKILL.md +174 -0
- package/vendor/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
- package/vendor/superpowers/skills/writing-skills/SKILL.md +689 -0
- package/vendor/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/vendor/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/vendor/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/vendor/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
- package/vendor/superpowers/skills/writing-skills/render-graphs.js +168 -0
- package/vendor/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-commit
|
|
3
|
+
description: Preview and create a structured local commit without staging.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Commit
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call the read-only `workflow_git_context` context tool with any selected paths; its result is ground truth.
|
|
11
|
+
3. Draft the exact Conventional Commit message and the already-staged file set.
|
|
12
|
+
4. Use native `question` with concise choices and allow a custom answer before committing.
|
|
13
|
+
5. Call `workflow_commit` only after approval with `confirmed: true` and the reviewed `message`.
|
|
14
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
15
|
+
|
|
16
|
+
Never stage files automatically: `workflow_commit` commits the current index only. Stop for an empty index, partial staging ambiguity, unrelated staged files, secrets, protected branches, or failed hooks. Never push, bypass hooks, use `--no-verify`, or claim files were committed unless the result proves it. Keep related code, tests, and docs in one coherent commit; do not invent extra commit groups. `todowrite` and `task` are unnecessary here.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-docs-refresh
|
|
3
|
+
description: Refresh stale repository documentation from structured change context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Docs refresh
|
|
7
|
+
|
|
8
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
9
|
+
2. Call the read-only `workflow_docs_context` context tool; its result is ground truth.
|
|
10
|
+
3. Draft the smallest factual documentation edit from structured facts.
|
|
11
|
+
4. Use native `question` with concise choices and allow a custom answer only if the requested edit scope is ambiguous.
|
|
12
|
+
5. Apply approved edits with normal OpenCode file tools, then call `workflow_verify`.
|
|
13
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
14
|
+
|
|
15
|
+
Prefer README changes when stale, then directly related tracked documentation. Preserve tone and structure; do not invent features, commands, environment variables, screenshots, or install steps. Do not make stylistic rewrites, commit, or modify product code. Report verification exactly. Use `todowrite` only when multiple requested documents need tracking; `task` is unnecessary.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-handoff
|
|
3
|
+
description: Create and optionally select a seeded OpenCode continuation session.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Handoff
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call the automatic `workflow_handoff_session` tool with the full user message as `message`; its result is ground truth.
|
|
11
|
+
3. The tool resolves the tracked spec, plan, and SDD context and seeds the continuation session.
|
|
12
|
+
4. This workflow needs no `question`: the explicit invocation is approval.
|
|
13
|
+
5. Pass only `message`; the tool itself recognizes an exact `--stay` flag and otherwise selects the new session.
|
|
14
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
15
|
+
7. After any `workflow_handoff_session` result—success, partial, or failure—end the originating turn immediately after one status message. Never create todos, execute the plan inline, modify files, retry handoff, or call another tool.
|
|
16
|
+
|
|
17
|
+
Never emit a continuation prompt, use the clipboard, or ask the user to copy text. If selected, report the session ID only if the current session remains visible. If staying, report the seeded session ID. On failure, report `stage` and `error`; preserve any returned session for the session picker and never recreate it automatically. `todowrite` and `task` are unnecessary here.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-implement
|
|
3
|
+
description: Coordinate a tracked Superpowers plan with delegated implementation and reviews.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Implement
|
|
8
|
+
|
|
9
|
+
The parent agent is coordinator-only. It must not edit product code or perform delegated exploration.
|
|
10
|
+
|
|
11
|
+
## Native setup
|
|
12
|
+
|
|
13
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
14
|
+
2. Call read-only `workflow_plan_tasks` and `workflow_sdd_context`; their structured results are ground truth.
|
|
15
|
+
3. Call `workflow_flow_status` with the plan path and hard-stop unless `spec.status === "approved"`, `plan.status === "approved"`, and `menu.presented === true`. If any gate is missing, run the required approval flow (`workflow_spec_approve`/`workflow_plan_approve` after the user's native-question approval, `workflow_plan_menu` after the post-plan menu) and re-check — never start tasks on a draft or unapproved plan.
|
|
16
|
+
4. Initialize native `todowrite` from returned tasks and mark ledger-completed task IDs completed.
|
|
17
|
+
5. Call `workflow_resolve_branch`, then show the current branch, target branch, and stash behavior before any branch checkout/setup mutation.
|
|
18
|
+
6. Always use native `question` before that mutation. For a clean tree, ask whether to proceed or cancel. For a dirty tree, add the stash choice and state what will be stashed; allow a custom answer.
|
|
19
|
+
7. Call `workflow_branch_setup` with `confirmed: true` only after approval; never use worktrees.
|
|
20
|
+
8. Report any setup failure stage or partial result; never infer success.
|
|
21
|
+
9. Fill specs/plans from the quality templates: `templates/spec-template.md` for specs, `templates/plan-template.md` for plans. After `workflow_docs_validate`, surface the returned `quality` findings: hard findings (missing required section, missing CA-XX) block task start unless the user explicitly waives them; warnings are advisory.
|
|
22
|
+
|
|
23
|
+
State lives only in tracked `docs/<slug>/sdd/<slug>/`. Never use an untracked or legacy SDD directory. Load the package-neutral execution contract by name, not an installation-specific path.
|
|
24
|
+
|
|
25
|
+
## Per-task loop
|
|
26
|
+
|
|
27
|
+
For every plan task whose ID is absent from `completed_task_ids`:
|
|
28
|
+
|
|
29
|
+
1. Mark it `in_progress` with `todowrite`.
|
|
30
|
+
2. Create its brief with `workflow_sdd_task_brief` using `confirmed: true` and the parsed `section_text`.
|
|
31
|
+
3. Use `task` with the built-in `explore` agent for read-only discovery when needed, then a fresh built-in `general` agent to implement from the brief. The parent remains coordinator-only.
|
|
32
|
+
4. Require product changes to follow TDD: failing check first, minimal implementation, passing focused check.
|
|
33
|
+
5. Create the review package with `workflow_sdd_review_package` using `confirmed: true`.
|
|
34
|
+
6. Dispatch separate `general` agents for spec-compliance review and code-quality review. **Blocking findings** (Critical, Important, or spec-compliance) may trigger at most **two** fix+re-review rounds per task. **Advisory** findings (Minor, style, YAGNI, taste) never pause the loop — append them to `<SDD_DIR>/advisories.md` with the task id.
|
|
35
|
+
7. Append the validated ledger line with `workflow_sdd_append_progress` using `confirmed: true`, then mark the task completed with `todowrite`.
|
|
36
|
+
|
|
37
|
+
Never redispatch completed task IDs. Pass task briefs and review diffs to agents; do not make them reparse the plan. Keep commits on the in-place feature/bugfix branch.
|
|
38
|
+
|
|
39
|
+
## Final gate
|
|
40
|
+
|
|
41
|
+
After all remaining tasks, dispatch a final full-branch code review, run `workflow_verify`, and report exact per-check results. Present the full `<SDD_DIR>/advisories.md` roll-up once, then use native `question` so the user can choose which advisory items to fix, discuss, or discard. Only then may advisory fixes run. Use `workflow_git_context` for the final commit preview and the `wk-commit` skill for any approved commit. If a tracked stash reference exists, preview reapplication with `question`, then call `workflow_branch_setup` with `confirmed: true` only after approval.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-init
|
|
3
|
+
description: Preview and apply one-time workit configuration.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Init
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call the read-only `workflow_toolkit_init_status` context tool; its result is ground truth.
|
|
11
|
+
3. Draft an exact preview of each missing scaffold and the active VCS provider.
|
|
12
|
+
4. For each guarded mutation, use native `question` with concise choices and allow a custom answer.
|
|
13
|
+
5. Call `workflow_toolkit_init_apply` only after approval with `confirmed: true` and the chosen action.
|
|
14
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
15
|
+
|
|
16
|
+
Never ask for or accept tokens in chat. For missing YouTrack configuration, preview `youtrack_scaffold`; for missing VCS configuration, ask GitLab or GitHub, preview `vcs_scaffold`, and pass `vcs_provider`. Both provider token placeholders may be created, but identify which one is active. Show the returned token-create URL and local edit path after apply. Verification remains a separate `wk-status` run. `todowrite` and `task` are unnecessary here.
|
|
17
|
+
|
|
18
|
+
## Guided config (action: "config")
|
|
19
|
+
|
|
20
|
+
When the user wants to personalize the toolkit (locale, timezone, branch policy), ask native questions one at a time:
|
|
21
|
+
|
|
22
|
+
1. **Locale** — present a combobox of `localeOptions` (en, es-CL, es-MX, es-AR, pt-BR) + custom answer; validate the answer against BCP-47 (`^[a-z]{2,3}(-[A-Z]{2})?$`) before passing it.
|
|
23
|
+
2. **Timezone** — e.g. `America/Santiago`, custom allowed.
|
|
24
|
+
3. **Branch policy preset** — gitflow / github-flow / trunk-based / custom.
|
|
25
|
+
4. **Custom branch lists** (only when preset = custom): allowed patterns (`feature/*`, `codex/*`, …) and protected names (`main`, …).
|
|
26
|
+
|
|
27
|
+
Then call `workflow_toolkit_init_apply` with `action: "config"`, `confirmed: true`, and the answered values. Report the written `config.json` path and its contents.
|
|
28
|
+
|
|
29
|
+
After config, call `workflow_toolkit_init_apply` with `action: "gitignore"` and `confirmed: true` to ensure the project `.gitignore` covers `docs/*/sdd/` and common OS/editor entries (creates it if missing, preserves existing entries).
|
|
30
|
+
|
|
31
|
+
After gitignore, call `workflow_toolkit_init_apply` with `action: "hygiene"`, `confirmed: true`, and `include_open_source: true` for open-source repos — creates CHANGELOG.md (Keep a Changelog), README.md, .editorconfig, .gitattributes, and optionally LICENSE + CONTRIBUTING.md. Never overwrites existing files.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-issue-update
|
|
3
|
+
description: Draft and post a reviewed es-CL YouTrack task update with time.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Issue update
|
|
8
|
+
|
|
9
|
+
Read [references/youtrack-update-style.md](references/youtrack-update-style.md) before drafting. Chat follows the user's language; the comment body is manager-friendly Spanish (`es-CL`).
|
|
10
|
+
|
|
11
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
12
|
+
2. Ask in plain prose for the user-provided issue URL or ID, call `workflow_youtrack_parse_issue`, then read-only `workflow_youtrack_context`; structured results are ground truth.
|
|
13
|
+
3. Gather the user's notes, call `workflow_youtrack_parse_duration`, polish only supported facts, and call `workflow_youtrack_draft` for the exact comment preview.
|
|
14
|
+
4. Use native `question` with concise choices and allow a custom answer to approve the reviewed comment and time entry.
|
|
15
|
+
5. Call `workflow_youtrack_post` only after approval with `confirmed: true`, `issueId`, `markdown`, and `minutes`.
|
|
16
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
17
|
+
|
|
18
|
+
Never guess the issue, compute minutes, pass a date, expose tokens, or post Git/file details as the update. Never present a clickable `question` option whose label is an instruction to type free text (e.g. "Type the issue URL/ID"): clicking an option returns the label literal, not the typed value, so ask for free text in prose instead, with the custom answer field enabled. Preserve the user's paragraph voice, explain technical terms plainly, and avoid robotic status bullets. `todowrite` and `task` are unnecessary here.
|
|
19
|
+
|
|
20
|
+
Consume the standard Result envelope:
|
|
21
|
+
|
|
22
|
+
- If `result.ok` is true, report only effects proven by `result.data`.
|
|
23
|
+
- If false, use `result.data.postedComment` and `result.data.loggedMinutes` to distinguish completed effects.
|
|
24
|
+
- If `result.data.retry === "workflow_youtrack_post"`, use native `question` to ask whether to retry the unchanged reviewed `issueId`, `markdown`, and `minutes`. On approval, call `workflow_youtrack_post` with `confirmed: true` at most once; never loop.
|
|
25
|
+
- If `result.data.retry === "workflow_youtrack_log_time"`, use native `question` to ask whether to retry the same `issueId` and `minutes`. On approval, call `workflow_youtrack_log_time` with `confirmed: true`, `issueId`, `minutes` at most once; never repost a known posted comment.
|
|
26
|
+
- If the second attempt fails, stop and report its structured result. Never switch retry tools or infer that either effect succeeded.
|
|
27
|
+
- If outcome is `unknown` or `result.data.retry` is absent, show `result.data.instructions` when present, reconcile manually, and do not retry either mutation.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# YouTrack update style (Cristhofer / es-CL)
|
|
2
|
+
|
|
3
|
+
Use when writing or polishing the comment body before `workflow_youtrack_draft`. **Preserve the author's voice** — like the ChatGPT revision thread: grammar, flow, and light structure, not a changelog.
|
|
4
|
+
|
|
5
|
+
## Audience
|
|
6
|
+
|
|
7
|
+
**@Alejandra.Flores is the primary reader — she is not a developer.** Write for a technical project manager:
|
|
8
|
+
|
|
9
|
+
- Lead with **what you worked on and why it mattered**, not implementation mechanics.
|
|
10
|
+
- If you mention something technical (OpenAPI, flags, component names, GUAS, MFE), add **one short plain-language clause** so the reader understands impact without knowing the stack.
|
|
11
|
+
- Prefer product/feature language: *data sources*, *integración con el backend*, *selector de color*, *vista del segundo factor*.
|
|
12
|
+
|
|
13
|
+
### Technical detail — clarify, don't drop
|
|
14
|
+
|
|
15
|
+
| Too dev (avoid alone) | Better for manager |
|
|
16
|
+
|-----------------------|-------------------|
|
|
17
|
+
| overlays fuera del shadow DOM en el host | el selector de color no se veía bien cuando el reporte está embebido en la web principal |
|
|
18
|
+
| `replaceUrl: true` en el interceptor | para que al volver atrás no se repitiera el mismo error en bucle |
|
|
19
|
+
| Migré a `daisy-overlay-tokens` | ajusté los estilos del overlay para que respeten el tema de la web |
|
|
20
|
+
|
|
21
|
+
Only include dev terms the user actually brought up — then **translate or contextualize** in the same breath.
|
|
22
|
+
|
|
23
|
+
## Shape
|
|
24
|
+
|
|
25
|
+
1. `# Actualización` (single H1)
|
|
26
|
+
2. Blank line
|
|
27
|
+
3. `@Alejandra.Flores` + greeting (`Hola, buenos días.` / `Hola, buenas tardes.`) — same line or next paragraph OK
|
|
28
|
+
4. **Body: paragraphs**, not bullet dumps
|
|
29
|
+
|
|
30
|
+
Optional second H1 when the user has a long tangent block:
|
|
31
|
+
|
|
32
|
+
- `## Off-topic` — only when the user's material is clearly a side topic (tooling, proceso, ideas). Keep the main work under `# Actualización`.
|
|
33
|
+
|
|
34
|
+
## Openers (only if the user's material implies it)
|
|
35
|
+
|
|
36
|
+
- `Hoy estuve trabajando en…` / `Hoy por la tarde he estado full con…`
|
|
37
|
+
- `Hoy estuve full con <proyecto>.`
|
|
38
|
+
- `Dado lo que conversamos,…`
|
|
39
|
+
|
|
40
|
+
Do **not** force an opener.
|
|
41
|
+
|
|
42
|
+
## Voice
|
|
43
|
+
|
|
44
|
+
- First person, Chilean Spanish: *harto*, *darle una vuelta*, *al día*, *trasteando*, *ojalá*.
|
|
45
|
+
- Honest: *al parecer*, *creo que*, *imagino que*, *no alcancé a*, *entiendo que*.
|
|
46
|
+
- Explain **why** and **what's next**, not file trees.
|
|
47
|
+
- Close with forward look when relevant: *Mañana…*, *me falta…*, *de momento va bien*.
|
|
48
|
+
|
|
49
|
+
## Tangents
|
|
50
|
+
|
|
51
|
+
Natural bridges: `Por otro lado,…`, `Como comentario adicional,…`, `Como punto aparte,…`, `Quiero comentar algo que puede ser interesante.`
|
|
52
|
+
|
|
53
|
+
Long tooling/process tangents → `## Off-topic` (exemplar 4).
|
|
54
|
+
|
|
55
|
+
## Allowed formatting
|
|
56
|
+
|
|
57
|
+
- Backticks for product/component names the user mentioned: `` `color-picker` ``, `` `button` ``
|
|
58
|
+
- Links and screenshots the user attached
|
|
59
|
+
- Short inline lists **only** when comparing options the manager needs to understand (exemplar 4: OpenAPI vs backend vs frontend) — as **prose or one flowing sentence**, not a task checklist
|
|
60
|
+
|
|
61
|
+
## Forbidden (unless user wrote them verbatim)
|
|
62
|
+
|
|
63
|
+
- Branch names, SHAs, `src/...` paths
|
|
64
|
+
- Nested `###` subsections for work items
|
|
65
|
+
- Bullet lists of completed tasks (PR style)
|
|
66
|
+
- Stacked changelog verbs: *Implementé*, *Migré*, *Alineé*
|
|
67
|
+
- Invented work or metrics
|
|
68
|
+
- Pasting `git log`, agent session, or `facts.*` into the comment
|
|
69
|
+
- Jargon without a plain-language gloss
|
|
70
|
+
|
|
71
|
+
## Polish level (ChatGPT-thread)
|
|
72
|
+
|
|
73
|
+
1. Grammar and spelling.
|
|
74
|
+
2. Smooth sentences; similar length to input.
|
|
75
|
+
3. Split wall-of-text into paragraphs; add bridges only when needed.
|
|
76
|
+
4. **Do not** add facts the user did not supply.
|
|
77
|
+
5. **Do** add a brief gloss when the user used opaque tech terms.
|
|
78
|
+
|
|
79
|
+
## Length
|
|
80
|
+
|
|
81
|
+
Match the user. Never pad.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-meetings
|
|
3
|
+
description: Log meeting time only to the configured YouTrack meeting issue.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Meetings
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call read-only `workflow_youtrack_context` with `mode: "meetings"`; its sole configured target is ground truth.
|
|
11
|
+
3. Ask for duration text, call `workflow_youtrack_parse_duration`, and draft the exact IRPT-12 time entry only.
|
|
12
|
+
4. Use native `question` with concise choices and allow a custom answer to approve the shown issue, minutes, and work-item text.
|
|
13
|
+
5. Call `workflow_youtrack_log_time` only after approval with `confirmed: true`, `issueId`, `minutes`, `text`.
|
|
14
|
+
6. If `result.data.outcome` is `unknown`, tell the user to reconcile manually and do not retry. Retry `workflow_youtrack_log_time` at most once only when `result.data.outcome` is `not_applied` and `result.data.retry` names that tool; follow `result.data.instructions` and correct invalid input before retrying.
|
|
15
|
+
7. Report the structured success or failure stage; never infer success.
|
|
16
|
+
|
|
17
|
+
Use the configured meeting issue even if its default label is IRPT-12. Never compute minutes, pass a date, ask for a meeting type, post a comment, or call `workflow_youtrack_post`. `todowrite` and `task` are unnecessary here.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-pr
|
|
3
|
+
description: Preview and create a pull or merge request from branch-exclusive facts.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Pull request
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call the read-only `workflow_pr_context` context tool for branch-exclusive commits and changes; its result is ground truth.
|
|
11
|
+
3. Call `workflow_verify`, then draft the exact title, body, base, head, and draft state from structured facts.
|
|
12
|
+
4. **Show** the exact title and body in chat before any create question.
|
|
13
|
+
5. Use native `question` with concise choices and allow a custom answer before creation.
|
|
14
|
+
6. Call `workflow_pr_create` only after approval with `confirmed: true` and the reviewed fields.
|
|
15
|
+
7. Report the structured success, failure stage, or partial result; never infer success.
|
|
16
|
+
|
|
17
|
+
## GitHub issue linking
|
|
18
|
+
|
|
19
|
+
When the resolved workspace is github with `link_on_pr` — `bash scripts/vcs/config.sh resolve` returns `issues_provider: "github"` and `link_on_pr: true` — and no issue is derivable (no `WORKFLOW_GH_ISSUE` env, no numeric branch id like `feature/42-title`, which auto-links without asking), ask with native `question` before creation, exactly three options:
|
|
20
|
+
|
|
21
|
+
1. **Use an existing issue** — the user provides the number (extract it from a URL if pasted); verify it exists with `gh issue view <n>` before proceeding.
|
|
22
|
+
2. **Create a new issue** — via `gh issue create --title "<title>" --body "<body>"`; on success pass the returned number. Reuse the missing-CLI guard: if `gh` is not installed, surface the structured error with the install link and ask the user to confirm once installed.
|
|
23
|
+
3. **Skip linking** — no issue line in the PR body.
|
|
24
|
+
|
|
25
|
+
Pass the chosen issue to pr-create via env: `WORKFLOW_GH_ISSUE=<n>` and, when the PR does NOT resolve the issue, `WORKFLOW_GH_ISSUE_RELATION=related` (default `closes`). The youtrack linking flow (`youtrack.link_issues`) for work workspaces is unchanged.
|
|
26
|
+
|
|
27
|
+
Only feature or bugfix branches may target the configured base; never create from a protected branch. The body must describe only branch-exclusive changes, follow the repository template when present, and disclose failed or skipped verification. Never expose tokens, edit product files, or fall back to provider CLIs. `todowrite` and `task` are unnecessary here.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-release-notes
|
|
3
|
+
description: Draft user-facing release notes for an explicit range.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Release notes
|
|
7
|
+
|
|
8
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
9
|
+
2. Require an exact version, tag, or commit range, then call the read-only `workflow_release_notes_context`; its result is ground truth.
|
|
10
|
+
3. Draft notes from structured facts and include both requested and resolved range metadata.
|
|
11
|
+
4. Use native `question` only when the exact range must be supplied or corrected; allow a custom answer.
|
|
12
|
+
5. This workflow has no mutation tool.
|
|
13
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
14
|
+
|
|
15
|
+
Write for users: supported highlights, fixes, upgrade notes, and known issues only. Omit empty sections except Highlights, and say directly when the resolved range contains no user-facing changes. Do not edit files, publish a release, or infer a range. `todowrite` and `task` are unnecessary here.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-status
|
|
3
|
+
description: Report workit, YouTrack, and VCS health.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Status
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call the read-only `workflow_toolkit_status` context tool once; its result is ground truth.
|
|
11
|
+
3. Draft the health report from structured facts.
|
|
12
|
+
4. This workflow has no guarded mutation and does not need `question`.
|
|
13
|
+
5. Do not call any mutation tool.
|
|
14
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
15
|
+
|
|
16
|
+
Show every `items[]` result, the resolved YouTrack settings and verification, the VCS provider and verification, and the exact `ready` verdict. For placeholders, point to the returned token creation and edit paths; never request tokens in chat. Use only `workflow_toolkit_status` and report its structured state. Do not run shell, Git, direct HTTP, isolated token verification, or any mutation. `todowrite` and `task` are unnecessary for this read-only workflow.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wk-verify
|
|
3
|
+
description: Discover and run project validation with workflow_verify.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Verify
|
|
8
|
+
|
|
9
|
+
1. Load this skill explicitly through OpenCode's `skill` tool.
|
|
10
|
+
2. Call the read-only `workflow_verify` context tool with `dry_run: true`; its result is ground truth.
|
|
11
|
+
3. Draft the discovered checks and the proposed selected run from structured facts.
|
|
12
|
+
4. When the user must choose checks, use native `question` with concise choices and allow a custom answer.
|
|
13
|
+
5. Call `workflow_verify` with `dry_run: false` only for the approved run.
|
|
14
|
+
6. Report the structured success, failure stage, or partial result; never infer success.
|
|
15
|
+
|
|
16
|
+
Do not edit files or fix failures. Report every check exactly as pass, fail, or skipped, including its command, exit code, and skip reason. Success requires every executed check to exit 0. If the user's message says `--dry-run`, stop after discovery.
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { gitContext } from "./git";
|
|
5
|
+
import { readConfig, resolveBranchPolicy } from "./config";
|
|
6
|
+
|
|
7
|
+
const policy = () => resolveBranchPolicy(readConfig());
|
|
8
|
+
const allowedBranch = (name: string) => policy().allowed.some((r) => r.test(name));
|
|
9
|
+
const isProtected = (name: string) => policy().protected.has(name.toLowerCase());
|
|
10
|
+
const DECLARE_RE = /^\s*\*+Branch:\*+\s*`?([^`\s|]+)`?\s*$/gim;
|
|
11
|
+
const USE_CURRENT_RE = /^\s*\*+Branch:\*+\s*use-current\s*$/im;
|
|
12
|
+
const readSafe = (p: string): string | null => {
|
|
13
|
+
try { return readFileSync(p, "utf8"); } catch { return null; }
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const normalizeBranch = (name: string): string | null => {
|
|
17
|
+
const n = name.trim().replace(/`/g, "").replace(/\.+$/, "");
|
|
18
|
+
if (isProtected(n)) return null;
|
|
19
|
+
if (!allowedBranch(n)) return null;
|
|
20
|
+
const parts = n.toLowerCase().split("/").map((p) =>
|
|
21
|
+
p.replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-"));
|
|
22
|
+
if (parts.some((p) => !p)) return null;
|
|
23
|
+
return parts.join("/");
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const deriveSlug = (planPath: string): string => {
|
|
27
|
+
// New layout: plan lives at docs/<slug>/plan.md — slug is the dir name.
|
|
28
|
+
const dirName = path.basename(path.dirname(planPath));
|
|
29
|
+
return dirName === "." || dirName === "/" || dirName === "" ? "" : dirName;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const deriveKind = (planPath: string, fallback: "feature" | "bugfix" = "feature"): "feature" | "bugfix" => {
|
|
33
|
+
const slug = deriveSlug(planPath);
|
|
34
|
+
const text = readSafe(planPath) ?? "";
|
|
35
|
+
let kind = fallback;
|
|
36
|
+
if (/\bbugfix\b/i.test(slug) || /^fix-/i.test(slug)) {
|
|
37
|
+
kind = "bugfix";
|
|
38
|
+
} else {
|
|
39
|
+
const goal = text.split("\n").find((line) => line.startsWith("**Goal:**"))?.toLowerCase() ?? "";
|
|
40
|
+
if (/\b(bugfix|bug fix)\b/.test(goal) && !/\b(feat|feature|upgrade|add)\b/.test(goal)) {
|
|
41
|
+
kind = "bugfix";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return kind;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Port of scripts/lib/resolve-handoff-branch.sh
|
|
48
|
+
export const resolveBranch = ({
|
|
49
|
+
spec_path,
|
|
50
|
+
plan_path,
|
|
51
|
+
workspace_root,
|
|
52
|
+
}: { spec_path: string; plan_path: string; workspace_root: string }) => {
|
|
53
|
+
const cwd = path.resolve(workspace_root);
|
|
54
|
+
const abs = (p: string) => (path.isAbsolute(p) ? p : path.join(cwd, p));
|
|
55
|
+
const spec = abs(spec_path);
|
|
56
|
+
const plan = abs(plan_path);
|
|
57
|
+
const git = gitContext(cwd);
|
|
58
|
+
const current = git.branch;
|
|
59
|
+
|
|
60
|
+
const finish = (branch: string, source: string) => ({
|
|
61
|
+
branch,
|
|
62
|
+
source,
|
|
63
|
+
current_branch: current,
|
|
64
|
+
dirty: Boolean(git.status_short.trim()),
|
|
65
|
+
needs_checkout: current !== branch,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
for (const file of [spec, plan]) {
|
|
69
|
+
const text = readSafe(file);
|
|
70
|
+
if (!text) continue;
|
|
71
|
+
if (USE_CURRENT_RE.test(text)) {
|
|
72
|
+
if (!current || !allowedBranch(current) || isProtected(current)) {
|
|
73
|
+
return { error: `use-current but HEAD ${current} is not an allowed branch` };
|
|
74
|
+
}
|
|
75
|
+
return finish(current, "use-current");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (current && allowedBranch(current) && !isProtected(current)) return finish(current, "keep-current");
|
|
80
|
+
|
|
81
|
+
let declaredButInvalid: string | null = null;
|
|
82
|
+
for (const file of [spec, plan]) {
|
|
83
|
+
const text = readSafe(file);
|
|
84
|
+
if (!text) continue;
|
|
85
|
+
for (const match of text.matchAll(DECLARE_RE)) {
|
|
86
|
+
const normalized = normalizeBranch(match[1]);
|
|
87
|
+
if (normalized) return finish(normalized, file === spec ? "spec" : "plan");
|
|
88
|
+
declaredButInvalid ??= match[1];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (declaredButInvalid) {
|
|
92
|
+
return { error: `declared branch ${JSON.stringify(declaredButInvalid)} is not allowed by the branch policy` };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const slug = deriveSlug(plan);
|
|
96
|
+
if (!slug) return { error: `cannot derive branch slug from plan ${plan}` };
|
|
97
|
+
const kind = deriveKind(plan);
|
|
98
|
+
return finish(`${kind}/${slug}`, "derived");
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Port of scripts/lib/resolve-docs-branch.sh
|
|
102
|
+
export const docsBranch = ({
|
|
103
|
+
plan_path,
|
|
104
|
+
kind,
|
|
105
|
+
workspace_root,
|
|
106
|
+
}: { plan_path?: string; kind?: string; workspace_root: string }) => {
|
|
107
|
+
const cwd = path.resolve(workspace_root);
|
|
108
|
+
const git = gitContext(cwd);
|
|
109
|
+
const current = git.branch;
|
|
110
|
+
const kindArg = (kind ?? "feature").toLowerCase();
|
|
111
|
+
|
|
112
|
+
if (current && allowedBranch(current) && !isProtected(current)) {
|
|
113
|
+
return { branch: current, action: "keep", current_branch: current, base: "develop", dirty: Boolean(git.status_short.trim()) };
|
|
114
|
+
}
|
|
115
|
+
if (current === "main" || current === "master" || current === "develop") {
|
|
116
|
+
let slug = "";
|
|
117
|
+
if (plan_path) {
|
|
118
|
+
const plan = path.isAbsolute(plan_path) ? plan_path : path.join(cwd, plan_path);
|
|
119
|
+
slug = deriveSlug(plan);
|
|
120
|
+
}
|
|
121
|
+
if (!slug) {
|
|
122
|
+
return { error: "plan_path required to derive branch slug when not on feature/* or bugfix/*" };
|
|
123
|
+
}
|
|
124
|
+
const branchKind = kindArg === "bugfix" ? "bugfix" : "feature";
|
|
125
|
+
return { branch: `${branchKind}/${slug}`, action: "create_from_develop", current_branch: current, base: "develop", dirty: Boolean(git.status_short.trim()) };
|
|
126
|
+
}
|
|
127
|
+
return { error: `cannot resolve docs branch from HEAD ${JSON.stringify(current)}` };
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Port of scripts/lib/ensure-develop-base.sh
|
|
131
|
+
export const ensureDevelopBase = (cwd: string): { ok: boolean; error?: string } => {
|
|
132
|
+
const git = gitContext(cwd);
|
|
133
|
+
if (!git.branch || git.branch === "unknown") return { ok: false, error: "not in a git repository" };
|
|
134
|
+
const run = (args: string[]) => execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
135
|
+
try {
|
|
136
|
+
try {
|
|
137
|
+
run(["fetch", "origin", "develop", "--prune"]);
|
|
138
|
+
} catch {
|
|
139
|
+
run(["fetch", "origin", "--prune"]);
|
|
140
|
+
}
|
|
141
|
+
let hasOriginDevelop = true;
|
|
142
|
+
try { execFileSync("git", ["show-ref", "--verify", "--quiet", "refs/remotes/origin/develop"], { cwd, stdio: "pipe" }); } catch { hasOriginDevelop = false; }
|
|
143
|
+
if (!hasOriginDevelop) return { ok: false, error: "origin/develop missing — push develop before creating feature/* or bugfix/* branches" };
|
|
144
|
+
let hasLocalDevelop = true;
|
|
145
|
+
try { execFileSync("git", ["show-ref", "--verify", "--quiet", "refs/heads/develop"], { cwd, stdio: "pipe" }); } catch { hasLocalDevelop = false; }
|
|
146
|
+
if (hasLocalDevelop) {
|
|
147
|
+
run(["checkout", "develop"]);
|
|
148
|
+
try { run(["merge", "--ff-only", "origin/develop"]); } catch { /* non-fast-forward: keep local */ }
|
|
149
|
+
} else {
|
|
150
|
+
run(["checkout", "-b", "develop", "--track", "origin/develop"]);
|
|
151
|
+
}
|
|
152
|
+
return { ok: true };
|
|
153
|
+
} catch (error) {
|
|
154
|
+
return { ok: false, error: error instanceof Error ? error.message : "ensure-develop-base failed" };
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Port of scripts/branch/setup-branch.sh
|
|
159
|
+
export const branchSetup = ({
|
|
160
|
+
action,
|
|
161
|
+
sdd_dir,
|
|
162
|
+
target_branch,
|
|
163
|
+
stash,
|
|
164
|
+
workspace_root,
|
|
165
|
+
}: { action?: string; sdd_dir?: string; target_branch?: string; stash?: string; workspace_root: string }) => {
|
|
166
|
+
const cwd = path.resolve(workspace_root);
|
|
167
|
+
const exec = (args: string[]): string =>
|
|
168
|
+
execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
169
|
+
const current = gitContext(cwd).branch;
|
|
170
|
+
if (!current || current === "unknown") return { error: "not in a git repository" };
|
|
171
|
+
const sdd = sdd_dir ?? "docs";
|
|
172
|
+
const manifestPath = path.isAbsolute(sdd) ? path.join(sdd, "manifest.json") : path.join(cwd, sdd, "manifest.json");
|
|
173
|
+
mkdirSync(path.dirname(manifestPath), { recursive: true, mode: 0o755 });
|
|
174
|
+
const readManifest = (): Record<string, unknown> => {
|
|
175
|
+
try { return JSON.parse(readFileSync(manifestPath, "utf8")); } catch { return {}; }
|
|
176
|
+
};
|
|
177
|
+
const writeManifest = (data: Record<string, unknown>) =>
|
|
178
|
+
writeFileSync(manifestPath, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
179
|
+
|
|
180
|
+
if (action === "reapply_stash") {
|
|
181
|
+
const manifest = readManifest();
|
|
182
|
+
const ref = manifest.stash_ref;
|
|
183
|
+
if (!ref) return { error: "no stash_ref in manifest" };
|
|
184
|
+
try { exec(["stash", "pop", String(ref)]); } catch (error) {
|
|
185
|
+
return { error: error instanceof Error ? error.message : "stash pop failed" };
|
|
186
|
+
}
|
|
187
|
+
delete manifest.stash_ref;
|
|
188
|
+
delete manifest.stash_created_at;
|
|
189
|
+
writeManifest(manifest);
|
|
190
|
+
return { action: "reapply_stash", ok: true };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const target = target_branch ?? "";
|
|
194
|
+
if (!target) return { error: "target branch required" };
|
|
195
|
+
if (isProtected(target)) return { error: `protected branch ${target}` };
|
|
196
|
+
if (!allowedBranch(target)) return { error: `target branch ${target} is not allowed by the branch policy` };
|
|
197
|
+
|
|
198
|
+
let stash_ref: string | undefined;
|
|
199
|
+
if (current !== target) {
|
|
200
|
+
const dirty = Boolean(gitContext(cwd).status_short.trim());
|
|
201
|
+
if (dirty) {
|
|
202
|
+
if (stash !== "yes") {
|
|
203
|
+
return { error: "dirty working tree — ask with native question, then call workflow_branch_setup with stash=yes" };
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
exec(["stash", "push", "-u", "-m", `workit: pre-checkout ${target}`, "--", ":!docs/*/sdd"]);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
return { error: error instanceof Error ? error.message : "stash push failed" };
|
|
209
|
+
}
|
|
210
|
+
stash_ref = "stash@{0}";
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
exec(["checkout", target]);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
const message = error instanceof Error ? error.message : "checkout failed";
|
|
216
|
+
if (/worktree/i.test(message)) {
|
|
217
|
+
return { error: `branch ${target} is locked by an existing git worktree — remove it first (we do not use worktrees)` };
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
// Branch does not exist yet: base it on develop (never main/master).
|
|
221
|
+
const current = gitContext(cwd).branch;
|
|
222
|
+
if (current === "main" || current === "master") {
|
|
223
|
+
const baseResult = ensureDevelopBase(cwd);
|
|
224
|
+
if (!baseResult.ok) return { error: baseResult.error };
|
|
225
|
+
} else {
|
|
226
|
+
// Already on develop or another feature branch: still require origin/develop to exist.
|
|
227
|
+
const baseResult = ensureDevelopBase(cwd);
|
|
228
|
+
if (!baseResult.ok) return { error: baseResult.error };
|
|
229
|
+
}
|
|
230
|
+
exec(["checkout", "-b", target]);
|
|
231
|
+
} catch (createError) {
|
|
232
|
+
return { error: createError instanceof Error ? createError.message : "branch create failed" };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const manifest = readManifest();
|
|
238
|
+
manifest.branch = target;
|
|
239
|
+
manifest.previous_branch = current;
|
|
240
|
+
if (stash_ref) {
|
|
241
|
+
manifest.stash_ref = stash_ref;
|
|
242
|
+
manifest.stash_created_at = new Date().toISOString();
|
|
243
|
+
}
|
|
244
|
+
writeManifest(manifest);
|
|
245
|
+
return { action: "setup", ok: true, branch: target, previous_branch: current, stash_ref: stash_ref ?? null, manifest: manifestPath };
|
|
246
|
+
};
|