kushi-agents 4.0.0 → 4.2.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.
@@ -37,6 +37,7 @@ Project Q&A also auto-dispatches when the user names a known project under the e
37
37
  - `.kushi/instructions/` — doctrine (citations, WorkIQ-first, freshness gates)
38
38
  - `.kushi/reference-packs/` — bundled domain doctrine (override at project / workspace / packaged layers)
39
39
  - `.kushi/config/` — **user-editable** (project-evidence.yml, integrations.yml, reference-overrides). Seeded on first install; never overwritten on upgrade.
40
+ - `.kushi/tracking/` — **agent working memory** (runs/, qa/, fde/, research/). Per-run Markdown journals: what was asked, what was done, what was decided, what's still open. Gitignored by default. See `instructions/tracking.instructions.md`.
40
41
  - `.kushi/kushi-install.json` — profile manifest written by the installer
41
42
 
42
43
  Full docs: <https://gim-home.github.io/kushi/>
package/bin/cli.mjs CHANGED
@@ -29,6 +29,13 @@ if (args.includes('--help') || args.includes('-h')) {
29
29
  check (useful for scripted or agent-driven installs)
30
30
  --no-settings Skip .vscode/settings.json update (vscode target only)
31
31
  --no-instructions Skip .github/copilot-instructions.md merge (vscode target only)
32
+
33
+ WorkIQ (REQUIRED — Kushi cannot pull evidence without it):
34
+ --with-workiq Auto-install WorkIQ via winget (Windows) / brew (macOS)
35
+ --workiq-path <abs> Use this explicit path to the workiq binary
36
+ --skip-workiq-check Bypass the WorkIQ pre-flight check (CI / inspection only —
37
+ bootstrap/refresh will block until WorkIQ is installed)
38
+
32
39
  --help, -h Show this help
33
40
 
34
41
  After install, talk to Kushi:
@@ -62,6 +69,9 @@ const options = {
62
69
  noInstructions: args.includes('--no-instructions'),
63
70
  target,
64
71
  profile: getFlag('--profile'),
72
+ withWorkiq: args.includes('--with-workiq'),
73
+ workiqPath: getFlag('--workiq-path'),
74
+ skipWorkiqCheck: args.includes('--skip-workiq-check'),
65
75
  };
66
76
 
67
77
  main(options).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kushi-agents",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "Install Kushi — multi-source project evidence agent with snapshot+stream capture across Email, Teams, OneNote, SharePoint, Meetings, CRM, ADO. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,66 @@
1
+ ---
2
+ applyTo: "**"
3
+ description: "Identity auto-resolution — Kushi never asks the user for alias / email / display_name. On the first bootstrap (or whenever those fields are <auto> / placeholder in .kushi/config/project-evidence.yml), Kushi resolves them from WorkIQ in a single call, persists them, and continues. Skipped entirely if the user has set explicit values."
4
+ ---
5
+
6
+ # Identity Resolution — Don't Ask, Probe
7
+
8
+ Kushi must not prompt the user for `alias`, `email`, or `display_name`. These are derivable from WorkIQ in one call, and asking is poor UX.
9
+
10
+ ## When to resolve
11
+
12
+ On the **first step of every prompt** that reads contributor identity (bootstrap, refresh, aggregate, ask, fde-*, propose-ado, apply-ado), check `<workspace>/.kushi/config/project-evidence.yml`:
13
+
14
+ * If `alias`, `email`, or `display_name` is **missing**, set to `<auto>`, or matches a placeholder pattern (`<your-alias>`, `<Your Full Name>`, `your.email@example.com`) → **resolve from WorkIQ**.
15
+ * If all three are explicit non-placeholder values → **skip**. Respect the user's override.
16
+
17
+ ## How to resolve
18
+
19
+ Single WorkIQ call:
20
+
21
+ ```bash
22
+ workiq ask -q "Who am I? Return my UPN (email), display name, and mail nickname as JSON: {\"upn\":\"...\",\"displayName\":\"...\",\"mailNickname\":\"...\"}"
23
+ ```
24
+
25
+ Map the response:
26
+
27
+ | Config field | Source | Fallback if missing |
28
+ |----------------|-------------------------------------|--------------------------------------|
29
+ | `email` | `upn` | Block — must be present |
30
+ | `display_name` | `displayName` | Same as `alias` |
31
+ | `alias` | `mailNickname` | `upn.split('@')[0]` (lowercase) |
32
+
33
+ ## After resolution
34
+
35
+ 1. **Persist back** to `<workspace>/.kushi/config/project-evidence.yml` (preserving comments + indentation). The user sees the resolved values on next open; no surprise.
36
+ 2. **Echo back** to the user, one line:
37
+ > ✓ Identity: `Alex Smith <alex@microsoft.com>` (alias=`alex`). Edit `.kushi/config/project-evidence.yml` to override.
38
+ 3. **Continue** the prompt.
39
+
40
+ ## Failure modes
41
+
42
+ | Scenario | Behavior |
43
+ |-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
44
+ | WorkIQ returns auth error | Block: "Sign in to WorkIQ first: `workiq accept-eula && workiq ask -q ping`". Do not proceed. |
45
+ | WorkIQ returns empty / NO_RESULTS | Block: "WorkIQ could not resolve your identity. Try `workiq ask -q 'who am I'` and retry." |
46
+ | WorkIQ binary missing | This should already have been caught by the installer's pre-flight. If reached, block with the same install hint. |
47
+ | User has explicit non-placeholder values | Skip resolution entirely. Never overwrite user-set values. |
48
+ | Alias collision with another contributor | Bootstrap detects existing `Evidence/<alias>/` whose `contributors.yml` records a different email → ask the user to disambiguate (suggest `<alias>-<tenant-prefix>` e.g. `alex-ms`). |
49
+
50
+ ## What NOT to do
51
+
52
+ * Do NOT ask the user `What alias should Kushi use?`. The legacy onboarding prompt is gone.
53
+ * Do NOT call `m365_*` / Graph as a fallback. WorkIQ is the single source of identity truth (`workiq-first.instructions.md`).
54
+ * Do NOT resolve on every run. Once persisted, the config values are authoritative.
55
+
56
+ ## Integration with other doctrine
57
+
58
+ * `workiq-first.instructions.md` — identity resolution is the canonical example of WorkIQ-first. Add to the inventory.
59
+ * `bootstrap-project` SKILL — Step 0 is identity resolution. Step 1 is project context.
60
+ * `tracking.instructions.md` — the resolved identity goes into the tracking artifact's frontmatter under `actor:`.
61
+
62
+ ## References
63
+
64
+ * `workiq-first.instructions.md` — the parent doctrine.
65
+ * `engagement-root-resolution.instructions.md` — `projects_root` resolution (separate from identity).
66
+ * `templates/init/project-evidence.template.yml` — defaults to `<auto>` for these three fields.
@@ -0,0 +1,165 @@
1
+ ---
2
+ applyTo: "**"
3
+ description: "Kushi tracking convention — every Kushi prompt/skill writes its working memory (what it was asked, what it did, what it decided, what's still open) to `<workspace>/.kushi/tracking/` so users can see, edit, diff, and resume the agent's work. This is host-agnostic (VS Code Chat, Clawpilot, Cursor) and complements — never replaces — Evidence/ (canonical outputs) or State/ (rollups)."
4
+ ---
5
+
6
+ # Tracking — Agent Working Memory
7
+
8
+ Kushi agents must leave a visible trail. Every meaningful run produces a small Markdown artifact under `<workspace>/.kushi/tracking/` describing what was asked, what was done, what was decided, and what is still open.
9
+
10
+ This is **the journey**, not the **output**. Outputs land under `Evidence/`, `State/`, `Reports/`, `ado-updates/`, etc. Tracking files explain *why* and *how* those outputs ended up the way they did, so the user (or a future agent) can pick up where you left off.
11
+
12
+ ## Why this exists
13
+
14
+ * **Visible thinking.** The user can read what the agent considered and rejected, not just the final artifact.
15
+ * **Reliable handoff.** Stable filenames mean Bootstrap → Refresh → State → Ask never loses context across `/clear`, new chats, or host swaps.
16
+ * **Resumability.** A 60-minute pull that died at 80% can be resumed from its last tracking entry instead of restarted.
17
+ * **Audit + replay.** Diff-able, grep-able, commit-able (or gitignored — user's choice).
18
+ * **Single convention across hosts.** Same shape in VS Code Chat, Clawpilot, Cursor, Cline.
19
+
20
+ ## Folder layout
21
+
22
+ ```
23
+ <workspace>/.kushi/tracking/
24
+ .gitignore ← ignore everything by default
25
+ runs/{{YYYY-MM-DD}}-<project>-<verb>.md ← bootstrap / refresh / aggregate / state / consolidate
26
+ qa/{{YYYY-MM-DD}}-<project>-<question-slug>.md ← /ask answers + citations, archived
27
+ fde/intake/{{YYYY-MM-DD}}-<project>-<slug>.md ← /fde-intake drafts
28
+ fde/report/{{YYYY-MM-DD}}-<project>-<slug>.md ← /fde-report drafts
29
+ fde/triage/{{YYYY-MM-DD}}-<project>-<slug>.md ← /fde-triage drafts
30
+ research/{{YYYY-MM-DD}}-<topic>.md ← optional deep-dive notes
31
+ ```
32
+
33
+ Rules:
34
+
35
+ * Filenames start with `YYYY-MM-DD` (ISO date, UTC if ambiguous) so chronological sort works everywhere.
36
+ * `<project>` is the engagement folder name (slugified — lowercase, hyphenated, no spaces).
37
+ * `<verb>` is the prompt name without slash (`bootstrap`, `refresh`, ...).
38
+ * `<slug>` / `<question-slug>` is 3–6 word kebab-case derived from the user's ask.
39
+ * Create directories as needed on first write.
40
+
41
+ ## On first write — seed `.gitignore`
42
+
43
+ If `<workspace>/.kushi/tracking/` does not yet exist, create it and write `<workspace>/.kushi/tracking/.gitignore` with:
44
+
45
+ ```gitignore
46
+ # Kushi tracking files are working memory, not source of truth.
47
+ # Outputs live under Evidence/, State/, Reports/, ado-updates/.
48
+ # Uncomment the next line to start committing tracking artifacts.
49
+ *
50
+ !.gitignore
51
+ ```
52
+
53
+ A user who wants to commit their agent transcripts deletes `*` from this file. Default is private.
54
+
55
+ ## Required sections in every tracking artifact
56
+
57
+ Every tracking file is Markdown with frontmatter + a small set of named sections. Keep it short — this is a journal, not a report.
58
+
59
+ ```markdown
60
+ ---
61
+ prompt: bootstrap # /bootstrap, /refresh, /ask, /fde-intake, ...
62
+ project: hca # slugified engagement folder name
63
+ window: last 30 days # bootstrap/refresh only; otherwise omit
64
+ started: 2026-05-19T14:02:00-04:00
65
+ finished: 2026-05-19T14:38:12-04:00 # omit if still in progress
66
+ status: complete # complete | in-progress | blocked | failed
67
+ host: vscode # vscode | clawpilot | cursor | cline | other
68
+ kushi_version: 4.1.0
69
+ ---
70
+
71
+ ## Ask
72
+
73
+ > Verbatim or near-verbatim of what the user asked for. One short paragraph.
74
+
75
+ ## Inputs resolved
76
+
77
+ - Engagement root: `C:/.../Engagement Assets`
78
+ - Project folder: `HCA Healthcare`
79
+ - Alias: `ushak`
80
+ - Config: `<workspace>/.kushi/config/project-evidence.yml`
81
+
82
+ ## Steps taken
83
+
84
+ 1. Resolved project context via `engagement-root-resolution.instructions.md`.
85
+ 2. Ran `pull-email` (WorkIQ) → 142 messages, 30-day window.
86
+ 3. Ran `pull-teams` (WorkIQ) → 11 chats, 308 messages.
87
+ 4. … (one line per meaningful step)
88
+
89
+ ## Decisions
90
+
91
+ - Skipped `pull-crm` — `integrations.yml` has no `crm.engagement_id` for this project.
92
+ - Used WorkIQ-only path; no `m365_*` fallback triggered.
93
+
94
+ ## Outputs
95
+
96
+ - `HCA Healthcare/Evidence/ushak/email/snapshot/2026-05-19.md`
97
+ - `HCA Healthcare/Evidence/ushak/teams/snapshot/2026-05-19.md`
98
+ - `HCA Healthcare/State/00_overview.md` (updated)
99
+
100
+ ## Open questions / next steps
101
+
102
+ - ADO field `Custom.FDEStatusSummary` is empty — recommend running `/fde-report hca` next.
103
+ - 3 OneNote pages returned `page-body-unavailable`; see notes in `Evidence/ushak/onenote/run-notes.md`.
104
+
105
+ ## Errors / fallbacks
106
+
107
+ - None.
108
+
109
+ ## Citations
110
+
111
+ - `Evidence/ushak/email/snapshot/2026-05-19.md` · 2026-05-19
112
+ - `Evidence/ushak/teams/snapshot/2026-05-19.md` · 2026-05-19
113
+ ```
114
+
115
+ Section rules:
116
+
117
+ * **Ask** — required. One short paragraph.
118
+ * **Steps taken** — required. One bullet per meaningful action. Skip trivial tool calls.
119
+ * **Decisions** — required when you chose A over B, skipped a step, or applied a fallback.
120
+ * **Outputs** — required. Bullet list of files written/updated this run.
121
+ * **Open questions / next steps** — required, even if empty (write "None.").
122
+ * **Errors / fallbacks** — required when anything failed, retried, or fell back to a classified-fallback path (e.g., WorkIQ → `m365_*`).
123
+ * **Citations** — required when the artifact references Evidence files; same format as everywhere else in Kushi (`<source-path> · <YYYY-MM-DD>`).
124
+
125
+ ## When to write
126
+
127
+ * **First step of every prompt run:** create the file with frontmatter (`status: in-progress`) so a crash leaves something behind.
128
+ * **As you go:** append "Steps taken" lines. Update "Outputs" when files land.
129
+ * **Last step of every prompt run:** set `status: complete` (or `blocked` / `failed`), set `finished`, and fill in the closing sections.
130
+
131
+ If the prompt runs multiple sub-skills in parallel, the orchestrating prompt owns the tracking file. Sub-skills do not write their own runs/ entry; they report back and the parent appends.
132
+
133
+ ## When NOT to write
134
+
135
+ * `intro`, `status`, `self-check` — trivial / introspective. Skip the tracking file.
136
+ * Any prompt that does nothing but read a single file and answer.
137
+ * Dry-run / preview invocations (`--dry-run`, `--preview`) — log to stdout only.
138
+
139
+ ## Interaction with other doctrine
140
+
141
+ * `update-ledger.instructions.md` — write-path skills (ADO apply, future CRM apply) still write a **ledger** under `<project>/ado-updates/<date>/`. The tracking file additionally records that a write happened and links to the ledger. Ledger is authoritative for *what was written*; tracking is the *story around it*.
142
+ * `evidence-layout-canonical.instructions.md` — tracking files are NEVER a substitute for Evidence/. Evidence/ is the contract; tracking is the journal.
143
+ * `answer-from-evidence.instructions.md` — `/ask` writes its answer to `qa/` *in addition to* returning it in chat, so the same question asked tomorrow can be answered from the archive (with a freshness check).
144
+
145
+ ## Cross-host behavior
146
+
147
+ * Path is always relative to the **workspace root** (the folder the user opened in VS Code / Clawpilot / Cursor).
148
+ * In Clawpilot specifically, the workspace root is whichever folder the user is operating on (an engagement folder, a code repo, etc.) — *not* `~/.copilot/m-skills/kushi/`. The Kushi install location and the tracking location are independent.
149
+ * The Clawpilot weekly automation (`~/.copilot/kushi-projects.json`) is unaffected — it operates on engagement folders and produces tracking artifacts in each engagement folder's `.kushi/tracking/`.
150
+
151
+ ## Self-check coverage
152
+
153
+ Future self-check rule **C14: tracking-artifact required** will verify:
154
+
155
+ * Every prompt under `plugin/prompts/` (except the opt-out list above) references this instruction file.
156
+ * Every prompt's closing step is "write/update the tracking artifact".
157
+
158
+ C14 is added when this convention reaches 1.0 across all prompts.
159
+
160
+ ## References
161
+
162
+ * `evidence-layout-canonical.instructions.md` — Evidence/ shape (the canonical output).
163
+ * `update-ledger.instructions.md` — write-path ledger (orthogonal, additive).
164
+ * `citation-ledger.instructions.md` — citation format used inside tracking artifacts.
165
+ * `engagement-root-resolution.instructions.md` — how to resolve `<project>` for the filename slug.
@@ -28,6 +28,7 @@ Applies to ALL evidence retrieval from these M365 sources:
28
28
  - Email bodies and attachments
29
29
  - SharePoint file contents (when text extraction is needed)
30
30
  - Calendar events (when not already known by id)
31
+ - **Contributor identity** (UPN / displayName / mailNickname) — see `identity-resolution.instructions.md` for the canonical "who am I?" probe.
31
32
 
32
33
  **Out of scope** (these are NOT WorkIQ — they remain on their direct paths):
33
34
 
@@ -22,3 +22,5 @@ This is the **pull-only** verb. Every enabled source is pulled and per-user stre
22
22
  ```
23
23
 
24
24
  See `skills/aggregate-project/SKILL.md` for the full sequence and output contract.
25
+
26
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/runs/{{YYYY-MM-DD}}-<project>-aggregate.md` as the final step.
@@ -14,3 +14,5 @@ Read-only. NEVER triggers a `pull-*` skill — if evidence is stale or missing,
14
14
  You don't actually need this prompt — `ask-project` auto-routes whenever your message names a known project and asks a question (what / who / when / status / summarize / etc.). The slash form just provides an explicit handle.
15
15
 
16
16
  Delegates to `ask-project` skill.
17
+
18
+ Tracking: see `tracking.instructions.md`. Archive every answer to `<workspace>/.kushi/tracking/qa/{{YYYY-MM-DD}}-<project>-<question-slug>.md` (frontmatter + Ask + Answer + Citations + freshness note).
@@ -20,4 +20,6 @@ Produces:
20
20
  - `<engagement-root>/<project>/Evidence/{contributors.yml, run-log.yml, <alias>/.settings.yml, <alias>/{email,teams,meetings,onenote,sharepoint,crm,ado}/{snapshot,stream}/}`
21
21
  - `<engagement-root>/<project>/State/{00..09}_*.md`
22
22
 
23
- Delegates to `bootstrap-project` skill. After scaffolding, calls each `pull-<source>` skill, then `build-state`.
23
+ Delegates to `bootstrap-project` skill. After scaffolding, calls each `pull-<source>` skill, then `build-state`.
24
+
25
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/runs/{{YYYY-MM-DD}}-<project>-bootstrap.md` as the final step.
@@ -18,4 +18,6 @@ Writes:
18
18
 
19
19
  Provenance tags retained (source: <alias>/<source>/<file>) per `citation-ledger.instructions.md`.
20
20
 
21
- Delegates to `consolidate-evidence` skill.
21
+ Delegates to `consolidate-evidence` skill.
22
+
23
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/runs/{{YYYY-MM-DD}}-<project>-consolidate.md` as the final step.
@@ -39,3 +39,5 @@ Authors (first time) or updates (subsequent runs) the **FDE Intake** at `<engage
39
39
  - `skills/fde-intake/SKILL.md` for the full step-by-step.
40
40
  - `@Kushi fde-triage <project>` — produces the 7-file triage bundle that builds ON the intake.
41
41
  - `@Kushi fde-report <project> stage-readiness` — separate "should we advance the stage?" check.
42
+
43
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/fde/intake/{{YYYY-MM-DD}}-<project>-<slug>.md` as the final step.
@@ -44,3 +44,5 @@ Generates an FDE-shaped engagement report. Read-only against Evidence; no outbou
44
44
  - `skills/fde-report/SKILL.md` for the full step-by-step.
45
45
  - `@Kushi fde-intake <project>` — precursor first-artifact intake document.
46
46
  - `@Kushi fde-triage <project>` — full 7-file triage bundle (analysis + fitness + risk + 6Q + mobilization readiness + executive readout + reuse lens + validation warnings).
47
+
48
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/fde/report/{{YYYY-MM-DD}}-<project>-<shape>.md` as the final step.
@@ -44,3 +44,5 @@ Re-running on the same day overwrites files 00–06 in place and **merges file 0
44
44
  - `skills/fde-triage/SKILL.md` for the full step-by-step.
45
45
  - `@Kushi fde-intake <project>` — first-artifact intake document (precursor to the bundle).
46
46
  - `@Kushi fde-report <project> [shape]` — individual report shapes (weekly / short / long / fitness / stage-readiness).
47
+
48
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/fde/triage/{{YYYY-MM-DD}}-<project>-bundle.md` as the final step (one summary entry, not 7 — the bundle itself lives under `Reports/triage/`).
@@ -14,4 +14,6 @@ Window resolution (per `refresh-project` skill):
14
14
 
15
15
  Output is always weekly-bucketed regardless of input window.
16
16
 
17
- Delegates to `refresh-project` skill. Skips `pull-<source>` for sources marked disabled in `integrations.yml` or whose config is missing.
17
+ Delegates to `refresh-project` skill. Skips `pull-<source>` for sources marked disabled in `integrations.yml` or whose config is missing.
18
+
19
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/runs/{{YYYY-MM-DD}}-<project>-refresh.md` as the final step.
@@ -14,4 +14,6 @@ Pure renderer. Reads:
14
14
  Writes:
15
15
  - `<engagement-root>/<project>/State/{00_overview, 01_decisions, 02_stakeholders, 03_architecture-and-solution, 04_workshops-and-key-meetings, 05_action-items, 06_risks-and-issues, 07_timeline-and-milestones, 08_artifacts-and-deliverables, 09_open-questions}.md`
16
16
 
17
- Delegates to `build-state` skill. Use this when you've manually edited Evidence files and want State refreshed without re-pulling.
17
+ Delegates to `build-state` skill. Use this when you've manually edited Evidence files and want State refreshed without re-pulling.
18
+
19
+ Tracking: see `tracking.instructions.md`. Write `<workspace>/.kushi/tracking/runs/{{YYYY-MM-DD}}-<project>-state.md` as the final step.
@@ -35,10 +35,25 @@ After every run (success or coverage-gaps), write `<project>/bootstrap-status.md
35
35
 
36
36
  - `<project>` — engagement name (fuzzy-matched per `engagement-root-resolution.instructions.md`).
37
37
  - `<window>` — defaults to **last 30 days** (override with `last N days` / `since <date>`).
38
- - Implicit: current contributor `<alias>` (from personal config).
38
+ - Implicit: current contributor `<alias>` (resolved in Step 0 — see below).
39
39
 
40
40
  ## Steps
41
41
 
42
+ ### Step 0 — Identity resolution (REQUIRED, never asks the user)
43
+
44
+ Per `identity-resolution.instructions.md`. Read `<workspace>/.kushi/config/project-evidence.yml`:
45
+
46
+ * If `alias`, `email`, or `display_name` is missing / `<auto>` / matches a placeholder → call WorkIQ once:
47
+ ```
48
+ workiq ask -q "Who am I? Return UPN, displayName, mailNickname as JSON."
49
+ ```
50
+ Map `upn → email`, `displayName → display_name`, `mailNickname → alias` (fallback `email.split('@')[0]`).
51
+ * Persist resolved values back to the YAML (preserve comments).
52
+ * Echo one line: `✓ Identity: <displayName> <<UPN>> (alias=<alias>). Edit .kushi/config/project-evidence.yml to override.`
53
+ * If all three are already explicit non-placeholder values → skip silently.
54
+
55
+ Hard stop if WorkIQ returns auth error or empty — print the WorkIQ sign-in hint and exit. Never fall back to asking the user.
56
+
42
57
  ### Step 1 — Machine preflight (SETUP)
43
58
 
44
59
  Verify in order. Stop on hard failures.
@@ -5,14 +5,23 @@
5
5
  # maintains their own. Nothing here is a secret, but it IS personal —
6
6
  # add `.kushi/config/` to .gitignore before committing the rest of .kushi/.
7
7
  #
8
- # Edit the values below (lines marked FILL ME IN), then run `bootstrap <project>`.
8
+ # IDENTITY auto-detected on first bootstrap.
9
+ # On the first run of `bootstrap <project>`, Kushi asks WorkIQ "who am I?"
10
+ # and fills these three fields in for you (UPN, displayName, mailNickname).
11
+ # You only need to override them if you want a different folder name or
12
+ # a friendlier display label. Leave them at the placeholder values to
13
+ # trigger auto-detection.
9
14
 
10
- # FILL ME IN — short id used as your evidence subfolder name (e.g. "alex", "jordan").
11
- alias: <your-alias>
15
+ # Optional override — short id used as your Evidence/ subfolder name.
16
+ # Leave as <auto> to derive from the part before "@" in your email.
17
+ alias: <auto>
12
18
 
13
- # FILL ME IN
14
- display_name: <Your Full Name>
15
- email: your.email@example.com
19
+ # Optional override — friendly label used in run logs.
20
+ # Leave as <auto> to pull from WorkIQ's displayName.
21
+ display_name: <auto>
22
+
23
+ # Optional override — your work email. Leave as <auto> to pull from WorkIQ.
24
+ email: <auto>
16
25
 
17
26
  # FILL ME IN — where your engagement-root lives. The parent folder containing
18
27
  # one subfolder per project (typically synced from a team SharePoint library).
@@ -35,4 +44,5 @@ active_projects:
35
44
  # 2. `workiq` on PATH
36
45
  # 3. ~/.kushi/bin/workiq.cmd (Windows) / ~/.kushi/bin/workiq (Linux/macOS)
37
46
  # workiq:
38
- # cli_path: 'C:\Users\<you>\.kushi\bin\workiq.cmd'
47
+ # cli_path: 'C:\Users\<you>\.kushi\bin\workiq.cmd'
48
+
@@ -0,0 +1,125 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync, statSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+
6
+ /**
7
+ * Probe for a working WorkIQ install.
8
+ *
9
+ * Resolution order:
10
+ * 1. explicit absolute path supplied via --workiq-path / opts.workiqPath
11
+ * 2. `workiq` on PATH (via `where` on Windows, `command -v` elsewhere)
12
+ * 3. Kushi-managed bin: ~/.kushi/bin/workiq.cmd (Win) or ~/.kushi/bin/workiq
13
+ *
14
+ * Returns:
15
+ * { ok: true, path, version } — usable WorkIQ found
16
+ * { ok: false, reason, hint } — not found / not runnable
17
+ *
18
+ * Reasons:
19
+ * 'not-found' — no workiq binary anywhere we looked
20
+ * 'path-invalid' — explicit --workiq-path was given but the file doesn't exist
21
+ * 'not-executable' — found but `--version` failed (corrupt install, missing deps, etc.)
22
+ */
23
+ export function checkWorkIQ(opts = {}) {
24
+ const isWin = process.platform === 'win32';
25
+ const homeBin = path.join(
26
+ os.homedir(),
27
+ '.kushi',
28
+ 'bin',
29
+ isWin ? 'workiq.cmd' : 'workiq',
30
+ );
31
+
32
+ if (opts.workiqPath) {
33
+ const abs = path.resolve(opts.workiqPath);
34
+ if (!existsSync(abs) || !statSync(abs).isFile()) {
35
+ return {
36
+ ok: false,
37
+ reason: 'path-invalid',
38
+ hint: `--workiq-path "${opts.workiqPath}" does not point at an existing file.`,
39
+ };
40
+ }
41
+ return runVersion(abs);
42
+ }
43
+
44
+ const onPath = findOnPath('workiq');
45
+ if (onPath) return runVersion(onPath);
46
+
47
+ if (existsSync(homeBin) && statSync(homeBin).isFile()) {
48
+ return runVersion(homeBin);
49
+ }
50
+
51
+ return {
52
+ ok: false,
53
+ reason: 'not-found',
54
+ hint: installHint(),
55
+ };
56
+ }
57
+
58
+ function findOnPath(name) {
59
+ const isWin = process.platform === 'win32';
60
+ const cmd = isWin ? 'where' : 'command';
61
+ const args = isWin ? [name] : ['-v', name];
62
+ const res = spawnSync(cmd, args, { encoding: 'utf-8', shell: !isWin });
63
+ if (res.status !== 0) return null;
64
+ const first = (res.stdout || '').split(/\r?\n/).map((s) => s.trim()).find(Boolean);
65
+ return first || null;
66
+ }
67
+
68
+ function runVersion(binPath) {
69
+ const res = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10_000 });
70
+ if (res.status !== 0) {
71
+ return {
72
+ ok: false,
73
+ reason: 'not-executable',
74
+ hint: `Found WorkIQ at ${binPath} but \`workiq --version\` failed (exit ${res.status}). Try reinstalling. ${installHint()}`,
75
+ };
76
+ }
77
+ const version = (res.stdout || res.stderr || '').trim().split(/\r?\n/)[0] || 'unknown';
78
+ return { ok: true, path: binPath, version };
79
+ }
80
+
81
+ function installHint() {
82
+ const plat = process.platform;
83
+ if (plat === 'win32') {
84
+ return 'Install with: winget install Microsoft.WorkIQ';
85
+ }
86
+ if (plat === 'darwin') {
87
+ return 'Install with: brew install --cask microsoft-workiq';
88
+ }
89
+ return 'See https://gim-home.github.io/kushi/getting-started/install-workiq/ for Linux instructions.';
90
+ }
91
+
92
+ /**
93
+ * Best-effort auto-install via the platform's package manager.
94
+ * Only invoked when --with-workiq is passed. Non-blocking on failure —
95
+ * caller decides whether to hard-fail.
96
+ *
97
+ * Returns { ok, reason, output }.
98
+ */
99
+ export function tryInstallWorkIQ() {
100
+ const plat = process.platform;
101
+ let cmd, args;
102
+ if (plat === 'win32') {
103
+ cmd = 'winget';
104
+ args = ['install', '--id', 'Microsoft.WorkIQ', '-e', '--accept-package-agreements', '--accept-source-agreements'];
105
+ } else if (plat === 'darwin') {
106
+ cmd = 'brew';
107
+ args = ['install', '--cask', 'microsoft-workiq'];
108
+ } else {
109
+ return {
110
+ ok: false,
111
+ reason: 'unsupported-platform',
112
+ output: 'Auto-install is not supported on Linux. See https://gim-home.github.io/kushi/getting-started/install-workiq/',
113
+ };
114
+ }
115
+
116
+ const res = spawnSync(cmd, args, { encoding: 'utf-8', stdio: 'inherit' });
117
+ if (res.error || res.status !== 0) {
118
+ return {
119
+ ok: false,
120
+ reason: 'install-failed',
121
+ output: res.error ? res.error.message : `${cmd} exited with status ${res.status}`,
122
+ };
123
+ }
124
+ return { ok: true, output: `${cmd} ${args.join(' ')} succeeded` };
125
+ }
package/src/main.mjs CHANGED
@@ -17,6 +17,7 @@ import { copyAssets, copyProjectFiles } from './copy-assets.mjs';
17
17
  import { mergeSettings } from './settings.mjs';
