@hagicode/hagitask 0.1.0-dev.6

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.
Files changed (32) hide show
  1. package/README.md +241 -0
  2. package/dist/cli.d.ts +4 -0
  3. package/dist/cli.js +36 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/validate-command.d.ts +4 -0
  6. package/dist/commands/validate-command.js +14 -0
  7. package/dist/commands/validate-command.js.map +1 -0
  8. package/dist/index.d.ts +15 -0
  9. package/dist/index.js +31 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/validation/diagnostics.d.ts +13 -0
  12. package/dist/validation/diagnostics.js +16 -0
  13. package/dist/validation/diagnostics.js.map +1 -0
  14. package/dist/validation/package-discovery.d.ts +10 -0
  15. package/dist/validation/package-discovery.js +45 -0
  16. package/dist/validation/package-discovery.js.map +1 -0
  17. package/dist/validation/package-validator.d.ts +4 -0
  18. package/dist/validation/package-validator.js +374 -0
  19. package/dist/validation/package-validator.js.map +1 -0
  20. package/dist/validation/schema-loader.d.ts +8 -0
  21. package/dist/validation/schema-loader.js +50 -0
  22. package/dist/validation/schema-loader.js.map +1 -0
  23. package/package.json +52 -0
  24. package/schemas/community-index-v1.schema.json +159 -0
  25. package/schemas/community-task-detail-v1.schema.json +182 -0
  26. package/schemas/task-preset-plugin/commands.schema.json +122 -0
  27. package/schemas/task-preset-plugin/locales.schema.json +24 -0
  28. package/schemas/task-preset-plugin/manifest.schema.json +225 -0
  29. package/schemas/task-preset-plugin/panel.schema.json +190 -0
  30. package/schemas/task-preset-plugin/prompt-package.schema.json +262 -0
  31. package/schemas/task-preset-plugin/store-page-frontmatter.schema.json +73 -0
  32. package/schemas/task-preset-plugin/task-preset.schema.json +153 -0
