@orkestrel/scaffold 0.0.100 → 0.0.101

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.
@@ -293,6 +293,12 @@ Build/check config alignment:
293
293
 
294
294
  - Typechecker: `vue-tsc` only where Vue SFCs are checked; `tsc` elsewhere.
295
295
  - Linter: Oxlint with `.oxlintrc.json`, independent from typechecking.
296
+ - Place caller-selected local build inspection in `tools/artifacts/` or
297
+ `.orkestrel/<package>/instruments/**/tools/artifacts/`, and published runtime artifact
298
+ loaders in `src/server/artifacts/`. Permit computed ESM imports at those boundaries in
299
+ `.js`, `.mjs`, `.ts`, and `.mts` modules, and keep ordinary implementation dependencies
300
+ statically named. A source adapter admitted by a runtime loader remains a separately
301
+ selected inventory; it does not widen the loader's built-package admission.
296
302
  - Formatter: Oxfmt with `.oxfmtrc.json`.
297
303
  - Bundler: Vite.
298
304
  - Tests: Vitest; `@vitest/browser-playwright` for browser projects.
@@ -912,6 +912,14 @@ export async function environmentAssetSources(
912
912
  } else if (node.source.type === 'TemplateLiteral' && node.source.expressions.length === 0) {
913
913
  value = node.source.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')
914
914
  } else {
915
+ const location = workspacePath(path)
916
+ if (
917
+ location !== undefined &&
918
+ /^(?:src\/server\/artifacts\/|tools\/artifacts\/|\.orkestrel\/[^/]+\/instruments\/(?:[^/]+\/)*tools\/artifacts\/).+\.(?:js|mjs|ts|mts)$/.test(
919
+ location,
920
+ )
921
+ )
922
+ return
915
923
  throw new Error(
916
924
  '[orkestrel-environment-boundary] Dynamic imports must use static string values',
917
925
  )
@@ -47,3 +47,4 @@ playwright-report/
47
47
 
48
48
  # Agent worktrees (created by an isolated subagent dispatch, never committed)
49
49
  .claude/worktrees/
50
+
@@ -70,6 +70,16 @@
70
70
  "restriction": "off"
71
71
  },