18
18
  import { mergeCopilotInstructions } from './copilot-instructions.mjs';
19
19
  import { seedConfig } from './seed-config.mjs';
20
+ import { checkWorkIQ, tryInstallWorkIQ } from './check-workiq.mjs';
20
21
  import {
21
22
  resolveProfile,
22
23
  makeIncludeFilter,
@@ -71,6 +72,9 @@ export async function main(options = {}) {
71
72
  console.log(` Profile chain: ${resolved.chain.join(' -> ')}`);
72
73
  console.log(` ${resolved.description}\n`);
73
74
 
75
+ // Hard prerequisite: WorkIQ. Kushi cannot pull evidence without it.
76
+ await preflightWorkIQ(options);
77
+
74
78
  if (target === TARGET_CLAWPILOT) {
75
79
  await installClawpilot(options, resolved, version);
76
80
  } else {
@@ -290,6 +294,56 @@ async function confirmOverwriteIfExists(fullDest, displayDest, force) {
290
294
  }
291
295
  }
292
296
 
297
+ /**
298
+ * Hard prerequisite: WorkIQ must be installed and runnable before Kushi will
299
+ * copy any assets. Kushi's pull-* skills are useless without it. Three modes:
300
+ *
301
+ * --skip-workiq-check → print a warning and continue (CI / asset-inspection only)
302
+ * --with-workiq → attempt auto-install via winget/brew first, then re-check
303
+ * default → probe; on failure, print install hint and exit 1
304
+ *
305
+ * Always prints the resolved WorkIQ path + version on success so users have a
306
+ * record in their terminal scrollback.
307
+ */
308
+ async function preflightWorkIQ(options) {
309
+ if (options.skipWorkiqCheck) {
310
+ console.warn(
311
+ ' ⚠️ WorkIQ pre-flight skipped (--skip-workiq-check).',
312
+ );
313
+ console.warn(
314
+ ' Kushi will install, but bootstrap/refresh will block until WorkIQ is present.\n',
315
+ );
316
+ return;
317
+ }
318
+
319
+ let result = checkWorkIQ({ workiqPath: options.workiqPath });
320
+
321
+ if (!result.ok && options.withWorkiq) {
322
+ console.log(' WorkIQ not found — attempting auto-install (--with-workiq)…\n');
323
+ const ins = tryInstallWorkIQ();
324
+ if (!ins.ok) {
325
+ console.error(`\n ✖ Auto-install failed: ${ins.output}\n`);
326
+ console.error(` ${result.hint || ''}\n`);
327
+ process.exit(1);
328
+ }
329
+ result = checkWorkIQ({ workiqPath: options.workiqPath });
330
+ }
331
+
332
+ if (!result.ok) {
333
+ console.error('\n ✖ WorkIQ is required and was not found.\n');
334
+ console.error(' Kushi cannot capture evidence without WorkIQ. Install it first:\n');
335
+ console.error(` ${result.hint}\n`);
336
+ console.error(' Then run `workiq ask -q "ping"` to confirm sign-in, and re-run this installer.\n');
337
+ console.error(' Escape hatches (NOT recommended):');
338
+ console.error(' • --workiq-path <abs> supply a non-standard install path');
339
+ console.error(' • --with-workiq let the installer try winget/brew');
340
+ console.error(' • --skip-workiq-check install assets anyway (bootstrap will still block)\n');
341
+ process.exit(1);
342
+ }
343
+
344
+ console.log(` ✓ WorkIQ detected at ${result.path} (${result.version})\n`);
345
+ }
346
+
293
347
  /**
294
348
  * Detect whether the cwd looks like a sane install target and, if not, print
295
349
  * an actionable message. Three cases: