Skip to content

Comments

Add manifest-driven scaffolding with create and scaffold-cleanup commands#97

Open
ericelliott wants to merge 29 commits intomainfrom
claude/execute-aidd-create-epic-orEHx
Open

Add manifest-driven scaffolding with create and scaffold-cleanup commands#97
ericelliott wants to merge 29 commits intomainfrom
claude/execute-aidd-create-epic-orEHx

Conversation

@ericelliott
Copy link
Collaborator

@ericelliott ericelliott commented Feb 18, 2026

Overview

This PR implements the npx aidd create epic by adding two new CLI subcommands that enable manifest-driven project scaffolding:

  • create [type|URI] <folder> — Scaffolds new projects from named scaffolds, local file:// URIs, or remote HTTP(S) URIs
  • scaffold-cleanup [folder] — Removes temporary .aidd/ working directories after scaffolding

New Requirements

  • For custom URL - assume those point to GitHub repos. Download the latest release into the scaffold folder
  • Add documentation explaining how to stage files to be included in the scaffold: use the standard files array in package.json as if you were packaging an npm module

Key Changes

New Modules

lib/scaffold-resolver.js

  • Resolves scaffold sources (named, file://, or HTTP/HTTPS URIs) to local paths
  • Handles remote code warnings and user confirmation before downloading
  • Fetches and caches remote scaffolds in .aidd/scaffold/
  • Displays README contents to users
  • Supports AIDD_CUSTOM_EXTENSION_URI environment variable for custom defaults

lib/scaffold-runner.js

  • Parses YAML manifest files into executable steps
  • Executes run steps as shell commands
  • Executes prompt steps via agent CLI (default: claude) with proper argument escaping
  • Runs bin/extension.js after all manifest steps if present
  • Halts on first failure with clear error messages

lib/scaffold-cleanup.js

  • Removes .aidd/ directory from scaffolded projects
  • Reports whether cleanup was performed or nothing was found

CLI Integration

Updated bin/aidd.js to add:

  • create command with --agent flag for specifying the AI agent
  • scaffold-cleanup command for post-scaffold cleanup
  • Proper error handling and user feedback with chalk colors

Scaffolds

Added two scaffold fixtures:

ai/scaffolds/scaffold-example/ — E2E test fixture

  • Initializes npm project with npm init -y
  • Installs testing dependencies (riteway, vitest, @playwright/test, error-causes, @paralleldrive/cuid2)
  • Configures test script

ai/scaffolds/next-shadcn/ — Default scaffold (placeholder)

  • Stub implementation with prompt step
  • Full implementation planned for future release

Tests

Added comprehensive test suites:

  • lib/scaffold-resolver.test.js (378 lines) — Tests named scaffolds, file:// URIs, HTTP/HTTPS URIs, remote code warnings, and environment variable handling
  • lib/scaffold-runner.test.js (329 lines) — Tests manifest parsing, step execution, error handling, and extension.js invocation
  • lib/scaffold-cleanup.test.js (70 lines) — Tests directory removal and not-found cases
  • bin/create-e2e.test.js (292 lines) — End-to-end tests for create and scaffold-cleanup commands with real file I/O

Security Considerations

  • Remote HTTP/HTTPS scaffolds require explicit user confirmation before download
  • Warning message includes the full URI for transparency
  • Prompt step arguments passed as array elements (no shell injection risk)
  • User can cancel remote downloads at confirmation prompt

Test Plan

All changes are covered by automated tests:

  • Unit tests verify resolver, runner, and cleanup logic with mocked I/O
  • E2E tests verify CLI integration with real file system operations
  • Tests use temporary directories and proper cleanup
  • CI will run full test suite to validate functionality

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63


Note

Medium Risk
Adds new CLI flows that download/extract and execute scaffold-defined commands, so regressions could impact developer machines and DX; mitigated by HTTPS-only, confirmation prompts, manifest validation, and broad test coverage.

Overview
Adds manifest-driven project scaffolding to the CLI via new subcommands: create (runs SCAFFOLD-MANIFEST.yml steps, supports --agent), verify-scaffold (validates a scaffold without running it), scaffold-cleanup (removes .aidd/ working dirs), and set (persists defaults to ~/.aidd/config.yml).

Introduces a scaffold resolver/runner pipeline that supports named scaffolds, file:// URIs, and HTTPS remote sources (including auto-resolving bare GitHub repo URLs to latest release tarballs), with explicit remote-code confirmation, path-traversal guards, safer YAML parsing/validation, and typed error handling; also bundles next-shadcn (stub) and scaffold-example scaffolds plus extensive unit/E2E coverage.

Improves developer workflow/docs: pre-commit now runs unit tests only (E2E manual), AGENTS.md/CLAUDE.md guidance updated/auto-created, and README/docs expanded for create, scaffold authoring, and aidd-custom/ overrides.

Written by Cursor Bugbot for commit 683d794. This will update automatically on new commits. Configure here.

Implements the `npx aidd create` epic with manifest-driven scaffolding:

- `aidd create [type|URI] <folder>` resolves named scaffolds, HTTP/HTTPS
  URIs (with remote-code warning + confirmation), and file:// URIs.
  Reads SCAFFOLD-MANIFEST.yml and executes run/prompt steps sequentially;
  supports `--agent <name>` (default: claude) for prompt steps; warns about
  remote code and halts on step failure; leaves .aidd/scaffold/ in place
  and suggests scaffold-cleanup on completion.
- `aidd scaffold-cleanup [folder]` removes the .aidd/ working directory
  and reports gracefully when nothing exists to clean up.
- `lib/scaffold-resolver.js` with full unit test coverage.
- `lib/scaffold-runner.js` with parseManifest (gray-matter YAML parsing)
  and runManifest with injectable execStep for isolation.
- `lib/scaffold-cleanup.js` with unit tests.
- `ai/scaffolds/scaffold-example` — minimal E2E test fixture that inits
  npm, sets vitest test script, and installs riteway/vitest/playwright/
  error-causes/@paralleldrive/cuid2 at @latest.
- `ai/scaffolds/next-shadcn` — default named scaffold stub with README
  describing the intended Next.js + shadcn/ui setup.
- `bin/create-e2e.test.js` — E2E tests covering scaffold creation,
  AIDD_CUSTOM_EXTENSION_URI file:// override, scaffold-cleanup, and
  --agent flag passthrough.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
- Fix command injection in scaffold-runner: prompt steps now use
  spawn([agent, promptText]) array form instead of shell interpolation,
  so prompt content cannot inject shell commands
- Fix extension.js execution to also use array spawn (node, path)
- Add 30s network timeout to defaultFetchText to prevent indefinite hangs
- Extract isHttpUrl/isFileUrl predicates and DEFAULT_SCAFFOLD_TYPE constant
  in scaffold-resolver for readability and to eliminate repeated string checks
- Remove dead _noFetch variable from scaffold-resolver test
- Fix fragile cwd-default test in scaffold-cleanup using vi.spyOn(process, cwd)
  instead of depending on ambient filesystem state
- Mark npx-aidd-create-epic as DONE and log activity

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 18, 2026 04:22
@ericelliott
Copy link
Collaborator Author

@cursor please /review

@cursor
Copy link

cursor bot commented Feb 18, 2026

✅ No technical debt markers (TODO/FIXME) in new code

9. Specific Issues Summary

Critical:
None

High:

  1. Missing error-causes usage - Should use project's error handling standard
  2. SSRF vulnerability - No validation on HTTP/HTTPS URLs to prevent SSRF attacks

Medium:
3. No integrity checks - Remote scaffolds lack checksum/signature verification
4. Missing JSDoc - Public API functions lack minimal docblocks

Low:
5. Security logging - Consider adding audit trail for scaffold operations
6. Error context - Errors should include more structured metadata

10. Actionable Recommendations

Must Fix (Before Merge):

  1. Add error-causes support:
// In lib/scaffold-resolver.js
import { createError } from "error-causes";

// Replace all throw new Error() with:
throw createError({
  name: 'ScaffoldError',
  message: 'Remote extension download cancelled by user.',
  code: 'USER_CANCELLED',
  uri: effectiveType
});
  1. Add SSRF protection:
import { URL } from 'url';

const validateHttpUrl = (urlString) => {
  try {
    const url = new URL(urlString);
    const hostname = url.hostname;
    
    // Block private IP ranges
    if (
      hostname === 'localhost' ||
      hostname.startsWith('127.') ||
      hostname.startsWith('10.') ||
      hostname.startsWith('192.168.') ||
      hostname.startsWith('169.254.') ||
      hostname.match(/^172\.(1[6-9]|2[0-9]|3[0-1])\./)
    ) {
      throw createError({
        name: 'InvalidScaffoldUri',
        message: 'Private IP addresses are not allowed',
        code: 'PRIVATE_IP_BLOCKED',
        uri: urlString
      });
    }
    
    return true;
  } catch (err) {
    throw createError({
      name: 'InvalidScaffoldUri',
      message: 'Invalid URL format',
      code: 'INVALID_URL',
      uri: urlString,
      cause: err
    });
  }
};

// Use before fetching
if (isHttpUrl(effectiveType)) {
  validateHttpUrl(effectiveType);
  // ... rest of logic
}

Should Fix (Post-Merge):

  1. Add JSDoc to public APIs:
/**
 * Resolves a scaffold source to local file paths.
 * Supports named scaffolds, file:// URIs, and HTTP(S) URIs.
 * @param {Object} options - Configuration options
 * @param {string} [options.type] - Scaffold type: name, file://, or http(s):// URI
 * @param {string} options.folder - Target folder path
 * @param {string} [options.packageRoot] - Package root directory
 * @returns {Promise<{manifestPath: string, extensionJsPath: string, readmePath: string}>}
 */
  1. Add integrity verification for remote scaffolds:

    • Consider supporting a .sha256 file alongside remote scaffolds
    • Verify checksum before executing
  2. Add security logging:

    • Log scaffold downloads with timestamps
    • Log executed commands for audit trail

11. Vision Alignment

✅ The PR aligns well with the vision document:

  • Enhances developer experience with clear, intuitive commands
  • Follows the "universal compatibility" principle
  • Open-source first approach
  • Professional quality implementation

Final Verdict

Status: ⚠️ Conditionally Approve - High quality implementation with excellent test coverage, but requires two security fixes before merge:

  1. Must add error-causes for consistency with project standards
  2. Must add SSRF protection for HTTP/HTTPS URLs

Overall Quality: 8.5/10

  • Excellent code organization and testing
  • Good architectural patterns
  • Strong adherence to functional programming principles
  • Security considerations present but incomplete

Test Coverage: 10/10 - Comprehensive and well-written

Code Quality: 9/10 - Clean, functional, follows project standards (minus error-causes)

Security: 7/10 - Good injection prevention, but SSRF risk and missing integrity checks

The implementation is solid and the test coverage is exemplary. Once the two security issues are addressed, this will be an excellent addition to the codebase.

Open in Cursor Open in Web

Define ScaffoldCancelledError, ScaffoldNetworkError, and ScaffoldStepError
in lib/scaffold-errors.js using the errorCauses() factory so every call-site
that builds a handler is exhaustiveness-checked at setup time.

- scaffold-resolver: throw createError({...ScaffoldCancelledError}) on user
  cancellation; wrap fetchAndSaveExtension failures in ScaffoldNetworkError
- scaffold-runner: defaultExecStep now rejects with createError({...ScaffoldStepError})
  so spawn failures carry a typed cause
- bin/aidd.js create action: replace generic catch with handleScaffoldErrors()
  for typed branching (cancelled → info, network → retry hint, step → manifest hint)

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements manifest-driven project scaffolding for the aidd CLI by adding create and scaffold-cleanup subcommands, along with the supporting resolver/runner/cleanup libraries, scaffold fixtures, and test coverage.

Changes:

  • Added scaffold source resolution (named scaffolds, file://, http(s):// with confirmation) and a manifest runner for run/prompt steps.
  • Integrated new create and scaffold-cleanup subcommands into the CLI.
  • Added scaffold fixtures (scaffold-example, next-shadcn) plus unit + E2E test suites.

Reviewed changes

Copilot reviewed 17 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tasks/npx-aidd-create-epic.md Marks the epic status as DONE.
lib/scaffold-runner.js New manifest parser + step runner (run/prompt + optional extension.js).
lib/scaffold-runner.test.js Unit tests for manifest parsing and execution ordering/failure behavior.
lib/scaffold-resolver.js New resolver for named/file/http scaffolds with caching under .aidd/scaffold.
lib/scaffold-resolver.test.js Unit tests for named/file/http resolution, confirmation, and env var defaulting.
lib/scaffold-cleanup.js New cleanup helper to remove .aidd/ working directory.
lib/scaffold-cleanup.test.js Unit tests for cleanup behavior and default folder handling.
bin/aidd.js Adds create (with --agent) and scaffold-cleanup subcommands.
bin/create-e2e.test.js E2E tests for create, env defaulting, --agent, and cleanup.
ai/scaffolds/index.md Adds index entry for scaffold directory.
ai/index.md Links to ai/scaffolds/ from the top-level AI index.
ai/scaffolds/scaffold-example/README.md Documents the scaffold-example fixture scaffold.
ai/scaffolds/scaffold-example/SCAFFOLD-MANIFEST.yml Defines manifest steps for the E2E fixture (npm init/pkg/test/install).
ai/scaffolds/scaffold-example/index.md Generated directory index for scaffold-example.
ai/scaffolds/scaffold-example/bin/index.md Generated directory index for bin/.
ai/scaffolds/next-shadcn/README.md Documents default scaffold (stub).
ai/scaffolds/next-shadcn/SCAFFOLD-MANIFEST.yml Placeholder manifest with a prompt step.
ai/scaffolds/next-shadcn/index.md Generated directory index for next-shadcn.
activity-log.md Adds an entry describing the new commands and modules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The previous implementation fetched only README.md, SCAFFOLD-MANIFEST.yml,
and bin/extension.js over HTTP(S). This prevented scaffolds from carrying
arbitrary file trees, templates, package.json dependencies, config files,
bin scripts, etc.

Replace fetchAndSaveExtension + manual HTTP(S) fetch with a git clone
(defaultGitClone) that clones the full repo into <folder>/.aidd/scaffold/.
The injectable `clone` parameter keeps tests fast and network-free.

Also drop the now-unused http/https node built-ins and FETCH_TIMEOUT_MS.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
1. YAML document-start marker silently drops all steps (medium severity)
   The gray-matter wrapper trick ("---\n" + content + "\n---") caused
   gray-matter to see two consecutive --- lines and parse empty frontmatter
   when a manifest author included the standard --- marker. Replace with
   matter.engines.yaml.parse(content), a direct call to js-yaml's load()
   which handles --- markers correctly.

   Test added: "parses steps when manifest begins with YAML document-start marker"

2. npx aidd create (no args) crashes with TypeError (high severity)
   Both positionals were optional, so Commander allowed zero arguments.
   folderArg became undefined and path.resolve(cwd, undefined) threw.
   Flip the arg order to <folder> [type] — folder is now required and
   Commander rejects the call before the action runs.

   Also note: the defaultFetchText res.resume() socket-leak issue reported
   separately is moot — defaultFetchText was removed in the previous commit
   when HTTP fetching was replaced with git clone.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 18, 2026 19:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 20 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ent GitHub release workflow

TDD: added failing tests first, then implemented to pass.

- scaffold-errors.js: add ScaffoldValidationError (code SCAFFOLD_VALIDATION_ERROR)
- scaffold-runner.js: parseManifest now validates that steps is an array of plain
  objects with at least one recognized key (run/prompt); throws ScaffoldValidationError
  with a descriptive message on any violation instead of silently iterating wrong values
- scaffold-runner.test.js: 5 new tests covering string steps, object steps, bare-string
  items, unrecognized-key items, and the error message content
- scaffold-verifier.js + scaffold-verifier.test.js: new verifyScaffold() function
  (8 tests) that checks manifest existence, valid YAML, valid step shapes, and
  non-empty steps list — returns { valid, errors } for clean reporting
- bin/aidd.js: add `verify-scaffold [type]` subcommand; update `create` error handler
  to cover ScaffoldValidationError
- scaffold-example/SCAFFOLD-MANIFEST.yml: add release-it install + scripts.release step
  so generated projects have a release command out of the box
- scaffold-example/package.json: new file so scaffold AUTHORS can release their scaffold
  as a GitHub release with `npm run release`
- tasks/npx-aidd-create-epic.md: update requirements — GitHub releases instead of git
  clone for remote scaffolds; add verify-scaffold, steps validation, and scaffold
  author release workflow sections
- docs/scaffold-authoring.md: new guide covering manifest format, validation, the
  distinction between npm's files array (npm publish only) and GitHub release assets,
  and how to publish a scaffold as a GitHub release

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
…rst, folder second

The previous fix made <folder> required (correct) but accidentally swapped the
positional order to `create <folder> [type]`. Every E2E test, both scaffold
READMEs, the epic requirements, the activity log, and the docs all call the
command as `create [type] <folder>` (e.g. `create scaffold-example my-project`).

With the wrong order, `create scaffold-example test-project` would bind
folder="scaffold-example" and type="test-project", creating a directory named
after the scaffold and trying to resolve a nonexistent scaffold named after the
folder — completely backwards.

Restores `.command("create [type] <folder>")` with action `(type, folder, opts)`.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 19, 2026 00:20
…full e2e in pre-commit

Argument parsing:
  The previous [type] <folder> definition caused Commander to assign the
  single-argument form (create my-folder) to `type`, leaving folder missing.
  Restore [typeOrFolder] [folder] with manual validation so all three calling
  patterns work correctly:
    create scaffold-example my-project  →  type=scaffold-example, folder=my-project
    create my-project                   →  type=undefined (env/default), folder=my-project
    create                              →  explicit 'missing required argument' error

Pre-commit hook:
  Changed from `npm run test:unit` to `npm test` so e2e tests run on every
  commit. The arg-order regression slipped through exactly because e2e was
  excluded from the hook. Full suite is ~50s but catches integration bugs.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 25 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The internal [typeOrFolder] [folder] signature (needed to work around
Commander's left-to-right arg assignment) showed both as optional in --help.
Add a .usage() override and .addHelpText() so the displayed usage reads
`[options] [type] <folder>` with an Arguments section that explicitly marks
<folder> as required and shows four calling-convention examples.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copy link
Contributor

Copilot AI commented Feb 19, 2026

@ericelliott I've opened a new pull request, #99, to work on those changes. Once the pull request is ready, I'll request review from you.

* Initial plan

* fix: use @paralleldrive/cuid2 in task requirements for consistency

Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ericelliott <364727+ericelliott@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 19, 2026 23:30
…on exit code

- defaultConfirm: add error + close event handlers to readline interface;
  promise rejects instead of hanging when stdin closes before answer
- resolveExtension: catch confirm() rejections (stdin-close) and wrap in
  ScaffoldCancelledError rather than letting them surface as raw errors
- defaultDownloadAndExtract: add child.stdin.on('error', reject) guard
  to prevent EPIPE from crashing Node when tar exits before consuming stdin
- create + verify-scaffold commands: process.exit(0) on ScaffoldCancelledError
  (graceful abort is not a failure — exit 1 only for errors)
- Archive completed remediation epic 2 and remove from plan.md

262 unit tests passing.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 21, 2026 01:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 38 out of 42 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Named scaffolds (e.g. scaffold-example) do not download a tarball, so
no .aidd/scaffold/ directory is created and the cleanup tip should not
appear. Updated the E2E assertion to expect false, matching the
conditional-tip behaviour introduced in the remediation pass.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
…n CI

runCreate called fs.ensureDir(folder) unconditionally, causing unit tests
that pass fake absolute paths (e.g. /abs/, /absolute/) to attempt real
directory creation and fail with EACCES in restricted CI environments.

Added ensureDirFn injectable parameter (default: fs.ensureDir) and
updated all runCreate test callsites to pass noopEnsureDir.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 21, 2026 22:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 38 out of 42 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The implementation auto-resolves https://github.com/owner/repo to the
latest release tarball via the GitHub API. The authoring doc still showed
the old direct tarball URL format; updated the example and description to
match the actual behaviour.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
- Rename AIDD_CUSTOM_EXTENSION_URI → AIDD_CUSTOM_CREATE_URI everywhere
- Add lib/aidd-config.js: readConfig/writeConfig for .aidd-config.json
- resolveExtension reads config file as fallback (type > env var > config > default)
  with injectable readConfigFn for unit testing
- Add \`npx aidd set <key> <value>\` command (validates key is "create-uri")
  writes to .aidd-config.json in cwd; readable by subsequent \`npx aidd create\`
- 9 new unit tests (4 aidd-config, 2 resolver config-fallback, 2 resolver precedence)

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 21, 2026 22:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 44 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +34 to +54
const defaultResolveRelease = async (repoUrl) => {
const { pathname } = new URL(repoUrl);
const [, owner, repo] = pathname.split("/");
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/releases/latest`;
const response = await fetch(apiUrl, {
headers: {
Accept: "application/vnd.github+json",
"User-Agent": "aidd-cli",
},
});
if (!response.ok) {
throw new Error(
`GitHub API returned ${response.status} for ${repoUrl} — no releases found or repo is private`,
);
}
const release = await response.json();
if (!release.tarball_url) {
throw new Error(`No tarball URL in latest release of ${repoUrl}`);
}
return release.tarball_url;
};
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub API request does not include authentication, which means it's subject to GitHub's unauthenticated rate limits (60 requests per hour per IP). For a CLI tool that might be used frequently, consider documenting that users can set a GITHUB_TOKEN environment variable for higher rate limits, or handle 403 rate limit responses with a clear error message explaining the limit and suggesting authentication.

Copilot uses AI. Check for mistakes.

- 🚀 - `npx aidd create` - New `create [type|URI] <folder>` subcommand with manifest-driven scaffolding (run/prompt steps, --agent flag, remote code warning)
- 🚀 - `npx aidd scaffold-cleanup` - New cleanup subcommand removes `.aidd/` working directory
- 🔧 - Extension resolver - Supports named scaffolds, `file://`, `http://`, `https://` with confirmation prompt for remote code
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The activity log states that the extension resolver "Supports named scaffolds, file://, http://, https://" but the implementation at scaffold-resolver.js:177-182 explicitly rejects http:// URIs with an error. The activity log should be updated to remove http:// from the list of supported protocols since only https:// is accepted for security reasons.

Suggested change
- 🔧 - Extension resolver - Supports named scaffolds, `file://`, `http://`, `https://` with confirmation prompt for remote code
- 🔧 - Extension resolver - Supports named scaffolds, `file://`, `https://` with confirmation prompt for remote code

Copilot uses AI. Check for mistakes.
});

