@alex.botez/elaborate 1.0.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 (162) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/durable/index.d.ts +10 -0
  4. package/dist/durable/index.d.ts.map +1 -0
  5. package/dist/durable/index.js +9 -0
  6. package/dist/durable/index.js.map +1 -0
  7. package/dist/durable/workflow.d.ts +165 -0
  8. package/dist/durable/workflow.d.ts.map +1 -0
  9. package/dist/durable/workflow.js +224 -0
  10. package/dist/durable/workflow.js.map +1 -0
  11. package/dist/interview/classification.d.ts +16 -0
  12. package/dist/interview/classification.d.ts.map +1 -0
  13. package/dist/interview/classification.js +25 -0
  14. package/dist/interview/classification.js.map +1 -0
  15. package/dist/interview/composition.d.ts +12 -0
  16. package/dist/interview/composition.d.ts.map +1 -0
  17. package/dist/interview/composition.js +19 -0
  18. package/dist/interview/composition.js.map +1 -0
  19. package/dist/interview/describe.d.ts +41 -0
  20. package/dist/interview/describe.d.ts.map +1 -0
  21. package/dist/interview/describe.js +80 -0
  22. package/dist/interview/describe.js.map +1 -0
  23. package/dist/interview/deviation.d.ts +91 -0
  24. package/dist/interview/deviation.d.ts.map +1 -0
  25. package/dist/interview/deviation.js +137 -0
  26. package/dist/interview/deviation.js.map +1 -0
  27. package/dist/interview/extraction.d.ts +32 -0
  28. package/dist/interview/extraction.d.ts.map +1 -0
  29. package/dist/interview/extraction.js +102 -0
  30. package/dist/interview/extraction.js.map +1 -0
  31. package/dist/interview/index.d.ts +25 -0
  32. package/dist/interview/index.d.ts.map +1 -0
  33. package/dist/interview/index.js +22 -0
  34. package/dist/interview/index.js.map +1 -0
  35. package/dist/interview/macros.d.ts +91 -0
  36. package/dist/interview/macros.d.ts.map +1 -0
  37. package/dist/interview/macros.js +138 -0
  38. package/dist/interview/macros.js.map +1 -0
  39. package/dist/interview/preambles.d.ts +18 -0
  40. package/dist/interview/preambles.d.ts.map +1 -0
  41. package/dist/interview/preambles.js +93 -0
  42. package/dist/interview/preambles.js.map +1 -0
  43. package/dist/interview/progress.d.ts +31 -0
  44. package/dist/interview/progress.d.ts.map +1 -0
  45. package/dist/interview/progress.js +51 -0
  46. package/dist/interview/progress.js.map +1 -0
  47. package/dist/interview/prompt.d.ts +20 -0
  48. package/dist/interview/prompt.d.ts.map +1 -0
  49. package/dist/interview/prompt.js +58 -0
  50. package/dist/interview/prompt.js.map +1 -0
  51. package/dist/phases/aggregate/assumptions.d.ts +14 -0
  52. package/dist/phases/aggregate/assumptions.d.ts.map +1 -0
  53. package/dist/phases/aggregate/assumptions.js +33 -0
  54. package/dist/phases/aggregate/assumptions.js.map +1 -0
  55. package/dist/phases/aggregate/findings.d.ts +10 -0
  56. package/dist/phases/aggregate/findings.d.ts.map +1 -0
  57. package/dist/phases/aggregate/findings.js +20 -0
  58. package/dist/phases/aggregate/findings.js.map +1 -0
  59. package/dist/phases/aggregate/goals.d.ts +28 -0
  60. package/dist/phases/aggregate/goals.d.ts.map +1 -0
  61. package/dist/phases/aggregate/goals.js +74 -0
  62. package/dist/phases/aggregate/goals.js.map +1 -0
  63. package/dist/phases/aggregate/index.d.ts +128 -0
  64. package/dist/phases/aggregate/index.d.ts.map +1 -0
  65. package/dist/phases/aggregate/index.js +165 -0
  66. package/dist/phases/aggregate/index.js.map +1 -0
  67. package/dist/phases/aggregate/pam.d.ts +19 -0
  68. package/dist/phases/aggregate/pam.d.ts.map +1 -0
  69. package/dist/phases/aggregate/pam.js +37 -0
  70. package/dist/phases/aggregate/pam.js.map +1 -0
  71. package/dist/phases/aggregate/scope.d.ts +24 -0
  72. package/dist/phases/aggregate/scope.d.ts.map +1 -0
  73. package/dist/phases/aggregate/scope.js +67 -0
  74. package/dist/phases/aggregate/scope.js.map +1 -0
  75. package/dist/phases/aggregate/shared.d.ts +16 -0
  76. package/dist/phases/aggregate/shared.d.ts.map +1 -0
  77. package/dist/phases/aggregate/shared.js +26 -0
  78. package/dist/phases/aggregate/shared.js.map +1 -0
  79. package/dist/phases/aggregate/stakeholders.d.ts +27 -0
  80. package/dist/phases/aggregate/stakeholders.d.ts.map +1 -0
  81. package/dist/phases/aggregate/stakeholders.js +90 -0
  82. package/dist/phases/aggregate/stakeholders.js.map +1 -0
  83. package/dist/phases/aggregate/waitingRoom.d.ts +16 -0
  84. package/dist/phases/aggregate/waitingRoom.d.ts.map +1 -0
  85. package/dist/phases/aggregate/waitingRoom.js +32 -0
  86. package/dist/phases/aggregate/waitingRoom.js.map +1 -0
  87. package/dist/phases/assumptions.d.ts +19 -0
  88. package/dist/phases/assumptions.d.ts.map +1 -0
  89. package/dist/phases/assumptions.js +224 -0
  90. package/dist/phases/assumptions.js.map +1 -0
  91. package/dist/phases/configuration.d.ts +8 -0
  92. package/dist/phases/configuration.d.ts.map +1 -0
  93. package/dist/phases/configuration.js +14 -0
  94. package/dist/phases/configuration.js.map +1 -0
  95. package/dist/phases/goals.d.ts +15 -0
  96. package/dist/phases/goals.d.ts.map +1 -0
  97. package/dist/phases/goals.js +297 -0
  98. package/dist/phases/goals.js.map +1 -0
  99. package/dist/phases/index.d.ts +21 -0
  100. package/dist/phases/index.d.ts.map +1 -0
  101. package/dist/phases/index.js +56 -0
  102. package/dist/phases/index.js.map +1 -0
  103. package/dist/phases/opening.d.ts +12 -0
  104. package/dist/phases/opening.d.ts.map +1 -0
  105. package/dist/phases/opening.js +99 -0
  106. package/dist/phases/opening.js.map +1 -0
  107. package/dist/phases/purpose.d.ts +17 -0
  108. package/dist/phases/purpose.d.ts.map +1 -0
  109. package/dist/phases/purpose.js +207 -0
  110. package/dist/phases/purpose.js.map +1 -0
  111. package/dist/phases/schema.d.ts +861 -0
  112. package/dist/phases/schema.d.ts.map +1 -0
  113. package/dist/phases/schema.js +157 -0
  114. package/dist/phases/schema.js.map +1 -0
  115. package/dist/phases/scope.d.ts +18 -0
  116. package/dist/phases/scope.d.ts.map +1 -0
  117. package/dist/phases/scope.js +440 -0
  118. package/dist/phases/scope.js.map +1 -0
  119. package/dist/phases/session/archive.d.ts +19 -0
  120. package/dist/phases/session/archive.d.ts.map +1 -0
  121. package/dist/phases/session/archive.js +49 -0
  122. package/dist/phases/session/archive.js.map +1 -0
  123. package/dist/phases/session/file.d.ts +31 -0
  124. package/dist/phases/session/file.d.ts.map +1 -0
  125. package/dist/phases/session/file.js +113 -0
  126. package/dist/phases/session/file.js.map +1 -0
  127. package/dist/phases/session/index.d.ts +8 -0
  128. package/dist/phases/session/index.d.ts.map +1 -0
  129. package/dist/phases/session/index.js +8 -0
  130. package/dist/phases/session/index.js.map +1 -0
  131. package/dist/phases/session/persistence.d.ts +30 -0
  132. package/dist/phases/session/persistence.d.ts.map +1 -0
  133. package/dist/phases/session/persistence.js +91 -0
  134. package/dist/phases/session/persistence.js.map +1 -0
  135. package/dist/phases/shared.d.ts +64 -0
  136. package/dist/phases/shared.d.ts.map +1 -0
  137. package/dist/phases/shared.js +100 -0
  138. package/dist/phases/shared.js.map +1 -0
  139. package/dist/phases/stakeholders.d.ts +17 -0
  140. package/dist/phases/stakeholders.d.ts.map +1 -0
  141. package/dist/phases/stakeholders.js +370 -0
  142. package/dist/phases/stakeholders.js.map +1 -0
  143. package/dist/phases/validation.d.ts +13 -0
  144. package/dist/phases/validation.d.ts.map +1 -0
  145. package/dist/phases/validation.js +130 -0
  146. package/dist/phases/validation.js.map +1 -0
  147. package/dist/skill/adapter.d.ts +16 -0
  148. package/dist/skill/adapter.d.ts.map +1 -0
  149. package/dist/skill/adapter.js +278 -0
  150. package/dist/skill/adapter.js.map +1 -0
  151. package/dist/skill/index.d.ts +12 -0
  152. package/dist/skill/index.d.ts.map +1 -0
  153. package/dist/skill/index.js +11 -0
  154. package/dist/skill/index.js.map +1 -0
  155. package/dist/skill/log.d.ts +18 -0
  156. package/dist/skill/log.d.ts.map +1 -0
  157. package/dist/skill/log.js +53 -0
  158. package/dist/skill/log.js.map +1 -0
  159. package/package.json +83 -0
  160. package/skills/elaborate/SKILL.md +97 -0
  161. package/skills/elaborate/scripts/elaborate.cjs +589 -0
  162. package/skills/project-brief/SKILL.md +45 -0
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Skill adapter — shell interface to the durable session workflow.
3
+ *
4
+ * Translates shell arguments into durable execute calls and returns JSON to stdout.
5
+ * Bundled alongside SKILL.md into a single deployable artifact.
6
+ *
7
+ * Commands:
8
+ * start Create session or resume, return current prompt
9
+ * response --message="..." Answer pending prompt with user message (or pipe text to stdin)
10
+ * inference --data='{...}' Answer pending infer with extraction data (or pipe JSON to stdin)
11
+ * status Query session state
12
+ *
13
+ * All output is JSON to stdout. Errors: { error: "..." } + exit code 1.
14
+ */
15
+ import { existsSync } from "node:fs";
16
+ import { dirname, join } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { Suspend, execute } from "../durable/index.js";
19
+ import { createSession, ArtifactAggregate, createFilePersistence, archiveSession, archiveCorrupted, CorruptedSessionError } from "../phases/index.js";
20
+ import { isDeviationError } from "../interview/index.js";
21
+ import { createLogger, noopLogger } from "./log.js";
22
+ function getArg(args, prefix) {
23
+ const match = args.find((a) => a.startsWith(`${prefix}=`));
24
+ if (match)
25
+ return match.slice(prefix.length + 1);
26
+ const idx = args.indexOf(prefix);
27
+ if (idx !== -1 && idx + 1 < args.length)
28
+ return args[idx + 1];
29
+ return undefined;
30
+ }
31
+ let logger = noopLogger;
32
+ function output(data) {
33
+ console.log(JSON.stringify(data));
34
+ }
35
+ function error(message) {
36
+ logger.error({ event: "error" }, message);
37
+ output({ error: message });
38
+ process.exit(1);
39
+ }
40
+ /** Oneshot resolver: resolves one matching response, suspends everything else. No response = suspend all. */
41
+ function createResolver(response) {
42
+ return async (prompt) => {
43
+ if (response && prompt.id === response.id)
44
+ return response.value;
45
+ throw new Suspend(prompt.id, prompt);
46
+ };
47
+ }
48
+ /** prompt → target: user, infer → target: agent */
49
+ function formatPrompt(prompt) {
50
+ if (prompt.type === "prompt") {
51
+ return {
52
+ message: prompt.request.message,
53
+ target: "user",
54
+ schema: {},
55
+ };
56
+ }
57
+ return {
58
+ message: prompt.request.message,
59
+ target: "agent",
60
+ schema: (prompt.request.schema ?? {}),
61
+ };
62
+ }
63
+ const END_OUTPUT = {
64
+ message: "This session is complete.",
65
+ target: "end",
66
+ schema: {},
67
+ };
68
+ /** Bridge session title from aggregate purpose to persistence. */
69
+ function bridgeTitle(agg, persistence) {
70
+ const purpose = agg.data.purpose?.statement;
71
+ if (purpose)
72
+ persistence.setTitle(purpose);
73
+ }
74
+ /** Execute workflow; output END on completion, or the suspended prompt on Suspend. */
75
+ async function handle(cwd, persistence, workflow, resolver, agg, opts) {
76
+ try {
77
+ const result = await execute(persistence, workflow, resolver);
78
+ logFidelity(result.fidelity);
79
+ if (agg.userConcern)
80
+ persistence.setUserConcern(agg.userConcern);
81
+ bridgeTitle(agg, persistence);
82
+ archiveSession(cwd);
83
+ output(END_OUTPUT);
84
+ }
85
+ catch (e) {
86
+ if (e instanceof Suspend) {
87
+ if (!e.value || typeof e.value !== "object" || !("type" in e.value)) {
88
+ throw new Error(`Suspend at ${e.id} carried non-Prompt value`);
89
+ }
90
+ const prompt = e.value;
91
+ logger.info({
92
+ event: "suspend",
93
+ id: e.id,
94
+ type: prompt.type,
95
+ promptMessage: prompt.request.message,
96
+ ...("schema" in prompt.request ? { schema: prompt.request.schema } : {}),
97
+ });
98
+ bridgeTitle(agg, persistence);
99
+ const out = formatPrompt(prompt);
100
+ if (opts?.includeContext)
101
+ out.context = agg.summarize();
102
+ if (opts?.existingSession)
103
+ out.existingSession = true;
104
+ output(out);
105
+ return;
106
+ }
107
+ throw e;
108
+ }
109
+ }
110
+ /** Log per-extraction debug details and a summary warning when mismatches occurred. */
111
+ function logFidelity(result) {
112
+ if (result.mismatched === 0)
113
+ return;
114
+ for (const d of result.details) {
115
+ logger.info({
116
+ event: "fidelity:mismatch",
117
+ id: d.id,
118
+ expectedKeys: d.expectedKeys,
119
+ actualKeys: d.actualKeys,
120
+ missingKeys: d.missingKeys,
121
+ });
122
+ }
123
+ logger.error({
124
+ event: "fidelity:summary",
125
+ checked: result.checked,
126
+ mismatched: result.mismatched,
127
+ }, `Extraction fidelity: ${result.mismatched}/${result.checked} extractions had missing keys`);
128
+ }
129
+ function requireSuspendedId(persistence) {
130
+ const id = persistence.suspendedId();
131
+ if (!id)
132
+ error("No pending prompt. Run 'start' first.");
133
+ return id;
134
+ }
135
+ async function handleStart(cwd, persistence, args) {
136
+ const isNew = args.includes("--new");
137
+ let existingSession = false;
138
+ try {
139
+ if (persistence.hasSession()) {
140
+ if (persistence.status() === "completed" || isNew) {
141
+ archiveSession(cwd);
142
+ }
143
+ else {
144
+ existingSession = true;
145
+ }
146
+ }
147
+ }
148
+ catch (e) {
149
+ if (e instanceof CorruptedSessionError && isNew) {
150
+ // --new on a corrupt session: archive with timestamp and proceed fresh.
151
+ const archived = archiveCorrupted(cwd);
152
+ logger.info({ event: "recover:archive-corrupted", archived });
153
+ }
154
+ else {
155
+ throw e;
156
+ }
157
+ }
158
+ const agg = new ArtifactAggregate();
159
+ const workflow = createSession(agg);
160
+ const resolver = createResolver();
161
+ await handle(cwd, persistence, workflow, resolver, agg, existingSession ? { includeContext: true, existingSession: true } : undefined);
162
+ }
163
+ async function handleResponse(cwd, persistence, args) {
164
+ let message = getArg(args, "--message");
165
+ if (message === undefined) {
166
+ if (process.stdin.isTTY) {
167
+ error("Missing message. Provide --message argument or pipe text to stdin.");
168
+ }
169
+ message = await readStdin();
170
+ if (!message.trim()) {
171
+ error("No message received on stdin.");
172
+ }
173
+ }
174
+ const id = requireSuspendedId(persistence);
175
+ logger.info({ event: "resolve", id, type: "prompt", message });
176
+ const agg = new ArtifactAggregate();
177
+ const workflow = createSession(agg);
178
+ const resolver = createResolver({ id, value: message });
179
+ await handle(cwd, persistence, workflow, resolver, agg);
180
+ }
181
+ async function readStdin() {
182
+ return new Promise((resolve, reject) => {
183
+ let data = "";
184
+ process.stdin.setEncoding("utf8");
185
+ process.stdin.on("data", (chunk) => (data += chunk));
186
+ process.stdin.on("end", () => resolve(data));
187
+ process.stdin.on("error", reject);
188
+ });
189
+ }
190
+ async function handleInference(cwd, persistence, args) {
191
+ let dataStr = getArg(args, "--data");
192
+ if (dataStr === undefined) {
193
+ if (process.stdin.isTTY) {
194
+ error("Missing data. Provide --data argument or pipe JSON to stdin.");
195
+ }
196
+ dataStr = await readStdin();
197
+ if (!dataStr.trim()) {
198
+ error("No data received on stdin.");
199
+ }
200
+ }
201
+ let data;
202
+ try {
203
+ data = JSON.parse(dataStr);
204
+ }
205
+ catch {
206
+ error("Invalid JSON in --data argument.");
207
+ }
208
+ const id = requireSuspendedId(persistence);
209
+ logger.info({ event: "resolve", id, type: "infer", data });
210
+ const agg = new ArtifactAggregate();
211
+ const workflow = createSession(agg);
212
+ const resolver = createResolver({ id, value: data });
213
+ await handle(cwd, persistence, workflow, resolver, agg);
214
+ }
215
+ function handleStatus(persistence) {
216
+ if (!persistence.hasSession()) {
217
+ output({ active: false });
218
+ return;
219
+ }
220
+ const status = persistence.status();
221
+ const title = persistence.title();
222
+ output({
223
+ active: true,
224
+ phase: persistence.phase() ?? "unknown",
225
+ sessionId: persistence.sessionId(),
226
+ ...(title ? { title } : {}),
227
+ ...(status === "failed" ? { status: "failed" } : {}),
228
+ });
229
+ }
230
+ async function main() {
231
+ const skillDir = typeof __dirname !== "undefined"
232
+ ? __dirname
233
+ : dirname(fileURLToPath(import.meta.url));
234
+ // Drop a .debug file next to the bundle to attach a debugger on launch
235
+ if (existsSync(join(skillDir, ".debug"))) {
236
+ const inspector = await import("node:inspector");
237
+ inspector.default.open(9229, "127.0.0.1", true);
238
+ }
239
+ const args = process.argv.slice(2);
240
+ const command = args[0];
241
+ const cwd = process.cwd();
242
+ const persistence = createFilePersistence(cwd);
243
+ logger = createLogger(skillDir, cwd, {
244
+ sessionId: () => persistence.sessionId(),
245
+ });
246
+ try {
247
+ switch (command) {
248
+ case "start":
249
+ await handleStart(cwd, persistence, args.slice(1));
250
+ break;
251
+ case "response":
252
+ await handleResponse(cwd, persistence, args.slice(1));
253
+ break;
254
+ case "inference":
255
+ await handleInference(cwd, persistence, args.slice(1));
256
+ break;
257
+ case "status":
258
+ handleStatus(persistence);
259
+ break;
260
+ default:
261
+ error(`Unknown command: ${command ?? "(none)"}\n\nUsage:\n elaborate start [--new] Create session (--new: archive existing)\n elaborate response --message="..." Process stakeholder message\n elaborate inference --data='{...}' Provide extraction results\n elaborate status Query session state`);
262
+ }
263
+ }
264
+ catch (e) {
265
+ const err = e instanceof Error ? e : new Error(String(e));
266
+ logger.error({ event: "error", class: err.constructor.name }, err.message);
267
+ if (err instanceof CorruptedSessionError) {
268
+ error(`${err.message}\n\nRun 'elaborate start --new' to archive the corrupt file and start fresh.`);
269
+ }
270
+ if (isDeviationError(err)) {
271
+ output({ error: "deviation_exhausted", deviation: err.name, response: err.response });
272
+ process.exit(1);
273
+ }
274
+ error(err.message);
275
+ }
276
+ }
277
+ main();
278
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/skill/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Skill layer — public barrel.
3
+ *
4
+ * The skill is consumed primarily via the `bin` entry (`dist/skill/adapter.js`),
5
+ * not via library import. This barrel exists for toolkit-shape symmetry and
6
+ * surfaces only the logger interface for testability and any future
7
+ * programmatic adapter use. `adapter.ts` itself self-invokes `main()` and is
8
+ * not designed for library consumption.
9
+ */
10
+ export { createLogger, noopLogger } from "./log.js";
11
+ export type { Logger, LogContext } from "./log.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skill/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Skill layer — public barrel.
3
+ *
4
+ * The skill is consumed primarily via the `bin` entry (`dist/skill/adapter.js`),
5
+ * not via library import. This barrel exists for toolkit-shape symmetry and
6
+ * surfaces only the logger interface for testability and any future
7
+ * programmatic adapter use. `adapter.ts` itself self-invokes `main()` and is
8
+ * not designed for library consumption.
9
+ */
10
+ export { createLogger, noopLogger } from "./log.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skill/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Opt-in structured logging for the adapter layer.
3
+ *
4
+ * Enabled by a `.log` marker file in the skill directory. When active, appends
5
+ * structured JSONL entries to `.elaborate/log.jsonl`. When inactive, returns a
6
+ * no-op logger (null-object pattern).
7
+ *
8
+ * Observation boundary: the logger captures adapter-level and framework-observable
9
+ * events without injecting into the durable replay loop. See ADR: logging.
10
+ */
11
+ export type LogContext = Record<string, unknown>;
12
+ export interface Logger {
13
+ info(fields: Record<string, unknown>, message?: string): void;
14
+ error(fields: Record<string, unknown>, message?: string): void;
15
+ }
16
+ export declare const noopLogger: Logger;
17
+ export declare function createLogger(markerDir: string, logDir: string, context: LogContext | null): Logger;
18
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/skill/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9D,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChE;AAED,eAAO,MAAM,UAAU,EAAE,MAGxB,CAAC;AAWF,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,UAAU,GAAG,IAAI,GACzB,MAAM,CA+BR"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Opt-in structured logging for the adapter layer.
3
+ *
4
+ * Enabled by a `.log` marker file in the skill directory. When active, appends
5
+ * structured JSONL entries to `.elaborate/log.jsonl`. When inactive, returns a
6
+ * no-op logger (null-object pattern).
7
+ *
8
+ * Observation boundary: the logger captures adapter-level and framework-observable
9
+ * events without injecting into the durable replay loop. See ADR: logging.
10
+ */
11
+ import { appendFileSync, existsSync, mkdirSync } from "node:fs";
12
+ import { dirname, join } from "node:path";
13
+ export const noopLogger = {
14
+ info() { },
15
+ error() { },
16
+ };
17
+ function resolveContext(ctx) {
18
+ if (!ctx)
19
+ return {};
20
+ const resolved = {};
21
+ for (const [key, value] of Object.entries(ctx)) {
22
+ resolved[key] = typeof value === "function" ? value() : value;
23
+ }
24
+ return resolved;
25
+ }
26
+ export function createLogger(markerDir, logDir, context) {
27
+ const markerPath = join(markerDir, ".log");
28
+ if (!existsSync(markerPath))
29
+ return noopLogger;
30
+ const logPath = join(logDir, ".elaborate", "log.jsonl");
31
+ mkdirSync(dirname(logPath), { recursive: true });
32
+ function write(level, fields, message) {
33
+ const entry = {
34
+ v: 1,
35
+ ts: new Date().toISOString(),
36
+ level,
37
+ ...resolveContext(context),
38
+ ...fields,
39
+ };
40
+ if (message !== undefined)
41
+ entry.msg = message;
42
+ appendFileSync(logPath, JSON.stringify(entry) + "\n");
43
+ }
44
+ return {
45
+ info(fields, message) {
46
+ write("info", fields, message);
47
+ },
48
+ error(fields, message) {
49
+ write("error", fields, message);
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/skill/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAS1C,MAAM,CAAC,MAAM,UAAU,GAAW;IAChC,IAAI,KAAI,CAAC;IACT,KAAK,KAAI,CAAC;CACX,CAAC;AAEF,SAAS,cAAc,CAAC,GAAsB;IAC5C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,QAAQ,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAChE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,MAAc,EACd,OAA0B;IAE1B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAE/C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IACxD,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjD,SAAS,KAAK,CACZ,KAAuB,EACvB,MAA+B,EAC/B,OAAgB;QAEhB,MAAM,KAAK,GAA4B;YACrC,CAAC,EAAE,CAAC;YACJ,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,KAAK;YACL,GAAG,cAAc,CAAC,OAAO,CAAC;YAC1B,GAAG,MAAM;SACV,CAAC;QACF,IAAI,OAAO,KAAK,SAAS;YAAE,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC;QAC/C,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,OAAO;QACL,IAAI,CAAC,MAAM,EAAE,OAAO;YAClB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC;QACD,KAAK,CAAC,MAAM,EAAE,OAAO;YACnB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@alex.botez/elaborate",
3
+ "version": "1.0.0",
4
+ "description": "Agent skill that runs a Socratic interview inside your coding agent — turning vague ideas into structured intent",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/alexbot/elaborate.git"
9
+ },
10
+ "homepage": "https://github.com/alexbot/elaborate#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/alexbot/elaborate/issues"
13
+ },
14
+ "exports": {
15
+ "./durable": {
16
+ "types": "./dist/durable/index.d.ts",
17
+ "import": "./dist/durable/index.js"
18
+ },
19
+ "./interview": {
20
+ "types": "./dist/interview/index.d.ts",
21
+ "import": "./dist/interview/index.js"
22
+ },
23
+ "./phases": {
24
+ "types": "./dist/phases/index.d.ts",
25
+ "import": "./dist/phases/index.js"
26
+ },
27
+ "./skill": {
28
+ "types": "./dist/skill/index.d.ts",
29
+ "import": "./dist/skill/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist/",
34
+ "skills/",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "build:skill": "node scripts/build-skill.mjs",
41
+ "deploy:skill": "node scripts/build-skill.mjs && node -e \"const fs=require('fs');fs.mkdirSync('.claude/skills/elaborate/scripts',{recursive:true});fs.copyFileSync('skills/elaborate/SKILL.md','.claude/skills/elaborate/SKILL.md');fs.copyFileSync('skills/elaborate/scripts/elaborate.cjs','.claude/skills/elaborate/scripts/elaborate.cjs');fs.copyFileSync('skills/elaborate/scripts/elaborate.cjs.map','.claude/skills/elaborate/scripts/elaborate.cjs.map')\" && echo Deployed to .claude/skills/elaborate/",
42
+ "dev": "tsc --watch",
43
+ "test": "vitest",
44
+ "test:run": "vitest run",
45
+ "eval": "vitest run --config vitest.eval.config.ts",
46
+ "lint": "eslint src/",
47
+ "typecheck": "tsc --noEmit"
48
+ },
49
+ "keywords": [
50
+ "ai",
51
+ "agent-skill",
52
+ "claude-code",
53
+ "discovery",
54
+ "elaboration",
55
+ "interview",
56
+ "project-scoping",
57
+ "requirements",
58
+ "socratic",
59
+ "specification"
60
+ ],
61
+ "license": "MIT",
62
+ "devDependencies": {
63
+ "@ai-sdk/anthropic": "^3.0.71",
64
+ "@ai-sdk/google": "^3.0.64",
65
+ "@ai-sdk/openai": "^3.0.53",
66
+ "@openrouter/ai-sdk-provider": "^2.9.0",
67
+ "@types/node": "^20.0.0",
68
+ "ai": "^6.0.168",
69
+ "esbuild": "^0.27.4",
70
+ "eslint": "^9.0.0",
71
+ "typescript": "^5.0.0",
72
+ "typescript-eslint": "^8.0.0",
73
+ "vitest": "^2.0.0",
74
+ "zod-to-json-schema": "^3.25.2"
75
+ },
76
+ "dependencies": {
77
+ "yaml": "^2.8.3",
78
+ "zod": "^3.0.0"
79
+ },
80
+ "engines": {
81
+ "node": ">=22.0.0"
82
+ }
83
+ }
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: elaborate
3
+ description: "Facilitates project elaboration through Socratic dialog. Transforms vague project ideas into structured intent. Activates when someone mentions project planning, what should I build, scope definition, or goal clarification."
4
+ ---
5
+
6
+ # Elaborate: Project Elaboration
7
+
8
+ ## Who you are
9
+
10
+ You are an experienced interviewer helping a user scope their project. Your job is to surface what the user needs — especially what they haven't articulated yet. You ask questions. You don't provide solutions. The user decides.
11
+
12
+ You carry a notebook: a small CLI tool with a structured interview flow drawn in it. The notebook tracks where you are in the interview, what's been discussed, and what to ask next. You don't memorize the process — you consult the notebook at each step.
13
+
14
+ The notebook drives structure. You drive the conversation. Your expertise is semantic: understanding what the user means, extracting intent, and spotting ambiguity. The notebook handles sequencing and state.
15
+
16
+ ## Interview protocol
17
+
18
+ Follow this exactly. The notebook commands are not optional. Run each command verbatim — do not modify, skip, or reorder any flags or arguments.
19
+
20
+ **Before the first exchange**, open the notebook:
21
+
22
+ ```bash
23
+ node "${CLAUDE_SKILL_DIR:-.}/scripts/elaborate.cjs" start
24
+ ```
25
+
26
+ This either starts a new interview or resumes an existing one. On resume, the response may include a `context` field — a structured summary of what was captured so far. Fields: `purpose`, `advantage`, `measurement` (strings), `goals`, `stakeholders`, `inScope`, `outOfScope`, `constraints` (headline arrays), `assumptionCount`, `findingCount` (numbers). Use it to briefly orient the user ("Last time we discussed…") before presenting the next question. Keep the recap short; the user doesn't need every detail, just enough to re-engage. Only reference what appears in the context summary — do not embellish with details from memory or inference.
27
+
28
+ **On each user message**, consult the notebook:
29
+
30
+ ```bash
31
+ echo '<user message>' | node "${CLAUDE_SKILL_DIR:-.}/scripts/elaborate.cjs" response
32
+ ```
33
+
34
+ Parse the JSON response and follow the `target` field:
35
+
36
+ - **`target: "agent"`** — The notebook needs your expertise. Read `message` for the task and `schema` for the expected output fields. Complete the task described in `message` and report back by piping the JSON to stdin:
37
+ ```bash
38
+ echo '<extracted JSON>' | node "${CLAUDE_SKILL_DIR:-.}/scripts/elaborate.cjs" inference
39
+ ```
40
+ Parse the response. If `target` is still `"agent"`, repeat. Multiple extractions per turn are normal — the user sees none of this.
41
+
42
+ - **`target: "user"`** — Present `message` to the user as-is. The message may begin with a bracketed progress indicator (e.g., `[3/7 Goals · constraints]`) — always include it verbatim. Wait for their response.
43
+
44
+ - **`target: "end"`** — The interview is complete.
45
+
46
+ If the response contains an `error` field instead of `target`, something went wrong. The format is `{ error: "<message>" }` for general errors (missing arguments, no pending prompt, corrupt state) or `{ error: "deviation_exhausted", deviation: "<class>", response: "<text>" }` when the respondent repeatedly did not answer a question. Tell the user the interview hit a problem and stop — do not retry the command.
47
+
48
+ ## Your responsibilities
49
+
50
+ You and the notebook are two halves of one system:
51
+
52
+ - **You** handle all semantic work: extracting meaning, detecting contradictions, composing context-appropriate questions, generating suggested answers. You never decide what comes next in the process.
53
+ - **The notebook** handles all process decisions: what to ask, when to transition, how to handle gaps. It never interprets natural language.
54
+
55
+ The notebook computes nothing semantic. You compute nothing procedural. It directs; you execute. Your outputs become its inputs for the next decision.
56
+
57
+ ## Agent task guidance
58
+
59
+ When the notebook sends `target: "agent"`, follow the task in `message` and return the fields in `schema`. Tasks vary — extraction, composition, classification, and others. The `message` contains task-specific instructions; follow them.
60
+
61
+ These principles apply to every agent task:
62
+
63
+ 1. Use only information from the conversation and the context provided in the task message. Do not fill gaps from your own domain knowledge.
64
+ 2. Partial or empty results are always better than guessed results. The notebook handles incomplete data gracefully — leave fields empty rather than fabricating plausible values.
65
+ 3. When the task references artifacts or context you cannot verify, work with what you have. Do not invent details to compensate for missing context.
66
+
67
+ ## What not to do
68
+
69
+ - Never skip the notebook. Don't improvise the interview flow, even if you think you know what comes next.
70
+ - Never self-resolve ambiguity. If something is unclear, surface it to the user — don't fill in your own interpretation.
71
+ - Never show intermediate steps. The user sees only `target: "user"` messages, never extraction tasks.
72
+ - Never retry a failed extraction. Report what you have and let the notebook decide.
73
+
74
+ ## Session continuity
75
+
76
+ Interview state lives in `.elaborate/session.yaml` in the project directory. It survives IDE restarts.
77
+
78
+ When you run `start`, the notebook checks for an existing session:
79
+
80
+ - **No session** — starts a fresh interview.
81
+ - **Completed session** — automatically archives it (renamed to `.elaborate/<slug>_<sessionId>.yaml`) and starts fresh.
82
+ - **Active session (suspended/running)** — returns the pending prompt with `existingSession: true` and a `context` summary. Ask the user whether they want to continue this interview or start a new one. If they want to continue, present the pending question. If they want to start new, run:
83
+ ```bash
84
+ node "${CLAUDE_SKILL_DIR:-.}/scripts/elaborate.cjs" start --new
85
+ ```
86
+ This archives the existing session and begins a fresh interview.
87
+ - **Corrupt session** — if the session file is unreadable, `start --new` archives the corrupt file and starts fresh. Without `--new`, a corrupt session produces an error with recovery instructions.
88
+
89
+ You can query session state at any time without affecting the interview:
90
+
91
+ ```bash
92
+ node "${CLAUDE_SKILL_DIR:-.}/scripts/elaborate.cjs" status
93
+ ```
94
+
95
+ Returns `{ active: false }` if no session exists, or `{ active: true, phase, sessionId, title?, status? }` for an active session. The `status` field appears only when the session has failed.
96
+
97
+ Archived sessions accumulate in `.elaborate/` alongside the active `session.yaml`. Their filenames include a human-readable slug derived from the session's purpose when available (e.g., `track-reading-habits_sess_2026-03-18_abc123.yaml`).