package/README.md ADDED
@@ -0,0 +1,241 @@
1
+ # hagitask
2
+
3
+ HagiTask is the canonical repository for preset-task contribution assets inside the
4
+ HagiCode monorepo. It is the maintained source of truth for shipped preset-task
5
+ schemas and preset packages.
6
+
7
+ ## npm CLI
8
+
9
+ The repository is also published as `@hagicode/hagitask` (Node.js 20 or newer).
10
+ Install it with `npm install --save-dev @hagicode/hagitask`, then validate a
11
+ repository or one package:
12
+
13
+ ```bash
14
+ npx hagitask validate .
15
+ npx hagitask validate ./data/my-task --json
16
+ ```
17
+
18
+ `validate` discovers packages directly under `presets/` and `data/`, or validates
19
+ a directory containing `manifest.json`. It returns exit code `0` only when all
20
+ discovered packages pass. Human-readable diagnostics are printed by default;
21
+ `--json` prints the stable `{ packages, errors, valid }` result on stdout for CI.
22
+ Validation reads `schemas/` shipped inside the npm package (and never requires a
23
+ network connection). The CLI is the new reusable validator; Contrib and Community
24
+ Packages retain their existing workflows until a separate migration.
25
+
26
+ > Authoring location: contributors add and update preset-task packages **here**, in
27
+ > `repos/hagitask`, not in `repos/hagicode-core/src/PCode.Web/plugins/task-presets/`.
28
+ > The `hagicode-core` copy is a transitional asset that is kept only until the backend
29
+ > loading cutover lands.
30
+
31
+ ## Repository Layout
32
+
33
+ ```text
34
+ repos/hagitask/
35
+ schemas/
36
+ task-preset-plugin/
37
+ manifest.schema.json # Preset package manifest contract
38
+ panel.schema.json # Frontend panel definition contract
39
+ commands.schema.json # Frontend command catalog contract
40
+ locales.schema.json # Locale bundle contract
41
+ task-preset.schema.json # Backend task-preset contract
42
+ prompt-package.schema.json # Backend prompt package contract
43
+ store-page-frontmatter.schema.json # Store-page frontmatter contract
44
+ community-index-v1.schema.json # Published /index.json contract
45
+ community-task-detail-v1.schema.json # Published /tasks/<taskId>.json contract
46
+ presets/
47
+ <presetTaskId>/
48
+ manifest.json
49
+ frontend/
50
+ panel.json
51
+ commands.json # Optional, only when the preset ships commands
52
+ backend/
53
+ task-preset.json
54
+ prompts.json
55
+ templates/<locale>/...
56
+ locales/
57
+ en-US.json
58
+ zh-CN.json
59
+ store-page/
60
+ index.en-US.md
61
+ index.zh-CN.md
62
+ ```
63
+
64
+ ## Schema Layers
65
+
66
+ `schemas/` holds three schema layers. They validate different documents, at different
67
+ points in the pipeline, and are owned by different producers.
68
+
69
+ | Layer | Schemas | Validates | Produced by |
70
+ | --- | --- | --- | --- |
71
+ | Package schemas | `schemas/task-preset-plugin/*.schema.json` | the JSON files inside a preset or community package (`manifest.json`, `frontend/*`, `backend/*`, `locales/*`) | contributors, by hand |
72
+ | Community discovery schema | `schemas/community-index-v1.schema.json` | the published `/index.json` catalog | `hagitask-site` build |
73
+ | Community detail schema | `schemas/community-task-detail-v1.schema.json` | each published `/tasks/<taskId>.json` document | `hagitask-site` build |
74
+
75
+ Package schemas describe **authored source**. The community schemas describe
76
+ **generated publication output** and carry fields that do not exist in any package file
77
+ (`generatedAt`, `detailUrl`, `packageUrl`, `integrity.sha256`, and so on). Choosing the
78
+ wrong layer is the most common source of confusion: if you are editing a file inside a
79
+ package directory, the matching contract is always under `schemas/task-preset-plugin/`.
80
+
81
+ Community packages live in
82
+ [`hagitask-community-packages`](https://github.com/HagiCode-org/hagitask-community-packages).
83
+ That repository mounts HagiTask as a **nested submodule** and consumes these schemas
84
+ directly from `hagitask/schemas/task-preset-plugin/` — it no longer vendors its own copy.
85
+ [`hagitask-site`](https://github.com/HagiCode-org/hagitask-site) in turn mounts the
86
+ community repository as its `community-packages/` submodule, reads task packages from
87
+ `community-packages/data/`, and loads the publication schemas from
88
+ `community-packages/hagitask/schemas`. Shipped presets live in `presets/` in this
89
+ repository. All three — HagiTask presets, community packages, and the site build — use the
90
+ same package schemas from this directory.
91
+
92
+ ## Package `$schema` Reference
93
+
94
+ `schemas/task-preset-plugin/` is the authoritative home for the JSON schemas that
95
+ validate preset packages. Every shipped and community preset package resolves its
96
+ `$schema` references against this directory, so contributors never need files from
97
+ `repos/hagicode-core` to validate a package.
98
+
99
+ The shipped preset packages use these relative `$schema` paths from inside
100
+ `presets/<presetTaskId>/`:
101
+
102
+ | Package file | `$schema` path |
103
+ |------------------------------------|-------------------------------------------------------------------------|
104
+ | `manifest.json` | `../../schemas/task-preset-plugin/manifest.schema.json` |
105
+ | `frontend/panel.json` | `../../../schemas/task-preset-plugin/panel.schema.json` |
106
+ | `frontend/commands.json` | `../../../schemas/task-preset-plugin/commands.schema.json` |
107
+ | `backend/task-preset.json` | `../../../schemas/task-preset-plugin/task-preset.schema.json` |
108
+ | `backend/prompts.json` | `../../../schemas/task-preset-plugin/prompt-package.schema.json` |
109
+ | `locales/<locale>.json` | `../../../schemas/task-preset-plugin/locales.schema.json` |
110
+
111
+ Prompt packages may optionally declare `commandSystemPrompts`, mapping a command id
112
+ to locale-specific system-template paths:
113
+
114
+ ```json
115
+ {
116
+ "commandSystemPrompts": {
117
+ "initialize": {
118
+ "en-US": "./templates/en-US/commands/initialize.md",
119
+ "zh-CN": "./templates/zh-CN/commands/initialize.md"
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ The selected command template is rendered with the same context as the user and
126
+ base system templates. Locale resolution uses an exact match, then the language
127
+ portion, then the package default locale. Missing mappings, blank commands, and
128
+ legacy packages simply omit the additional system section. Final prompt order is
129
+ user prompt, command-specific system prompt, then base system prompt; existing
130
+ command preludes remain supported.
131
+
132
+ Community packages use the identical values, so a package can move between
133
+ `presets/<presetTaskId>/` and the community repository without rewriting references.
134
+
135
+ ## Publication Data Flow
136
+
137
+ ```mermaid
138
+ flowchart LR
139
+ SRC["Community package source<br/>data/&lt;taskId&gt;/manifest.json, frontend/, backend/, locales/, store-page/"]
140
+ PKG["Package schemas<br/>hagitask/schemas/task-preset-plugin/*.schema.json"]
141
+ SUB["hagitask-site community-packages/ submodule (nested hagitask)"]
142
+ NORM["Site build: normalize + digest"]
143
+ IDX["/index.json"]
144
+ DET["/tasks/&lt;taskId&gt;.json"]
145
+ ZIP["/packages/&lt;taskId&gt;.zip"]
146
+ CIDX["community-index-v1.schema.json"]
147
+ CDET["community-task-detail-v1.schema.json"]
148
+
149
+ PKG -.validates.-> SRC
150
+ SRC --> SUB --> NORM
151
+ NORM --> IDX
152
+ NORM --> DET
153
+ NORM --> ZIP
154
+ CIDX -.validates.-> IDX
155
+ CDET -.validates.-> DET
156
+ ```
157
+
158
+ How source edits reach the published documents:
159
+
160
+ | Source change | Affected published fields |
161
+ | --- | --- |
162
+ | `manifest.json` → `version` | `version` in index and detail |
163
+ | `manifest.json` → `owner` | `publisher` in index and detail |
164
+ | `backend/task-preset.json` → `requirements` | `requirements` in detail, and the derived `compatibility.agent` / `.skills` / `.cli` in both documents |
165
+ | `store-page/index.<locale>.md` → `title` / `summary` | `name`, `summary`, `description`, and `localization.supportedLocales` |
166
+ | `store-page/index.en-US.md` → `catalog` / `tags` | `category` and `tags` |
167
+ | any file in the package directory | the zip contents, plus `integrity.sha256` in the index and `installation.size` / `installation.sha256` in the detail |
168
+
169
+ ## Generated Output Is Not Editable
170
+
171
+ `/index.json`, `/tasks/<taskId>.json`, and `/packages/<taskId>.zip` are produced from
172
+ scratch on every site build. They are not stored in any repository as editable source and
173
+ hand edits are discarded on the next publish. The only way to change a published field is
174
+ to change the package file it is derived from.
175
+
176
+ When schema validation fails:
177
+
178
+ 1. Read which document failed. A `task-preset-plugin` failure points at a package file you
179
+ authored; a `community-index-v1` or `community-task-detail-v1` failure means the site
180
+ build normalized your source into something that violates the publication contract.
181
+ 2. Fix the source package file. Do not relax `$schema`, delete the `$schema` reference,
182
+ skip validation, or patch the generated output.
183
+ 3. Re-run the site build to confirm the fix.
184
+ 4. If the package data is genuinely correct and the schema is wrong, change the schema
185
+ **here**, in this repository, as a deliberate contract change.
186
+
187
+ ## Preset Package Directory
188
+
189
+ `presets/` is the root for preset-task packages. Each package lives in its own
190
+ `presets/<presetTaskId>/` directory and preserves the loader-compatible plugin
191
+ package shape (`manifest.json`, `frontend/`, `backend/`, `locales/`, and
192
+ `store-page/`). This means the backend can load migrated packages without a
193
+ HagiTask-specific adapter.
194
+
195
+ Currently shipped packages:
196
+
197
+ - `normal-session`
198
+ - `research-investigation`
199
+
200
+ `agents-md-update`, `goal`, `last30days`, `openspec-spec-compress`, `ponytail`, and
201
+ `ui-master` are published as community tasks and live in
202
+ [`hagitask-community-packages`](https://github.com/HagiCode-org/hagitask-community-packages),
203
+ not in `presets/`.
204
+
205
+ ## Source-of-Truth Ownership
206
+
207
+ HagiTask owns preset-task schemas and shipped preset packages. When you add a new
208
+ preset, update an existing one, or change a schema, do it here.
209
+
210
+ The legacy copies under `repos/hagicode-core/src/PCode.Web/plugins/task-presets/`
211
+ are kept unchanged during the copy-first transition phase. After the later backend
212
+ loading cutover (see `openspec/changes/migrate-preset-task-to-hagitask-repo`),
213
+ `hagicode-core` will load shipped presets from `repos/hagitask/presets` through the
214
+ `TaskPresetPlugins.PresetGroups` configuration and the backend-owned copy will no
215
+ longer be the shipped source of truth.
216
+
217
+ Until that cutover lands, every shipped preset update — including `openspec-spec-compress` —
218
+ must keep the `hagicode-core` runtime copy synchronized with the canonical HagiTask package.
219
+
220
+ ## Contributing a Preset Package
221
+
222
+ HagiTask owns the Schema and shipped preset source. Preset packages use the loader-compatible
223
+ layout described above and must keep their JSON resources aligned with
224
+ `schemas/task-preset-plugin/`. Validate authored files against those schemas before submitting:
225
+
226
+ ```bash
227
+ npm run validate
228
+ ```
229
+
230
+ The validator checks every shipped preset, all manifest resource references, package
231
+ JSON schemas, prompt template references, and compatibility binding aliases. It is
232
+ intentionally package-local so the same command can run in a clean checkout without
233
+ depending on Core or site-generated output.
234
+
235
+ For the user-facing walkthrough covering package creation, locale and store-page resources,
236
+ validation, semantic versioning, and Pull Requests, see the
237
+ [HagiTask community guide](https://docs.hagicode.com/guides/hagitask/community/). A community
238
+ task belongs in
239
+ [`hagitask-community-packages`](https://github.com/HagiCode-org/hagitask-community-packages),
240
+ not in this repository. This README remains the technical reference for Schema ownership,
241
+ preset source data, and the transitional runtime copy.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ export declare function createCli(): Command;
4
+ export declare function main(argv?: string[]): void;
package/dist/cli.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { readFileSync } from 'node:fs';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { runValidateCommand } from './commands/validate-command.js';
7
+ function packageVersion() {
8
+ try {
9
+ const packagePath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
10
+ return JSON.parse(readFileSync(packagePath, 'utf8')).version;
11
+ }
12
+ catch {
13
+ return '0.1.0';
14
+ }
15
+ }
16
+ export function createCli() {
17
+ const program = new Command();
18
+ program
19
+ .name('hagitask')
20
+ .description('Validate HagiTask preset and community packages offline.')
21
+ .version(packageVersion());
22
+ program
23
+ .command('validate [path]')
24
+ .description('validate packages under presets/, data/, or a single package directory')
25
+ .option('--json', 'print machine-readable JSON diagnostics')
26
+ .action((path, options) => {
27
+ process.exitCode = runValidateCommand(path ?? process.cwd(), options);
28
+ });
29
+ return program;
30
+ }
31
+ export function main(argv = process.argv) {
32
+ createCli().parse(argv);
33
+ }
34
+ if (import.meta.url === `file://${process.argv[1]}`)
35
+ main();
36
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAC3F,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO;SACJ,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CAAC,0DAA0D,CAAC;SACvE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC7B,OAAO;SACJ,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,wEAAwE,CAAC;SACrF,MAAM,CAAC,QAAQ,EAAE,yCAAyC,CAAC;SAC3D,MAAM,CAAC,CAAC,IAAwB,EAAE,OAA2B,EAAE,EAAE;QAChE,OAAO,CAAC,QAAQ,GAAG,kBAAkB,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IACL,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI;IACtC,SAAS,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export interface ValidateCommandOptions {
2
+ json?: boolean;
3
+ }
4
+ export declare function runValidateCommand(path?: string, options?: ValidateCommandOptions): number;
@@ -0,0 +1,14 @@
1
+ import { validatePackages } from '../index.js';
2
+ import { formatValidationText } from '../validation/diagnostics.js';
3
+ export function runValidateCommand(path = process.cwd(), options = {}) {
4
+ const result = validatePackages(path);
5
+ const output = options.json
6
+ ? JSON.stringify(result, null, 2)
7
+ : formatValidationText(result);
8
+ if (options.json || result.valid)
9
+ console.log(output);
10
+ else
11
+ console.error(output);
12
+ return result.valid ? 0 : 1;
13
+ }
14
+ //# sourceMappingURL=validate-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-command.js","sourceRoot":"","sources":["../../src/commands/validate-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAMpE,MAAM,UAAU,kBAAkB,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,UAAkC,EAAE;IAC3F,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI;QACzB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;;QACjD,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,15 @@
1
+ export type { DiscoveredPackage, DiscoveryResult } from './validation/package-discovery.js';
2
+ export type { ValidationError, ValidationResult } from './validation/diagnostics.js';
3
+ export declare const PACKAGE_NAME = "@hagicode/hagitask";
4
+ export declare const PACKAGE_VERSION = "0.1.0";
5
+ export declare const packageMetadata: {
6
+ readonly name: "@hagicode/hagitask";
7
+ readonly version: "0.1.0";
8
+ };
9
+ export interface ValidateOptions {
10
+ /** Override the directory containing the published schemas. */
11
+ packageRoot?: string;
12
+ }
13
+ export declare function validatePackages(targetPath?: string, options?: ValidateOptions): import("./validation/diagnostics.js").ValidationResult;
14
+ export { discoverPackages } from './validation/package-discovery.js';
15
+ export { formatValidationError, formatValidationText } from './validation/diagnostics.js';
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ import { dirname, resolve } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { discoverPackages } from './validation/package-discovery.js';
4
+ import { validateDiscoveredPackages } from './validation/package-validator.js';
5
+ export const PACKAGE_NAME = '@hagicode/hagitask';
6
+ export const PACKAGE_VERSION = '0.1.0';
7
+ export const packageMetadata = {
8
+ name: PACKAGE_NAME,
9
+ version: PACKAGE_VERSION,
10
+ };
11
+ export function validatePackages(targetPath = process.cwd(), options = {}) {
12
+ const root = resolve(targetPath);
13
+ const discovery = discoverPackages(root);
14
+ const packageRoot = options.packageRoot ?? resolve(dirname(fileURLToPath(import.meta.url)), '..');
15
+ if (discovery.errors.length > 0) {
16
+ return {
17
+ packages: discovery.packages.map((pkg) => pkg.rel).sort(),
18
+ errors: discovery.errors.map((message) => ({
19
+ packageId: '',
20
+ file: root,
21
+ field: 'path',
22
+ message,
23
+ })),
24
+ valid: false,
25
+ };
26
+ }
27
+ return validateDiscoveredPackages(discovery.packages, root, packageRoot);
28
+ }
29
+ export { discoverPackages } from './validation/package-discovery.js';
30
+ export { formatValidationError, formatValidationText } from './validation/diagnostics.js';
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAI/E,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,eAAe;CAChB,CAAC;AAOX,MAAM,UAAU,gBAAgB,CAC9B,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,EAC1B,UAA2B,EAAE;IAE7B,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAClG,IAAI,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;YACzD,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACzC,SAAS,EAAE,EAAE;gBACb,IAAI,EAAE,IAAI;gBACV,KAAK,EAAE,MAAM;gBACb,OAAO;aACR,CAAC,CAAC;YACH,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;IACD,OAAO,0BAA0B,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAC3E,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface ValidationError {
2
+ packageId: string;
3
+ file: string;
4
+ field: string;
5
+ message: string;
6
+ }
7
+ export interface ValidationResult {
8
+ packages: string[];
9
+ errors: ValidationError[];
10
+ valid: boolean;
11
+ }
12
+ export declare function formatValidationError(error: ValidationError): string;
13
+ export declare function formatValidationText(result: ValidationResult): string;
@@ -0,0 +1,16 @@
1
+ export function formatValidationError(error) {
2
+ return `${error.packageId}: ${error.file}: ${error.field}: ${error.message}`;
3
+ }
4
+ export function formatValidationText(result) {
5
+ const lines = [
6
+ `HagiTask package validation ${result.valid ? 'passed' : 'failed'}`,
7
+ `Packages discovered: ${result.packages.length}`,
8
+ `Packages: ${result.packages.join(', ') || '(none)'}`,
9
+ `Errors: ${result.errors.length}`,
10
+ ];
11
+ if (result.errors.length > 0) {
12
+ lines.push('', ...result.errors.map((error) => `- ${formatValidationError(error)}`));
13
+ }
14
+ return lines.join('\n');
15
+ }
16
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/validation/diagnostics.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,qBAAqB,CAAC,KAAsB;IAC1D,OAAO,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAwB;IAC3D,MAAM,KAAK,GAAG;QACZ,+BAA+B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;QACnE,wBAAwB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE;QAChD,aAAa,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE;QACrD,WAAW,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE;KAClC,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface DiscoveredPackage {
2
+ dirName: string;
3
+ dir: string;
4
+ rel: string;
5
+ }
6
+ export interface DiscoveryResult {
7
+ packages: DiscoveredPackage[];
8
+ errors: string[];
9
+ }
10
+ export declare function discoverPackages(targetPath: string): DiscoveryResult;
@@ -0,0 +1,45 @@
1
+ import { existsSync, readdirSync, statSync } from 'node:fs';
2
+ import { basename, join, resolve } from 'node:path';
3
+ function packageInDir(dir, rel) {
4
+ if (!statSync(dir, { throwIfNoEntry: false })?.isDirectory())
5
+ return undefined;
6
+ if (!existsSync(join(dir, 'manifest.json')))
7
+ return undefined;
8
+ return { dirName: basename(dir), dir, rel };
9
+ }
10
+ export function discoverPackages(targetPath) {
11
+ const root = resolve(targetPath);
12
+ if (!existsSync(root)) {
13
+ return { packages: [], errors: [`target path does not exist: ${root}`] };
14
+ }
15
+ if (!statSync(root).isDirectory()) {
16
+ return { packages: [], errors: [`target path is not a directory: ${root}`] };
17
+ }
18
+ const direct = packageInDir(root, basename(root));
19
+ if (direct)
20
+ return { packages: [direct], errors: [] };
21
+ const layouts = ['presets', 'data'].filter((name) => {
22
+ const path = join(root, name);
23
+ return existsSync(path) && statSync(path).isDirectory();
24
+ });
25
+ if (layouts.length === 0) {
26
+ return {
27
+ packages: [],
28
+ errors: [`unsupported package layout at ${root}; expected presets/<taskId>/, data/<taskId>/, or a package directory containing manifest.json`],
29
+ };
30
+ }
31
+ const packages = [];
32
+ for (const layout of layouts) {
33
+ const layoutDir = join(root, layout);
34
+ for (const entry of readdirSync(layoutDir, { withFileTypes: true })) {
35
+ if (!entry.isDirectory())
36
+ continue;
37
+ const pkg = packageInDir(join(layoutDir, entry.name), `${layout}/${entry.name}`);
38
+ if (pkg)
39
+ packages.push(pkg);
40
+ }
41
+ }
42
+ packages.sort((a, b) => a.rel.localeCompare(b.rel));
43
+ return { packages, errors: [] };
44
+ }
45
+ //# sourceMappingURL=package-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-discovery.js","sourceRoot":"","sources":["../../src/validation/package-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAY,OAAO,EAAE,MAAM,WAAW,CAAC;AAa9D,SAAS,YAAY,CAAC,GAAW,EAAE,GAAW;IAC5C,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE;QAAE,OAAO,SAAS,CAAC;IAC/E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9D,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,+BAA+B,IAAI,EAAE,CAAC,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,mCAAmC,IAAI,EAAE,CAAC,EAAE,CAAC;IAC/E,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAEtD,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9B,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,QAAQ,EAAE,EAAE;YACZ,MAAM,EAAE,CAAC,iCAAiC,IAAI,+FAA+F,CAAC;SAC/I,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YACnC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACjF,IAAI,GAAG;gBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { DiscoveredPackage } from './package-discovery.js';
2
+ import type { ValidationError, ValidationResult } from './diagnostics.js';
3
+ export declare function validatePackage(pkg: DiscoveredPackage, targetRoot: string, packageRoot: string): ValidationError[];
4
+ export declare function validateDiscoveredPackages(packages: DiscoveredPackage[], targetRoot: string, packageRoot: string): ValidationResult;