laymos 0.0.9 → 0.0.11

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 (60) hide show
  1. package/README.md +259 -142
  2. package/dist/architecture-analysis-schema/module-source-schema.d.ts +4 -0
  3. package/dist/architecture-analysis-schema/module-source-schema.d.ts.map +1 -1
  4. package/dist/architecture-analysis-schema/module-source-schema.js +4 -0
  5. package/dist/change-set-schema/change-set-schema.js +2 -2
  6. package/dist/cli/run.d.ts +1 -1
  7. package/dist/cli/run.d.ts.map +1 -1
  8. package/dist/cli/run.js +2 -0
  9. package/dist/cli/skills.d.ts +6 -0
  10. package/dist/cli/skills.d.ts.map +1 -0
  11. package/dist/cli/skills.js +9 -0
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -2
  15. package/dist/orchestrator/load-changes/index.d.ts +1 -1
  16. package/dist/orchestrator/load-changes/index.d.ts.map +1 -1
  17. package/dist/orchestrator/load-changes/index.js +1 -1
  18. package/dist/orchestrator/load-changes/load-changes.d.ts +4 -3
  19. package/dist/orchestrator/load-changes/load-changes.d.ts.map +1 -1
  20. package/dist/orchestrator/load-changes/load-changes.js +14 -9
  21. package/dist/orchestrator/load-source-files/index.d.ts +1 -1
  22. package/dist/orchestrator/load-source-files/index.d.ts.map +1 -1
  23. package/dist/orchestrator/load-source-files/index.js +1 -1
  24. package/dist/orchestrator/load-source-files/load-source-files.d.ts +20 -4
  25. package/dist/orchestrator/load-source-files/load-source-files.d.ts.map +1 -1
  26. package/dist/orchestrator/load-source-files/load-source-files.js +46 -7
  27. package/dist/services/git/changed-paths.d.ts +1 -0
  28. package/dist/services/git/changed-paths.d.ts.map +1 -1
  29. package/dist/services/git/changed-paths.js +8 -0
  30. package/dist/services/git/git.d.ts +1 -0
  31. package/dist/services/git/git.d.ts.map +1 -1
  32. package/dist/services/git/git.js +5 -1
  33. package/dist/skills-command/index.d.ts +2 -0
  34. package/dist/skills-command/index.d.ts.map +1 -0
  35. package/dist/skills-command/index.js +1 -0
  36. package/dist/skills-command/skills-command.d.ts +21 -0
  37. package/dist/skills-command/skills-command.d.ts.map +1 -0
  38. package/dist/skills-command/skills-command.js +64 -0
  39. package/dist/story/schema/index.d.ts +2 -2
  40. package/dist/story/schema/index.d.ts.map +1 -1
  41. package/dist/story/schema/index.js +1 -1
  42. package/dist/story/schema/story-report-schema.d.ts +264 -132
  43. package/dist/story/schema/story-report-schema.d.ts.map +1 -1
  44. package/dist/story/schema/story-report-schema.js +4 -4
  45. package/dist/story/story.d.ts +3 -1
  46. package/dist/story/story.d.ts.map +1 -1
  47. package/dist/story/story.js +4 -5
  48. package/package.json +18 -11
  49. package/schema.json +60 -55
  50. package/skills/deep-module/SKILL.md +55 -0
  51. package/skills/domain-modeling/ADR-FORMAT.md +47 -0
  52. package/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  53. package/skills/domain-modeling/SKILL.md +74 -0
  54. package/skills/domain-modeling/agents/openai.yaml +3 -0
  55. package/skills/laymos/SKILL.md +130 -0
  56. package/skills/laymos/references/config.md +96 -0
  57. package/skills/laymos/references/design.md +166 -0
  58. package/skills/laymos/references/graphs.md +85 -0
  59. package/skills/laymos/references/visibility.md +60 -0
  60. package/skills/to-laymos/SKILL.md +60 -0