return verifyScaffoldFn({ manifestPath: paths.manifestPath });
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verify-scaffold leaks downloaded HTTP/HTTPS scaffolds

Medium Severity

The verify-scaffold command downloads HTTP/HTTPS scaffolds to .aidd/scaffold/ in the current directory but never cleans them up. Unlike the create command which suggests running scaffold-cleanup, verify-scaffold silently leaves the downloaded files behind. A verification command should not leave persistent side effects on the filesystem.

Additional Locations (1)

Fix in Cursor Fix in Web

…-custom docs

- lib/aidd-config.js: rewrite to use YAML at ~/.aidd/config.yml (token-friendly
  for AI context); injectable configFile param for testability
- lib/aidd-config.test.js: update tests for YAML format + injectable path
- bin/aidd.js: apply ~/.aidd/config.yml to process.env at startup so set create-uri
  acts as a persistent env var; update set command description + output
- lib/scaffold-resolver.js: revert readConfigFn — resolveExtension reads only
  type arg or AIDD_CUSTOM_CREATE_URI env var, no config file lookup
- lib/scaffold-resolver.test.js: remove config-fallback tests, restore original
  two-test shape (renamed env var only)
- README.md: add "Customizing aidd Framework for your Project" section documenting
  aidd-custom/, config.yml, and AGENTS.md; document set create-uri command
