@bluewombat/manager-fake 0.1.0

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 (99) hide show
  1. package/README.md +58 -0
  2. package/SPECS.md +65 -0
  3. package/dist/adapter/fetch/run-fetch.d.ts +24 -0
  4. package/dist/adapter/fetch/run-fetch.d.ts.map +1 -0
  5. package/dist/adapter/fetch/run-fetch.js +119 -0
  6. package/dist/adapter/fetch/run-fetch.js.map +1 -0
  7. package/dist/adapter/normalize/fingerprint.d.ts +8 -0
  8. package/dist/adapter/normalize/fingerprint.d.ts.map +1 -0
  9. package/dist/adapter/normalize/fingerprint.js +26 -0
  10. package/dist/adapter/normalize/fingerprint.js.map +1 -0
  11. package/dist/adapter/normalize/normalize.d.ts +17 -0
  12. package/dist/adapter/normalize/normalize.d.ts.map +1 -0
  13. package/dist/adapter/normalize/normalize.js +199 -0
  14. package/dist/adapter/normalize/normalize.js.map +1 -0
  15. package/dist/adapter/progress/emit.d.ts +3 -0
  16. package/dist/adapter/progress/emit.d.ts.map +1 -0
  17. package/dist/adapter/progress/emit.js +6 -0
  18. package/dist/adapter/progress/emit.js.map +1 -0
  19. package/dist/adapter/raw/parse-raw.d.ts +14 -0
  20. package/dist/adapter/raw/parse-raw.d.ts.map +1 -0
  21. package/dist/adapter/raw/parse-raw.js +47 -0
  22. package/dist/adapter/raw/parse-raw.js.map +1 -0
  23. package/dist/adapter/run/run-adapter.d.ts +25 -0
  24. package/dist/adapter/run/run-adapter.d.ts.map +1 -0
  25. package/dist/adapter/run/run-adapter.js +125 -0
  26. package/dist/adapter/run/run-adapter.js.map +1 -0
  27. package/dist/adapter/types.d.ts +51 -0
  28. package/dist/adapter/types.d.ts.map +1 -0
  29. package/dist/adapter/types.js +3 -0
  30. package/dist/adapter/types.js.map +1 -0
  31. package/dist/emitter/event/field-matrix.d.ts +29 -0
  32. package/dist/emitter/event/field-matrix.d.ts.map +1 -0
  33. package/dist/emitter/event/field-matrix.js +93 -0
  34. package/dist/emitter/event/field-matrix.js.map +1 -0
  35. package/dist/emitter/progress/emit.d.ts +3 -0
  36. package/dist/emitter/progress/emit.d.ts.map +1 -0
  37. package/dist/emitter/progress/emit.js +6 -0
  38. package/dist/emitter/progress/emit.js.map +1 -0
  39. package/dist/emitter/render/render-event.d.ts +14 -0
  40. package/dist/emitter/render/render-event.d.ts.map +1 -0
  41. package/dist/emitter/render/render-event.js +116 -0
  42. package/dist/emitter/render/render-event.js.map +1 -0
  43. package/dist/emitter/render/truncate.d.ts +9 -0
  44. package/dist/emitter/render/truncate.d.ts.map +1 -0
  45. package/dist/emitter/render/truncate.js +10 -0
  46. package/dist/emitter/render/truncate.js.map +1 -0
  47. package/dist/emitter/run/run-emitter.d.ts +21 -0
  48. package/dist/emitter/run/run-emitter.d.ts.map +1 -0
  49. package/dist/emitter/run/run-emitter.js +89 -0
  50. package/dist/emitter/run/run-emitter.js.map +1 -0
  51. package/dist/emitter/thread/slug.d.ts +7 -0
  52. package/dist/emitter/thread/slug.d.ts.map +1 -0
  53. package/dist/emitter/thread/slug.js +18 -0
  54. package/dist/emitter/thread/slug.js.map +1 -0
  55. package/dist/emitter/thread/thread.d.ts +32 -0
  56. package/dist/emitter/thread/thread.d.ts.map +1 -0
  57. package/dist/emitter/thread/thread.js +58 -0
  58. package/dist/emitter/thread/thread.js.map +1 -0
  59. package/dist/emitter/types.d.ts +45 -0
  60. package/dist/emitter/types.d.ts.map +1 -0
  61. package/dist/emitter/types.js +3 -0
  62. package/dist/emitter/types.js.map +1 -0
  63. package/dist/index.d.ts +16 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +98 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/listener/delivery/run-hook.d.ts +8 -0
  68. package/dist/listener/delivery/run-hook.d.ts.map +1 -0
  69. package/dist/listener/delivery/run-hook.js +50 -0
  70. package/dist/listener/delivery/run-hook.js.map +1 -0
  71. package/dist/listener/progress/emit.d.ts +3 -0
  72. package/dist/listener/progress/emit.d.ts.map +1 -0
  73. package/dist/listener/progress/emit.js +6 -0
  74. package/dist/listener/progress/emit.js.map +1 -0
  75. package/dist/listener/run/run-listener.d.ts +31 -0
  76. package/dist/listener/run/run-listener.d.ts.map +1 -0
  77. package/dist/listener/run/run-listener.js +173 -0
  78. package/dist/listener/run/run-listener.js.map +1 -0
  79. package/dist/listener/source/list-source.d.ts +13 -0
  80. package/dist/listener/source/list-source.d.ts.map +1 -0
  81. package/dist/listener/source/list-source.js +35 -0
  82. package/dist/listener/source/list-source.js.map +1 -0
  83. package/dist/listener/source/read-event.d.ts +7 -0
  84. package/dist/listener/source/read-event.d.ts.map +1 -0
  85. package/dist/listener/source/read-event.js +47 -0
  86. package/dist/listener/source/read-event.js.map +1 -0
  87. package/dist/listener/source/select-events.d.ts +13 -0
  88. package/dist/listener/source/select-events.d.ts.map +1 -0
  89. package/dist/listener/source/select-events.js +23 -0
  90. package/dist/listener/source/select-events.js.map +1 -0
  91. package/dist/listener/types.d.ts +42 -0
  92. package/dist/listener/types.d.ts.map +1 -0
  93. package/dist/listener/types.js +3 -0
  94. package/dist/listener/types.js.map +1 -0
  95. package/dist/manager.d.ts +17 -0
  96. package/dist/manager.d.ts.map +1 -0
  97. package/dist/manager.js +114 -0
  98. package/dist/manager.js.map +1 -0
  99. package/package.json +47 -0