@@ -1 +1 @@
1
- {"version":3,"file":"load-changes.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/load-changes/load-changes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EACV,MAAM,EACN,SAAS,EACT,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE1E,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,OAAO,SAAS,GACf,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAKpC;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,SAAS,GACf,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAKnC;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC,CAK5C"}
1
+ {"version":3,"file":"load-changes.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/load-changes/load-changes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EACV,MAAM,EACN,SAAS,EACT,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAI1E,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,OAAO,SAAS,GACf,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAKpC;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,SAAS,GACf,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAKnC;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC,CAK5C;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC,CAK5C"}
@@ -1,24 +1,29 @@
1
- import { dirname, resolve } from 'node:path';
1
+ import { resolve } from 'node:path';
2
2
  import { Effect } from 'effect';
3
3
  import { Git, GitLive } from '../../services/git/index.js';
4
- export function loadChangeSet(configPath, baseRef = 'HEAD') {
4
+ // Each loader works on any folder inside a git repository; paths are relative
5
+ // to that folder.
6
+ export function loadChangeSet(folder, baseRef = 'HEAD') {
5
7
  return Effect.gen(function* () {
6
8
  const git = yield* Git;
7
- return yield* git.changeSet(projectDir(configPath), baseRef);
9
+ return yield* git.changeSet(resolve(folder), baseRef);
8
10
  }).pipe(Effect.provide(GitLive));
9
11
  }
10
- export function loadFileDiff(configPath, path, baseRef = 'HEAD') {
12
+ export function loadFileDiff(folder, path, baseRef = 'HEAD') {
11
13
  return Effect.gen(function* () {
12
14
  const git = yield* Git;
13
- return yield* git.fileDiff(projectDir(configPath), baseRef, path);
15
+ return yield* git.fileDiff(resolve(folder), baseRef, path);
14
16
  }).pipe(Effect.provide(GitLive));
15
17
  }
16
- export function loadBranches(configPath) {
18
+ export function loadBranches(folder) {
17
19
  return Effect.gen(function* () {
18
20
  const git = yield* Git;
19
- return yield* git.branches(projectDir(configPath));
21
+ return yield* git.branches(resolve(folder));
20
22
  }).pipe(Effect.provide(GitLive));
21
23
  }
22
- function projectDir(configPath) {
23
- return dirname(resolve(configPath));
24
+ export function loadKnownFiles(folder) {
25
+ return Effect.gen(function* () {
26
+ const git = yield* Git;
27
+ return yield* git.knownFiles(resolve(folder));
28
+ }).pipe(Effect.provide(GitLive));
24
29
  }
@@ -1,2 +1,2 @@
1
- export { loadSourceFiles, SourceFileReadError } from './load-source-files.js';
1
+ export { loadFolderFiles, loadSourceFiles, SourceFileReadError, } from './load-source-files.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/load-source-files/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/load-source-files/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,eAAe,EACf,mBAAmB,GACpB,MAAM,wBAAwB,CAAC"}
@@ -1 +1 @@
1
- export { loadSourceFiles, SourceFileReadError } from './load-source-files.js';
1
+ export { loadFolderFiles, loadSourceFiles, SourceFileReadError, } from './load-source-files.js';
@@ -2,15 +2,31 @@ import { Effect } from 'effect';
2
2
  import { SourceFileReadError } from './errors.js';
3
3
  export { SourceFileReadError } from './errors.js';
4
4
  /**
5
- * Reads every analyzed file at or below one of the given project-relative
6
- * path prefixes — a Configured Module's, Module Graph's, or Layer scope's
7
- * own root. A prefix outside the analysis universe matches nothing, so a
8
- * caller can never use this to read a file outside the Project.
5
+ * Reads every file at or below one of the given project-relative path
6
+ * prefixes — a Configured Module's, Module Graph's, or Layer scope's own root.
7
+ * Files git knows beside the analyzed ones are read too, marked as Unanalyzed
8
+ * files; without git, only analyzed files are read. Only paths inside the Project are ever listed, so a caller can never
9
+ * use this to read a file outside it.
9
10
  */
10
11
  export declare function loadSourceFiles(configPath: string, pathPrefixes: readonly string[]): Effect.Effect<{
11
12
  files: {
12
13
  readonly path: string;
13
14
  readonly content: string;
15
+ readonly binary?: boolean | undefined;
16
+ readonly unanalyzed?: boolean | undefined;
14
17
  }[];
15
18
  }, import("../../services/config/errors.js").ConfigError | import("../../services/file-cruiser/errors.js").CruiseError | SourceFileReadError, never>;
19
+ /**
20
+ * Reads every file git knows at or below one of the given paths of a folder,
21
+ * such as a Package's files within its Monorepo. Paths are relative to the
22
+ * folder, and only paths inside it are ever listed.
23
+ */
24
+ export declare function loadFolderFiles(folder: string, pathPrefixes: readonly string[]): Effect.Effect<{
25
+ files: {
26
+ readonly path: string;
27
+ readonly content: string;
28
+ readonly binary?: boolean | undefined;
29
+ readonly unanalyzed?: boolean | undefined;
30
+ }[];
31
+ }, import("../../services/git/errors.js").GitError | SourceFileReadError, never>;
16
32
  //# sourceMappingURL=load-source-files.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load-source-files.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/load-source-files/load-source-files.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAc,MAAM,QAAQ,CAAC;AAM5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,SAAS,MAAM,EAAE;;;;;qJA2BhC"}
1
+ {"version":3,"file":"load-source-files.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/load-source-files/load-source-files.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAc,MAAM,QAAQ,CAAC;AAO5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAKlD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,SAAS,MAAM,EAAE;;;;;;;qJAuBhC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,SAAS,MAAM,EAAE;;;;;;;iFAUhC"}
@@ -3,28 +3,67 @@ import { NodeServices } from '@effect/platform-node';
3
3
  import { Effect, FileSystem } from 'effect';
4
4
  import { ConfigServiceLive } from '../../services/config/index.js';
5
5
  import { CruiserLive } from '../../services/file-cruiser/index.js';
6
+ import { Git, GitLive } from '../../services/git/index.js';
6
7
  import { loadProject } from '../load-project/index.js';
7
8
  import { SourceFileReadError } from './errors.js';
8
9
  export { SourceFileReadError } from './errors.js';
10
+ // Git's own test for binary content: a NUL byte near the start.
11
+ const binarySniffLength = 8000;
9
12
  /**
10
- * Reads every analyzed file at or below one of the given project-relative
11
- * path prefixes — a Configured Module's, Module Graph's, or Layer scope's
12
- * own root. A prefix outside the analysis universe matches nothing, so a
13
- * caller can never use this to read a file outside the Project.
13
+ * Reads every file at or below one of the given project-relative path
14
+ * prefixes — a Configured Module's, Module Graph's, or Layer scope's own root.
15
+ * Files git knows beside the analyzed ones are read too, marked as Unanalyzed
16
+ * files; without git, only analyzed files are read. Only paths inside the Project are ever listed, so a caller can never
17
+ * use this to read a file outside it.
14
18
  */
15
19
  export function loadSourceFiles(configPath, pathPrefixes) {
16
20
  const absoluteConfigPath = resolve(configPath);
17
21
  const baseDir = dirname(absoluteConfigPath);
18
22
  return Effect.gen(function* () {
19
23
  const { fileGraph } = yield* loadProject(absoluteConfigPath);
20
- const paths = [...fileGraph.keys()]
24
+ const known = yield* knownFiles(baseDir).pipe(Effect.orElseSucceed(() => []));
25
+ const paths = [...new Set([...fileGraph.keys(), ...known])]
21
26
  .filter((path) => underAnyPrefix(path, pathPrefixes))
22
27
  .sort((left, right) => left.localeCompare(right));
23
- const fileSystem = yield* FileSystem.FileSystem;
24
- const files = yield* Effect.forEach(paths, (path) => fileSystem.readFileString(resolve(baseDir, path)).pipe(Effect.map((content) => ({ path, content })), Effect.mapError((cause) => new SourceFileReadError({ filePath: path, cause }))));
28
+ const files = yield* readFiles(baseDir, paths, (path) => fileGraph.has(path));
25
29
  return { files };
26
30
  }).pipe(Effect.provide(ConfigServiceLive), Effect.provide(CruiserLive), Effect.provide(NodeServices.layer));
27
31
  }
32
+ /**
33
+ * Reads every file git knows at or below one of the given paths of a folder,
34
+ * such as a Package's files within its Monorepo. Paths are relative to the
35
+ * folder, and only paths inside it are ever listed.
36
+ */
37
+ export function loadFolderFiles(folder, pathPrefixes) {
38
+ const baseDir = resolve(folder);
39
+ return Effect.gen(function* () {
40
+ const paths = (yield* knownFiles(baseDir)).filter((path) => underAnyPrefix(path, pathPrefixes));
41
+ const files = yield* readFiles(baseDir, paths, () => true);
42
+ return { files };
43
+ }).pipe(Effect.provide(NodeServices.layer));
44
+ }
45
+ function knownFiles(baseDir) {
46
+ return Effect.gen(function* () {
47
+ const git = yield* Git;
48
+ return yield* git.knownFiles(baseDir);
49
+ }).pipe(Effect.provide(GitLive));
50
+ }
51
+ function readFiles(baseDir, paths, isAnalyzed) {
52
+ return Effect.gen(function* () {
53
+ const fileSystem = yield* FileSystem.FileSystem;
54
+ const files = yield* Effect.forEach(paths, (path) => fileSystem.readFile(resolve(baseDir, path)).pipe(Effect.map((bytes) => sourceFile(path, bytes, isAnalyzed(path))), Effect.mapError((cause) => new SourceFileReadError({ filePath: path, cause }))));
55
+ return files;
56
+ });
57
+ }
58
+ function sourceFile(path, bytes, analyzed) {
59
+ const binary = bytes.subarray(0, binarySniffLength).includes(0);
60
+ return {
61
+ path,
62
+ content: binary ? '' : new TextDecoder().decode(bytes),
63
+ ...(binary ? { binary } : {}),
64
+ ...(analyzed ? {} : { unanalyzed: true }),
65
+ };
66
+ }
28
67
  function underAnyPrefix(path, pathPrefixes) {
29
68
  return pathPrefixes.some((prefix) => prefix === '.' || path === prefix || path.startsWith(`${prefix}/`));
30
69
  }
@@ -2,4 +2,5 @@ import type { Branch, ChangeSet, DiffHunk } from '../../change-set-schema/index.
2
2
  export declare function readChangeSet(baseDir: string, baseRef: string): Promise<ChangeSet>;
3
3
  export declare function readFileDiff(baseDir: string, baseRef: string, path: string): Promise<readonly DiffHunk[]>;
4
4
  export declare function listBranches(baseDir: string): Promise<Branch[]>;
5
+ export declare function listKnownFiles(baseDir: string): Promise<string[]>;
5
6
  //# sourceMappingURL=changed-paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"changed-paths.d.ts","sourceRoot":"","sources":["../../../src/services/git/changed-paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAEN,SAAS,EAET,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAY1C,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,CAAC,CA+BpB;AA8CD,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,SAAS,QAAQ,EAAE,CAAC,CAiB9B;AAYD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBrE"}
1
+ {"version":3,"file":"changed-paths.d.ts","sourceRoot":"","sources":["../../../src/services/git/changed-paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAEN,SAAS,EAET,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAY1C,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,CAAC,CA+BpB;AA8CD,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,SAAS,QAAQ,EAAE,CAAC,CAiB9B;AAYD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBrE;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBvE"}
@@ -80,6 +80,14 @@ export async function listBranches(baseDir) {
80
80
  .map((name) => ({ name, remote: true, current: false }));
81
81
  return [...local, ...remote];
82
82
  }
83
+ export async function listKnownFiles(baseDir) {
84
+ await requireGit(baseDir, ['rev-parse', '--show-toplevel'], 'not-a-repo');
85
+ const known = splitNul(await requireGit(baseDir, ['ls-files', '--cached', '--others', '--exclude-standard', '-z'], 'command-failed'));
86
+ const deleted = new Set(splitNul(await requireGit(baseDir, ['ls-files', '--deleted', '-z'], 'command-failed')));
87
+ return [...new Set(known)]
88
+ .filter((path) => !deleted.has(path))
89
+ .sort((left, right) => left.localeCompare(right));
90
+ }
83
91
  function splitLines(stdout) {
84
92
  return stdout
85
93
  .split('\n')
@@ -5,6 +5,7 @@ declare const Git_base: Context.ServiceClass<Git, "Git", {
5
5
  readonly changeSet: (baseDir: string, baseRef: string) => Effect.Effect<ChangeSet, GitError>;
6
6
  readonly fileDiff: (baseDir: string, baseRef: string, path: string) => Effect.Effect<FileDiff, GitError>;
7
7
  readonly branches: (baseDir: string) => Effect.Effect<readonly Branch[], GitError>;
8
+ readonly knownFiles: (baseDir: string) => Effect.Effect<readonly string[], GitError>;
8
9
  }>;
9
10
  export declare class Git extends Git_base {
10
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/services/git/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,KAAK,EACV,MAAM,EACN,SAAS,EACT,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;;wBAKf,CAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC;uBACpB,CACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,KACT,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;uBACnB,CACjB,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC;;AAdnD,qBAAa,GAAI,SAAQ,QAgBf;CAAG;AAEb,eAAO,MAAM,OAAO,gCAmBlB,CAAC"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/services/git/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,KAAK,EACV,MAAM,EACN,SAAS,EACT,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAO1C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;;wBAKf,CAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC;uBACpB,CACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,KACT,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;uBACnB,CACjB,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC;yBAG1B,CACnB,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC;;AAnBnD,qBAAa,GAAI,SAAQ,QAqBf;CAAG;AAEb,eAAO,MAAM,OAAO,gCAwBlB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { Context, Effect, Layer } from 'effect';
2
- import { listBranches, readChangeSet, readFileDiff } from './changed-paths.js';
2
+ import { listBranches, listKnownFiles, readChangeSet, readFileDiff, } from './changed-paths.js';
3
3
  import { GitError } from './errors.js';
4
4
  export class Git extends Context.Service()('Git') {
5
5
  }
@@ -19,6 +19,10 @@ export const GitLive = Layer.succeed(Git)({
19
19
  try: () => listBranches(baseDir),
20
20
  catch: (cause) => asGitError(cause, baseDir),
21
21
  }),
22
+ knownFiles: (baseDir) => Effect.tryPromise({
23
+ try: () => listKnownFiles(baseDir),
24
+ catch: (cause) => asGitError(cause, baseDir),
25
+ }),
22
26
  });
23
27
  function asGitError(cause, baseDir) {
24
28
  return cause instanceof GitError
@@ -0,0 +1,2 @@
1
+ export { makeSkillsCommand, type SkillsCommandOptions, } from './skills-command.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills-command/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1 @@
1
+ export { makeSkillsCommand, } from './skills-command.js';
@@ -0,0 +1,21 @@
1
+ import { FileSystem } from 'effect';
2
+ import { Command } from 'effect/unstable/cli';
3
+ export type SkillsCommandOptions = {
4
+ /** Folder holding one sub-folder per skill, each with a `SKILL.md`. */
5
+ readonly skillsRoot: string;
6
+ /** Skill folder names in listing order. */
7
+ readonly names: ReadonlyArray<string>;
8
+ /** The CLI's own name, used in help text. */
9
+ readonly cliName: string;
10
+ };
11
+ /**
12
+ * Builds a `skills` subcommand: `skills` lists, `skills <name>` prints one
13
+ * SKILL.md, and `--install <dir>` copies one or every skill folder into
14
+ * `<dir>/<name>/`, overwriting what is there.
15
+ */
16
+ export declare const makeSkillsCommand: ({ skillsRoot, names, cliName, }: SkillsCommandOptions) => Command.Command<"skills", {
17
+ readonly name: import("effect/Option").Option<string>;
18
+ readonly install: import("effect/Option").Option<string>;
19
+ readonly format: "json" | "text";
20
+ }, {}, import("effect/PlatformError").PlatformError, FileSystem.FileSystem>;
21
+ //# sourceMappingURL=skills-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-command.d.ts","sourceRoot":"","sources":["../../src/skills-command/skills-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,UAAU,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,EAAY,OAAO,EAAQ,MAAM,qBAAqB,CAAC;AAE9D,MAAM,MAAM,oBAAoB,GAAG;IACjC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAoCF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,oCAI3B,oBAAoB;;;;2EAwEtB,CAAC"}
@@ -0,0 +1,64 @@
1
+ import path from 'node:path';
2
+ import { Console, Effect, FileSystem } from 'effect';
3
+ import { Argument, Command, Flag } from 'effect/unstable/cli';
4
+ const descriptionOf = (markdown) => /^description:\s*(.+)$/m.exec(markdown)?.[1]?.trim() ?? '';
5
+ const renderList = (skills) => skills.map((skill) => `${skill.name} ${skill.description}`).join('\n');
6
+ const fail = (message) => Console.error(message).pipe(Effect.andThen(Effect.sync(() => {
7
+ process.exitCode = 1;
8
+ })));
9
+ const nameArgument = Argument.string('name').pipe(Argument.withDescription('Skill to print or install; omit for all skills'), Argument.optional);
10
+ const installFlag = Flag.directory('install', { mustExist: false }).pipe(Flag.withDescription('Copy the skill folder(s) into <dir>/<name>/ instead of printing'), Flag.optional);
11
+ const formatFlag = Flag.choice('format', ['json', 'text']).pipe(Flag.withDescription('List skills as readable text or JSON'), Flag.withDefault('text'));
12
+ /**
13
+ * Builds a `skills` subcommand: `skills` lists, `skills <name>` prints one
14
+ * SKILL.md, and `--install <dir>` copies one or every skill folder into
15
+ * `<dir>/<name>/`, overwriting what is there.
16
+ */
17
+ export const makeSkillsCommand = ({ skillsRoot, names, cliName, }) => {
18
+ const skillDir = (name) => path.join(skillsRoot, name);
19
+ const summarize = (name) => Effect.gen(function* () {
20
+ const fs = yield* FileSystem.FileSystem;
21
+ const markdown = yield* fs.readFileString(path.join(skillDir(name), 'SKILL.md'));
22
+ return { name, description: descriptionOf(markdown), markdown };
23
+ });
24
+ const printSkill = (name) => Effect.gen(function* () {
25
+ const fs = yield* FileSystem.FileSystem;
26
+ const { markdown } = yield* summarize(name);
27
+ yield* Console.log(markdown.trimEnd());
28
+ const files = yield* fs.readDirectory(skillDir(name), {
29
+ recursive: true,
30
+ });
31
+ const extra = files.filter((file) => file !== 'SKILL.md').length;
32
+ if (extra > 0) {
33
+ yield* Console.error(`Note: ${name} ships ${extra} more file(s). Use --install <dir> to get all of them.`);
34
+ }
35
+ });
36
+ const installSkills = (selected, directory) => Effect.gen(function* () {
37
+ const fs = yield* FileSystem.FileSystem;
38
+ const root = path.resolve(directory);
39
+ yield* fs.makeDirectory(root, { recursive: true });
40
+ for (const name of selected) {
41
+ const target = path.join(root, name);
42
+ yield* fs.copy(skillDir(name), target, { overwrite: true });
43
+ yield* Console.log(`Installed skill ${name} at ${target}`);
44
+ }
45
+ });
46
+ return Command.make('skills', { name: nameArgument, install: installFlag, format: formatFlag }, ({ name, install, format }) => Effect.gen(function* () {
47
+ if (name._tag === 'Some' && !names.includes(name.value)) {
48
+ return yield* fail(`Unknown skill: ${name.value}. Available: ${names.join(', ')}`);
49
+ }
50
+ const selected = name._tag === 'Some' ? [name.value] : names;
51
+ if (install._tag === 'Some') {
52
+ return yield* installSkills(selected, install.value);
53
+ }
54
+ if (name._tag === 'Some')
55
+ return yield* printSkill(name.value);
56
+ const skills = yield* Effect.forEach(names, (skill) => Effect.map(summarize(skill), ({ name, description }) => ({
57
+ name,
58
+ description,
59
+ })));
60
+ yield* Console.log(format === 'json'
61
+ ? JSON.stringify(skills, null, 2)
62
+ : renderList(skills));
63
+ })).pipe(Command.withDescription(`List the agent skills shipped with ${cliName}, print one, or install them into a skills folder`));
64
+ };
@@ -1,5 +1,5 @@
1
- export { CapturedTraceSchema, QuestionReportSchema, QuestionSectionSchema, RecordedFlowSchema, StoryAssertionSchema, StoryReportSchema, StoryVerdictSchema, } from './story-report-schema.js';
2
- export type { CapturedTrace, JsonValue, QuestionReport, QuestionSection, RecordedFlow, StoryAssertion, StoryReport, StoryVerdict, } from './story-report-schema.js';
1
+ export { CapturedTraceSchema, QuestionReportSchema, QuestionSectionSchema, JournalSchema, StoryAssertionSchema, StoryReportSchema, StoryVerdictSchema, } from './story-report-schema.js';
2
+ export type { CapturedTrace, JsonValue, QuestionReport, QuestionSection, Journal, StoryAssertion, StoryReport, StoryVerdict, } from './story-report-schema.js';
3
3
  export { slugifyQuestion } from './slug.js';
4
4
  export { QuestionLeafSchema, StoryLeafSchema, StoryPageSchema, StorySourceSchema, StoryTreeGroupSchema, StoryTreeSchema, } from './story-tree-schema.js';
5
5
  export type { QuestionLeaf, StoryLeaf, StoryPage, StorySource, StoryTree, StoryTreeGroup, } from './story-tree-schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/story/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,aAAa,EACb,SAAS,EACT,cAAc,EACd,eAAe,EACf,YAAY,EACZ,cAAc,EACd,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,cAAc,GACf,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/story/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,aAAa,EACb,SAAS,EACT,cAAc,EACd,eAAe,EACf,OAAO,EACP,cAAc,EACd,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,cAAc,GACf,MAAM,wBAAwB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  // RPC transports and renderers use this browser-safe Story report contract.
2
- export { CapturedTraceSchema, QuestionReportSchema, QuestionSectionSchema, RecordedFlowSchema, StoryAssertionSchema, StoryReportSchema, StoryVerdictSchema, } from './story-report-schema.js';
2
+ export { CapturedTraceSchema, QuestionReportSchema, QuestionSectionSchema, JournalSchema, StoryAssertionSchema, StoryReportSchema, StoryVerdictSchema, } from './story-report-schema.js';
3
3
  export { slugifyQuestion } from './slug.js';
4
4
  export { QuestionLeafSchema, StoryLeafSchema, StoryPageSchema, StorySourceSchema, StoryTreeGroupSchema, StoryTreeSchema, } from './story-tree-schema.js';