- AGENTS.md: add "Project Customizations" section referencing aidd-custom/AGENTS.md

NOTE: design of set create-uri persistence mechanism still under discussion —
user is evaluating whether ~/.aidd/config.yml is the right approach vs eval pattern.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
The set create-uri command no longer writes to ~/.aidd/config.yml.
Instead it prints `export AIDD_CUSTOM_CREATE_URI=<uri>` to stdout
(machine-readable for eval) with guidance on stderr.

Usage:
  eval "$(npx aidd set create-uri <uri>)"  # apply in current shell
  # or copy the printed export into ~/.bashrc / ~/.zshrc

- Delete lib/aidd-config.js and lib/aidd-config.test.js (not needed)
- Remove startup config-reading block from bin/aidd.js
- set action: stdout = export statement, stderr = chalk guidance
- Update README to document eval pattern instead of config file

resolveExtension still reads only <type> arg or AIDD_CUSTOM_CREATE_URI env var.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 22, 2026 00:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 38 out of 42 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


- `steps` is not an array (e.g. a string or plain object)
- Any step is not a plain object (e.g. a bare string or `null`)
- Any step has no recognized keys (`run` or `prompt`)
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation rules documentation at lines 40-44 does not mention that a step with both run and prompt keys is also rejected as ambiguous. However, this validation is implemented in the code (lib/scaffold-runner.js lines 92-97) and documented elsewhere (ai/scaffolds/SCAFFOLD-AUTHORING.md line 42).