72
72
  "overrides": [
73
+ {
74
+ "files": [
75
+ "src/server/artifacts/**/*.{js,mjs,ts,mts}",
76
+ "tools/artifacts/**/*.{js,mjs,ts,mts}",
77
+ ".orkestrel/*/instruments/**/tools/artifacts/**/*.{js,mjs,ts,mts}"
78
+ ],
79
+ "rules": {
80
+ "import/no-dynamic-require": ["error", { "esmodule": false }]
81
+ }
82
+ },
73
83
  {
74
84
  "files": ["*.config.ts", "*.config.js"],
75
85
  "rules": {
@@ -598,7 +598,7 @@
598
598
  "storage": "claude/rules/workspace.md",
599
599
  "destination": ".claude/rules/workspace.md",
600
600
  "executable": false,
601
- "digest": "f62b3c7321444d6fc30b587d9221915d0835ea3bb78204868e27beeb3ea5450b"
601
+ "digest": "6a30bd6e76ebebd5abf62562444e5865120957081530cdd8c6e6095d73ff2eac"
602
602
  },
603
603
  {
604
604
  "storage": "claude/rules/writing.md",
@@ -766,7 +766,7 @@
766
766
  "storage": "configs/helpers.ts",
767
767
  "destination": "configs/helpers.ts",
768
768
  "executable": false,
769
- "digest": "ae5a045cf6f535037fcc38a32e2d0bfc8fdae1f1549472bf3b19737a3db490cf"
769
+ "digest": "04b835f736602dcb3c491c126fc9192ae6af68833c4269acd1ef2625047f6141"
770
770
  },
771
771
  {
772
772
  "storage": "configs/policy.ts",
@@ -802,7 +802,7 @@
802
802
  "storage": "dotfiles/gitignore",
803
803
  "destination": ".gitignore",
804
804
  "executable": false,
805
- "digest": "e8789a7b46ab16a8a4127127fa5e9f131f7fb559936c878ef07d59afafcc08cb"
805
+ "digest": "2472976473578fb70df5569db6d0e752352ea909d11f18d0d7212c61417f4480"
806
806
  },
807
807
  {
808
808
  "storage": "dotfiles/mcp.json",
@@ -826,7 +826,7 @@
826
826
  "storage": "dotfiles/oxlintrc.json",
827
827
  "destination": ".oxlintrc.json",
828
828
  "executable": false,
829
- "digest": "c3777d98a2c48a4007397ef90912b2530d7e40bc4d2f85155830e6d1135dc241"
829
+ "digest": "75c465335e5f14291262b66897e9622f9320f227bcf1b41e864c17459a6d93ea"
830
830
  },
831
831
  {
832
832
  "storage": "dotfiles/prettierignore",
@@ -1180,7 +1180,7 @@
1180
1180
  "storage": "tests/config.test.ts",
1181
1181
  "destination": "tests/config.test.ts",
1182
1182
  "executable": false,
1183
- "digest": "6d5079e1eed5b45c74ef788c966527e336444f32dc15afde19b7ae360e046854"
1183
+ "digest": "df4c527b6192ec5b2f8a6b0f7b7e7b22eec88f78e962c9aef6ef46da8745f71b"
1184
1184
  },
1185
1185
  {
1186
1186
  "storage": "tests/policy.test.ts",
@@ -1192,7 +1192,7 @@
1192
1192
  "storage": "tests/setupPolicy.ts",
1193
1193
  "destination": "tests/setupPolicy.ts",
1194
1194
  "executable": false,
1195
- "digest": "2571274f92e75e6caffa86b2703ef9a38828db4ec8f51a7b38510f8bc48c6aee"
1195
+ "digest": "1219f0c1d5b8fecd155c3231902d3a7d0b2507a722365ce398ba22e3bc005633"
1196
1196
  }
1197
1197
  ],
1198
1198
  "roots": [
@@ -2120,5 +2120,5 @@
2120
2120
  ]
2121
2121
  }
2122
2122
  ],
2123
- "digest": "2eb5a827baa67b121d77f333051acf59bd11b1572c9f26f7364444b1b4d9a9f4"
2123
+ "digest": "f5c512aa30b4d0d93c7d7bd860c18718aed7b5370093acb88d549d83166edf5f"
2124
2124
  }
@@ -57,6 +57,7 @@ import configuration, { resolveWorkspacePath } from '../vite.config.js'
57
57
  import * as rootConfiguration from '../vite.config.js'
58
58
  import tsconfig from '../tsconfig.json' with { type: 'json' }
