kushi-agents 4.3.0 → 4.4.1
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/package.json +2 -4
- package/plugin/agents/kushi.agent.md +3 -3
- package/plugin/instructions/ado-engagement-tree.instructions.md +1 -1
- package/plugin/instructions/az-auth-conditional.instructions.md +2 -2
- package/plugin/instructions/azure-auth-patterns.instructions.md +8 -8
- package/plugin/instructions/bootstrap-status-format.instructions.md +37 -2
- package/plugin/instructions/cleanup-on-resolution.instructions.md +1 -1
- package/plugin/instructions/crm-bootstrap-discovery.instructions.md +1 -1
- package/plugin/instructions/deferred-retry-on-workiq-fail.instructions.md +155 -0
- package/plugin/instructions/engagement-root-resolution.instructions.md +16 -13
- package/plugin/instructions/evidence-layout-canonical.instructions.md +2 -2
- package/plugin/instructions/identity-resolution.instructions.md +19 -12
- package/plugin/instructions/m365-id-registry.instructions.md +1 -1
- package/plugin/instructions/multi-user-shared-files.instructions.md +87 -0
- package/plugin/instructions/run-reports.instructions.md +1 -1
- package/plugin/instructions/scope-boundaries.instructions.md +4 -4
- package/plugin/instructions/side-by-side-config.instructions.md +23 -17
- package/plugin/instructions/tracking.instructions.md +1 -1
- package/plugin/instructions/workiq-only.instructions.md +6 -4
- package/plugin/lib/Get-KushiConfig.ps1 +214 -0
- package/plugin/prompts/bootstrap.prompt.md +64 -35
- package/plugin/reference-packs/README.md +1 -1
- package/plugin/skills/apply-ado-update/SKILL.md +2 -2
- package/plugin/skills/ask-project/SKILL.md +1 -1
- package/plugin/skills/bootstrap-project/SKILL.md +18 -16
- package/plugin/skills/intro/SKILL.md +2 -2
- package/plugin/skills/propose-ado-update/SKILL.md +4 -4
- package/plugin/skills/pull-ado/SKILL.md +6 -6
- package/plugin/skills/pull-crm/SKILL.md +5 -5
- package/plugin/skills/pull-email/SKILL.md +2 -2
- package/plugin/skills/pull-meetings/SKILL.md +1 -1
- package/plugin/skills/pull-onenote/scripts/recapture-section-url.mjs +2 -1
- package/plugin/skills/pull-onenote/write-snapshot.mjs +2 -1
- package/plugin/skills/pull-sharepoint/SKILL.md +1 -1
- package/plugin/skills/pull-teams/SKILL.md +1 -1
- package/plugin/skills/refresh-project/SKILL.md +21 -1
- package/plugin/skills/self-check/run.ps1 +24 -1
- package/plugin/templates/ado-update/integrations-ado-writes.example.yml +1 -1
- package/plugin/templates/init/azuredevops.template.json +159 -0
- package/plugin/templates/init/dynamics365.template.json +412 -0
- package/plugin/templates/init/m365-auth.template.json +5 -5
- package/{.github/config/m365-mutable.json.example → plugin/templates/init/m365-mutable.example.json} +1 -1
- package/plugin/templates/init/project-integrations.template.yml +2 -2
- package/plugin/templates/init/rsi-program-catalog.template.json +107 -0
- package/plugin/templates/snapshot/onenote-page.template.md +3 -3
- package/src/config-loader.mjs +156 -0
- package/src/constants.mjs +54 -18
- package/src/copy-assets.mjs +0 -76
- package/src/main.mjs +30 -26
- package/src/seed-config.mjs +88 -23
- package/src/seed-config.test.mjs +150 -0
- package/plugin/templates/init/ado-config.template.yml +0 -21
- package/plugin/templates/init/crm-config.template.yml +0 -16
- /package/{.github/config/m365-auth.json.example → plugin/templates/init/m365-auth.example.json} +0 -0
|
@@ -21,13 +21,13 @@ This skill does **NOT** create a new top-level config file. It reads from the co
|
|
|
21
21
|
|
|
22
22
|
| What | Where | Maintained by |
|
|
23
23
|
|---|---|---|
|
|
24
|
-
| ADO tenant + org + apiVersion + auth strategy | `<
|
|
24
|
+
| ADO tenant + org + apiVersion + auth strategy | `<workspace>/.kushi/config/shared/integrations.yml` | `bootstrap-project` (global, one-time) |
|
|
25
25
|
| Per-project Initiative ID (`engagement_id`), area, title filter, discovery hints | `<engagement-root>/<project>/integrations.yml` under `ado:` | `bootstrap-project` + `pull-ado` (auto-discovers and persists) |
|
|
26
26
|
| Per-project **writes block** (allowlist, autoApply per field, strategy, fieldRefName) | `<engagement-root>/<project>/integrations.yml` under `ado.writes:` | First run of this skill scaffolds the block from the template, then user edits |
|
|
27
27
|
|
|
28
28
|
**Resolution is fully deterministic** — never ask the user for paths the bootstrap layer already resolved:
|
|
29
29
|
|
|
30
|
-
1. `<engagement-root>` ← `<workspace>/.kushi/config/project-evidence.yml engagement_root` (per `engagement-root-resolution.instructions.md`).
|
|
30
|
+
1. `<engagement-root>` ← `<workspace>/.kushi/config/user/project-evidence.yml engagement_root` (per `engagement-root-resolution.instructions.md`).
|
|
31
31
|
2. `<project>` folder ← fuzzy-match per `engagement-root-resolution.instructions.md` (knownSections → active_projects → subfolders).
|
|
32
32
|
3. `<project>/integrations.yml ado.engagement_id` — REQUIRED. If `0` or missing → see "Prerequisites" below; never invent an ID.
|
|
33
33
|
4. `<project>/integrations.yml ado.writes` — if missing, append the block from `<KUSHI_ROOT>/plugin/templates/ado-update/integrations-ado-writes.example.yml` and stop for user confirmation of `fieldRefName`.
|
|
@@ -41,7 +41,7 @@ Refuse to produce `proposed.md` and tell the user exactly what's missing if any
|
|
|
41
41
|
|---|---|
|
|
42
42
|
| `<project>/integrations.yml` exists | "Project not bootstrapped. Run `@Kushi bootstrap <project>` first." |
|
|
43
43
|
| `ado.engagement_id` > 0 | "ADO Initiative not yet linked for `<project>` (engagement_id is 0). pull-ado will auto-discover on next refresh; once `engagement_id` is set in `integrations.yml`, retry." |
|
|
44
|
-
| `<
|
|
44
|
+
| `<workspace>/.kushi/config/shared/integrations.yml` exists with non-placeholder `organization` | "Global ADO config missing or has placeholder org. Run `@Kushi bootstrap <project>` to scaffold, then fill `.kushi/config/shared/integrations.yml`." |
|
|
45
45
|
| At least one `Evidence/_Consolidated/<date>_consolidated.md` exists | "No consolidated evidence yet for `<project>`. Run `@Kushi refresh <project>` then `consolidate` first." |
|
|
46
46
|
| Latest consolidated file ≤ 8 days old | Continue but flag `stale-evidence` at top of `proposed.md`. |
|
|
47
47
|
|
|
@@ -76,7 +76,7 @@ Refuse to produce `proposed.md` and tell the user exactly what's missing if any
|
|
|
76
76
|
## What this skill does NOT do
|
|
77
77
|
|
|
78
78
|
- Does NOT call any ADO `PATCH` or `POST` endpoint.
|
|
79
|
-
- Does NOT create or modify the global `.
|
|
79
|
+
- Does NOT create or modify the global `.kushi/config/shared/integrations.yml`.
|
|
80
80
|
- Does NOT touch `<project>/integrations.yml` other than appending the `ado.writes:` sub-block on first run (preserving every existing key).
|
|
81
81
|
- Does NOT re-pull evidence (uses the most recent `_Consolidated/` file as-is).
|
|
82
82
|
- Does NOT write to the ledger (the ledger is written only by `apply-ado-update`).
|
|
@@ -27,9 +27,9 @@ WorkIQ-first per `workiq-first.instructions.md` — but **for ADO, REST is prefe
|
|
|
27
27
|
- `<project>` — already-resolved project name.
|
|
28
28
|
- `<alias>` — current contributor.
|
|
29
29
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
30
|
-
- (read) `<
|
|
30
|
+
- (read) `<workspace>/.kushi/config/shared/integrations.yml` — connection.
|
|
31
31
|
- (read) `<engagement-root>/<project>/integrations.yml#ado` — per-project pinned IDs.
|
|
32
|
-
- (read) `<
|
|
32
|
+
- (read) `<workspace>/.kushi/config/user/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints.
|
|
33
33
|
- (read) `<engagement-root>/<project>/Evidence/<alias>/.settings.yml` — per-(project x user) overrides.
|
|
34
34
|
|
|
35
35
|
## Resolution hints (pinned in mutable)
|
|
@@ -42,15 +42,15 @@ WorkIQ-first per `workiq-first.instructions.md` — but **for ADO, REST is prefe
|
|
|
42
42
|
|
|
43
43
|
This skill is **HARD-fail** without both:
|
|
44
44
|
|
|
45
|
-
1. Global config: `<
|
|
45
|
+
1. Global config: `<workspace>/.kushi/config/shared/integrations.yml` exists with non-placeholder `organization` AND `defaultProject`.
|
|
46
46
|
2. Per-project boundary: `<engagement-root>/<project>/integrations.yml#boundaries.ado.area_paths` is non-empty (OR `boundaries.ado.work_item_ids` is pinned).
|
|
47
47
|
|
|
48
48
|
If either is missing, refuse with the exact message:
|
|
49
49
|
|
|
50
50
|
```
|
|
51
51
|
ado-config-missing — drop a filled config.yml at
|
|
52
|
-
<
|
|
53
|
-
plugin/templates/init/
|
|
52
|
+
<workspace>/.kushi/config/shared/integrations.yml. See template at
|
|
53
|
+
plugin/templates/init/integrations.template.yml (ado: block). Then add boundaries.ado.area_paths
|
|
54
54
|
to <project>/integrations.yml.
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -61,7 +61,7 @@ tenant-wide title-fuzzy scan in v3.7.0+.
|
|
|
61
61
|
## Auth (deterministic, no improvisation)
|
|
62
62
|
|
|
63
63
|
```powershell
|
|
64
|
-
$cfg = Get-Content "<
|
|
64
|
+
$cfg = Get-Content "<workspace>/.kushi/config/shared/integrations.yml" | ConvertFrom-Yaml
|
|
65
65
|
$tok = az account get-access-token `
|
|
66
66
|
--resource $cfg.azDevOpsResourceId `
|
|
67
67
|
--tenant $cfg.tenantId `
|
|
@@ -27,7 +27,7 @@ WorkIQ-first per `workiq-first.instructions.md`. Thoroughness per `evidence-thor
|
|
|
27
27
|
- `<project>` — already-resolved project name.
|
|
28
28
|
- `<alias>` — current contributor.
|
|
29
29
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
30
|
-
- (read) `<
|
|
30
|
+
- (read) `<workspace>/.kushi/config/user/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints.
|
|
31
31
|
- (read) `<engagement-root>/<project>/Evidence/<alias>/.settings.yml` — per-(project x user) overrides.
|
|
32
32
|
|
|
33
33
|
## Resolution hints (pinned in mutable)
|
|
@@ -40,15 +40,15 @@ WorkIQ-first per `workiq-first.instructions.md`. Thoroughness per `evidence-thor
|
|
|
40
40
|
|
|
41
41
|
This skill is **HARD-fail** without both:
|
|
42
42
|
|
|
43
|
-
1. Global config: `<
|
|
43
|
+
1. Global config: `<workspace>/.kushi/config/shared/integrations.yml` exists with non-placeholder `environmentUrl`.
|
|
44
44
|
2. Per-project boundary: `<engagement-root>/<project>/integrations.yml#boundaries.crm.record_ids` OR `boundaries.crm.request_ids` is non-empty.
|
|
45
45
|
|
|
46
46
|
If either is missing, refuse with the exact message:
|
|
47
47
|
|
|
48
48
|
```
|
|
49
49
|
crm-config-missing — drop a filled config.yml at
|
|
50
|
-
<
|
|
51
|
-
plugin/templates/init/
|
|
50
|
+
<workspace>/.kushi/config/shared/integrations.yml. See template at
|
|
51
|
+
plugin/templates/init/integrations.template.yml (crm: block). Then add boundaries.crm.record_ids
|
|
52
52
|
(or request_ids) to <project>/integrations.yml.
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -195,7 +195,7 @@ If a week file already exists, MERGE (dedupe by event ID, append new events, kee
|
|
|
195
195
|
|
|
196
196
|
## Tools (in order)
|
|
197
197
|
|
|
198
|
-
1. **Dataverse REST Web API** (preferred for snapshot — gives explicit `$select` + `$expand` control) via `az account get-access-token` against the configured tenant. Read connection from `<
|
|
198
|
+
1. **Dataverse REST Web API** (preferred for snapshot — gives explicit `$select` + `$expand` control) via `az account get-access-token` against the configured tenant. Read connection from `<workspace>/.kushi/config/shared/integrations.yml`.
|
|
199
199
|
2. **WorkIQ** — only when REST is unavailable; phrase queries to demand verbatim long-text + every annotation (see Step B template above). WorkIQ summarizes by default, so use this path only as fallback.
|
|
200
200
|
3. **Graph REST** — last resort, soft-fail per `az-auth-conditional.instructions.md`.
|
|
201
201
|
4. **Ask user** — paste verbatim source content if all above fail.
|
|
@@ -26,7 +26,7 @@ Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + aut
|
|
|
26
26
|
- `<project>` — already-resolved project name.
|
|
27
27
|
- `<alias>` — current contributor.
|
|
28
28
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
29
|
-
- (read) `<
|
|
29
|
+
- (read) `<workspace>/.kushi/config/user/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints.
|
|
30
30
|
- (read) `<engagement-root>/<project>/Evidence/<alias>/.settings.yml` — per-(project x user) overrides.
|
|
31
31
|
|
|
32
32
|
## Resolution hints (pinned in mutable)
|
|
@@ -43,7 +43,7 @@ This skill REFUSES to query unless `<engagement-root>/<project>/integrations.yml
|
|
|
43
43
|
- `boundaries.email.subject_keywords` — optional narrowing.
|
|
44
44
|
- `boundaries.date_window_days` — defaults to 30 if absent.
|
|
45
45
|
|
|
46
|
-
Every WorkIQ ask
|
|
46
|
+
Every WorkIQ ask MUST be scoped to those mailboxes + (if set) sender_domains + subject_keywords. Empty hits inside the boundary → write Coverage Notes citing the limiting key; do NOT widen the scope. (`m365_search_emails` / `m365_list_emails` / any Graph call is FORBIDDEN per `workiq-only.instructions.md`; on WorkIQ failure, write a deferred-retry marker per `deferred-retry-on-workiq-fail.instructions.md` and continue.)
|
|
47
47
|
|
|
48
48
|
Refusal message when boundary is missing:
|
|
49
49
|
|
|
@@ -30,7 +30,7 @@ Auth + retry + error logging per `auth-and-retry.instructions.md`. WorkIQ-only p
|
|
|
30
30
|
- `<project>` — already-resolved project name.
|
|
31
31
|
- `<alias>` — current contributor.
|
|
32
32
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
33
|
-
- (read) `<
|
|
33
|
+
- (read) `<workspace>/.kushi/config/user/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints (`calendarContext.subjectKeywords`, `calendarContext.knownSeries`).
|
|
34
34
|
|
|
35
35
|
## Discovery (snapshot pass — WorkIQ ONLY per `workiq-only.instructions.md`)
|
|
36
36
|
|
|
@@ -49,7 +49,8 @@ if (!PROJECT || !ENGAGEMENT_ROOT) {
|
|
|
49
49
|
process.exit(2);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const
|
|
52
|
+
const WORKSPACE = args.workspace || process.cwd();
|
|
53
|
+
const REG_PATH = path.join(WORKSPACE, '.kushi', 'config', 'user', 'm365-mutable.json');
|
|
53
54
|
if (!fs.existsSync(REG_PATH)) {
|
|
54
55
|
console.error(`[recapture-section-url] Registry not found: ${REG_PATH}`);
|
|
55
56
|
process.exit(3);
|
|
@@ -54,7 +54,8 @@ const TIMEOUT_MS = args.timeout || '120000';
|
|
|
54
54
|
const PROJECT = args.project;
|
|
55
55
|
const ROOT = args['engagement-root'];
|
|
56
56
|
const ALIAS = args.alias || 'ushak';
|
|
57
|
-
const
|
|
57
|
+
const WORKSPACE = args.workspace || process.cwd();
|
|
58
|
+
const MUTABLE_PATH = args.mutable || path.join(WORKSPACE, '.kushi', 'config', 'user', 'm365-mutable.json');
|
|
58
59
|
|
|
59
60
|
if ((!JSON_PATH && !SECTION_URL) || !PROJECT || !ROOT) {
|
|
60
61
|
console.error('Usage: (--json <runner-output> | --section-url <url>) --project <name> --engagement-root <root> [--alias ushak] [--mutable <path>] [--timeout 120000]');
|
|
@@ -28,7 +28,7 @@ Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + aut
|
|
|
28
28
|
- `<project>` — already-resolved project name.
|
|
29
29
|
- `<alias>` — current contributor.
|
|
30
30
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
31
|
-
- (read) `<
|
|
31
|
+
- (read) `<workspace>/.kushi/config/user/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints.
|
|
32
32
|
- (read) `<engagement-root>/<project>/Evidence/<alias>/.settings.yml` — per-(project x user) overrides.
|
|
33
33
|
|
|
34
34
|
## Resolution hints (pinned in mutable)
|
|
@@ -28,7 +28,7 @@ Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + aut
|
|
|
28
28
|
- `<project>` — already-resolved project name.
|
|
29
29
|
- `<alias>` — current contributor.
|
|
30
30
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
31
|
-
- (read) `<
|
|
31
|
+
- (read) `<workspace>/.kushi/config/user/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints.
|
|
32
32
|
- (read) `<engagement-root>/<project>/Evidence/<alias>/.settings.yml` — per-(project x user) overrides.
|
|
33
33
|
|
|
34
34
|
## Resolution hints (pinned in mutable)
|
|
@@ -8,7 +8,7 @@ description: "Incremental refresh for an already-bootstrapped project. Reads run
|
|
|
8
8
|
|
|
9
9
|
> **Verbatim-by-default**: This orchestrator MUST dispatch every enabled `pull-<source>` skill whose boundary in `integrations.yml#boundaries.<source>` is satisfied. Skipping a source silently is a defect. See `verbatim-by-default.instructions.md`.
|
|
10
10
|
>
|
|
11
|
-
> **Discover once, consume deterministically**: Refresh MUST read canonical M365 IDs from `<
|
|
11
|
+
> **Discover once, consume deterministically**: Refresh MUST read canonical M365 IDs from `<workspace>/.kushi/config/user/m365-mutable.json#knownSections.<projectKey>` and pass them verbatim into each `pull-*`'s index-extractor query. **Refresh never re-discovers.** If the project entry is missing or a per-source key is empty, re-dispatch through `bootstrap-project` for that source's discovery only, then resume. See `m365-id-registry.instructions.md`.
|
|
12
12
|
>
|
|
13
13
|
> **Per-user refresh report REQUIRED**: At end of run, write `<project>/Evidence/<alias>/refresh-reports/<YYYY-MM-DD-HHmm>_refresh.md` per `run-reports.instructions.md`. Even on a no-op run. Cite the registry: `Resolved IDs sourced from m365-mutable.json#knownSections.<projectKey>`.
|
|
14
14
|
>
|
|
@@ -50,6 +50,26 @@ Profile is read from `kushi-install.json#profile` next to the agent file. Defaul
|
|
|
50
50
|
- Else if `sources.<src>.watermark` exists → use `(watermark, today)`.
|
|
51
51
|
- Else (first refresh after bootstrap, or new source) → fallback to `last 7 days`.
|
|
52
52
|
|
|
53
|
+
### Step 2a — Drain deferred-retry queue (REQUIRED, kushi v4.4.1+, per `deferred-retry-on-workiq-fail.instructions.md`)
|
|
54
|
+
|
|
55
|
+
**Before per-source dispatch**, drain any markers that previous runs deferred. The queue lives at:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
<engagement-root>/<project>/Evidence/<alias>/_deferred-retries/*.yml
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For each marker (chronological order):
|
|
62
|
+
|
|
63
|
+
1. Load the YAML marker. Parse `source`, `target`, `window`, `workiq.command`.
|
|
64
|
+
2. Re-issue the canonical WorkIQ query (NOT the doubled-strict — give the first prompt another chance first; if it fails, then doubled-strict).
|
|
65
|
+
3. If success → write the artifact to its canonical `Evidence/<alias>/<source>/{snapshot,stream}/` path per the source's normal write rules. Delete the marker. Append a `drained:` entry to the refresh report's `## Deferred-retry drain` section.
|
|
66
|
+
4. If failure → increment `attempts`, update `last_attempt_at`, leave marker in place. Append a `still-deferred:` entry to the report.
|
|
67
|
+
5. If `attempts >= 5` after this run → also promote to a row in `<project>/OPEN-QUESTIONS-DRAFT.md` (or `State/09_open-questions.md` on `full` profile) per the doctrine's escalation rule.
|
|
68
|
+
|
|
69
|
+
**NEVER call `m365_get_*` / Graph as a fallback during drain.** A drain failure is just another deferral.
|
|
70
|
+
|
|
71
|
+
After drain, proceed to Step 2 even if some markers remain — the orchestrator never blocks on deferred-retry failures.
|
|
72
|
+
|
|
53
73
|
### Step 2 — Per-source dispatch
|
|
54
74
|
|
|
55
75
|
For each enabled source (or just the requested one), call its `pull-<source>` skill with the effective window.
|
|
@@ -616,7 +616,7 @@ if ($Deep) {
|
|
|
616
616
|
if (-not (Test-Path $layoutInst)) {
|
|
617
617
|
Add-Finding D14 'Evidence layout' 'warning' "plugin/instructions/evidence-layout-canonical.instructions.md is missing" "Restore the canonical-layout doctrine from kushi v3.12.1." $layoutInst 0
|
|
618
618
|
}
|
|
619
|
-
$allowedSiblings = @('Evidence','State','Reports','.kushi','.kushi-reference','.
|
|
619
|
+
$allowedSiblings = @('Evidence','State','Reports','.kushi','.kushi-reference','.vscode','.git')
|
|
620
620
|
$sourceTokens = @(
|
|
621
621
|
'email-context','email-summary','email-summaries',
|
|
622
622
|
'teams-context','teams-summary','teams-summaries',
|
|
@@ -655,6 +655,29 @@ if ($Deep) {
|
|
|
655
655
|
}
|
|
656
656
|
}
|
|
657
657
|
}
|
|
658
|
+
|
|
659
|
+
# D15: legacy path regression guard — no `.project-evidence/{m365,crm,ado}` refs outside CHANGELOG/learnings.
|
|
660
|
+
# v4.4.0+ moved per-user config to `<workspace>/.kushi/config/{user,shared}/`. Any plugin/docs file
|
|
661
|
+
# still referencing the legacy `<engagement-root>/.project-evidence/(m365|crm|ado)` path will mislead
|
|
662
|
+
# skills and authors. CHANGELOG and learnings/ legitimately mention the legacy path for history.
|
|
663
|
+
$legacyPattern = '\.project-evidence[\\/](?:m365|crm|ado)'
|
|
664
|
+
$legacyTargets = @(
|
|
665
|
+
(Join-Path $Root 'plugin'),
|
|
666
|
+
(Join-Path $Root 'docs')
|
|
667
|
+
)
|
|
668
|
+
foreach ($target in $legacyTargets) {
|
|
669
|
+
if (-not (Test-Path $target)) { continue }
|
|
670
|
+
$legacyHits = Get-ChildItem -Path $target -Recurse -File -Include '*.md','*.ps1','*.mjs','*.json','*.yml','*.yaml' -ErrorAction SilentlyContinue |
|
|
671
|
+
Where-Object { $_.FullName -notmatch '[\\/]learnings[\\/]' -and $_.Name -ne 'CHANGELOG.md' } |
|
|
672
|
+
Select-String -Pattern $legacyPattern -ErrorAction SilentlyContinue
|
|
673
|
+
foreach ($m in $legacyHits) {
|
|
674
|
+
# Allow lines that explicitly mark as historical breadcrumb (contain "legacy" or "v4.4.0+" or "was")
|
|
675
|
+
if ($m.Line -match '(?i)\blegacy\b|v4\.4\.0\+|\bwas\b|\breplaces?\b|\bdeprecated\b|\bhistorical\b') { continue }
|
|
676
|
+
$msg = 'Legacy .project-evidence/{m365|crm|ado} reference — v4.4.0+ moved per-user config to <workspace>/.kushi/config/{user,shared}/'
|
|
677
|
+
$fix = "Replace with the new path; if intentionally documenting history, add the word 'legacy' or 'v4.4.0+ replaces' on the same line."
|
|
678
|
+
Add-Finding D15 'Legacy paths' 'warning' $msg $fix $m.Path $m.LineNumber
|
|
679
|
+
}
|
|
680
|
+
}
|
|
658
681
|
}
|
|
659
682
|
|
|
660
683
|
# === Output ===
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# read from the SAME integrations.yml that pull-ado already uses — no separate config file.
|
|
5
5
|
#
|
|
6
6
|
# Global ADO connection (tenantId, organization, apiVersion, auth) lives at:
|
|
7
|
-
# <
|
|
7
|
+
# <workspace>/.kushi/config/shared/integrations.yml
|
|
8
8
|
# Do NOT duplicate those keys here.
|
|
9
9
|
|
|
10
10
|
ado:
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
{
|
|
2
|
+
"azureDevOps": {
|
|
3
|
+
"organizationUrl": "https://dev.azure.com/IndustrySolutions",
|
|
4
|
+
"project": "IS Engagements",
|
|
5
|
+
"apiVersion": "7.1",
|
|
6
|
+
"resource": "499b84ac-1321-427f-aa17-267ca6975798",
|
|
7
|
+
"tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
|
|
8
|
+
"allowedTenantIds": [
|
|
9
|
+
"72f988bf-86f1-41af-91ab-2d7cd011db47"
|
|
10
|
+
],
|
|
11
|
+
"workItemTypes": {
|
|
12
|
+
"engagement": "Engagement",
|
|
13
|
+
"activity": "Activity"
|
|
14
|
+
},
|
|
15
|
+
"queryTemplates": {
|
|
16
|
+
"engagementByExactTitle": "SELECT [System.Id], [System.Title], [System.State], [System.ChangedDate] FROM WorkItems WHERE [System.TeamProject] = '@project' AND [System.WorkItemType] = '@engagementType' AND [System.Title] = '@title' ORDER BY [System.ChangedDate] DESC",
|
|
17
|
+
"engagementByPartialTitle": "SELECT [System.Id], [System.Title], [System.State], [System.ChangedDate] FROM WorkItems WHERE [System.TeamProject] = '@project' AND [System.WorkItemType] = '@engagementType' AND [System.Title] CONTAINS '@titlePart' ORDER BY [System.ChangedDate] DESC",
|
|
18
|
+
"activityByParentEngagementId": "SELECT [System.Id], [System.Title], [System.State], [System.ChangedDate] FROM WorkItems WHERE [System.TeamProject] = '@project' AND [System.WorkItemType] = '@activityType' AND [System.Parent] = @engagementId ORDER BY [System.ChangedDate] DESC"
|
|
19
|
+
},
|
|
20
|
+
"fieldMappings": {
|
|
21
|
+
"common": {
|
|
22
|
+
"id": "System.Id",
|
|
23
|
+
"title": "System.Title",
|
|
24
|
+
"state": "System.State",
|
|
25
|
+
"assignedTo": "System.AssignedTo",
|
|
26
|
+
"tags": "System.Tags",
|
|
27
|
+
"changedDate": "System.ChangedDate",
|
|
28
|
+
"parent": "System.Parent",
|
|
29
|
+
"historyWrite": "System.History"
|
|
30
|
+
},
|
|
31
|
+
"activity": {
|
|
32
|
+
"activityType": "Custom.activity_type",
|
|
33
|
+
"goal": "Custom.activity_goal",
|
|
34
|
+
"successCriteria": "Custom.activity_successcriteria",
|
|
35
|
+
"startDate": "Custom.activity_startdate",
|
|
36
|
+
"endDate": "Custom.activity_enddate",
|
|
37
|
+
"rrStatus": "Custom.activity_rr_status",
|
|
38
|
+
"rr1Type": "Custom.activity_rr1_type",
|
|
39
|
+
"assignedResource1": "Custom.AssignedResource1",
|
|
40
|
+
"rrStartDate1": "Custom.RRStartDate1",
|
|
41
|
+
"rrEndDate1": "Custom.RREndDate1",
|
|
42
|
+
"rr2Type": "Custom.activity_rr2_type",
|
|
43
|
+
"assignedResource2": "Custom.AssignedResource2",
|
|
44
|
+
"rrStartDate2": "Custom.RRStartDate2",
|
|
45
|
+
"rrEndDate2": "Custom.RREndDate2",
|
|
46
|
+
"country": "Custom.Country"
|
|
47
|
+
},
|
|
48
|
+
"engagement": {
|
|
49
|
+
"_comment_status": "Confirm exact engagement status field reference name",
|
|
50
|
+
"status": "System.State",
|
|
51
|
+
"_comment_customer": "Confirm exact customer/account field reference name",
|
|
52
|
+
"customer": "",
|
|
53
|
+
"_comment_primaryLead": "Confirm exact engagement owner/lead field reference name",
|
|
54
|
+
"primaryLead": "System.AssignedTo",
|
|
55
|
+
"_comment_joinKeyIsCrmOpportunityGuid": "Confirm this field exists in this process template",
|
|
56
|
+
"isCrmId": "Custom.ISCRMID",
|
|
57
|
+
"_comment_msxOpportunityId": "Optional if available in your process template",
|
|
58
|
+
"msxOpportunityId": "Custom.MSXOpportunityID"
|
|
59
|
+
},
|
|
60
|
+
"discussion": {
|
|
61
|
+
"_comment_historyRead": "History is available as revisions; confirm whether dedicated comments API should be the primary read path",
|
|
62
|
+
"historyWrite": "System.History",
|
|
63
|
+
"useCommentsApiRead": true,
|
|
64
|
+
"useCommentsApiWrite": false
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"joinMapping": {
|
|
68
|
+
"crmToAdo": {
|
|
69
|
+
"primary": "Custom.ISCRMID",
|
|
70
|
+
"secondary": "System.Title"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"activity": {
|
|
74
|
+
"activityTypeField": "Custom.activity_type",
|
|
75
|
+
"advisoryValue": "Advisory",
|
|
76
|
+
"defaultState": "02 Active",
|
|
77
|
+
"defaultTags": "#FDE; #recon"
|
|
78
|
+
},
|
|
79
|
+
"queries": {
|
|
80
|
+
"maxSearchResults": 10,
|
|
81
|
+
"partialMatchEnabled": true,
|
|
82
|
+
"partialMatchMinScore": 0.6,
|
|
83
|
+
"searchFields": [
|
|
84
|
+
"System.Title",
|
|
85
|
+
"System.Tags"
|
|
86
|
+
],
|
|
87
|
+
"defaultOrderBy": "[System.ChangedDate] DESC"
|
|
88
|
+
},
|
|
89
|
+
"linking": {
|
|
90
|
+
"preferredModel": "System.Parent",
|
|
91
|
+
"fallbackAllowed": false,
|
|
92
|
+
"allowPartialMatchSelection": true,
|
|
93
|
+
"candidateLimit": 5
|
|
94
|
+
},
|
|
95
|
+
"discussion": {
|
|
96
|
+
"mode": "history",
|
|
97
|
+
"sourceOfTruthForTranscriptUpdates": true,
|
|
98
|
+
"writeTarget": "pending-decision",
|
|
99
|
+
"contextReadSources": [
|
|
100
|
+
"engagement",
|
|
101
|
+
"activity",
|
|
102
|
+
"allChildren"
|
|
103
|
+
],
|
|
104
|
+
"includeTranscriptSource": true,
|
|
105
|
+
"maxEntryChars": 8000,
|
|
106
|
+
"dedupe": {
|
|
107
|
+
"enabled": true,
|
|
108
|
+
"keyPattern": "meetingDate|transcriptId",
|
|
109
|
+
"includeWorkItemId": true
|
|
110
|
+
},
|
|
111
|
+
"template": {
|
|
112
|
+
"header": "Meeting Update",
|
|
113
|
+
"sections": [
|
|
114
|
+
"MeetingDate",
|
|
115
|
+
"Participants",
|
|
116
|
+
"Summary",
|
|
117
|
+
"Decisions",
|
|
118
|
+
"Actions",
|
|
119
|
+
"Risks",
|
|
120
|
+
"TranscriptSource"
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"contextRead": {
|
|
125
|
+
"dualSource": true,
|
|
126
|
+
"preferAdoDiscussion": true,
|
|
127
|
+
"includeCrmDuringMigration": true,
|
|
128
|
+
"childWorkItemDiscovery": {
|
|
129
|
+
"enabled": true,
|
|
130
|
+
"includeAllChildren": true,
|
|
131
|
+
"includeChildDiscussions": true,
|
|
132
|
+
"preferredChildTypeForExecution": "Activity",
|
|
133
|
+
"preferredActivityTypeValue": "Advisory"
|
|
134
|
+
},
|
|
135
|
+
"precedence": [
|
|
136
|
+
"ado.engagement.discussion",
|
|
137
|
+
"ado.children.discussion",
|
|
138
|
+
"ado.activity.discussion",
|
|
139
|
+
"ado.engagement",
|
|
140
|
+
"ado.children",
|
|
141
|
+
"ado.activities",
|
|
142
|
+
"crm.profile",
|
|
143
|
+
"crm.notes",
|
|
144
|
+
"transcript.unposted",
|
|
145
|
+
"external.docs"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
"validation": {
|
|
149
|
+
"requireExplicitSelectionOnAmbiguousMatch": true,
|
|
150
|
+
"requiredFieldsOnCreate": [
|
|
151
|
+
"System.Title",
|
|
152
|
+
"Custom.activity_type"
|
|
153
|
+
],
|
|
154
|
+
"requiredFieldsOnLink": [
|
|
155
|
+
"System.Parent"
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|