Add a fourth bullet point to the validation rules:

  • Any step has both run and prompt keys (ambiguous step)
Suggested change
- Any step has no recognized keys (`run` or `prompt`)
- Any step has no recognized keys (`run` or `prompt`)
- Any step has both `run` and `prompt` keys (ambiguous step)

Copilot uses AI. Check for mistakes.
Comment on lines +448 to +484
## ⚙️ Customizing aidd Framework for your Project

After installing the aidd system, create an `aidd-custom/` directory at your project root to extend or override the defaults without touching the built-in `ai/` files. Changes in `aidd-custom/` supersede the project root in case of any conflict.

```
your-project/
├── ai/ # built-in aidd framework files (don't edit)
├── aidd-custom/ # your project-specific customizations
│ ├── config.yml # project-level aidd settings
│ └── AGENTS.md # project-specific agent instructions
└── ...
```

### `aidd-custom/config.yml`

Store project-level aidd settings as YAML (token-friendly for AI context injection):

```yaml
# aidd-custom/config.yml
stack: next-shadcn
team: my-org
```

### `aidd-custom/AGENTS.md`

Project-specific instructions for AI agents. Write rules, constraints, and context that apply only to your project. AI agents are instructed to read `aidd-custom/AGENTS.md` after `AGENTS.md` — directives here override the defaults.