59
59
  import {
60
+ ARTIFACT_IMPORT_CASES,
60
61
  collectSheets,
61
62
  collectFrameworks,
62
63
  readConfigRecord,
@@ -2575,6 +2576,78 @@ createSomething({
2575
2576
  expect(DATA_SOURCE_FILES).not.toContain('plugins.ts')
2576
2577
  })
2577
2578
 
2579
+ it('admits computed ESM imports only in artifact loaders while refusing computed require', () => {
2580
+ const fixture = createPolicyScratch({ prefix: 'artifact-imports-' })
2581
+ try {
2582
+ fixture.write('configs/policy.ts', readFileSync(resolve(root, 'configs/policy.ts'), 'utf8'))
2583
+ const configured = readConfigRecord(
2584
+ JSON.parse(readFileSync(resolve(root, '.oxlintrc.json'), 'utf8')),
2585
+ )
2586
+ // Include campaign fixtures even when the workspace's default lint walk ignores them.
2587
+ fixture.write('.oxlintrc.json', JSON.stringify({ ...configured, ignorePatterns: [] }))
2588
+ const paths: string[] = []
2589
+ const requires: string[] = []
2590
+ for (const [path, admitted] of ARTIFACT_IMPORT_CASES) {
2591
+ fixture.write(path, 'const selected = process.argv[2]\nvoid import(selected)\ndebugger\n')
2592
+ paths.push(path)
2593
+ if (admitted) {
2594
+ const required = path.replace(/\.(\w+)$/u, '.require.$1')
2595
+ fixture.write(
2596
+ required,
2597
+ 'const selected = process.argv[2]\nvoid require(selected)\ndebugger\n',
2598
+ )
2599
+ requires.push(required)
2600
+ }
2601
+ }
2602
+ const codes = readImportDiagnostics(fixture.path, [...paths, ...requires])
2603
+ for (const [path, admitted] of ARTIFACT_IMPORT_CASES) {
2604
+ expect({ path, refused: codes.has('import(no-dynamic-require) ' + path) }).toEqual({
2605
+ path,
2606
+ refused: !admitted,
2607
+ })
2608
+ expect(codes.has('eslint(no-debugger) ' + path)).toBe(true)
2609
+ }
2610
+ for (const path of requires) {
2611
+ expect(codes.has('import(no-dynamic-require) ' + path)).toBe(true)
2612
+ expect(codes.has('eslint(no-debugger) ' + path)).toBe(true)
2613
+ }
2614
+
2615
+ expect(readConfigRecord(configured.rules)['import/no-dynamic-require']).toEqual([
2616
+ 'error',
2617
+ { esmodule: true },
2618
+ ])
2619
+ if (!Array.isArray(configured.overrides)) throw new Error('Missing lint overrides')
2620
+ const overrides = configured.overrides.map(readConfigRecord)
2621
+ const artifact = overrides.filter(
2622
+ (override) => readConfigRecord(override.rules)['import/no-dynamic-require'] !== undefined,
2623
+ )
2624
+ expect(artifact).toEqual([
2625
+ {
2626
+ files: [
2627
+ 'src/server/artifacts/**/*.{js,mjs,ts,mts}',
2628
+ 'tools/artifacts/**/*.{js,mjs,ts,mts}',
2629
+ '.orkestrel/*/instruments/**/tools/artifacts/**/*.{js,mjs,ts,mts}',
2630
+ ],
2631
+ rules: { 'import/no-dynamic-require': ['error', { esmodule: false }] },
2632
+ },
2633
+ ])
2634
+ fixture.write(
2635
+ '.oxlintrc.json',
2636
+ JSON.stringify({
2637
+ ...configured,
2638
+ ignorePatterns: [],
2639
+ overrides: overrides.filter((override) => !artifact.includes(override)),
2640
+ }),
2641
+ )
2642
+ const original = readImportDiagnostics(fixture.path, [...paths, ...requires])
2643
+ for (const path of [...paths, ...requires]) {
2644
+ expect(original.has('import(no-dynamic-require) ' + path)).toBe(true)
2645
+ }
2646
+ } finally {
2647
+ fixture.destroy()
2648
+ }
2649
+ })
2650
+
2578
2651
  it('matches every isolated import pattern with refused and admitted fixtures', () => {
2579
2652
  const fixture = createPolicyScratch({ prefix: 'propagation-patterns-' })
2580
2653
  const scratch = fixture.path
@@ -3409,6 +3482,32 @@ describe('configuration helpers', () => {
3409
3482
  )
3410
3483
  })
3411
3484
 
3485
+ it('admits computed artifact imports through Vite while retaining literal boundary inspection', async () => {
3486
+ for (const [path] of ARTIFACT_IMPORT_CASES.filter(([, admitted]) => admitted)) {
3487
+ await expect(
3488
+ configHelpers.environmentAssetSources('void import(process.argv[2])', resolve(root, path)),
3489
+ ).resolves.toEqual([])
3490
+ }
3491
+ for (const [path] of ARTIFACT_IMPORT_CASES.filter(([, admitted]) => !admitted)) {
3492
+ await expect(
3493
+ configHelpers.environmentAssetSources('void import(process.argv[2])', resolve(root, path)),
3494
+ ).rejects.toThrow('Dynamic imports must use static string values')
3495
+ }
3496
+ await expect(
3497
+ configHelpers.environmentAssetSources(
3498
+ "void import('@src/browser')",
3499
+ resolve(root, 'src/server/artifacts/Artifacts.ts'),
3500
+ ),
3501
+ ).resolves.toEqual(['@src/browser'])
3502
+ expect(configHelpers.environmentSourceError('src/server', '@src/browser')).toBeDefined()
3503
+ await expect(
3504
+ configHelpers.environmentAssetSources(
3505
+ 'void import(process.argv[2])',
3506
+ resolve(root, '../outside/src/server/artifacts/Artifacts.ts'),
3507
+ ),
3508
+ ).rejects.toThrow('Dynamic imports must use static string values')
3509
+ })
3510
+
3412
3511
  it('drives each plugin through its real Vite hooks', async () => {
3413
3512
  const environments: ReadonlyArray<
3414
3513
  'src/core' | 'src/browser' | 'src/server' | 'app/core' | 'app/browser' | 'app/server'
@@ -3968,6 +3968,37 @@ export function inspectSheetConfiguration(project: unknown, script?: string): re
3968
3968
  return failures
3969
3969
  }
3970
3970
 
3971
+ /** Lists artifact-loader paths and the computed ESM imports each boundary admits. */
3972
+ export const ARTIFACT_IMPORT_CASES: ReadonlyArray<readonly [string, boolean]> = Object.freeze([
3973
+ ['src/server/artifacts/Artifacts.ts', true],
3974
+ ['src/server/artifacts/nested/inspect.mts', true],
3975
+ ['src/server/artifacts/inspect.js', true],
3976
+ ['src/server/artifacts/inspect.mjs', true],
3977
+ ['src/server/artifacts-lookalike/inspect.ts', false],
3978
+ ['src/browser/artifacts/inspect.ts', false],
3979
+ ['src/core/artifacts/inspect.ts', false],
3980
+ ['app/server/artifacts/inspect.ts', false],
3981
+ ['src/server/artifacts/inspect.cts', false],
3982
+ ['src/server/artifacts/inspect.cjs', false],
3983
+ ['tools/artifacts/inspect.ts', true],
3984
+ ['tools/artifacts/nested/inspect.mts', true],
3985
+ ['tools/artifacts/inspect.js', true],
3986
+ ['tools/artifacts/inspect.mjs', true],
3987
+ ['.orkestrel/sample/instruments/tools/artifacts/inspect.ts', true],
3988
+ ['.orkestrel/sample/instruments/harness/tools/artifacts/nested/inspect.mts', true],
3989
+ ['.orkestrel/sample/instruments/harness/tools/artifacts/inspect.js', true],
3990
+ ['.orkestrel/sample/instruments/harness/tools/artifacts/inspect.mjs', true],
3991
+ ['src/server/inspect.ts', false],
3992
+ ['src/server/tools/artifacts/inspect.ts', false],
3993
+ ['configs/inspect.ts', false],
3994
+ ['scripts/inspect.ts', false],
3995
+ ['.orkestrel/sample/instruments/harness/inspect.ts', false],
3996
+ ['tools/artifacts-lookalike/inspect.ts', false],
3997
+ ['.orkestrel/sample/instruments/harness/tools/artifacts-lookalike/inspect.ts', false],
3998
+ ['tools/artifacts/inspect.cts', false],
3999
+ ['tools/artifacts/inspect.cjs', false],
4000
+ ])
4001
+
3971
4002
  /**
3972
4003
  * Reads import restrictions and collection sentinels from the installed linter.
3973
4004
  * @param directory - The fixture workspace containing the lint configuration.
@@ -4,7 +4,7 @@ let _orkestrel_template = require("@orkestrel/template");
4
4
  let _orkestrel_emitter = require("@orkestrel/emitter");
5
5
  var package_default = {
6
6
  name: "@orkestrel/scaffold",
7
- version: "0.0.100",
7
+ version: "0.0.101",
8
8
  description: "Scaffold workspaces with commands: new, audit, repair, catalog, and overwrite.",
9
9
  keywords: [
10
10
  "audit",