Skip to content

Commit 9ba3bc8

Browse files
vibeCoder500SwagDrivenDeveloperTushar SinghalvibeCoder500Copilot
authored
Enhance Markdown artifact review in Wizard and SDD canvases (#29)
* Enhance Markdown artifact review in Wizard and SDD canvases Add one shared reader and independently packaged assets inside the existing canvas preview surfaces. Preserve existing workflows and action contracts, and add scoped reads, revision-bound clarification validation, navigation, and regression coverage. Keep preview distribution and repository discovery outside this change. * Make composition path fixture portable for Linux CI * Keep the compact reader drawer above canvas headers * Recover expired canvas review contexts on explicit refresh * Fix canvas arrows to navigate neighboring folder documents Choose available Markdown siblings in natural filename order, preserve revision-matched positions, and prevent background refresh from leaving the reader unmounted. Add folder-boundary, loading, refresh-race and actual-shell regressions. * Fix standalone staging for Wizard E2E assets Exclude upstream Playwright E2E sources and configuration from independent App payloads, and verify that packaging boundary. * Add branch and leaf icons to the reader TOC Render aligned tree/hash iconography in wide and compact outlines, cover wrapping and active states, and synchronize the generated reader assets to Wizard and SDD. * Address Markdown review feedback Constrain reference links to active review scopes, enforce aggregate clarification limits, release and deduplicate active review contexts, preserve loading invalidations, and connect SDD deep-link readers to change events. * fix(reader): revalidate references and preserve link activation * fix(reader): resolve remaining Copilot review summary items - Enforce remaining inspection budget during scanArtifactCandidates traversal - Preserve reading position across dropdown selection, link references, and same-revision refresh - Reset stale reader baseState on same-revision refresh and allow explicit refresh recovery after initial context failure - Queue Wizard artifact-target inference while reader is open and drain on return - Derive valid owningCommand for extension phase IDs (commands/speckit.*) - Reject nested clarification markers beneath heading/link/linkReference ancestors in parser and renderer - Include vite.parser.config.ts in reader tsconfig Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(reader): resolve ESLint globals, setup gating, watcher, and entity-offset findings - Declare browser globals for Playwright specs, SDD shell globals for sdd-shell.spec.mjs, and clearInterval in eslint.config.mjs - Gate reviewed clarification Apply/Rerun and auto-submission on setup completion in UI and /api/phase/submit - Watch .github recursively in startArtifactWatcher so newly created .github/skills files trigger rescan - Preserve clarification markers after preceding HTML entities or escapes while keeping escaped markers inert Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(reader): patch vulnerable build dependencies Refresh compatible transitive dependencies, upgrade Vite to its first patched 8.1 release, and regenerate both standalone reader payloads with the pinned toolchain. Document the lockfile provenance regeneration requirement. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(wizard): preserve artifact workflow bindings and navigation Prefer exact stage command matches before shared output paths. Admit read-only navigation through resolved extension artifact paths while preserving execution gates. Add service and DOM regressions, synchronize the SDD discovery copy, and document the behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(reader): address remaining review feedback Restore multiline clarification answers with strict identifier and size limits. Enforce fresh setup admission for legacy and reviewed phase submissions, preserve read-only artifact navigation, and reset composition refresh state without replacing the active reader. Declare Wizard-owned jsdom test dependencies and verify standalone installs. Update undici within its compatible range and regenerate shared payload metadata. Keep the strict audit gate unchanged; the unavailable patched minimatch remains an explicitly reported blocker for PR #29. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(reader): resolve nine review and registry findings Regenerate both dependency lockfiles from public npm with SHA-512 integrity and pin validation actions to immutable v7 commits. Apply the approved patched minimatch override without weakening strict audit gates. Restore formatted clarification questions with shared phrasing-source spans, preserved GFM positions and markup, and exact callback bindings. Revalidate answers after the awaited setup scan, improve safe synchronization diagnostics, and move the SDD test below imports. Rebuild both independently packaged payloads and add regression coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(wizard): omit test dependencies from runtime bootstrap Keep first-open and recovery installs runtime-only while preserving developer npm ci/test behavior. Apply --omit=dev consistently in quiet/progress modes and recovery guidance, add regression coverage, and document the bootstrap boundary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: SwagDrivenDeveloper <250078488+SwagDrivenDeveloper@users.noreply.github.com> Co-authored-by: Tushar Singhal <tushar.singhal+microsoft@microsoft.com> Co-authored-by: vibeCoder500 <226498802+vibeCoder500@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f77d25d commit 9ba3bc8

99 files changed

Lines changed: 96630 additions & 143 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitattributes‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/.gitattributes text eol=lf
2+
3+
# Preserve exact bytes used by runtime package hash checks.
4+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/ui/vendor/markdown-reader/** -text linguist-generated=true
5+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-read.mjs -text
6+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-review.mjs -text
7+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-discovery.mjs -text
8+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-clarifications.mjs -text linguist-generated=true
9+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-clarifications.NOTICES.txt -text linguist-generated=true
10+
/plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/ui/artifact-review.js -text
11+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/vendor/markdown-reader/** -text linguist-generated=true
12+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/vendor/artifact-read.mjs -text linguist-generated=true
13+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/vendor/artifact-review.mjs -text linguist-generated=true
14+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/vendor/artifact-discovery.mjs -text linguist-generated=true
15+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/vendor/artifact-clarifications.mjs -text linguist-generated=true
16+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/vendor/artifact-clarifications.NOTICES.txt -text linguist-generated=true
17+
/plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/ui/artifact-review.js -text linguist-generated=true
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Canvas Reader Validation
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
paths:
7+
- "plugins/spec-kit-copilot-wizard/**"
8+
- "plugins/spec-kit-copilot-sdd/**"
9+
- "scripts/canvas-reader/**"
10+
- "docs/markdown-artifact-review.md"
11+
- ".github/workflows/canvas-reader-validation.yml"
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
validate:
18+
name: Automated checks (${{ matrix.os }})
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
os: [windows-latest, ubuntu-latest]
23+
runs-on: ${{ matrix.os }}
24+
timeout-minutes: 25
25+
defaults:
26+
run:
27+
shell: pwsh
28+
working-directory: plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/ui/markdown-reader
29+
steps:
30+
- name: Checkout repository
31+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32+
with:
33+
persist-credentials: false
34+
35+
- name: Set up Node
36+
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
37+
with:
38+
node-version: 24.19.0
39+
cache: npm
40+
cache-dependency-path: plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/ui/markdown-reader/package-lock.json
41+
42+
- name: Install locked build dependencies without lifecycle scripts
43+
run: |
44+
npm ci --ignore-scripts --no-fund
45+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
46+
47+
- name: Install existing Wizard runtime from its lockfile
48+
run: |
49+
npm ci --prefix ../.. --ignore-scripts --no-fund
50+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
51+
52+
- name: Audit dependencies
53+
run: |
54+
npm audit --audit-level=low --ignore-scripts
55+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
56+
57+
- name: Typecheck configuration
58+
run: |
59+
npm run typecheck
60+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
61+
62+
- name: Lint implemented surfaces
63+
run: |
64+
npm run lint
65+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
66+
67+
- name: Build without repairing committed payload copies
68+
run: |
69+
npm run build:reader
70+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
71+
npm run build:parser
72+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
73+
npm run verify:package
74+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
75+
76+
- name: Reader rendering and security tests
77+
run: |
78+
npm test
79+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
80+
81+
- name: Wizard and SDD regression and security suites
82+
env:
83+
CANVAS_READER_REQUIRE_WINDOWS: ${{ runner.os == 'Windows' && '1' || '0' }}
84+
run: |
85+
node --test "../../test/*.test.mjs" "../../../../../spec-kit-copilot-sdd/extensions/sdd-canvas/tests/*.test.mjs"
86+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
87+
88+
- name: Independent payload and read-only security tests
89+
run: |
90+
npm run test:tools
91+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
92+
93+
- name: Install isolated Chromium on Linux
94+
if: runner.os == 'Linux'
95+
run: |
96+
npm exec -- playwright install --with-deps chromium
97+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
98+
99+
- name: Actual-shell browser journeys
100+
run: |
101+
npm run test:browser
102+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
103+
104+
- name: Upload only synthetic preview screenshots
105+
if: always()
106+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
107+
with:
108+
name: canvas-reader-${{ matrix.os }}-screenshots
109+
path: test-results/canvas-reader/**/*.png
110+
if-no-files-found: ignore
111+
retention-days: 14

‎.gitignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
.DS_Store
22
node_modules/
33
.playwright-mcp/
4+
dist/
5+
build/
6+
coverage/
7+
test-results/
8+
playwright-report/
49
plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/test-results/
510

611
# Session artifacts (canvas runtime state, spec-kit init output, css coverage snapshots)

‎docs/markdown-artifact-review.md‎

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Markdown Artifact Review
2+
3+
The existing Wizard and SDD canvases share a Markdown reader inside their
4+
existing artifact previews. This is an enhancement to those canvases, not a
5+
new plugin, canvas, workflow, or installation method.
6+
7+
## Reading Artifacts
8+
9+
Open an existing artifact using the canvas's **View** control. Markdown
10+
previews include GitHub-flavored tables, lists, task lists, code blocks,
11+
footnotes, and a heading outline. The outline uses a side rail when the
12+
preview has room and a keyboard-accessible drawer in narrower containers.
13+
14+
The artifact selector includes the selected feature's supporting documents,
15+
contracts, checklists, and available project constitution. Wizard also
16+
supports command and template sources already known to its composition.
17+
Relative Markdown links open scoped documents in the same reader. Back and
18+
forward arrows select the previous or next available Markdown document in the
19+
current folder, in natural filename order, without requiring prior visits.
20+
They skip unavailable files, do not cross into subfolders, and stop at the first
21+
and last document. Returning to a visited document preserves its reading position
22+
when its revision is unchanged.
23+
Returning to the canvas restores the invoking control and current workflow
24+
state, including progress received while reading.
25+
26+
The source label identifies working-tree content. Existing canvas change
27+
notifications refresh artifact membership and mark changed content; **Refresh**
28+
loads the current revision. Missing, unavailable, oversized, or invalid text
29+
produces an in-preview state without closing the canvas.
30+
If a review context expires, explicit **Refresh** revalidates its scope and
31+
selected document in a new context. Context-bound history starts afresh, and
32+
old clarification bindings are not reused. A document that is no longer in
33+
the authorized scope remains unavailable.
34+
35+
## Existing Workflows
36+
37+
- Canvas identities, agent actions, stage commands, setup, Run/Rerun,
38+
overwrite confirmation, and prerequisite ordering are retained.
39+
- Wizard catalogs, composition, pipeline customization, folder browsing,
40+
and non-Markdown source previews retain their existing entry points.
41+
- SDD feature targeting, constitution, progress, optional quality gates,
42+
new-feature flow, and artifact deep links are retained.
43+
- Existing artifacts, including normalized extension pipeline entries, can be
44+
viewed even when setup or execution is gated. This intentionally makes SDD
45+
feature cards and Wizard artifact navigation available earlier; it does not
46+
enable execution or perform setup. Non-Markdown previews also keep
47+
clarification and Apply/Run controls gated, with setup rechecked on submission.
48+
- Reading, changing documents, following local links, and returning do not
49+
dispatch a workflow, install dependencies, or write project files. The
50+
Wizard startup still bootstraps missing runtime dependencies; development
51+
and test dependencies are omitted from that installation and recovery retry.
52+
53+
Clarification controls remain explicit workflow actions. SDD still confirms
54+
and submits a targeted answer; Wizard retains queued answers and its
55+
apply-and-rerun flow. Reader answers are additionally bound to the current
56+
context, artifact, revision, question, and owning command. When stages share an
57+
output file, the selected stage's command takes precedence over artifact-path
58+
matches. Changed questions must be refreshed and reconfirmed. Code examples and
59+
HTML comments do not become actionable clarification markers. Existing callers
60+
without reader metadata retain their original action contracts.
61+
Answers accept normal textarea whitespace (line breaks and tabs) while retaining
62+
the character and aggregate UTF-8 byte limits. Identifier validation remains strict.
63+
Questions may contain inline code, emphasis, URLs, and email addresses. Their raw
64+
source spans determine bindings; markers inside code examples, links, images,
65+
headings, comments, or escaped/entity-encoded prefixes remain inert.
66+
67+
## Read Boundary
68+
69+
The server derives membership from the existing canvas workspace and selected
70+
feature or composition, not from a browser-supplied absolute path. Additive
71+
`/api/review/*` endpoints use the existing canvas capability plus Host/Origin
72+
checks; legacy endpoint response shapes remain unchanged. Context, artifact,
73+
and pagination identifiers are opaque and instance-bound, not credentials.
74+
75+
Files must be ordinary, bounded, UTF-8 Markdown inside the authorized
76+
workspace. Path traversal, `.git`, symbolic links and junctions, Windows
77+
device aliases and alternate streams are rejected. Revisions hash exact
78+
file bytes; display-only BOM removal never rewrites the source. Errors shown
79+
by the reader are bounded and do not expose file contents or private paths.
80+
81+
Raw HTML is disabled, images are inert placeholders, and task checkboxes
82+
cannot edit documents. Local and external link decisions go through the
83+
host adapter. Unsafe schemes, protocol-relative URLs, and URLs containing
84+
credentials are inert; reading never passively fetches external content.
85+
86+
Limits are 5 MiB per artifact, 200 items per page, 10,000 inspected entries
87+
per discovery pass, and 50 history entries. Reaching the discovery limit
88+
returns a terminal partial result. This reader has no editing, remote
89+
repository discovery, authentication, or cloning feature.
90+
91+
## Maintainer Layout
92+
93+
The build-only package is
94+
[ui/markdown-reader](../plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/ui/markdown-reader/package.json)
95+
under Wizard. It owns rendering, outline, focus, and trusted clarification
96+
presentation. Each canvas keeps its own workflow state and server lifecycle.
97+
98+
Wizard's [review service](../plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-review.mjs)
99+
and browser adapter are canonical. The
100+
[synchronizer](../scripts/canvas-reader/sync-domain.mjs) copies the shared
101+
domain and adapter into SDD, and bundles the clarification parser for Node.
102+
[Asset synchronization](../scripts/canvas-reader/sync-assets.mjs) packages
103+
the reader, dependency notices, and provenance in each plugin independently.
104+
Neither installed plugin requires the sibling checkout or reader build
105+
dependencies. Generated payloads are marked in the repository attributes;
106+
edit their canonical sources and rebuild, not the copies.
107+
108+
## Build And Test
109+
110+
Use Node 24.19.0, npm 11.17.0, and the locked dependencies. From the repository
111+
root in PowerShell:
112+
113+
```powershell
114+
$wizard = "plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas"
115+
$reader = "$wizard/ui/markdown-reader"
116+
npm ci --prefix $wizard --ignore-scripts
117+
npm ci --prefix $reader --ignore-scripts
118+
npm --prefix $reader run typecheck
119+
npm --prefix $reader run lint
120+
npm --prefix $reader test
121+
npm --prefix $reader run build
122+
npm --prefix $reader run verify:package
123+
node --test "$wizard/test/*.test.mjs" "plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/tests/*.test.mjs"
124+
npm --prefix $reader run test:tools
125+
npm --prefix $reader run test:browser
126+
npm --prefix $reader audit --audit-level=low --ignore-scripts
127+
```
128+
129+
Both package lockfiles must use public `registry.npmjs.org` HTTPS tarball URLs
130+
and SHA-512 integrity for every dependency. Regenerate against that registry,
131+
not a user- or organization-configured mirror, and retain the package-contract
132+
checks. The reader temporarily overrides `minimatch` to 11.0.1 to address
133+
GHSA-g3hv-75wg-m249 until its lint dependencies accept the patched major; do not
134+
replace this with an audit exemption or an ESLint downgrade.
135+
136+
After dependency or lockfile updates, rebuild and verify both packaged payloads
137+
with this toolchain. The source fingerprint includes the lockfile, so tooling-only
138+
updates still require regenerated provenance manifests even if the bundled
139+
JavaScript and CSS remain unchanged.
140+
141+
The [validation workflow](../.github/workflows/canvas-reader-validation.yml)
142+
runs Windows and Linux checks. CI builds without synchronizing first, so
143+
stale committed payloads fail verification rather than being silently fixed.
144+
Browser tests use Edge on Windows and isolated Chromium on Linux, actual
145+
canvas shells, owned synthetic files, and mocked host sessions. They cover
146+
navigation, responsive layout, clarification, freshness, source preservation,
147+
and independent packaging without executing real workflows. They do not
148+
replace native Copilot App acceptance or real workflow acceptance.

‎plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/README.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ The agent opens the dashboard in a side panel. See
5858
- **Rendered artifact preview** — view `spec.md`, `plan.md`, `tasks.md`, and the
5959
constitution as formatted headings, lists, code, blockquotes, and tables in a
6060
dedicated full-width canvas view with a **Back to dashboard** control.
61+
The preview also includes a heading outline, related-artifact selection,
62+
history, and revision-aware refresh. See
63+
[Markdown Artifact Review](../../../../docs/markdown-artifact-review.md).
6164
- **Targeted clarification** — `[NEEDS CLARIFICATION: …]` markers in a spec render
6265
a **Clarify** action. The canvas requires an answer in a confirmation dialog
6366
before it sends a validated `clarify` run for that feature to the agent.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { createHash } from "node:crypto";
2+
import { resolve } from "node:path";
3+
import { CONSTITUTION, STAGES, scanFeatures } from "./sdd.mjs";
4+
import { ArtifactReadError } from "./vendor/artifact-read.mjs";
5+
import { createArtifactReviewService } from "./vendor/artifact-review.mjs";
6+
import { scanArtifactCandidates } from "./vendor/artifact-discovery.mjs";
7+
8+
export function sddPrimaryScope(state, selection, workspacePath) {
9+
if (!state?.projectRoot || resolve(state.projectRoot) !== resolve(workspacePath)) {
10+
throw new ArtifactReadError("workspace_unavailable");
11+
}
12+
const stage = selection.stage;
13+
let primary;
14+
let scopeType;
15+
if (stage === CONSTITUTION.key) {
16+
scopeType = "project";
17+
primary = { relativePath: CONSTITUTION.rel.join("/"), label: CONSTITUTION.label,
18+
role: "primary", owningStage: stage, owningCommand: CONSTITUTION.command };
19+
} else {
20+
const feature = selection.feature;
21+
if (typeof feature !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(feature) ||
22+
!state.features?.some((entry) => entry.slug === feature)) return null;
23+
const primaryStage = STAGES.find((entry) => entry.key === stage);
24+
if (!primaryStage) return null;
25+
scopeType = "feature";
26+
primary = { relativePath: `specs/${feature}/${primaryStage.file}`, label: primaryStage.label,
27+
role: "primary", owningStage: stage, owningCommand: primaryStage.command };
28+
}
29+
if (selection.source && selection.source !== primary.relativePath) return null;
30+
const scopeKey = createHash("sha256").update(JSON.stringify([scopeType, selection.feature ?? null, stage])).digest("hex");
31+
const candidates = [primary];
32+
const roots = [];
33+
if (scopeType === "feature") {
34+
roots.push(`specs/${selection.feature}`);
35+
for (const related of STAGES) {
36+
if (related.key === stage) continue;
37+
candidates.push({ relativePath: `specs/${selection.feature}/${related.file}`, label: related.file,
38+
role: "supporting", owningStage: related.key, owningCommand: related.command });
39+
}
40+
candidates.push({ relativePath: CONSTITUTION.rel.join("/"), label: "constitution.md",
41+
role: "supporting", owningStage: "constitution", optional: true });
42+
}
43+
return { scopeType, scopeKey, originStage: stage, originCommand: primary.owningCommand, primary, candidates, roots };
44+
}
45+
46+
export function createSddReviewService({ workspacePath, instanceId, getState = () => scanFeatures(workspacePath),
47+
discoverCandidates = (scope, options) => scanArtifactCandidates({ workspacePath, roots: scope.roots, explicit: scope.candidates, maxInspect: options?.maxInspect }) }) {
48+
return createArtifactReviewService({
49+
canvasId: "sdd-canvas", workspacePath, instanceId,
50+
getScope: async (selection) => sddPrimaryScope(await getState(), selection, workspacePath),
51+
discoverCandidates,
52+
});
53+
}

0 commit comments

Comments
 (0)