```markdown
# Project Agent Instructions

## Stack
We use Next.js 15 App Router with Tailwind CSS and shadcn/ui.

## Conventions
- All server actions live in `lib/actions/`
- Use `createRoute` from `aidd/server` for API routes
```
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README.md introduces a new section "Customizing aidd Framework for your Project" (lines 448-484) describing an aidd-custom/ directory feature that appears to be documented but not implemented in this PR.

The documentation describes aidd-custom/config.yml and aidd-custom/AGENTS.md as a way to extend or override defaults, and AGENTS.md references this feature (lines 47-49). However, there's no code in this PR that actually reads or processes the aidd-custom/ directory.

This creates a discrepancy where the feature is documented but not functional. Either:

  1. Remove the documentation if the feature is not yet implemented
  2. Add the implementation to make the feature work as documented
  3. Clarify that this is a planned feature and mark it accordingly in the documentation

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 145
# Scaffold Authoring Guide

A scaffold is a small repository that teaches `npx aidd create` how to bootstrap a new project. This guide covers the file layout, manifest format, how to validate your scaffold locally, and how to publish it as a GitHub release so consumers can reference it by URL.

---

## File layout

```
my-scaffold/
├── SCAFFOLD-MANIFEST.yml # required — list of steps to execute
├── README.md # optional — displayed to the user before steps run
├── bin/
│ └── extension.js # optional — Node.js script run after all steps
└── package.json # required for publishing — see below
```

