@wrongstack/requirement-intake 1.0.2 → 1.0.3
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.
- package/dist/index.d.ts +13 -13
- package/dist/index.js +316 -309
- package/dist/service.d.ts +2 -2
- package/dist/validation.d.ts +4 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
* development requests as structured intake records. Upstream of spec-driven
|
|
6
6
|
* development; this module never plans, specifies, or implements.
|
|
7
7
|
*/
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export { IntakeError,
|
|
11
|
-
export { requestTypeSchema, prioritySchema, metadataSchema, attachmentInputSchema, relatedResourceInputSchema, questionTemplateInputSchema, createIntakeSchema, updateIntakeSchema, answerInputSchema, attachResourceInputSchema, normalizeRequestType, isBlank, parseWithIssues, validateCreateInput, validateUpdateInput, validateAnswerInput, validateAttachResourceInput, validateAttachmentInput, validateRelatedResourceInput, validateQuestionTemplateInput, validateFieldSource, deterministicSummary, deterministicTitle, } from './validation.js';
|
|
12
|
-
export { ALLOWED_TRANSITIONS, MUTABLE_STATUSES, canTransition, assertTransition, isMutableStatus, isTerminalStatus, isKnownStatus, } from './lifecycle.js';
|
|
13
|
-
export { buildInitialQuestions, pendingQuestions, upsertQuestion } from './questions.js';
|
|
14
|
-
export { INTAKE_OPERATIONS, AllowAllIntakeAuthorizer, DenyAllIntakeAuthorizer, ProjectMembershipIntakeAuthorizer, type IntakeAuthorizer, type IntakeOperation, type ProjectMembershipIntakeAuthorizerOptions, } from './authorization.js';
|
|
15
|
-
export { NoopIntakeLogger, InMemoryIntakeLogger, type IntakeLogger, type IntakeLogFields, } from './logger.js';
|
|
16
|
-
export { INTAKE_COUNTERS, INTAKE_TIMERS, NoopIntakeMetrics, InMemoryIntakeMetrics, type IntakeCounter, type IntakeTimer, type IntakeMetrics, } from './metrics.js';
|
|
8
|
+
export { AllowAllIntakeAuthorizer, DenyAllIntakeAuthorizer, INTAKE_OPERATIONS, type IntakeAuthorizer, type IntakeOperation, ProjectMembershipIntakeAuthorizer, type ProjectMembershipIntakeAuthorizerOptions, } from './authorization.js';
|
|
9
|
+
export { DEFAULT_INTAKE_QUESTIONS, INTAKE_ATTACHMENT_KINDS, INTAKE_FIELD_SOURCES, INTAKE_FIELDS, INTAKE_ID_PREFIX, INTAKE_PRIORITIES, INTAKE_QUESTION_STATUSES, INTAKE_STATUSES, type IntakeAttachmentKind, type IntakeField, type IntakeFieldSource, type IntakePriority, type IntakeQuestionStatus, type IntakeQuestionTemplate, type IntakeStatus, MAX_ANSWER_LENGTH, MAX_ARRAY_ITEMS, MAX_ATTACHMENTS, MAX_HISTORY_ENTRIES, MAX_IDEMPOTENCY_KEY_LENGTH, MAX_METADATA_BYTES, MAX_METADATA_ENTRIES, MAX_QUESTION_LENGTH, MAX_REFERENCE_LENGTH, MAX_RELATED_RESOURCES, MAX_REQUEST_LENGTH, MAX_STRING_FIELD_LENGTH, MAX_SUGGESTIONS, MAX_SUMMARY_LENGTH, MAX_TITLE_LENGTH, RELATED_RESOURCE_KINDS, REQUEST_TYPES, type RelatedResourceKind, type RequestType, SUGGESTION_KINDS, SUGGESTION_STATUSES, type SuggestionKind, type SuggestionStatus, } from './constants.js';
|
|
10
|
+
export { IntakeAuthorizationError, IntakeConflictError, IntakeError, type IntakeErrorCode, IntakeNotFoundError, IntakeStateTransitionError, IntakeStatusLockedError, IntakeSuggestionError, IntakeValidationError, type IntakeValidationIssue, } from './errors.js';
|
|
17
11
|
export { IntakeEventEmitter } from './events.js';
|
|
18
|
-
export {
|
|
19
|
-
export {
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
12
|
+
export { ALLOWED_TRANSITIONS, assertTransition, canTransition, isKnownStatus, isMutableStatus, isTerminalStatus, MUTABLE_STATUSES, } from './lifecycle.js';
|
|
13
|
+
export { InMemoryIntakeLogger, type IntakeLogFields, type IntakeLogger, NoopIntakeLogger, } from './logger.js';
|
|
14
|
+
export { INTAKE_COUNTERS, INTAKE_TIMERS, InMemoryIntakeMetrics, type IntakeCounter, type IntakeMetrics, type IntakeTimer, NoopIntakeMetrics, } from './metrics.js';
|
|
15
|
+
export { buildInitialQuestions, pendingQuestions, upsertQuestion } from './questions.js';
|
|
16
|
+
export { type IntakeCreateResult, type IntakeListFilter, type IntakeSubmitResult, RequirementIntakeService, type RequirementIntakeServiceOptions, } from './service.js';
|
|
17
|
+
export { type IntakeIndexEntry, newIntakeId, RequirementIntakeStore, type RequirementIntakeStoreOptions, type StoreCreateResult, type StoreUpdateOptions, } from './store.js';
|
|
18
|
+
export { assertSuggestionString, type LlmSuggestionGenerator, type LlmSuggestionOutput, type LlmSuggestionRequest, llmSuggestionOutputSchema, type NormalizedLlmSuggestion, toProposals, validateLlmSuggestionOutput, } from './suggestions.js';
|
|
19
|
+
export { type AddAnswerInput, type AttachResourceInput, type ChangeHistoryEntry, type CreateIntakeInput, INTAKE_EVENT_NAMES, type IntakeActor, type IntakeAnswer, type IntakeAttachment, type IntakeAttachmentInput, type IntakeContext, type IntakeEvent, type IntakeEventName, type IntakeQuestion, type IntakeQuestionTemplateInput, type LlmSuggestionProposal, type RelatedResource, type RelatedResourceInput, type RequirementIntakeRecord, type UpdateIntakeInput, } from './types.js';
|
|
20
|
+
export { answerInputSchema, attachmentInputSchema, attachResourceInputSchema, createIntakeSchema, deterministicSummary, deterministicTitle, isBlank, metadataSchema, normalizeRequestType, parseWithIssues, prioritySchema, questionTemplateInputSchema, relatedResourceInputSchema, requestTypeSchema, updateIntakeSchema, validateAnswerInput, validateAttachmentInput, validateAttachResourceInput, validateCreateInput, validateFieldSource, validateQuestionTemplateInput, validateRelatedResourceInput, validateUpdateInput, } from './validation.js';
|
|
21
|
+
export { deriveVibeState, hasVibeTag, stripVibeTag, VIBE_TAG_REGEX, type VibeProtocolStage, type VibeProtocolState, } from './vibe.js';
|
|
22
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
+
// src/authorization.ts
|
|
2
|
+
var INTAKE_OPERATIONS = [
|
|
3
|
+
"create",
|
|
4
|
+
"read",
|
|
5
|
+
"list",
|
|
6
|
+
"update",
|
|
7
|
+
"answer",
|
|
8
|
+
"attach",
|
|
9
|
+
"suggest",
|
|
10
|
+
"accept_suggestion",
|
|
11
|
+
"reject_suggestion",
|
|
12
|
+
"submit",
|
|
13
|
+
"cancel",
|
|
14
|
+
"archive"
|
|
15
|
+
];
|
|
16
|
+
var AllowAllIntakeAuthorizer = class {
|
|
17
|
+
isAllowed(_operation, _ctx, _record) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var DenyAllIntakeAuthorizer = class {
|
|
22
|
+
isAllowed(_operation, _ctx, _record) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var ProjectMembershipIntakeAuthorizer = class {
|
|
27
|
+
projectsOf;
|
|
28
|
+
ownerOnly;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.projectsOf = options.projectsOf;
|
|
31
|
+
this.ownerOnly = options.ownerOnlyOperations ?? /* @__PURE__ */ new Set();
|
|
32
|
+
}
|
|
33
|
+
async isAllowed(operation, ctx, record) {
|
|
34
|
+
if (record && record.projectId !== ctx.projectId) return false;
|
|
35
|
+
const memberships = await this.projectsOf(ctx.id, ctx.type);
|
|
36
|
+
if (!memberships.has(ctx.projectId)) return false;
|
|
37
|
+
if (this.ownerOnly.has(operation) && record) {
|
|
38
|
+
return record.requestedBy === ctx.id;
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
1
44
|
// src/constants.ts
|
|
2
45
|
var INTAKE_ID_PREFIX = "reqi_";
|
|
3
46
|
var ANSWER_ID_PREFIX = "ans_";
|
|
@@ -97,16 +140,6 @@ var DEFAULT_INTAKE_QUESTIONS = [
|
|
|
97
140
|
}
|
|
98
141
|
];
|
|
99
142
|
|
|
100
|
-
// src/types.ts
|
|
101
|
-
var INTAKE_EVENT_NAMES = [
|
|
102
|
-
"RequirementIntakeCreated",
|
|
103
|
-
"RequirementIntakeUpdated",
|
|
104
|
-
"RequirementIntakeInformationRequested",
|
|
105
|
-
"RequirementIntakeSubmitted",
|
|
106
|
-
"RequirementIntakeCancelled",
|
|
107
|
-
"RequirementIntakeArchived"
|
|
108
|
-
];
|
|
109
|
-
|
|
110
143
|
// src/errors.ts
|
|
111
144
|
var IntakeError = class extends Error {
|
|
112
145
|
code;
|
|
@@ -176,176 +209,39 @@ var IntakeSuggestionError = class extends IntakeError {
|
|
|
176
209
|
}
|
|
177
210
|
};
|
|
178
211
|
|
|
179
|
-
// src/
|
|
180
|
-
|
|
181
|
-
var
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}, "must be a valid http(s) URL");
|
|
193
|
-
var idSchema = z.string().min(1).max(128).refine((value) => value.trim().length > 0, "must not be blank");
|
|
194
|
-
var nonBlankString = (max, label) => z.string().max(max, `${label} exceeds the maximum length of ${max} characters`).refine((value) => value.trim().length > 0, `${label} must not be empty or whitespace-only`);
|
|
195
|
-
var attachmentInputSchema = z.object({
|
|
196
|
-
name: nonBlankString(200, "attachment name"),
|
|
197
|
-
kind: z.enum(INTAKE_ATTACHMENT_KINDS),
|
|
198
|
-
path: z.string().max(MAX_REFERENCE_LENGTH).optional(),
|
|
199
|
-
url: httpUrlSchema.optional(),
|
|
200
|
-
sizeBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
201
|
-
mimeType: z.string().max(100).optional()
|
|
202
|
-
}).refine((value) => value.path === void 0 !== (value.url === void 0), {
|
|
203
|
-
message: "exactly one of path or url is required"
|
|
204
|
-
});
|
|
205
|
-
var relatedResourceInputSchema = z.object({
|
|
206
|
-
kind: z.enum(RELATED_RESOURCE_KINDS),
|
|
207
|
-
reference: nonBlankString(MAX_REFERENCE_LENGTH, "related resource reference"),
|
|
208
|
-
title: z.string().max(200).optional()
|
|
209
|
-
});
|
|
210
|
-
var questionTemplateInputSchema = z.object({
|
|
211
|
-
field: nonBlankString(64, "question field"),
|
|
212
|
-
question: nonBlankString(MAX_QUESTION_LENGTH, "question text"),
|
|
213
|
-
required: z.boolean().optional()
|
|
214
|
-
});
|
|
215
|
-
var metadataSchema = z.record(z.string().max(64), z.unknown()).superRefine((value, ctx) => {
|
|
216
|
-
const keys = Object.keys(value);
|
|
217
|
-
if (keys.length > MAX_METADATA_ENTRIES) {
|
|
218
|
-
ctx.addIssue({
|
|
219
|
-
code: "custom",
|
|
220
|
-
path: [],
|
|
221
|
-
message: `metadata exceeds the maximum of ${MAX_METADATA_ENTRIES} entries`
|
|
222
|
-
});
|
|
212
|
+
// src/events.ts
|
|
213
|
+
var MAX_LISTENERS = 200;
|
|
214
|
+
var IntakeEventEmitter = class {
|
|
215
|
+
listeners = /* @__PURE__ */ new Set();
|
|
216
|
+
/** Publish an event. Listener errors are swallowed so one bad listener cannot break others. */
|
|
217
|
+
emit(event, data) {
|
|
218
|
+
const payload = { event, timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...data };
|
|
219
|
+
for (const listener of [...this.listeners]) {
|
|
220
|
+
try {
|
|
221
|
+
listener(payload);
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
}
|
|
223
225
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
/** Subscribe; returns a disposer. Past the cap, returns a no-op disposer. */
|
|
227
|
+
subscribe(listener) {
|
|
228
|
+
if (this.listeners.size >= MAX_LISTENERS) {
|
|
229
|
+
const message = "Requirement intake event-emitter listener limit reached \u2014 callers must dispose subscriptions";
|
|
230
|
+
if (typeof process !== "undefined" && typeof process.emitWarning === "function") {
|
|
231
|
+
process.emitWarning(message, "IntakeEventEmitterWarning");
|
|
232
|
+
}
|
|
233
|
+
return () => {
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
this.listeners.add(listener);
|
|
237
|
+
return () => {
|
|
238
|
+
this.listeners.delete(listener);
|
|
239
|
+
};
|
|
230
240
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
code: "custom",
|
|
234
|
-
path: [],
|
|
235
|
-
message: `metadata exceeds the maximum size of ${MAX_METADATA_BYTES} bytes`
|
|
236
|
-
});
|
|
241
|
+
get listenerCount() {
|
|
242
|
+
return this.listeners.size;
|
|
237
243
|
}
|
|
238
|
-
}
|
|
239
|
-
var optionalString = (max) => z.string().max(max).optional();
|
|
240
|
-
var optionalStringArray = z.array(z.string().trim().min(1).max(MAX_STRING_FIELD_LENGTH)).max(MAX_ARRAY_ITEMS).optional();
|
|
241
|
-
var optionalAttachmentArray = z.array(attachmentInputSchema).max(MAX_ATTACHMENTS).optional();
|
|
242
|
-
var optionalRelatedResourceArray = z.array(relatedResourceInputSchema).max(MAX_RELATED_RESOURCES).optional();
|
|
243
|
-
var createIntakeSchema = z.object({
|
|
244
|
-
projectId: idSchema,
|
|
245
|
-
originalRequest: nonBlankString(MAX_REQUEST_LENGTH, "originalRequest"),
|
|
246
|
-
title: optionalString(MAX_TITLE_LENGTH),
|
|
247
|
-
requestType: z.string().max(64).optional(),
|
|
248
|
-
priority: prioritySchema.optional(),
|
|
249
|
-
requestedBy: idSchema,
|
|
250
|
-
businessGoal: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
251
|
-
targetUsers: optionalStringArray,
|
|
252
|
-
expectedOutcome: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
253
|
-
scopeNotes: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
254
|
-
constraints: optionalStringArray,
|
|
255
|
-
providedContext: optionalStringArray,
|
|
256
|
-
attachments: optionalAttachmentArray,
|
|
257
|
-
relatedResources: optionalRelatedResourceArray,
|
|
258
|
-
metadata: metadataSchema.optional(),
|
|
259
|
-
idempotencyKey: z.string().trim().max(MAX_IDEMPOTENCY_KEY_LENGTH).optional(),
|
|
260
|
-
knownFields: z.array(z.string().trim().min(1).max(64)).max(MAX_ARRAY_ITEMS).optional(),
|
|
261
|
-
questions: z.array(questionTemplateInputSchema).max(50).optional()
|
|
262
|
-
}).strict();
|
|
263
|
-
var updateIntakeSchema = z.object({
|
|
264
|
-
title: optionalString(MAX_TITLE_LENGTH),
|
|
265
|
-
requestType: z.string().max(64).optional(),
|
|
266
|
-
priority: prioritySchema.optional(),
|
|
267
|
-
businessGoal: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
268
|
-
targetUsers: optionalStringArray,
|
|
269
|
-
expectedOutcome: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
270
|
-
scopeNotes: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
271
|
-
constraints: optionalStringArray,
|
|
272
|
-
providedContext: optionalStringArray,
|
|
273
|
-
metadata: metadataSchema.optional()
|
|
274
|
-
}).strict();
|
|
275
|
-
var answerInputSchema = z.object({
|
|
276
|
-
field: nonBlankString(64, "answer field"),
|
|
277
|
-
answer: nonBlankString(MAX_ANSWER_LENGTH, "answer").max(
|
|
278
|
-
MAX_ANSWER_LENGTH,
|
|
279
|
-
`answer exceeds the maximum length of ${MAX_ANSWER_LENGTH} characters`
|
|
280
|
-
),
|
|
281
|
-
question: z.string().max(MAX_QUESTION_LENGTH).optional()
|
|
282
|
-
});
|
|
283
|
-
var attachResourceInputSchema = z.object({
|
|
284
|
-
attachment: attachmentInputSchema.optional(),
|
|
285
|
-
relatedResource: relatedResourceInputSchema.optional()
|
|
286
|
-
}).refine((value) => value.attachment === void 0 !== (value.relatedResource === void 0), {
|
|
287
|
-
message: "exactly one of attachment or relatedResource must be provided"
|
|
288
|
-
});
|
|
289
|
-
function normalizeRequestType(value) {
|
|
290
|
-
if (typeof value !== "string") return "unspecified";
|
|
291
|
-
const trimmed = value.trim().toLowerCase();
|
|
292
|
-
if (trimmed.length === 0) return "unspecified";
|
|
293
|
-
const normalized = trimmed.replace(/-/g, "_");
|
|
294
|
-
if (REQUEST_TYPES.includes(normalized)) return normalized;
|
|
295
|
-
return "other";
|
|
296
|
-
}
|
|
297
|
-
function isBlank(value) {
|
|
298
|
-
return value.trim().length === 0;
|
|
299
|
-
}
|
|
300
|
-
function parseWithIssues(schema, data, scope) {
|
|
301
|
-
const result = schema.safeParse(data);
|
|
302
|
-
if (result.success) return result.data;
|
|
303
|
-
const issues = result.error.issues.map((issue) => {
|
|
304
|
-
const path2 = issue.path.join(".");
|
|
305
|
-
return {
|
|
306
|
-
field: path2 === "" ? scope : `${scope}.${path2}`,
|
|
307
|
-
message: issue.message
|
|
308
|
-
};
|
|
309
|
-
});
|
|
310
|
-
throw new IntakeValidationError(issues);
|
|
311
|
-
}
|
|
312
|
-
function validateCreateInput(data) {
|
|
313
|
-
return parseWithIssues(createIntakeSchema, data, "createIntake");
|
|
314
|
-
}
|
|
315
|
-
function validateUpdateInput(data) {
|
|
316
|
-
return parseWithIssues(updateIntakeSchema, data, "updateIntake");
|
|
317
|
-
}
|
|
318
|
-
function validateAnswerInput(data) {
|
|
319
|
-
return parseWithIssues(answerInputSchema, data, "addAnswer");
|
|
320
|
-
}
|
|
321
|
-
function validateAttachResourceInput(data) {
|
|
322
|
-
return parseWithIssues(attachResourceInputSchema, data, "attachResource");
|
|
323
|
-
}
|
|
324
|
-
function validateAttachmentInput(data) {
|
|
325
|
-
return parseWithIssues(attachmentInputSchema, data, "attachment");
|
|
326
|
-
}
|
|
327
|
-
function validateRelatedResourceInput(data) {
|
|
328
|
-
return parseWithIssues(relatedResourceInputSchema, data, "relatedResource");
|
|
329
|
-
}
|
|
330
|
-
function validateQuestionTemplateInput(data) {
|
|
331
|
-
return parseWithIssues(questionTemplateInputSchema, data, "question");
|
|
332
|
-
}
|
|
333
|
-
function validateFieldSource(value) {
|
|
334
|
-
const parsed = fieldSourceSchema.safeParse(value);
|
|
335
|
-
if (parsed.success) return parsed.data;
|
|
336
|
-
throw new IntakeValidationError([{ field: "source", message: "invalid field source" }]);
|
|
337
|
-
}
|
|
338
|
-
function deterministicSummary(originalRequest, maxLength = 240) {
|
|
339
|
-
const collapsed = originalRequest.replace(/\s+/g, " ").trim();
|
|
340
|
-
if (collapsed.length <= maxLength) return collapsed;
|
|
341
|
-
return `${collapsed.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
|
|
342
|
-
}
|
|
343
|
-
function deterministicTitle(originalRequest, maxLength = MAX_TITLE_LENGTH) {
|
|
344
|
-
const firstLine = originalRequest.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
345
|
-
if (firstLine.length === 0) return "Untitled request";
|
|
346
|
-
if (firstLine.length <= maxLength) return firstLine;
|
|
347
|
-
return `${firstLine.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
|
|
348
|
-
}
|
|
244
|
+
};
|
|
349
245
|
|
|
350
246
|
// src/lifecycle.ts
|
|
351
247
|
var ALLOWED_TRANSITIONS = {
|
|
@@ -374,93 +270,6 @@ function isKnownStatus(value) {
|
|
|
374
270
|
return INTAKE_STATUSES.includes(value);
|
|
375
271
|
}
|
|
376
272
|
|
|
377
|
-
// src/questions.ts
|
|
378
|
-
import { ulid } from "@wrongstack/core/utils";
|
|
379
|
-
var FIELD_TO_INPUT_PROPERTY = {
|
|
380
|
-
description_scope: () => true,
|
|
381
|
-
// always answered by the original request
|
|
382
|
-
business_goal: (input) => input.businessGoal !== void 0 && input.businessGoal.trim().length > 0,
|
|
383
|
-
target_users: (input) => (input.targetUsers?.length ?? 0) > 0,
|
|
384
|
-
expected_outcome: (input) => input.expectedOutcome !== void 0 && input.expectedOutcome.trim().length > 0,
|
|
385
|
-
project_component: (input) => (input.providedContext?.length ?? 0) > 0,
|
|
386
|
-
constraints: (input) => (input.constraints?.length ?? 0) > 0,
|
|
387
|
-
related_resources: (input) => (input.relatedResources?.length ?? 0) > 0,
|
|
388
|
-
priority: (input) => input.priority !== void 0 && input.priority !== "unspecified",
|
|
389
|
-
attachments: (input) => (input.attachments?.length ?? 0) > 0
|
|
390
|
-
};
|
|
391
|
-
function makeQuestion(template, order, skipped) {
|
|
392
|
-
return {
|
|
393
|
-
id: `${QUESTION_ID_PREFIX}${ulid()}`,
|
|
394
|
-
field: template.field,
|
|
395
|
-
question: template.question,
|
|
396
|
-
required: template.required,
|
|
397
|
-
status: skipped ? "skipped" : "unanswered",
|
|
398
|
-
order
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
function buildInitialQuestions(input, catalog = DEFAULT_INTAKE_QUESTIONS) {
|
|
402
|
-
const known = new Set((input.knownFields ?? []).map((field) => field.trim()));
|
|
403
|
-
return catalog.map((template, index) => {
|
|
404
|
-
const answeredByInput = FIELD_TO_INPUT_PROPERTY[template.field]?.(input) ?? false;
|
|
405
|
-
const skipped = answeredByInput || known.has(template.field);
|
|
406
|
-
return makeQuestion(template, index, skipped);
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
function pendingQuestions(record) {
|
|
410
|
-
return record.questions.filter((question) => question.status === "unanswered").sort((a, b) => a.order - b.order);
|
|
411
|
-
}
|
|
412
|
-
function upsertQuestion(record, template) {
|
|
413
|
-
const existing = record.questions.find(
|
|
414
|
-
(question) => question.field === template.field && question.status !== "skipped"
|
|
415
|
-
);
|
|
416
|
-
if (existing) return false;
|
|
417
|
-
record.questions.push(makeQuestion(template, record.questions.length, false));
|
|
418
|
-
return true;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// src/authorization.ts
|
|
422
|
-
var INTAKE_OPERATIONS = [
|
|
423
|
-
"create",
|
|
424
|
-
"read",
|
|
425
|
-
"list",
|
|
426
|
-
"update",
|
|
427
|
-
"answer",
|
|
428
|
-
"attach",
|
|
429
|
-
"suggest",
|
|
430
|
-
"accept_suggestion",
|
|
431
|
-
"reject_suggestion",
|
|
432
|
-
"submit",
|
|
433
|
-
"cancel",
|
|
434
|
-
"archive"
|
|
435
|
-
];
|
|
436
|
-
var AllowAllIntakeAuthorizer = class {
|
|
437
|
-
isAllowed(_operation, _ctx, _record) {
|
|
438
|
-
return true;
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
var DenyAllIntakeAuthorizer = class {
|
|
442
|
-
isAllowed(_operation, _ctx, _record) {
|
|
443
|
-
return false;
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
var ProjectMembershipIntakeAuthorizer = class {
|
|
447
|
-
projectsOf;
|
|
448
|
-
ownerOnly;
|
|
449
|
-
constructor(options) {
|
|
450
|
-
this.projectsOf = options.projectsOf;
|
|
451
|
-
this.ownerOnly = options.ownerOnlyOperations ?? /* @__PURE__ */ new Set();
|
|
452
|
-
}
|
|
453
|
-
async isAllowed(operation, ctx, record) {
|
|
454
|
-
if (record && record.projectId !== ctx.projectId) return false;
|
|
455
|
-
const memberships = await this.projectsOf(ctx.id, ctx.type);
|
|
456
|
-
if (!memberships.has(ctx.projectId)) return false;
|
|
457
|
-
if (this.ownerOnly.has(operation) && record) {
|
|
458
|
-
return record.requestedBy === ctx.id;
|
|
459
|
-
}
|
|
460
|
-
return true;
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
|
|
464
273
|
// src/logger.ts
|
|
465
274
|
var NoopIntakeLogger = class {
|
|
466
275
|
info(_scope, _message, _fields) {
|
|
@@ -530,51 +339,64 @@ var InMemoryIntakeMetrics = class {
|
|
|
530
339
|
bucket.push(milliseconds);
|
|
531
340
|
this.durations.set(timer, bucket);
|
|
532
341
|
}
|
|
533
|
-
count(counter) {
|
|
534
|
-
return this.counters.get(counter) ?? 0;
|
|
535
|
-
}
|
|
536
|
-
/** Sum of recorded durations for a timer, or undefined when none recorded. */
|
|
537
|
-
durationSum(timer) {
|
|
538
|
-
const bucket = this.durations.get(timer);
|
|
539
|
-
if (!bucket || bucket.length === 0) return void 0;
|
|
540
|
-
return bucket.reduce((total, value) => total + value, 0);
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
// src/events.ts
|
|
545
|
-
var MAX_LISTENERS = 200;
|
|
546
|
-
var IntakeEventEmitter = class {
|
|
547
|
-
listeners = /* @__PURE__ */ new Set();
|
|
548
|
-
/** Publish an event. Listener errors are swallowed so one bad listener cannot break others. */
|
|
549
|
-
emit(event, data) {
|
|
550
|
-
const payload = { event, timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...data };
|
|
551
|
-
for (const listener of [...this.listeners]) {
|
|
552
|
-
try {
|
|
553
|
-
listener(payload);
|
|
554
|
-
} catch {
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
/** Subscribe; returns a disposer. Past the cap, returns a no-op disposer. */
|
|
559
|
-
subscribe(listener) {
|
|
560
|
-
if (this.listeners.size >= MAX_LISTENERS) {
|
|
561
|
-
const message = "Requirement intake event-emitter listener limit reached \u2014 callers must dispose subscriptions";
|
|
562
|
-
if (typeof process !== "undefined" && typeof process.emitWarning === "function") {
|
|
563
|
-
process.emitWarning(message, "IntakeEventEmitterWarning");
|
|
564
|
-
}
|
|
565
|
-
return () => {
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
this.listeners.add(listener);
|
|
569
|
-
return () => {
|
|
570
|
-
this.listeners.delete(listener);
|
|
571
|
-
};
|
|
342
|
+
count(counter) {
|
|
343
|
+
return this.counters.get(counter) ?? 0;
|
|
572
344
|
}
|
|
573
|
-
|
|
574
|
-
|
|
345
|
+
/** Sum of recorded durations for a timer, or undefined when none recorded. */
|
|
346
|
+
durationSum(timer) {
|
|
347
|
+
const bucket = this.durations.get(timer);
|
|
348
|
+
if (!bucket || bucket.length === 0) return void 0;
|
|
349
|
+
return bucket.reduce((total, value) => total + value, 0);
|
|
575
350
|
}
|
|
576
351
|
};
|
|
577
352
|
|
|
353
|
+
// src/questions.ts
|
|
354
|
+
import { ulid } from "@wrongstack/core/utils";
|
|
355
|
+
var FIELD_TO_INPUT_PROPERTY = {
|
|
356
|
+
description_scope: () => true,
|
|
357
|
+
// always answered by the original request
|
|
358
|
+
business_goal: (input) => input.businessGoal !== void 0 && input.businessGoal.trim().length > 0,
|
|
359
|
+
target_users: (input) => (input.targetUsers?.length ?? 0) > 0,
|
|
360
|
+
expected_outcome: (input) => input.expectedOutcome !== void 0 && input.expectedOutcome.trim().length > 0,
|
|
361
|
+
project_component: (input) => (input.providedContext?.length ?? 0) > 0,
|
|
362
|
+
constraints: (input) => (input.constraints?.length ?? 0) > 0,
|
|
363
|
+
related_resources: (input) => (input.relatedResources?.length ?? 0) > 0,
|
|
364
|
+
priority: (input) => input.priority !== void 0 && input.priority !== "unspecified",
|
|
365
|
+
attachments: (input) => (input.attachments?.length ?? 0) > 0
|
|
366
|
+
};
|
|
367
|
+
function makeQuestion(template, order, skipped) {
|
|
368
|
+
return {
|
|
369
|
+
id: `${QUESTION_ID_PREFIX}${ulid()}`,
|
|
370
|
+
field: template.field,
|
|
371
|
+
question: template.question,
|
|
372
|
+
required: template.required,
|
|
373
|
+
status: skipped ? "skipped" : "unanswered",
|
|
374
|
+
order
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function buildInitialQuestions(input, catalog = DEFAULT_INTAKE_QUESTIONS) {
|
|
378
|
+
const known = new Set((input.knownFields ?? []).map((field) => field.trim()));
|
|
379
|
+
return catalog.map((template, index) => {
|
|
380
|
+
const answeredByInput = FIELD_TO_INPUT_PROPERTY[template.field]?.(input) ?? false;
|
|
381
|
+
const skipped = answeredByInput || known.has(template.field);
|
|
382
|
+
return makeQuestion(template, index, skipped);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
function pendingQuestions(record) {
|
|
386
|
+
return record.questions.filter((question) => question.status === "unanswered").sort((a, b) => a.order - b.order);
|
|
387
|
+
}
|
|
388
|
+
function upsertQuestion(record, template) {
|
|
389
|
+
const existing = record.questions.find(
|
|
390
|
+
(question) => question.field === template.field && question.status !== "skipped"
|
|
391
|
+
);
|
|
392
|
+
if (existing) return false;
|
|
393
|
+
record.questions.push(makeQuestion(template, record.questions.length, false));
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/service-helpers.ts
|
|
398
|
+
import { ulid as ulid4 } from "@wrongstack/core/utils";
|
|
399
|
+
|
|
578
400
|
// src/store.ts
|
|
579
401
|
import { createHash } from "node:crypto";
|
|
580
402
|
import * as fsp from "node:fs/promises";
|
|
@@ -794,8 +616,186 @@ function newIntakeId() {
|
|
|
794
616
|
}
|
|
795
617
|
|
|
796
618
|
// src/suggestions.ts
|
|
797
|
-
import { z as z2 } from "zod";
|
|
798
619
|
import { ulid as ulid3 } from "@wrongstack/core/utils";
|
|
620
|
+
import { z as z2 } from "zod";
|
|
621
|
+
|
|
622
|
+
// src/validation.ts
|
|
623
|
+
import { z } from "zod";
|
|
624
|
+
var requestTypeSchema = z.enum(REQUEST_TYPES);
|
|
625
|
+
var prioritySchema = z.enum(INTAKE_PRIORITIES);
|
|
626
|
+
var intakeQuestionStatusSchema = z.enum(INTAKE_QUESTION_STATUSES);
|
|
627
|
+
var fieldSourceSchema = z.enum(["user", "llm", "deterministic", "system"]);
|
|
628
|
+
var httpUrlSchema = z.string().max(MAX_REFERENCE_LENGTH).refine((value) => {
|
|
629
|
+
try {
|
|
630
|
+
const url = new URL(value);
|
|
631
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
632
|
+
} catch {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
}, "must be a valid http(s) URL");
|
|
636
|
+
var idSchema = z.string().min(1).max(128).refine((value) => value.trim().length > 0, "must not be blank");
|
|
637
|
+
var nonBlankString = (max, label) => z.string().max(max, `${label} exceeds the maximum length of ${max} characters`).refine((value) => value.trim().length > 0, `${label} must not be empty or whitespace-only`);
|
|
638
|
+
var attachmentInputSchema = z.object({
|
|
639
|
+
name: nonBlankString(200, "attachment name"),
|
|
640
|
+
kind: z.enum(INTAKE_ATTACHMENT_KINDS),
|
|
641
|
+
path: z.string().max(MAX_REFERENCE_LENGTH).optional(),
|
|
642
|
+
url: httpUrlSchema.optional(),
|
|
643
|
+
sizeBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
644
|
+
mimeType: z.string().max(100).optional()
|
|
645
|
+
}).refine((value) => value.path === void 0 !== (value.url === void 0), {
|
|
646
|
+
message: "exactly one of path or url is required"
|
|
647
|
+
});
|
|
648
|
+
var relatedResourceInputSchema = z.object({
|
|
649
|
+
kind: z.enum(RELATED_RESOURCE_KINDS),
|
|
650
|
+
reference: nonBlankString(MAX_REFERENCE_LENGTH, "related resource reference"),
|
|
651
|
+
title: z.string().max(200).optional()
|
|
652
|
+
});
|
|
653
|
+
var questionTemplateInputSchema = z.object({
|
|
654
|
+
field: nonBlankString(64, "question field"),
|
|
655
|
+
question: nonBlankString(MAX_QUESTION_LENGTH, "question text"),
|
|
656
|
+
required: z.boolean().optional()
|
|
657
|
+
});
|
|
658
|
+
var metadataSchema = z.record(z.string().max(64), z.unknown()).superRefine((value, ctx) => {
|
|
659
|
+
const keys = Object.keys(value);
|
|
660
|
+
if (keys.length > MAX_METADATA_ENTRIES) {
|
|
661
|
+
ctx.addIssue({
|
|
662
|
+
code: "custom",
|
|
663
|
+
path: [],
|
|
664
|
+
message: `metadata exceeds the maximum of ${MAX_METADATA_ENTRIES} entries`
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
let bytes = 0;
|
|
668
|
+
try {
|
|
669
|
+
bytes = Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
670
|
+
} catch {
|
|
671
|
+
ctx.addIssue({ code: "custom", path: [], message: "metadata must be JSON-serializable" });
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
if (bytes > MAX_METADATA_BYTES) {
|
|
675
|
+
ctx.addIssue({
|
|
676
|
+
code: "custom",
|
|
677
|
+
path: [],
|
|
678
|
+
message: `metadata exceeds the maximum size of ${MAX_METADATA_BYTES} bytes`
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
var optionalString = (max) => z.string().max(max).optional();
|
|
683
|
+
var optionalStringArray = z.array(z.string().trim().min(1).max(MAX_STRING_FIELD_LENGTH)).max(MAX_ARRAY_ITEMS).optional();
|
|
684
|
+
var optionalAttachmentArray = z.array(attachmentInputSchema).max(MAX_ATTACHMENTS).optional();
|
|
685
|
+
var optionalRelatedResourceArray = z.array(relatedResourceInputSchema).max(MAX_RELATED_RESOURCES).optional();
|
|
686
|
+
var createIntakeSchema = z.object({
|
|
687
|
+
projectId: idSchema,
|
|
688
|
+
originalRequest: nonBlankString(MAX_REQUEST_LENGTH, "originalRequest"),
|
|
689
|
+
title: optionalString(MAX_TITLE_LENGTH),
|
|
690
|
+
requestType: z.string().max(64).optional(),
|
|
691
|
+
priority: prioritySchema.optional(),
|
|
692
|
+
requestedBy: idSchema,
|
|
693
|
+
businessGoal: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
694
|
+
targetUsers: optionalStringArray,
|
|
695
|
+
expectedOutcome: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
696
|
+
scopeNotes: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
697
|
+
constraints: optionalStringArray,
|
|
698
|
+
providedContext: optionalStringArray,
|
|
699
|
+
attachments: optionalAttachmentArray,
|
|
700
|
+
relatedResources: optionalRelatedResourceArray,
|
|
701
|
+
metadata: metadataSchema.optional(),
|
|
702
|
+
idempotencyKey: z.string().trim().max(MAX_IDEMPOTENCY_KEY_LENGTH).optional(),
|
|
703
|
+
knownFields: z.array(z.string().trim().min(1).max(64)).max(MAX_ARRAY_ITEMS).optional(),
|
|
704
|
+
questions: z.array(questionTemplateInputSchema).max(50).optional(),
|
|
705
|
+
isVibeMode: z.boolean().optional(),
|
|
706
|
+
vibeProtocol: z.any().optional()
|
|
707
|
+
}).strict();
|
|
708
|
+
var updateIntakeSchema = z.object({
|
|
709
|
+
title: optionalString(MAX_TITLE_LENGTH),
|
|
710
|
+
requestType: z.string().max(64).optional(),
|
|
711
|
+
priority: prioritySchema.optional(),
|
|
712
|
+
businessGoal: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
713
|
+
targetUsers: optionalStringArray,
|
|
714
|
+
expectedOutcome: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
715
|
+
scopeNotes: optionalString(MAX_STRING_FIELD_LENGTH),
|
|
716
|
+
constraints: optionalStringArray,
|
|
717
|
+
providedContext: optionalStringArray,
|
|
718
|
+
metadata: metadataSchema.optional(),
|
|
719
|
+
isVibeMode: z.boolean().optional(),
|
|
720
|
+
vibeProtocol: z.any().optional()
|
|
721
|
+
}).strict();
|
|
722
|
+
var answerInputSchema = z.object({
|
|
723
|
+
field: nonBlankString(64, "answer field"),
|
|
724
|
+
answer: nonBlankString(MAX_ANSWER_LENGTH, "answer").max(
|
|
725
|
+
MAX_ANSWER_LENGTH,
|
|
726
|
+
`answer exceeds the maximum length of ${MAX_ANSWER_LENGTH} characters`
|
|
727
|
+
),
|
|
728
|
+
question: z.string().max(MAX_QUESTION_LENGTH).optional()
|
|
729
|
+
});
|
|
730
|
+
var attachResourceInputSchema = z.object({
|
|
731
|
+
attachment: attachmentInputSchema.optional(),
|
|
732
|
+
relatedResource: relatedResourceInputSchema.optional()
|
|
733
|
+
}).refine((value) => value.attachment === void 0 !== (value.relatedResource === void 0), {
|
|
734
|
+
message: "exactly one of attachment or relatedResource must be provided"
|
|
735
|
+
});
|
|
736
|
+
function normalizeRequestType(value) {
|
|
737
|
+
if (typeof value !== "string") return "unspecified";
|
|
738
|
+
const trimmed = value.trim().toLowerCase();
|
|
739
|
+
if (trimmed.length === 0) return "unspecified";
|
|
740
|
+
const normalized = trimmed.replace(/-/g, "_");
|
|
741
|
+
if (REQUEST_TYPES.includes(normalized)) return normalized;
|
|
742
|
+
return "other";
|
|
743
|
+
}
|
|
744
|
+
function isBlank(value) {
|
|
745
|
+
return value.trim().length === 0;
|
|
746
|
+
}
|
|
747
|
+
function parseWithIssues(schema, data, scope) {
|
|
748
|
+
const result = schema.safeParse(data);
|
|
749
|
+
if (result.success) return result.data;
|
|
750
|
+
const issues = result.error.issues.map((issue) => {
|
|
751
|
+
const path2 = issue.path.join(".");
|
|
752
|
+
return {
|
|
753
|
+
field: path2 === "" ? scope : `${scope}.${path2}`,
|
|
754
|
+
message: issue.message
|
|
755
|
+
};
|
|
756
|
+
});
|
|
757
|
+
throw new IntakeValidationError(issues);
|
|
758
|
+
}
|
|
759
|
+
function validateCreateInput(data) {
|
|
760
|
+
return parseWithIssues(createIntakeSchema, data, "createIntake");
|
|
761
|
+
}
|
|
762
|
+
function validateUpdateInput(data) {
|
|
763
|
+
return parseWithIssues(updateIntakeSchema, data, "updateIntake");
|
|
764
|
+
}
|
|
765
|
+
function validateAnswerInput(data) {
|
|
766
|
+
return parseWithIssues(answerInputSchema, data, "addAnswer");
|
|
767
|
+
}
|
|
768
|
+
function validateAttachResourceInput(data) {
|
|
769
|
+
return parseWithIssues(attachResourceInputSchema, data, "attachResource");
|
|
770
|
+
}
|
|
771
|
+
function validateAttachmentInput(data) {
|
|
772
|
+
return parseWithIssues(attachmentInputSchema, data, "attachment");
|
|
773
|
+
}
|
|
774
|
+
function validateRelatedResourceInput(data) {
|
|
775
|
+
return parseWithIssues(relatedResourceInputSchema, data, "relatedResource");
|
|
776
|
+
}
|
|
777
|
+
function validateQuestionTemplateInput(data) {
|
|
778
|
+
return parseWithIssues(questionTemplateInputSchema, data, "question");
|
|
779
|
+
}
|
|
780
|
+
function validateFieldSource(value) {
|
|
781
|
+
const parsed = fieldSourceSchema.safeParse(value);
|
|
782
|
+
if (parsed.success) return parsed.data;
|
|
783
|
+
throw new IntakeValidationError([{ field: "source", message: "invalid field source" }]);
|
|
784
|
+
}
|
|
785
|
+
function deterministicSummary(originalRequest, maxLength = 240) {
|
|
786
|
+
const collapsed = originalRequest.replace(/\s+/g, " ").trim();
|
|
787
|
+
if (collapsed.length <= maxLength) return collapsed;
|
|
788
|
+
return `${collapsed.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
|
|
789
|
+
}
|
|
790
|
+
function deterministicTitle(originalRequest, maxLength = MAX_TITLE_LENGTH) {
|
|
791
|
+
const newlineIdx = originalRequest.search(/\r?\n/);
|
|
792
|
+
const firstLine = (newlineIdx >= 0 ? originalRequest.slice(0, newlineIdx) : originalRequest).trim();
|
|
793
|
+
if (firstLine.length === 0) return "Untitled request";
|
|
794
|
+
if (firstLine.length <= maxLength) return firstLine;
|
|
795
|
+
return `${firstLine.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/suggestions.ts
|
|
799
799
|
var outputQuestionSchema = z2.object({
|
|
800
800
|
field: z2.string().trim().min(1).max(64),
|
|
801
801
|
question: z2.string().trim().min(1).max(MAX_QUESTION_LENGTH),
|
|
@@ -879,9 +879,6 @@ function assertSuggestionString(value, label, max) {
|
|
|
879
879
|
return value;
|
|
880
880
|
}
|
|
881
881
|
|
|
882
|
-
// src/service-helpers.ts
|
|
883
|
-
import { ulid as ulid4 } from "@wrongstack/core/utils";
|
|
884
|
-
|
|
885
882
|
// src/vibe.ts
|
|
886
883
|
var VIBE_TAG_REGEX = /\[VIBE\]/i;
|
|
887
884
|
function hasVibeTag(text) {
|
|
@@ -1786,6 +1783,16 @@ var RequirementIntakeService = class {
|
|
|
1786
1783
|
}
|
|
1787
1784
|
}
|
|
1788
1785
|
};
|
|
1786
|
+
|
|
1787
|
+
// src/types.ts
|
|
1788
|
+
var INTAKE_EVENT_NAMES = [
|
|
1789
|
+
"RequirementIntakeCreated",
|
|
1790
|
+
"RequirementIntakeUpdated",
|
|
1791
|
+
"RequirementIntakeInformationRequested",
|
|
1792
|
+
"RequirementIntakeSubmitted",
|
|
1793
|
+
"RequirementIntakeCancelled",
|
|
1794
|
+
"RequirementIntakeArchived"
|
|
1795
|
+
];
|
|
1789
1796
|
export {
|
|
1790
1797
|
ALLOWED_TRANSITIONS,
|
|
1791
1798
|
AllowAllIntakeAuthorizer,
|
package/dist/service.d.ts
CHANGED
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
* The original request is immutable after creation: no API path can change
|
|
14
14
|
* `originalRequest`, and LLM suggestions can never write to it.
|
|
15
15
|
*/
|
|
16
|
-
import { type IntakeQuestionTemplate, type IntakeStatus } from './constants.js';
|
|
17
16
|
import type { IntakeAuthorizer } from './authorization.js';
|
|
17
|
+
import { type IntakeQuestionTemplate, type IntakeStatus } from './constants.js';
|
|
18
18
|
import { IntakeEventEmitter } from './events.js';
|
|
19
19
|
import { type IntakeLogger } from './logger.js';
|
|
20
20
|
import { type IntakeMetrics } from './metrics.js';
|
|
21
|
-
import { type LlmSuggestionGenerator } from './suggestions.js';
|
|
22
21
|
import type { RequirementIntakeStore } from './store.js';
|
|
22
|
+
import { type LlmSuggestionGenerator } from './suggestions.js';
|
|
23
23
|
import type { AddAnswerInput, AttachResourceInput, CreateIntakeInput, IntakeContext, IntakeEvent, IntakeQuestion, LlmSuggestionProposal, RequirementIntakeRecord, UpdateIntakeInput } from './types.js';
|
|
24
24
|
export interface RequirementIntakeServiceOptions {
|
|
25
25
|
store: RequirementIntakeStore;
|
package/dist/validation.d.ts
CHANGED
|
@@ -128,6 +128,8 @@ export declare const createIntakeSchema: z.ZodObject<{
|
|
|
128
128
|
question: z.ZodString;
|
|
129
129
|
required: z.ZodOptional<z.ZodBoolean>;
|
|
130
130
|
}, z.core.$strip>>>;
|
|
131
|
+
isVibeMode: z.ZodOptional<z.ZodBoolean>;
|
|
132
|
+
vibeProtocol: z.ZodOptional<z.ZodAny>;
|
|
131
133
|
}, z.core.$strict>;
|
|
132
134
|
export declare const updateIntakeSchema: z.ZodObject<{
|
|
133
135
|
title: z.ZodOptional<z.ZodString>;
|
|
@@ -146,6 +148,8 @@ export declare const updateIntakeSchema: z.ZodObject<{
|
|
|
146
148
|
constraints: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
147
149
|
providedContext: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
148
150
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
151
|
+
isVibeMode: z.ZodOptional<z.ZodBoolean>;
|
|
152
|
+
vibeProtocol: z.ZodOptional<z.ZodAny>;
|
|
149
153
|
}, z.core.$strict>;
|
|
150
154
|
export declare const answerInputSchema: z.ZodObject<{
|
|
151
155
|
field: z.ZodString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/requirement-intake",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack Requirements Intake — collect, preserve, validate, normalize, and submit unstructured software development requests as structured intake records. Upstream of spec-driven development: it never plans, specifies, or implements.",
|
|
6
6
|
"repository": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"!dist/**/*.map"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@wrongstack/core": "1.0.
|
|
30
|
+
"@wrongstack/core": "1.0.3",
|
|
31
31
|
"zod": "4.4.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|