@company-semantics/contracts 63.0.0 → 63.2.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.
- package/package.json +3 -3
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +103 -10
- package/src/comments/__tests__/schemas.test.ts +2 -0
- package/src/comments/__tests__/suggestion.test.ts +28 -2
- package/src/comments/schemas.ts +26 -0
- package/src/comments/suggestion.ts +36 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@company-semantics/contracts",
|
|
3
|
-
"version": "63.
|
|
3
|
+
"version": "63.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"anchor-corpus:sync": "tsx scripts/anchor-corpus.ts --sync",
|
|
119
119
|
"generate:spec-hash": "tsx scripts/generate-spec-hash.ts",
|
|
120
120
|
"generate:spec-hash:check": "tsx scripts/generate-spec-hash.ts --check",
|
|
121
|
-
"generate:api": "pnpm generate:api-types && pnpm generate:spec-hash && pnpm generate:openapi-routes",
|
|
121
|
+
"generate:api": "pnpm generate:api-types && pnpm generate:spec-hash && pnpm generate:openapi-routes && pnpm file-sizes:pin",
|
|
122
122
|
"generate:api:check": "pnpm generate:api-types:check && pnpm generate:spec-hash:check && pnpm generate:openapi-routes:check",
|
|
123
123
|
"generate:api-types": "openapi-typescript openapi/backend.yaml -o src/api/generated.ts",
|
|
124
124
|
"generate:openapi-routes": "tsx scripts/generate-openapi-routes.ts",
|
|
@@ -181,5 +181,5 @@
|
|
|
181
181
|
"*.md": "markdownlint-cli2",
|
|
182
182
|
"package.json": "node -e \"JSON.parse(require('fs').readFileSync('package.json'))\""
|
|
183
183
|
},
|
|
184
|
-
"securityRequirementsVersion": "
|
|
184
|
+
"securityRequirementsVersion": "b5085eaa2fcf9fee09a3c8d2a9e15eab119800def73c98dc6ab6937d1c6e07b2"
|
|
185
185
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = '387045558d18' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '387045558d1867722a744ddb05cf5ebb7260c54df0ff272b868bd4dd2ad2a973' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -4373,6 +4373,11 @@ export interface components {
|
|
|
4373
4373
|
/** @enum {string} */
|
|
4374
4374
|
origin?: "user" | "proactive";
|
|
4375
4375
|
launch: {
|
|
4376
|
+
/** @constant */
|
|
4377
|
+
kind: "structure-review";
|
|
4378
|
+
/** Format: uuid */
|
|
4379
|
+
proposalId: string;
|
|
4380
|
+
} | {
|
|
4376
4381
|
/** @constant */
|
|
4377
4382
|
kind: "workflow";
|
|
4378
4383
|
/** Format: uuid */
|
|
@@ -6961,12 +6966,19 @@ export interface components {
|
|
|
6961
6966
|
insertedText?: string;
|
|
6962
6967
|
};
|
|
6963
6968
|
body?: string;
|
|
6964
|
-
mentions?: {
|
|
6969
|
+
mentions?: ({
|
|
6970
|
+
/** @constant */
|
|
6971
|
+
kind: "user";
|
|
6965
6972
|
/** Format: uuid */
|
|
6966
6973
|
userId: string;
|
|
6967
6974
|
startOffset: number;
|
|
6968
6975
|
endOffset: number;
|
|
6969
|
-
}
|
|
6976
|
+
} | {
|
|
6977
|
+
/** @constant */
|
|
6978
|
+
kind: "agent";
|
|
6979
|
+
startOffset: number;
|
|
6980
|
+
endOffset: number;
|
|
6981
|
+
})[];
|
|
6970
6982
|
};
|
|
6971
6983
|
/** @description The written reply, and whether it auto-reopened a resolved thread. */
|
|
6972
6984
|
CommentReplyResponse: {
|
|
@@ -6975,12 +6987,19 @@ export interface components {
|
|
|
6975
6987
|
};
|
|
6976
6988
|
CommentReplyRequest: {
|
|
6977
6989
|
body: string;
|
|
6978
|
-
mentions?: {
|
|
6990
|
+
mentions?: ({
|
|
6991
|
+
/** @constant */
|
|
6992
|
+
kind: "user";
|
|
6979
6993
|
/** Format: uuid */
|
|
6980
6994
|
userId: string;
|
|
6981
6995
|
startOffset: number;
|
|
6982
6996
|
endOffset: number;
|
|
6983
|
-
}
|
|
6997
|
+
} | {
|
|
6998
|
+
/** @constant */
|
|
6999
|
+
kind: "agent";
|
|
7000
|
+
startOffset: number;
|
|
7001
|
+
endOffset: number;
|
|
7002
|
+
})[];
|
|
6984
7003
|
};
|
|
6985
7004
|
/** @description The comment after the mutation (redacted projection after delete). */
|
|
6986
7005
|
CommentResponse: {
|
|
@@ -6988,12 +7007,19 @@ export interface components {
|
|
|
6988
7007
|
};
|
|
6989
7008
|
EditCommentRequest: {
|
|
6990
7009
|
body: string;
|
|
6991
|
-
mentions?: {
|
|
7010
|
+
mentions?: ({
|
|
7011
|
+
/** @constant */
|
|
7012
|
+
kind: "user";
|
|
6992
7013
|
/** Format: uuid */
|
|
6993
7014
|
userId: string;
|
|
6994
7015
|
startOffset: number;
|
|
6995
7016
|
endOffset: number;
|
|
6996
|
-
}
|
|
7017
|
+
} | {
|
|
7018
|
+
/** @constant */
|
|
7019
|
+
kind: "agent";
|
|
7020
|
+
startOffset: number;
|
|
7021
|
+
endOffset: number;
|
|
7022
|
+
})[];
|
|
6997
7023
|
};
|
|
6998
7024
|
/** @description The thread after a resolve/reopen transition. */
|
|
6999
7025
|
CommentThreadSummaryResponse: {
|
|
@@ -7026,7 +7052,14 @@ export interface components {
|
|
|
7026
7052
|
};
|
|
7027
7053
|
/** @description A principal who can read the document and may therefore be mentioned. */
|
|
7028
7054
|
CompanyMdMentionableCandidate: {
|
|
7029
|
-
|
|
7055
|
+
principal: {
|
|
7056
|
+
/** @constant */
|
|
7057
|
+
kind: "user";
|
|
7058
|
+
userId: string;
|
|
7059
|
+
} | {
|
|
7060
|
+
/** @constant */
|
|
7061
|
+
kind: "agent";
|
|
7062
|
+
};
|
|
7030
7063
|
displayName: string;
|
|
7031
7064
|
avatarUrl: string | null;
|
|
7032
7065
|
};
|
|
@@ -7107,6 +7140,29 @@ export interface components {
|
|
|
7107
7140
|
/** @enum {string} */
|
|
7108
7141
|
kind: "comment" | "suggestion";
|
|
7109
7142
|
suggestion: components["schemas"]["Suggestion"] | null;
|
|
7143
|
+
origin: {
|
|
7144
|
+
/** @constant */
|
|
7145
|
+
kind: "comment";
|
|
7146
|
+
} | {
|
|
7147
|
+
/** @constant */
|
|
7148
|
+
kind: "doc_mention";
|
|
7149
|
+
byUser: ({
|
|
7150
|
+
/** @constant */
|
|
7151
|
+
kind: "user";
|
|
7152
|
+
userId: string;
|
|
7153
|
+
} | {
|
|
7154
|
+
/** @constant */
|
|
7155
|
+
kind: "agent";
|
|
7156
|
+
}) | null;
|
|
7157
|
+
introducedAt: string;
|
|
7158
|
+
};
|
|
7159
|
+
agentOutcomes: {
|
|
7160
|
+
triggerId: string;
|
|
7161
|
+
/** @enum {string} */
|
|
7162
|
+
status: "pending" | "replied" | "unanswered";
|
|
7163
|
+
reason: ("replies_off" | "mentioner_unavailable" | "delegate_unknown" | "subject_unreadable" | "rate_capped" | "turn_failed") | null;
|
|
7164
|
+
replyCommentId: string | null;
|
|
7165
|
+
}[];
|
|
7110
7166
|
createdByUserId: string | null;
|
|
7111
7167
|
resolvedByUserId: string | null;
|
|
7112
7168
|
resolvedAt: string | null;
|
|
@@ -7155,16 +7211,30 @@ export interface components {
|
|
|
7155
7211
|
Comment: {
|
|
7156
7212
|
id: string;
|
|
7157
7213
|
threadId: string;
|
|
7158
|
-
|
|
7214
|
+
author: ({
|
|
7215
|
+
/** @constant */
|
|
7216
|
+
kind: "user";
|
|
7217
|
+
userId: string;
|
|
7218
|
+
} | {
|
|
7219
|
+
/** @constant */
|
|
7220
|
+
kind: "agent";
|
|
7221
|
+
}) | null;
|
|
7159
7222
|
body: string | null;
|
|
7160
7223
|
editedAt: string | null;
|
|
7161
7224
|
deletedAt: string | null;
|
|
7162
7225
|
createdAt: string;
|
|
7163
7226
|
mentions: components["schemas"]["CommentMention"][];
|
|
7164
7227
|
};
|
|
7165
|
-
/** @description One mention on a comment: the mentioned
|
|
7228
|
+
/** @description One mention on a comment: the principal mentioned, its zero-based exclusive-end UTF-16 range (null until the offset columns exist), and the display name resolved at read time. */
|
|
7166
7229
|
CommentMention: {
|
|
7167
|
-
|
|
7230
|
+
target: {
|
|
7231
|
+
/** @constant */
|
|
7232
|
+
kind: "user";
|
|
7233
|
+
userId: string;
|
|
7234
|
+
} | {
|
|
7235
|
+
/** @constant */
|
|
7236
|
+
kind: "agent";
|
|
7237
|
+
};
|
|
7168
7238
|
startOffset: number | null;
|
|
7169
7239
|
endOffset: number | null;
|
|
7170
7240
|
displayName: string;
|
|
@@ -7191,6 +7261,29 @@ export interface components {
|
|
|
7191
7261
|
/** @enum {string} */
|
|
7192
7262
|
kind: "comment" | "suggestion";
|
|
7193
7263
|
suggestion: components["schemas"]["Suggestion"] | null;
|
|
7264
|
+
origin: {
|
|
7265
|
+
/** @constant */
|
|
7266
|
+
kind: "comment";
|
|
7267
|
+
} | {
|
|
7268
|
+
/** @constant */
|
|
7269
|
+
kind: "doc_mention";
|
|
7270
|
+
byUser: ({
|
|
7271
|
+
/** @constant */
|
|
7272
|
+
kind: "user";
|
|
7273
|
+
userId: string;
|
|
7274
|
+
} | {
|
|
7275
|
+
/** @constant */
|
|
7276
|
+
kind: "agent";
|
|
7277
|
+
}) | null;
|
|
7278
|
+
introducedAt: string;
|
|
7279
|
+
};
|
|
7280
|
+
agentOutcomes: {
|
|
7281
|
+
triggerId: string;
|
|
7282
|
+
/** @enum {string} */
|
|
7283
|
+
status: "pending" | "replied" | "unanswered";
|
|
7284
|
+
reason: ("replies_off" | "mentioner_unavailable" | "delegate_unknown" | "subject_unreadable" | "rate_capped" | "turn_failed") | null;
|
|
7285
|
+
replyCommentId: string | null;
|
|
7286
|
+
}[];
|
|
7194
7287
|
createdByUserId: string | null;
|
|
7195
7288
|
resolvedByUserId: string | null;
|
|
7196
7289
|
resolvedAt: string | null;
|
|
@@ -34,10 +34,36 @@ describe("the vocabulary tuples", () => {
|
|
|
34
34
|
expect([...SUGGESTION_OPS]).toEqual(["insert", "delete", "replace"]);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
it("SUGGESTION_STATUSES is exactly open, accepted and
|
|
37
|
+
it("SUGGESTION_STATUSES is exactly open, accepted, rejected and reverted", () => {
|
|
38
38
|
// The SECOND status level. The thread-level enum stays open|resolved —
|
|
39
39
|
// `./schemas.test.ts` pins that separately — and the decision lives here.
|
|
40
|
-
|
|
40
|
+
//
|
|
41
|
+
// PINNED AS A LIST, NOT A LENGTH, because widening it is the one change on
|
|
42
|
+
// this surface that cannot be walked back: a published `z.enum` refuses a
|
|
43
|
+
// member it has not shipped, and this one is nested inside the thread
|
|
44
|
+
// summary, so an unfamiliar status costs a client the whole document's
|
|
45
|
+
// comments. Failing here is the reminder that adding a member is a
|
|
46
|
+
// coordinated release — readers first, emitter second.
|
|
47
|
+
expect([...SUGGESTION_STATUSES]).toEqual([
|
|
48
|
+
"open",
|
|
49
|
+
"accepted",
|
|
50
|
+
"rejected",
|
|
51
|
+
"reverted",
|
|
52
|
+
]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("accepts a reverted payload", () => {
|
|
56
|
+
// The state a taken-back decision lands in. Parsed here so the widening is
|
|
57
|
+
// proven at the schema, not just in the tuple above.
|
|
58
|
+
expect(
|
|
59
|
+
SuggestionSchema.safeParse(
|
|
60
|
+
makeSuggestion({
|
|
61
|
+
op: "replace",
|
|
62
|
+
insertedText: "x",
|
|
63
|
+
status: "reverted",
|
|
64
|
+
}),
|
|
65
|
+
).success,
|
|
66
|
+
).toBe(true);
|
|
41
67
|
});
|
|
42
68
|
});
|
|
43
69
|
|
package/src/comments/schemas.ts
CHANGED
|
@@ -355,6 +355,32 @@ export const ThreadCapabilitiesSchema = z.object({
|
|
|
355
355
|
* their own suggestion.
|
|
356
356
|
*/
|
|
357
357
|
canWithdraw: z.boolean(),
|
|
358
|
+
/**
|
|
359
|
+
* Take back a decision on a DECIDED suggestion — the complement of
|
|
360
|
+
* `canDecideSuggestion`, exactly as `canReopen` is the complement of
|
|
361
|
+
* `canResolve` one kind over.
|
|
362
|
+
*
|
|
363
|
+
* The edit band, like deciding: undoing an acceptance puts the replaced
|
|
364
|
+
* passage back into the document, which is the same authority as putting the
|
|
365
|
+
* proposal in. A reverted suggestion offers it no longer — `reverted` is
|
|
366
|
+
* terminal, so this is false there as well as on an open one.
|
|
367
|
+
*/
|
|
368
|
+
canRevertSuggestion: z.boolean(),
|
|
369
|
+
/**
|
|
370
|
+
* Delete the whole thread — the conversation, not one comment in it.
|
|
371
|
+
*
|
|
372
|
+
* TRUE FOR BOTH KINDS, and it is the only capability here that does not
|
|
373
|
+
* mention one. A comment thread could previously only be dismantled by
|
|
374
|
+
* deleting its first comment, which cascaded; a suggestion thread could not be
|
|
375
|
+
* deleted at all, because its proposal is not a comment and there was nothing
|
|
376
|
+
* to aim the cascade at. One flag answers both.
|
|
377
|
+
*
|
|
378
|
+
* IT SAYS NOTHING ABOUT THE DOCUMENT. Deleting a thread whose suggestion was
|
|
379
|
+
* accepted leaves the accepted words where they are: they are the document's
|
|
380
|
+
* now, and taking them back is `canRevertSuggestion`'s act, deliberately kept
|
|
381
|
+
* separate so neither one silently performs the other.
|
|
382
|
+
*/
|
|
383
|
+
canDeleteThread: z.boolean(),
|
|
358
384
|
});
|
|
359
385
|
export type ThreadCapabilities = z.infer<typeof ThreadCapabilitiesSchema>;
|
|
360
386
|
|
|
@@ -37,14 +37,43 @@ export const SUGGESTION_OPS = ["insert", "delete", "replace"] as const;
|
|
|
37
37
|
export type SuggestionOp = (typeof SUGGESTION_OPS)[number];
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* open -> accepted | rejected
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
40
|
+
* `open -> accepted | rejected -> reverted`. This is the SECOND status level —
|
|
41
|
+
* the thread-level `status` enum stays exactly `open | resolved`, and a decided
|
|
42
|
+
* suggestion arrives as thread status `resolved` with this field carrying which
|
|
43
|
+
* way it went. Widening the closed thread enum instead would be a parse outage
|
|
44
|
+
* for every deployed client.
|
|
45
|
+
*
|
|
46
|
+
* A DECISION IS NO LONGER THE LAST WORD, BUT IT IS STILL ONE-WAY. This tuple
|
|
47
|
+
* read `open | accepted | rejected` with "terminal states are terminal: there is
|
|
48
|
+
* no reopen for a decided suggestion" written beside it, and that is now false:
|
|
49
|
+
* people are allowed to change their minds, and undoing an acceptance restores
|
|
50
|
+
* the passage the edit replaced. What has NOT changed is that the arrow never
|
|
51
|
+
* points back to `open`. `reverted` is its own terminal state rather than a
|
|
52
|
+
* return to the start, for two reasons — a reverted proposal is a decision
|
|
53
|
+
* somebody took and then took back, which is a different fact from one nobody
|
|
54
|
+
* has answered yet; and an `open` suggestion whose document still carries an
|
|
55
|
+
* application receipt is exactly the shape the server's reconciler treats as
|
|
56
|
+
* proof of an unacknowledged accept, so returning one to `open` would have it
|
|
57
|
+
* silently re-accepted by background maintenance.
|
|
58
|
+
*
|
|
59
|
+
* WIDENING THIS TUPLE IS ORDERED, NOT FREE. `SuggestionSchema` below is a
|
|
60
|
+
* `z.strictObject` nested inside `CommentThreadSummarySchema`, so for anyone who
|
|
61
|
+
* PARSES a thread list, one row carrying a status they do not know fails the
|
|
62
|
+
* whole list — every comment on that document, not just the odd suggestion — and
|
|
63
|
+
* it fails the first time somebody reverts rather than at deploy. No consumer in
|
|
64
|
+
* this workspace parses these at runtime today (the app is typed off the
|
|
65
|
+
* generated spec; the backend validates against its own local copies), which was
|
|
66
|
+
* checked rather than assumed, so this package leads the release and the emitter
|
|
67
|
+
* follows. The next person to add a member owes that check again for their own
|
|
68
|
+
* consumers — which is why `__tests__/suggestion.test.ts` pins this list
|
|
69
|
+
* exactly. See the ADR with slug `suggestion-revert-vocabulary`.
|
|
46
70
|
*/
|
|
47
|
-
export const SUGGESTION_STATUSES = [
|
|
71
|
+
export const SUGGESTION_STATUSES = [
|
|
72
|
+
"open",
|
|
73
|
+
"accepted",
|
|
74
|
+
"rejected",
|
|
75
|
+
"reverted",
|
|
76
|
+
] as const;
|
|
48
77
|
export type SuggestionStatus = (typeof SUGGESTION_STATUSES)[number];
|
|
49
78
|
|
|
50
79
|
/**
|