---

## SCAFFOLD-MANIFEST.yml

The manifest is a YAML file with a single `steps` key containing an ordered list of step objects. Each step must have exactly one of:

| Key | Type | Description |
|-----|------|-------------|
| `run` | string | Shell command executed in the project directory |
| `prompt` | string | Sent to the configured AI agent CLI (default: `claude`) |

```yaml
steps:
- run: npm init -y
- run: npm pkg set scripts.test="vitest run"
- run: npm pkg set scripts.release="release-it"
- run: npm install --save-dev vitest@latest release-it@latest
- prompt: Set up a basic project structure with src/ and tests/
```

### Validation rules

`npx aidd create` validates the manifest before executing any steps. Your manifest will be rejected with a clear error if:

- `steps` is not an array (e.g. a string or plain object)
- Any step is not a plain object (e.g. a bare string or `null`)
- Any step has no recognized keys (`run` or `prompt`)

Run `npx aidd verify-scaffold <name-or-uri>` at any time to check your manifest without executing it:

```bash
# Verify a named built-in scaffold
npx aidd verify-scaffold scaffold-example

# Verify a local scaffold by file URI
npx aidd verify-scaffold file:///path/to/my-scaffold
```

---

## The `package.json` `files` array vs GitHub release assets

These two concepts are independent:

### `files` in `package.json` → controls npm publishing

When you run `npm publish`, npm reads the `files` array to decide which paths are included in the package tarball uploaded to the npm registry. Files not listed here are excluded from `npm install`.

```json
{
"files": [
"SCAFFOLD-MANIFEST.yml",
"README.md",
"bin/**/*"
]
}
```

### GitHub release assets → controlled by git + release workflow

A GitHub release contains:

1. **Auto-generated source tarballs** (`Source code (zip)` / `Source code (tar.gz)`) — these are snapshots of everything in the git repository at the tagged commit. The `files` array in `package.json` has **no effect** on this.
2. **Manually uploaded release assets** — anything you explicitly upload via the GitHub UI or a release workflow step.

For scaffold distribution, consumers download the source tarball from a GitHub release. This means every file you commit to the repository at the release tag will be available. The `files` array only matters if you also publish the scaffold to npm.

---

## Adding a release command to your scaffold's `package.json`

Include `release-it` as a dev dependency and wire up a `release` script:

```json
{
"name": "my-aidd-scaffold",
"version": "1.0.0",
"type": "module",
"scripts": {
"release": "release-it"
},
"files": [
"SCAFFOLD-MANIFEST.yml",
"README.md",
"bin/**/*"
],
"devDependencies": {
"release-it": "latest"
}
}
```

Running `npm run release` will:

1. Bump the version
2. Create a git tag (`v1.0.0`)
3. Push the tag to GitHub
4. Create a GitHub release with auto-generated release notes

Scaffold consumers can then reference your scaffold by its GitHub release tarball URL:

```bash
npx aidd create https://github.com/your-org/my-scaffold my-project
```

---

## Distributing via GitHub releases (recommended) vs git clone

| | GitHub release tarball | git clone |
|---|---|---|
| **Versioned** | Yes — pinned to a tag | No — always HEAD |
| **Reproducible** | Yes | No |
| **Download size** | Small — source only | Large — includes git history |
| **No git required on consumer** | Yes (HTTP download) | No (requires git) |

The AIDD resolver will download and extract the release tarball rather than cloning the repository, giving users a fast, versioned, reproducible scaffold install.

---

## Testing your scaffold locally

Use a `file://` URI to test your scaffold without publishing:

```bash
npx aidd verify-scaffold file:///path/to/my-scaffold
npx aidd create file:///path/to/my-scaffold my-test-project
```
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two very similar scaffold authoring documentation files: docs/scaffold-authoring.md and ai/scaffolds/SCAFFOLD-AUTHORING.md. Both files cover the same topic with nearly identical content but slightly different organization and wording. This creates a maintenance burden as changes need to be kept in sync across both files, and developers may be unsure which one to reference or update.

Consider consolidating these into a single canonical documentation file, or clearly differentiate their purposes (e.g., one for external users vs. one for internal contributors) with appropriate cross-references.