@@ -0,0 +1,89 @@
1
+ import { renderEvent } from "../render/render-event.js";
2
+ import { appendOnce, hasEventId, pagePrefix, threadPathsFor } from "../thread/thread.js";
3
+ function exitCodeFor(outcome) {
4
+ switch (outcome) {
5
+ case "reported":
6
+ case "duplicate":
7
+ case "rendered":
8
+ return 0;
9
+ case "unreportable":
10
+ return 1;
11
+ case "invalid-invocation":
12
+ return 2;
13
+ case "interrupted":
14
+ return 130;
15
+ }
16
+ }
17
+ export function invalidInvocationResult(write, reason) {
18
+ write({ event: "result", outcome: "invalid-invocation", detail: reason });
19
+ return {
20
+ outcome: "invalid-invocation",
21
+ detail: reason,
22
+ exitCode: exitCodeFor("invalid-invocation"),
23
+ };
24
+ }
25
+ /**
26
+ * Run one FeatureEmitter invocation to a run outcome.
27
+ */
28
+ export function runEmitter(options) {
29
+ const { invocation } = options;
30
+ const write = options.write ?? (() => { });
31
+ const interruptState = options.interruptFlag ?? { interrupted: false };
32
+ const paths = threadPathsFor(invocation.target, invocation.key);
33
+ const finish = (outcome, detail) => {
34
+ const line = {
35
+ event: "result",
36
+ outcome,
37
+ key: invocation.key,
38
+ project: invocation.project,
39
+ thread: paths.slug,
40
+ };
41
+ if (detail !== undefined) {
42
+ line.detail = detail;
43
+ }
44
+ write(line);
45
+ const result = { outcome, thread: paths.slug, exitCode: exitCodeFor(outcome) };
46
+ if (detail !== undefined) {
47
+ result.detail = detail;
48
+ }
49
+ return result;
50
+ };
51
+ if (interruptState.interrupted) {
52
+ return finish("interrupted");
53
+ }
54
+ const rendered = renderEvent(invocation);
55
+ // The page title is part of what a first Event appends, so a preview that
56
+ // left it out would not be the bytes a real run writes.
57
+ const prefix = pagePrefix(paths.page, invocation.key);
58
+ if (invocation.dryRun) {
59
+ write({
60
+ event: "render",
61
+ key: invocation.key,
62
+ thread: paths.slug,
63
+ line: rendered.line,
64
+ section: `${prefix}${rendered.section}`,
65
+ });
66
+ return finish("rendered");
67
+ }
68
+ if (invocation.eventId !== undefined) {
69
+ const seen = hasEventId(paths.records, invocation.eventId);
70
+ if (!seen.ok) {
71
+ return finish("unreportable", seen.detail);
72
+ }
73
+ if (seen.seen) {
74
+ return finish("duplicate");
75
+ }
76
+ }
77
+ const records = appendOnce(paths.records, rendered.line);
78
+ if (!records.ok) {
79
+ return finish("unreportable", records.detail);
80
+ }
81
+ // The Event is committed: finishing the human surface costs one write, so
82
+ // a stop signal from here on does not abandon it half-reported.
83
+ const page = appendOnce(paths.page, `${prefix}${rendered.section}`);
84
+ if (!page.ok) {
85
+ return finish("unreportable", page.detail);
86
+ }
87
+ return finish("reported");
88
+ }
89
+ //# sourceMappingURL=run-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-emitter.js","sourceRoot":"","sources":["../../../src/emitter/run/run-emitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Thread file name for a Feature key. The hash suffix is always appended:
3
+ * slugging alone collides ("fake:42" and "fake/42"), and a collision silently
4
+ * merges two Features' history.
5
+ */
6
+ export declare function slugOf(key: string): string;
7
+ //# sourceMappingURL=slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/emitter/thread/slug.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS1C"}
@@ -0,0 +1,18 @@
1
+ import { createHash } from "node:crypto";
2
+ const NAME_LIMIT = 48;
3
+ /**
4
+ * Thread file name for a Feature key. The hash suffix is always appended:
5
+ * slugging alone collides ("fake:42" and "fake/42"), and a collision silently
6
+ * merges two Features' history.
7
+ */
8
+ export function slugOf(key) {
9
+ const readable = key
10
+ .toLowerCase()
11
+ .replace(/[^a-z0-9]+/g, "-")
12
+ .replace(/^-+|-+$/g, "")
13
+ .slice(0, NAME_LIMIT)
14
+ .replace(/-+$/g, "");
15
+ const digest = createHash("sha256").update(key).digest("hex").slice(0, 8);
16
+ return readable.length === 0 ? digest : `${readable}-${digest}`;
17
+ }
18
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../../src/emitter/thread/slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,GAAG,EAAE,CAAC;AAEtB;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,MAAM,QAAQ,GAAG,GAAG;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;SACpB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,MAAM,EAAE,CAAC;AAClE,CAAC"}
@@ -0,0 +1,32 @@
1
+ export type ThreadPaths = {
2
+ slug: string;
3
+ /** Machine surface, and the truth of the Thread. */
4
+ records: string;
5
+ /** Human surface, a rendering of the records. */
6
+ page: string;
7
+ };
8
+ export declare function threadPathsFor(target: string, key: string): ThreadPaths;
9
+ export type SeenResult = {
10
+ ok: true;
11
+ seen: boolean;
12
+ } | {
13
+ ok: false;
14
+ detail: string;
15
+ };
16
+ /**
17
+ * Whether this event id is already in the Thread. Scanning the records is
18
+ * enough at the scale of a directory a human reads; an index would be state to
19
+ * keep consistent with the truth it indexes.
20
+ */
21
+ export declare function hasEventId(recordsPath: string, eventId: string): SeenResult;
22
+ export type AppendResult = {
23
+ ok: true;
24
+ } | {
25
+ ok: false;
26
+ detail: string;
27
+ };
28
+ /** One append, so a line lands whole or not at all. */
29
+ export declare function appendOnce(path: string, content: string): AppendResult;
30
+ /** The `# <key>` title a page carries once, written with the first section. */
31
+ export declare function pagePrefix(page: string, key: string): string;
32
+ //# sourceMappingURL=thread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../../src/emitter/thread/thread.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAOvE;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAwB3E;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAOtE;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -0,0 +1,58 @@
1
+ import { appendFileSync, existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { slugOf } from "./slug.js";
4
+ export function threadPathsFor(target, key) {
5
+ const slug = slugOf(key);
6
+ return {
7
+ slug,
8
+ records: join(target, `${slug}.ndjson`),
9
+ page: join(target, `${slug}.md`),
10
+ };
11
+ }
12
+ /**
13
+ * Whether this event id is already in the Thread. Scanning the records is
14
+ * enough at the scale of a directory a human reads; an index would be state to
15
+ * keep consistent with the truth it indexes.
16
+ */
17
+ export function hasEventId(recordsPath, eventId) {
18
+ if (!existsSync(recordsPath)) {
19
+ return { ok: true, seen: false };
20
+ }
21
+ let content;
22
+ try {
23
+ content = readFileSync(recordsPath, "utf8");
24
+ }
25
+ catch (error) {
26
+ return { ok: false, detail: error instanceof Error ? error.message : String(error) };
27
+ }
28
+ for (const line of content.split("\n")) {
29
+ if (line.trim().length === 0) {
30
+ continue;
31
+ }
32
+ try {
33
+ const parsed = JSON.parse(line);
34
+ if (parsed.event_id === eventId) {
35
+ return { ok: true, seen: true };
36
+ }
37
+ }
38
+ catch {
39
+ // A line this Block did not write is not an event id it has to honour.
40
+ }
41
+ }
42
+ return { ok: true, seen: false };
43
+ }
44
+ /** One append, so a line lands whole or not at all. */
45
+ export function appendOnce(path, content) {
46
+ try {
47
+ appendFileSync(path, content, { encoding: "utf8" });
48
+ return { ok: true };
49
+ }
50
+ catch (error) {
51
+ return { ok: false, detail: error instanceof Error ? error.message : String(error) };
52
+ }
53
+ }
54
+ /** The `# <key>` title a page carries once, written with the first section. */
55
+ export function pagePrefix(page, key) {
56
+ return existsSync(page) ? "" : `# ${key}\n\n`;
57
+ }
58
+ //# sourceMappingURL=thread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.js","sourceRoot":"","sources":["../../../src/emitter/thread/thread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAUnC,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,GAAW;IACxD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC;QACvC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,KAAK,CAAC;KACjC,CAAC;AACJ,CAAC;AAID;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,OAAe;IAC7D,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;IACD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACvF,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA2B,CAAC;YAC1D,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAClC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;QACzE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC;AAID,uDAAuD;AACvD,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,OAAe;IACtD,IAAI,CAAC;QACH,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACpD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACvF,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,GAAW;IAClD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC;AAChD,CAAC"}
@@ -0,0 +1,45 @@
1
+ /** Domain types owned by FeatureEmitter. Names match the Block perimeter only. */
2
+ export type RunOutcome = "reported" | "duplicate" | "rendered" | "unreportable" | "invalid-invocation" | "interrupted";
3
+ export type EventName = "invalid" | "accepted" | "planned" | "progress" | "escalated" | "escalation_reminder" | "resumed" | "submitted" | "done" | "cancelled" | "reject_late";
4
+ export type Stage = "plan" | "unit" | "integrating" | "submitting" | "merging";
5
+ export type ResumePoint = "planning" | "running" | "integrating";
6
+ /** Every field an Event may carry beyond key, project and timestamp. */
7
+ export type EventFields = {
8
+ /** One sentence a reader gets first, under the heading and before any field. */
9
+ summary?: string;
10
+ reason?: string;
11
+ stage?: Stage;
12
+ trace?: string;
13
+ counters?: Record<string, string>;
14
+ plan?: string;
15
+ priority?: number;
16
+ unit?: string;
17
+ remaining?: number;
18
+ state?: string;
19
+ resume_point?: ResumePoint;
20
+ reference?: string;
21
+ /** On `done`: the work line's own name for the fold — a commit — when the Authority gave one. */
22
+ integration_reference?: string;
23
+ workspace_ref?: string;
24
+ };
25
+ export type Invocation = {
26
+ target: string;
27
+ event: EventName;
28
+ key: string;
29
+ project: string;
30
+ at: string;
31
+ eventId?: string;
32
+ fields: EventFields;
33
+ maxReportChars: number;
34
+ dryRun: boolean;
35
+ };
36
+ export type ParseResult = {
37
+ ok: true;
38
+ invocation: Invocation;
39
+ } | {
40
+ ok: false;
41
+ reason: string;
42
+ };
43
+ /** The record appended to the machine surface of a Thread. */
44
+ export type EventRecord = Record<string, unknown>;
45
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/emitter/types.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,WAAW,GACX,UAAU,GACV,cAAc,GACd,oBAAoB,GACpB,aAAa,CAAC;AAElB,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,UAAU,GACV,SAAS,GACT,UAAU,GACV,WAAW,GACX,qBAAqB,GACrB,SAAS,GACT,WAAW,GACX,MAAM,GACN,WAAW,GACX,aAAa,CAAC;AAElB,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,CAAC;AAEjE,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG;IACxB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iGAAiG;IACjG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/F,8DAA8D;AAC9D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Domain types owned by FeatureEmitter. Names match the Block perimeter only. */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/emitter/types.ts"],"names":[],"mappings":"AAAA,kFAAkF"}
@@ -0,0 +1,16 @@
1
+ import { type CreateManagerResult, type Finding, type ManagerContext, type ManagerScaffold } from "@bluewombat/manager-kit";
2
+ export type { FakeManagerOptions } from "./manager.js";
3
+ export { createFakeManager } from "./manager.js";
4
+ /**
5
+ * `manager: "@bluewombat/manager-fake"` in the config resolves here. Paths are
6
+ * relative to the config file, so a checked-in example needs no absolute path.
7
+ */
8
+ export declare function createManager(context: ManagerContext): CreateManagerResult;
9
+ /**
10
+ * What `mason init` writes. `createManager` still refuses a missing Source:
11
+ * this only prepares the directories so the first file has somewhere to go.
12
+ */
13
+ export declare function scaffoldManager(context: ManagerContext): ManagerScaffold;
14
+ /** What `mason doctor` reports. Filesystem only, no network. */
15
+ export declare function checkManager(context: ManagerContext): Finding[];
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,OAAO,EAEZ,KAAK,cAAc,EACnB,KAAK,eAAe,EAIrB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQjD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,mBAAmB,CAmB1E;AAKD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAaxE;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,EAAE,CAc/D"}
package/dist/index.js ADDED
@@ -0,0 +1,98 @@
1
+ import { existsSync, mkdirSync, statSync } from "node:fs";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import { intOption, PRODUCT, rejectUnknownOptions, stringOption, } from "@bluewombat/manager-kit";
4
+ import { createFakeManager } from "./manager.js";
5
+ export { createFakeManager } from "./manager.js";
6
+ const KNOWN_OPTIONS = ["source", "target", "defaultPriority"];
7
+ /**
8
+ * `manager: "@bluewombat/manager-fake"` in the config resolves here. Paths are
9
+ * relative to the config file, so a checked-in example needs no absolute path.
10
+ */
11
+ export function createManager(context) {
12
+ const read = readOptions(context);
13
+ if (!read.ok) {
14
+ return read;
15
+ }
16
+ if (!existsSync(read.source) || !statSync(read.source).isDirectory()) {
17
+ return { ok: false, reason: `managerOptions "source" is not a directory: ${read.source}` };
18
+ }
19
+ mkdirSync(read.target, { recursive: true });
20
+ const options = {
21
+ source: read.source,
22
+ emitterTarget: read.target,
23
+ durationMs: context.durationMs,
24
+ interruptFlag: context.interruptFlag,
25
+ };
26
+ if (read.defaultPriority !== undefined) {
27
+ options.defaultPriority = read.defaultPriority;
28
+ }
29
+ return { ok: true, manager: createFakeManager(options) };
30
+ }
31
+ const DEFAULT_SOURCE = `./.${PRODUCT}/source`;
32
+ const DEFAULT_TARGET = `./.${PRODUCT}/threads`;
33
+ /**
34
+ * What `mason init` writes. `createManager` still refuses a missing Source:
35
+ * this only prepares the directories so the first file has somewhere to go.
36
+ */
37
+ export function scaffoldManager(context) {
38
+ const source = typeof context.options.source === "string" ? context.options.source : DEFAULT_SOURCE;
39
+ const target = typeof context.options.target === "string" ? context.options.target : DEFAULT_TARGET;
40
+ return {
41
+ options: { source, target },
42
+ nextSteps: [`drop a JSON intention into ${source}`],
43
+ prepare(cwd) {
44
+ mkdirSync(resolve(cwd, source), { recursive: true });
45
+ mkdirSync(resolve(cwd, target), { recursive: true });
46
+ },
47
+ };
48
+ }
49
+ /** What `mason doctor` reports. Filesystem only, no network. */
50
+ export function checkManager(context) {
51
+ const read = readOptions(context);
52
+ if (!read.ok) {
53
+ return [{ level: "fail", label: "manager options", detail: read.reason }];
54
+ }
55
+ const sourceOk = existsSync(read.source) && statSync(read.source).isDirectory();
56
+ return [
57
+ sourceOk
58
+ ? { level: "ok", label: "Source directory", detail: read.source }
59
+ : { level: "fail", label: "Source directory", detail: `not a directory: ${read.source}` },
60
+ existsSync(read.target)
61
+ ? { level: "ok", label: "Thread directory", detail: read.target }
62
+ : { level: "warn", label: "Thread directory", detail: `created on run: ${read.target}` },
63
+ ];
64
+ }
65
+ function readOptions(context) {
66
+ const known = rejectUnknownOptions(context.options, KNOWN_OPTIONS);
67
+ if (!known.ok) {
68
+ return known;
69
+ }
70
+ const source = stringOption(context.options, "source");
71
+ if (!source.ok) {
72
+ return source;
73
+ }
74
+ if (source.value === undefined) {
75
+ return { ok: false, reason: 'managerOptions "source" is required (directory of intentions).' };
76
+ }
77
+ const target = stringOption(context.options, "target");
78
+ if (!target.ok) {
79
+ return target;
80
+ }
81
+ if (target.value === undefined) {
82
+ return { ok: false, reason: 'managerOptions "target" is required (directory of Threads).' };
83
+ }
84
+ const defaultPriority = intOption(context.options, "defaultPriority", 0, 100);
85
+ if (!defaultPriority.ok) {
86
+ return defaultPriority;
87
+ }
88
+ return {
89
+ ok: true,
90
+ source: absolute(source.value, context.configDir),
91
+ target: absolute(target.value, context.configDir),
92
+ defaultPriority: defaultPriority.value,
93
+ };
94
+ }
95
+ function absolute(path, configDir) {
96
+ return isAbsolute(path) ? path : resolve(configDir, path);
97
+ }
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Run --on-intention for one Delivery. The result is deliberately dropped:
3
+ * a non-zero exit, a missing command, or a hang never changes the run outcome
4
+ * and never rolls the Cursor back.
5
+ */
6
+ /** `cwd` undefined lets the hook inherit the caller's directory. */
7
+ export declare function runHook(argv: string[], cwd: string | undefined): Promise<void>;
8
+ //# sourceMappingURL=run-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-hook.d.ts","sourceRoot":"","sources":["../../../src/listener/delivery/run-hook.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,oEAAoE;AACpE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAyC9E"}
@@ -0,0 +1,50 @@
1
+ import { spawn } from "node:child_process";
2
+ /** Soft cap: --on-intention must not hold the subscription open forever. */
3
+ const HOOK_TIMEOUT_MS = 5_000;
4
+ /**
5
+ * Run --on-intention for one Delivery. The result is deliberately dropped:
6
+ * a non-zero exit, a missing command, or a hang never changes the run outcome
7
+ * and never rolls the Cursor back.
8
+ */
9
+ /** `cwd` undefined lets the hook inherit the caller's directory. */
10
+ export function runHook(argv, cwd) {
11
+ return new Promise((resolve) => {
12
+ const [file, ...args] = argv;
13
+ if (file === undefined) {
14
+ resolve();
15
+ return;
16
+ }
17
+ let settled = false;
18
+ let timer;
19
+ const finish = () => {
20
+ if (settled) {
21
+ return;
22
+ }
23
+ settled = true;
24
+ if (timer !== undefined) {
25
+ clearTimeout(timer);
26
+ }
27
+ resolve();
28
+ };
29
+ let child;
30
+ try {
31
+ child = spawn(file, args, { cwd, stdio: ["ignore", "ignore", "ignore"] });
32
+ }
33
+ catch {
34
+ finish();
35
+ return;
36
+ }
37
+ timer = setTimeout(() => {
38
+ try {
39
+ child.kill("SIGKILL");
40
+ }
41
+ catch {
42
+ // already gone
43
+ }
44
+ finish();
45
+ }, HOOK_TIMEOUT_MS);
46
+ child.on("error", finish);
47
+ child.on("close", finish);
48
+ });
49
+ }
50
+ //# sourceMappingURL=run-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-hook.js","sourceRoot":"","sources":["../../../src/listener/delivery/run-hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE9D,4EAA4E;AAC5E,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B;;;;GAIG;AACH,oEAAoE;AACpE,MAAM,UAAU,OAAO,CAAC,IAAc,EAAE,GAAuB;IAC7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAC7B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,KAAiC,CAAC;QACtC,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QAEF,IAAI,KAAmB,CAAC;QACxB,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,EAAE,CAAC;YACT,OAAO;QACT,CAAC;QAED,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,IAAI,CAAC;gBACH,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,eAAe;YACjB,CAAC;YACD,MAAM,EAAE,CAAC;QACX,CAAC,EAAE,eAAe,CAAC,CAAC;QAEpB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type ProgressWriter = (line: Record<string, unknown>) => void;
2
+ export declare function createStdoutProgressWriter(): ProgressWriter;
3
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/listener/progress/emit.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAErE,wBAAgB,0BAA0B,IAAI,cAAc,CAI3D"}
@@ -0,0 +1,6 @@
1
+ export function createStdoutProgressWriter() {
2
+ return (line) => {
3
+ process.stdout.write(`${JSON.stringify(line)}\n`);
4
+ };
5
+ }
6
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../src/listener/progress/emit.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,0BAA0B;IACxC,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { ProgressWriter } from "../progress/emit.js";
2
+ import type { Invocation, RunOutcome, StopReason } from "../types.js";
3
+ export type RunResult = {
4
+ outcome: RunOutcome;
5
+ /** Absent on invalid-invocation: nothing ran, so nothing stopped. */
6
+ stopReason?: StopReason;
7
+ /** Last committed Cursor; absent when no Event was consumed. */
8
+ cursor?: string;
9
+ delivered: number;
10
+ skipped: number;
11
+ scans: number;
12
+ exitCode: number;
13
+ };
14
+ export type RunOptions = {
15
+ invocation: Invocation;
16
+ write?: ProgressWriter;
17
+ /** Injectable clock for tests. */
18
+ now?: () => number;
19
+ /** When set, polled for interrupt; otherwise process signals are used. */
20
+ interruptFlag?: {
21
+ interrupted: boolean;
22
+ };
23
+ /** Working directory for the --on-intention child. Undefined lets it inherit. */
24
+ cwd?: string;
25
+ };
26
+ export declare function invalidInvocationResult(write: ProgressWriter, reason: string): RunResult;
27
+ /**
28
+ * Run one FeatureListener invocation to a run outcome.
29
+ */
30
+ export declare function runListener(options: RunOptions): Promise<RunResult>;
31
+ //# sourceMappingURL=run-listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-listener.d.ts","sourceRoot":"","sources":["../../../src/listener/run/run-listener.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtE,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,0EAA0E;IAC1E,aAAa,CAAC,EAAE;QAAE,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC;IACzC,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAeF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAgBxF;AAmBD;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CASzE"}