Copilot uses AI. Check for mistakes.
Comment on lines 120 to 121
// Reject path traversal: the resolved directory must stay inside scaffoldsRoot
if (!typeDir.startsWith(scaffoldsRoot + path.sep)) {
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path traversal validation at line 121 has a potential edge case issue. The check uses !typeDir.startsWith(scaffoldsRoot + path.sep) which would incorrectly reject a valid scaffold type when typeDir equals scaffoldsRoot exactly (i.e., when type is an empty string or ".").

For example, if type is "." or "", path.resolve(scaffoldsRoot, type) would return scaffoldsRoot itself, which would not start with scaffoldsRoot + path.sep.

The condition should be !typeDir.startsWith(scaffoldsRoot + path.sep) && typeDir !== scaffoldsRoot or use a more robust path containment check like:

const relative = path.relative(scaffoldsRoot, typeDir);
if (relative.startsWith('..') || path.isAbsolute(relative)) {
  throw createError(...);
}

However, this may be intentional behavior (rejecting empty scaffold names), in which case an explicit validation and error message for empty types would be clearer.

Suggested change
// Reject path traversal: the resolved directory must stay inside scaffoldsRoot
if (!typeDir.startsWith(scaffoldsRoot + path.sep)) {
// Explicitly reject empty or "." scaffold types for clarity
if (!type || type === ".") {
throw createError({
...ScaffoldValidationError,
message: `Invalid scaffold type "${type}": scaffold type name must be non-empty and not ".".`,
});
}
// Reject path traversal: the resolved directory must stay inside scaffoldsRoot
const relative = path.relative(scaffoldsRoot, typeDir);
if (relative.startsWith("..") || path.isAbsolute(relative)) {

Copilot uses AI. Check for mistakes.
…lver

Priority chain: CLI <type> arg > AIDD_CUSTOM_CREATE_URI env var > ~/.aidd/config.yml > default

Key design decision: config is read directly by resolveExtension (via injectable
readConfigFn) rather than being applied to process.env at startup. The env var
remains a distinct, higher-priority override for CI and one-off use.

Changes:
- lib/aidd-config.js: readConfig/writeConfig for ~/.aidd/config.yml using YAML
  (token-friendly for AI context); injectable configFile param for testability
- lib/aidd-config.test.js: 8 tests covering read/write/merge/overwrite/dir-creation
- lib/scaffold-resolver.js: add readConfigFn = readConfig param; effectiveType now
  reads type || AIDD_CUSTOM_CREATE_URI || config["create-uri"] || DEFAULT_SCAFFOLD_TYPE
- lib/scaffold-resolver.test.js: add config-fallback and env-var-precedence tests;
  inject readConfigFn: noConfig in existing tests to prevent real config interference
- bin/aidd.js: set command writes to ~/.aidd/config.yml via writeConfig; no startup
  env injection (config is consumed directly in the resolver)
- tasks/npx-aidd-create-epic.md: document rename, set command, architectural decision
- README.md: document set create-uri, priority chain, ~/.aidd/config.yml

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
const folderPath = path.resolve(process.cwd(), resolvedFolder);

return { folderPath, resolvedFolder, type };
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL-only argument silently treated as folder name

Medium Severity

resolveCreateArgs lacks a heuristic to detect when a single argument is a URL/URI rather than a folder name. If a user runs npx aidd create https://github.com/org/repo (forgetting the folder), the URL is silently interpreted as the folder name — creating a directory with a mangled URL path and scaffolding the wrong (default) scaffold into it. A check for http://, https://, or file:// prefixes on the single-arg path would catch this and return null (triggering the missing-folder error) or treat it as the type.

Additional Locations (1)

Fix in Cursor Fix in Web

should: "resolve to next-shadcn named scaffold",
actual: paths.readmePath.includes("next-shadcn"),
expected: true,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Env var restoration sets string "undefined" polluting tests

Low Severity

The env var restore pattern process.env.AIDD_CUSTOM_CREATE_URI = originalEnv sets the variable to the literal string "undefined" when originalEnv was undefined, because process.env coerces values to strings. This leaves a truthy env var that pollutes subsequent tests. The correct approach is to conditionally delete the env var when the original was undefined. Additionally, these tests don't use try/finally for cleanup, so a test failure skips restoration entirely.

Additional Locations (1)

Fix in Cursor Fix in Web

…ify isInsecureHttpUrl

- AGENTS.md: note ~/.aidd/config.yml as user-level config distinct from project-level
  aidd-custom/config.yml; instruct agents not to modify it without being asked
- README.md: add ~/.aidd/config.yml YAML example alongside set create-uri command
- docs/scaffold-authoring.md: fix "tarball URL" prose — users pass a bare repo URL;
  the resolver auto-resolves to the latest release tarball internally
- tasks/npx-aidd-create-epic.md: same prose fix in scaffold author release workflow
- lib/scaffold-resolver.js: simplify isInsecureHttpUrl — url.startsWith("http://")
  can never also start with "https://", so the second check was always redundant

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copilot AI review requested due to automatic review settings February 22, 2026 01:02
verify-scaffold was silently leaving downloaded HTTP/HTTPS scaffold files in
.aidd/scaffold/ of the current working directory, which may not even exist yet
at verification time (it's a pre-create check).

Changes:
- lib/scaffold-verify-cmd.js: pass os.homedir() as folder so the resolver puts
  downloads at ~/.aidd/scaffold/ (i.e. path.join(AIDD_HOME, "scaffold")); wrap
  resolve+verify in try/finally to always call cleanupFn regardless of outcome;
  export VERIFY_SCAFFOLD_DIR for test assertions
- lib/scaffold-verify-cmd.test.js: inject cleanupFn: noCleanup in all existing
  tests; add 3 new tests — folder is os.homedir(), cleanup called on success,
  cleanup called even when resolveExtension throws
- tasks/npx-aidd-create-epic.md: document fix with requirements

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
…leading error for type "."

type "." resolves to scaffoldsRoot itself (not outside it), so the old
startsWith(scaffoldsRoot + sep) message "Resolved outside the scaffolds
directory" was factually wrong. Using path.relative() cleanly separates
the two failure modes with accurate messages.

- !relative (e.g. type "."): "resolves to the scaffolds root directory, not a specific scaffold"
- relative starts with ".." or is absolute: "resolves outside the scaffolds directory"
- valid type (e.g. "next-shadcn"): passes unchanged

Note: type "" is treated as falsy by the || fallback chain and uses the
default scaffold — not a bug, intentional behavior preserved.

tasks/npx-aidd-create-epic.md: document both cases in requirements.
lib/scaffold-resolver.test.js: add failing tests first (TDD order), then fix.

https://claude.ai/code/session_01VxNxs3Ly9UQh9TZpJpjG63
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 44 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +70 to +97
for (let i = 0; i < steps.length; i++) {
const step = steps[i];

if (step === null || typeof step !== "object" || Array.isArray(step)) {
throw createError({
...ScaffoldValidationError,
message: `Manifest step ${i + 1} must be an object, got ${
step === null ? "null" : Array.isArray(step) ? "array" : typeof step
}`,
});
}

const knownKeys = Object.keys(step).filter((k) => KNOWN_STEP_KEYS.has(k));

if (knownKeys.length === 0) {
const found = Object.keys(step).join(", ") || "(empty)";
throw createError({
...ScaffoldValidationError,
message: `Manifest step ${i + 1} has no recognized keys (run, prompt). Found: ${found}`,
});
}

if (knownKeys.length > 1) {
throw createError({
...ScaffoldValidationError,
message: `Manifest step ${i + 1} has ambiguous keys: ${knownKeys.join(" and ")}. Each step must have exactly one of: run, prompt`,
});
}
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseManifest validates the shape of each step, but it doesn’t validate the value types for run/prompt. Because YAML can encode non-strings (arrays/objects/numbers), a manifest could produce spawn argument type errors or unexpected execution semantics. Consider enforcing typeof step.run === "string" and typeof step.prompt === "string" (and rejecting empty strings) as part of validation.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +15
const manifestExists = await fs.pathExists(manifestPath);
if (!manifestExists) {
errors.push("SCAFFOLD-MANIFEST.yml not found at expected path");
return { errors, valid: false };
}
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verifyScaffold returns a generic missing-manifest error without including the actual manifestPath. Including the path makes the output actionable (especially for file:// and downloaded scaffolds) and aligns with the goal of “descriptive” verification errors.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +29
* Throws on resolution errors (cancelled, network, etc.) — caller handles display.
*/
const runVerifyScaffold = async ({
type,
packageRoot = __dirname,
resolveExtensionFn = defaultResolveExtension,
verifyScaffoldFn = defaultVerifyScaffold,
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runVerifyScaffold resolves remote scaffolds into process.cwd()/.aidd/scaffold/, which means verify-scaffold can unexpectedly create a .aidd/ directory in whatever folder the user runs it from (and it doesn’t suggest cleanup). Consider downloading into a temp directory and removing it automatically after verification, or at least documenting/surfacing the cleanup path.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to 22
- Given no `<type>` and no `AIDD_CUSTOM_CREATE_URI`, should use the bundled `ai/scaffolds/next-shadcn` extension
- Given `AIDD_CUSTOM_CREATE_URI` env var is set and no `<type>` arg, should use the env URI (supports `http://`, `https://`, and `file://` schemes)
- Given `--agent <name>` flag, should use that agent CLI for `prompt` steps (default: `claude`)
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This epic still claims AIDD_CUSTOM_CREATE_URI supports http:// URIs, but the implementation now rejects insecure HTTP and requires https://. Updating this requirement text will keep the task spec consistent with the current security posture.

Copilot uses AI. Check for mistakes.

- 🚀 - `npx aidd create` - New `create [type|URI] <folder>` subcommand with manifest-driven scaffolding (run/prompt steps, --agent flag, remote code warning)
- 🚀 - `npx aidd scaffold-cleanup` - New cleanup subcommand removes `.aidd/` working directory
- 🔧 - Extension resolver - Supports named scaffolds, `file://`, `http://`, `https://` with confirmation prompt for remote code
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The activity log says the resolver supports http:// URIs, but the current resolver enforces HTTPS-only for remote scaffolds. Please update this entry to avoid documenting insecure HTTP support.

Suggested change
- 🔧 - Extension resolver - Supports named scaffolds, `file://`, `http://`, `https://` with confirmation prompt for remote code
- 🔧 - Extension resolver - Supports named scaffolds, `file://` and `https://` (remote scaffolds require HTTPS) with confirmation prompt for remote code

Copilot uses AI. Check for mistakes.
Comment on lines 9 to 19
"dependencies": {
"@paralleldrive/cuid2": "^3.1.0",
"@sinclair/typebox": "^0.34.41",
"chalk": "^4.1.2",
"commander": "^11.1.0",
"error-causes": "^3.0.2",
"fs-extra": "^11.1.1",
"gray-matter": "^4.0.3",
"js-sha3": "^0.9.3"
"js-sha3": "^0.9.3",
"js-yaml": "^4.1.1"
},
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib/scaffold-resolver.js relies on the global fetch, which requires Node 18+. Since package.json doesn’t declare an engines.node constraint, users on older Node versions may get a runtime ReferenceError: fetch is not defined. Consider adding an engines field (or a fetch polyfill dependency) to make the requirement explicit.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +52
await ensureDirFn(folder);

const paths = await resolveExtensionFn({
folder,
packageRoot,
type,
});

Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runCreate creates the target folder before calling resolveExtension. If the user cancels a remote scaffold confirmation (or resolution fails), this leaves an empty project directory behind even though no scaffolding occurred. Consider deferring ensureDirFn(folder) until after resolveExtensionFn succeeds (or only creating the folder immediately before runManifestFn).

Suggested change
await ensureDirFn(folder);
const paths = await resolveExtensionFn({
folder,
packageRoot,
type,
});
const paths = await resolveExtensionFn({
folder,
packageRoot,
type,
});
await ensureDirFn(folder);

Copilot uses AI. Check for mistakes.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

readConfigFn: noConfig,
});

process.env.AIDD_CUSTOM_CREATE_URI = originalEnv;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Env var restoration pollutes process.env with string "undefined"

Medium Severity

When AIDD_CUSTOM_CREATE_URI was never set, originalEnv is undefined. Assigning process.env.AIDD_CUSTOM_CREATE_URI = undefined in Node.js converts it to the string "undefined" rather than deleting the key. Since "undefined" is truthy, the || fallback chain in resolveExtension treats it as a valid scaffold type, potentially causing subsequent tests in the same process to resolve the wrong scaffold or fail unexpectedly.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants