@owlmeans/viable-common 0.0.24 → 0.0.26

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 (131) hide show
  1. package/README.md +4 -4
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/agent-presentation/SKILL.md +1 -1
  4. package/agent-meta/skills/viable-common/SKILL.md +115 -13
  5. package/build/blueprint/case.d.ts.map +1 -1
  6. package/build/blueprint/case.js +58 -16
  7. package/build/blueprint/case.js.map +1 -1
  8. package/build/blueprint/resolve.d.ts.map +1 -1
  9. package/build/blueprint/resolve.js +3 -0
  10. package/build/blueprint/resolve.js.map +1 -1
  11. package/build/blueprint/types.d.ts +44 -2
  12. package/build/blueprint/types.d.ts.map +1 -1
  13. package/build/blueprint/types.js +35 -1
  14. package/build/blueprint/types.js.map +1 -1
  15. package/build/branding.d.ts +5 -1
  16. package/build/branding.d.ts.map +1 -1
  17. package/build/branding.js +6 -0
  18. package/build/branding.js.map +1 -1
  19. package/build/connect/consts.d.ts +31 -43
  20. package/build/connect/consts.d.ts.map +1 -1
  21. package/build/connect/consts.js +34 -48
  22. package/build/connect/consts.js.map +1 -1
  23. package/build/connect/entrypoints.d.ts +36 -19
  24. package/build/connect/entrypoints.d.ts.map +1 -1
  25. package/build/connect/entrypoints.js +23 -4
  26. package/build/connect/entrypoints.js.map +1 -1
  27. package/build/connect/index.d.ts +0 -1
  28. package/build/connect/index.d.ts.map +1 -1
  29. package/build/connect/index.js +0 -1
  30. package/build/connect/index.js.map +1 -1
  31. package/build/connect/ops.d.ts +1 -4
  32. package/build/connect/ops.d.ts.map +1 -1
  33. package/build/connect/references.d.ts +33 -16
  34. package/build/connect/references.d.ts.map +1 -1
  35. package/build/connect/references.js +7 -1
  36. package/build/connect/references.js.map +1 -1
  37. package/build/connect/schemas.d.ts +17 -3
  38. package/build/connect/schemas.d.ts.map +1 -1
  39. package/build/connect/schemas.js +31 -5
  40. package/build/connect/schemas.js.map +1 -1
  41. package/build/connect/types.d.ts +63 -66
  42. package/build/connect/types.d.ts.map +1 -1
  43. package/build/consts.d.ts +1 -1
  44. package/build/consts.d.ts.map +1 -1
  45. package/build/consts.js +3 -0
  46. package/build/consts.js.map +1 -1
  47. package/build/design/runtime.d.ts +1 -1
  48. package/build/design/runtime.d.ts.map +1 -1
  49. package/build/metadata/types.d.ts +8 -0
  50. package/build/metadata/types.d.ts.map +1 -1
  51. package/build/metadata/types.js.map +1 -1
  52. package/build/planning/consts.d.ts +1 -1
  53. package/build/planning/consts.js +1 -1
  54. package/build/planning/helpers.d.ts +2 -1
  55. package/build/planning/helpers.d.ts.map +1 -1
  56. package/build/planning/helpers.js +5 -2
  57. package/build/planning/helpers.js.map +1 -1
  58. package/build/planning/index.d.ts +1 -0
  59. package/build/planning/index.d.ts.map +1 -1
  60. package/build/planning/index.js +1 -0
  61. package/build/planning/index.js.map +1 -1
  62. package/build/planning/landing.d.ts +25 -0
  63. package/build/planning/landing.d.ts.map +1 -0
  64. package/build/planning/landing.js +38 -0
  65. package/build/planning/landing.js.map +1 -0
  66. package/build/planning/schemas.d.ts.map +1 -1
  67. package/build/planning/schemas.js +13 -0
  68. package/build/planning/schemas.js.map +1 -1
  69. package/build/planning/types.d.ts +28 -3
  70. package/build/planning/types.d.ts.map +1 -1
  71. package/build/scaffold/consts.d.ts +8 -0
  72. package/build/scaffold/consts.d.ts.map +1 -1
  73. package/build/scaffold/consts.js +7 -0
  74. package/build/scaffold/consts.js.map +1 -1
  75. package/build/scaffold/schemas.d.ts.map +1 -1
  76. package/build/scaffold/schemas.js +257 -12
  77. package/build/scaffold/schemas.js.map +1 -1
  78. package/build/scaffold/types.d.ts +119 -4
  79. package/build/scaffold/types.d.ts.map +1 -1
  80. package/build/skills/catalogue.d.ts.map +1 -1
  81. package/build/skills/catalogue.js +150 -39
  82. package/build/skills/catalogue.js.map +1 -1
  83. package/build/skills/consts.d.ts +5 -0
  84. package/build/skills/consts.d.ts.map +1 -1
  85. package/build/skills/consts.js +8 -0
  86. package/build/skills/consts.js.map +1 -1
  87. package/build/skills/roles.d.ts.map +1 -1
  88. package/build/skills/roles.js +11 -5
  89. package/build/skills/roles.js.map +1 -1
  90. package/build/types.d.ts +30 -0
  91. package/build/types.d.ts.map +1 -1
  92. package/package.json +8 -8
  93. package/src/blueprint/case.ts +64 -16
  94. package/src/blueprint/resolve.ts +3 -0
  95. package/src/blueprint/types.ts +57 -1
  96. package/src/branding.ts +6 -0
  97. package/src/connect/consts.ts +32 -45
  98. package/src/connect/entrypoints.ts +51 -23
  99. package/src/connect/index.ts +0 -1
  100. package/src/connect/ops.ts +1 -4
  101. package/src/connect/references.ts +48 -29
  102. package/src/connect/schemas.ts +40 -11
  103. package/src/connect/types.ts +66 -69
  104. package/src/consts.ts +3 -0
  105. package/src/design/runtime.ts +1 -1
  106. package/src/metadata/types.ts +8 -0
  107. package/src/planning/consts.ts +1 -1
  108. package/src/planning/helpers.ts +5 -2
  109. package/src/planning/index.ts +1 -0
  110. package/src/planning/landing.ts +43 -0
  111. package/src/planning/schemas.ts +13 -0
  112. package/src/planning/types.ts +29 -3
  113. package/src/scaffold/consts.ts +10 -0
  114. package/src/scaffold/schemas.ts +262 -13
  115. package/src/scaffold/types.ts +105 -5
  116. package/src/skills/catalogue.ts +151 -39
  117. package/src/skills/consts.ts +8 -0
  118. package/src/skills/roles.ts +11 -5
  119. package/src/types.ts +30 -0
  120. package/tests/blueprint.spec.ts +98 -0
  121. package/tests/branding.spec.ts +21 -1
  122. package/tests/connect-convert.spec.ts +2 -8
  123. package/tests/connect-entrypoints.spec.ts +49 -28
  124. package/tests/planning.spec.ts +56 -1
  125. package/tests/scaffold.spec.ts +131 -0
  126. package/tests/skills.spec.ts +63 -2
  127. package/build/connect/jobs.d.ts +0 -25
  128. package/build/connect/jobs.d.ts.map +0 -1
  129. package/build/connect/jobs.js +0 -29
  130. package/build/connect/jobs.js.map +0 -1
  131. package/src/connect/jobs.ts +0 -40
@@ -5,12 +5,13 @@ import { connect } from './consts.js'
5
5
  import type { ConnectOp, ConnectOpResult } from './ops.js'
6
6
  import type { ConverterProjectLlmBody } from '../convert/index.js'
7
7
  import type {
8
- ConnectAttachBody, ConnectCapabilitiesView, ConnectConfirmBody, ConnectCreateBody, ConnectJob,
9
- ConnectConvertCreateBody, ConnectConvertProceedBody, ConnectInquiryAnswerBody, ConnectJobParams,
8
+ ConnectAttachBody, ConnectCapabilitiesView, ConnectConfirmBody, ConnectCreateBody,
9
+ ConnectConvertCreateBody, ConnectConvertProceedBody, ConnectInquiryAnswerBody,
10
10
  ConnectModifyBody, ConnectOpSubmission, ConnectPipelineParams, ConnectPipelineResumeBody,
11
- ConnectPipelineState, ConnectProjectLlmBody, ConnectProjectSettings, ConnectProjectStatus,
12
- ConnectProjectSummary, ConnectSessionOpen, ConnectSessionParams, ConnectSessionView,
13
- ConnectWaitQuery, ConversionStatusView, ConvertCheck,
11
+ ConnectPipelineState, ConnectProjectBranding, ConnectProjectBrandingSave, ConnectProjectLlmBody,
12
+ ConnectProjectSettings, ConnectProjectStatus, ConnectProjectSummary, ConnectPullQuery,
13
+ ConnectSessionOpen, ConnectSessionParams, ConnectSessionView, ConnectStoryStatus,
14
+ ConversionStatusView, ConvertCheck,
14
15
  } from './types.js'
15
16
 
16
17
  type ConnectReference<Request extends RequestShape, Response> =
@@ -26,39 +27,47 @@ export interface ConnectReferences {
26
27
  close: ConnectReference<{ params: ConnectSessionParams }, ConnectSessionView>
27
28
  }
28
29
  op: {
29
- pull: ConnectReference<{ params: ConnectSessionParams, query: ConnectWaitQuery }, ConnectOp[]>
30
+ pull: ConnectReference<{ params: ConnectSessionParams, query: ConnectPullQuery }, ConnectOp[]>
30
31
  submit: ConnectReference<{
31
32
  params: { sessionId: string, opId: string }, body: ConnectOpResult
32
33
  }, ConnectOpSubmission>
33
34
  }
34
35
  project: {
35
- create: ConnectReference<{ body: ConnectCreateBody }, ConnectJob>
36
- confirm: ConnectReference<{ params: { id: string }, body: ConnectConfirmBody }, ConnectJob>
36
+ create: ConnectReference<{ body: ConnectCreateBody }, ConnectProjectStatus>
37
+ confirm: ConnectReference<{ params: { id: string }, body: ConnectConfirmBody }, ConnectProjectStatus>
37
38
  list: ConnectReference<{}, ConnectProjectSummary[]>
38
39
  status: ConnectReference<{ params: { id: string } }, ConnectProjectStatus>
39
40
  attach: ConnectReference<{ body: ConnectAttachBody }, ConnectProjectStatus>
40
- reinit: ConnectReference<{ params: { id: string } }, ConnectJob>
41
- modify: ConnectReference<{ params: { id: string }, body: ConnectModifyBody }, ConnectJob>
41
+ reinit: ConnectReference<{ params: { id: string } }, ConnectProjectStatus>
42
+ modify: ConnectReference<{ params: { id: string }, body: ConnectModifyBody }, ConnectProjectStatus>
42
43
  settings: ConnectReference<{ params: { id: string } }, ConnectProjectSettings>
43
44
  llm: ConnectReference<{ params: { id: string }, body: ConnectProjectLlmBody }, ConnectProjectSettings>
44
45
  converterLlm: ConnectReference<{
45
46
  params: { id: string }, body: ConverterProjectLlmBody
46
47
  }, ConnectProjectSettings>
47
- job: ConnectReference<{ params: ConnectJobParams, query: ConnectWaitQuery }, ConnectJob>
48
+ branding: {
49
+ get: ConnectReference<{ params: { id: string } }, ConnectProjectBranding>
50
+ save: ConnectReference<{
51
+ params: { id: string }, body: ConnectProjectBrandingSave
52
+ }, ConnectProjectBranding>
53
+ }
54
+ }
55
+ story: {
56
+ status: ConnectReference<{ params: { id: string, storyId: string } }, ConnectStoryStatus>
48
57
  }
49
58
  files: {
50
59
  list: ConnectReference<{ params: { id: string } }, string[]>
51
60
  }
52
61
  convert: {
53
- create: ConnectReference<{ body: ConnectConvertCreateBody }, ConnectJob>
62
+ create: ConnectReference<{ body: ConnectConvertCreateBody }, ConversionStatusView>
54
63
  check: ConnectReference<{ params: { id: string } }, ConvertCheck>
55
- start: ConnectReference<{ params: { id: string } }, ConnectJob>
64
+ start: ConnectReference<{ params: { id: string } }, ConversionStatusView>
56
65
  proceed: ConnectReference<{
57
66
  params: { id: string }, body: ConnectConvertProceedBody
58
- }, ConnectJob>
59
- cancel: ConnectReference<{ params: { id: string } }, ConnectJob>
67
+ }, ConversionStatusView>
68
+ cancel: ConnectReference<{ params: { id: string } }, ConversionStatusView>
60
69
  status: ConnectReference<{ params: { id: string } }, ConversionStatusView>
61
- purge: ConnectReference<{ params: { id: string } }, ConnectJob>
70
+ purge: ConnectReference<{ params: { id: string } }, ConversionStatusView>
62
71
  }
63
72
  inquiry: {
64
73
  answer: ConnectReference<{
@@ -69,7 +78,7 @@ export interface ConnectReferences {
69
78
  state: ConnectReference<{ params: ConnectPipelineParams }, ConnectPipelineState>
70
79
  resume: ConnectReference<{
71
80
  params: ConnectPipelineParams, body: ConnectPipelineResumeBody
72
- }, ConnectJob>
81
+ }, ConnectPipelineState>
73
82
  }
74
83
  }
75
84
 
@@ -88,19 +97,19 @@ export const connectRef: ConnectReferences = {
88
97
  close: entrypointRef<{ params: ConnectSessionParams }, ConnectSessionView>(connect.session.close),
89
98
  },
90
99
  op: {
91
- pull: entrypointRef<{ params: ConnectSessionParams, query: ConnectWaitQuery }, ConnectOp[]>(connect.op.pull),
100
+ pull: entrypointRef<{ params: ConnectSessionParams, query: ConnectPullQuery }, ConnectOp[]>(connect.op.pull),
92
101
  submit: entrypointRef<{
93
102
  params: { sessionId: string, opId: string }, body: ConnectOpResult
94
103
  }, ConnectOpSubmission>(connect.op.submit),
95
104
  },
96
105
  project: {
97
- create: entrypointRef<{ body: ConnectCreateBody }, ConnectJob>(connect.project.create),
98
- confirm: entrypointRef<{ params: { id: string }, body: ConnectConfirmBody }, ConnectJob>(connect.project.confirm),
106
+ create: entrypointRef<{ body: ConnectCreateBody }, ConnectProjectStatus>(connect.project.create),
107
+ confirm: entrypointRef<{ params: { id: string }, body: ConnectConfirmBody }, ConnectProjectStatus>(connect.project.confirm),
99
108
  list: entrypointRef<{}, ConnectProjectSummary[]>(connect.project.list),
100
109
  status: entrypointRef<{ params: { id: string } }, ConnectProjectStatus>(connect.project.status),
101
110
  attach: entrypointRef<{ body: ConnectAttachBody }, ConnectProjectStatus>(connect.project.attach),
102
- reinit: entrypointRef<{ params: { id: string } }, ConnectJob>(connect.project.reinit),
103
- modify: entrypointRef<{ params: { id: string }, body: ConnectModifyBody }, ConnectJob>(connect.project.modify),
111
+ reinit: entrypointRef<{ params: { id: string } }, ConnectProjectStatus>(connect.project.reinit),
112
+ modify: entrypointRef<{ params: { id: string }, body: ConnectModifyBody }, ConnectProjectStatus>(connect.project.modify),
104
113
  settings: entrypointRef<{ params: { id: string } }, ConnectProjectSettings>(connect.project.settings),
105
114
  llm: entrypointRef<{
106
115
  params: { id: string }, body: ConnectProjectLlmBody
@@ -108,20 +117,30 @@ export const connectRef: ConnectReferences = {
108
117
  converterLlm: entrypointRef<{
109
118
  params: { id: string }, body: ConverterProjectLlmBody
110
119
  }, ConnectProjectSettings>(connect.project.converterLlm),
111
- job: entrypointRef<{ params: ConnectJobParams, query: ConnectWaitQuery }, ConnectJob>(connect.project.job),
120
+ branding: {
121
+ get: entrypointRef<{ params: { id: string } }, ConnectProjectBranding>(connect.project.branding.get),
122
+ save: entrypointRef<{
123
+ params: { id: string }, body: ConnectProjectBrandingSave
124
+ }, ConnectProjectBranding>(connect.project.branding.save),
125
+ },
126
+ },
127
+ story: {
128
+ status: entrypointRef<{
129
+ params: { id: string, storyId: string }
130
+ }, ConnectStoryStatus>(connect.story.status),
112
131
  },
113
132
  convert: {
114
- create: entrypointRef<{ body: ConnectConvertCreateBody }, ConnectJob>(connect.convert.create),
133
+ create: entrypointRef<{ body: ConnectConvertCreateBody }, ConversionStatusView>(connect.convert.create),
115
134
  check: entrypointRef<{ params: { id: string } }, ConvertCheck>(connect.convert.check),
116
- start: entrypointRef<{ params: { id: string } }, ConnectJob>(connect.convert.start),
135
+ start: entrypointRef<{ params: { id: string } }, ConversionStatusView>(connect.convert.start),
117
136
  proceed: entrypointRef<{
118
137
  params: { id: string }, body: ConnectConvertProceedBody
119
- }, ConnectJob>(connect.convert.proceed),
120
- cancel: entrypointRef<{ params: { id: string } }, ConnectJob>(connect.convert.cancel),
138
+ }, ConversionStatusView>(connect.convert.proceed),
139
+ cancel: entrypointRef<{ params: { id: string } }, ConversionStatusView>(connect.convert.cancel),
121
140
  status: entrypointRef<{
122
141
  params: { id: string }
123
142
  }, ConversionStatusView>(connect.convert.status),
124
- purge: entrypointRef<{ params: { id: string } }, ConnectJob>(connect.convert.purge),
143
+ purge: entrypointRef<{ params: { id: string } }, ConversionStatusView>(connect.convert.purge),
125
144
  },
126
145
  inquiry: {
127
146
  answer: entrypointRef<{
@@ -135,6 +154,6 @@ export const connectRef: ConnectReferences = {
135
154
  state: entrypointRef<{ params: ConnectPipelineParams }, ConnectPipelineState>(connect.pipeline.state),
136
155
  resume: entrypointRef<{
137
156
  params: ConnectPipelineParams, body: ConnectPipelineResumeBody
138
- }, ConnectJob>(connect.pipeline.resume),
157
+ }, ConnectPipelineState>(connect.pipeline.resume),
139
158
  },
140
159
  }
@@ -1,15 +1,17 @@
1
1
  import type { JSONSchemaType } from 'ajv'
2
2
  import { ConversionDecision, OriginKind } from '../convert/consts.js'
3
3
  import {
4
- CONNECT_INQUIRY_MAX_TEXT, ConnectHarness, ConnectLlm, ConnectOpErrorKind, ConnectSessionStatus,
5
- ConnectTarget, ConnectTransport, ModelTaskResultKind, ModelTier
4
+ CONNECT_BRANDING_COPYRIGHT_MAX, CONNECT_BRANDING_GOOGLE_TAG_MAX,
5
+ CONNECT_BRANDING_ORGANIZATION_MAX, CONNECT_BRANDING_URL_MAX, CONNECT_INQUIRY_MAX_TEXT,
6
+ ConnectHarness, ConnectLlm, ConnectOpErrorKind, ConnectSessionStatus, ConnectTarget,
7
+ ConnectTransport, ModelTaskResultKind, ModelTier
6
8
  } from './consts.js'
7
9
  import type { ConnectOpResult, InquiryAnswerPayload } from './ops.js'
8
10
  import type {
9
11
  ConnectAttachBody, ConnectConfirmBody, ConnectConvertCreateBody, ConnectConvertProceedBody,
10
- ConnectCreateBody, ConnectJobParams, ConnectLlmBody, ConnectModifyBody, ConnectPipelineParams,
11
- ConnectPipelineResumeBody, ConnectProjectLlmBody, ConnectSession, ConnectSessionOpen,
12
- ConnectSessionParams, ConnectWaitQuery
12
+ ConnectCreateBody, ConnectLlmBody, ConnectModifyBody, ConnectPipelineParams,
13
+ ConnectPipelineResumeBody, ConnectProjectBrandingSave, ConnectProjectLlmBody, ConnectSession,
14
+ ConnectSessionOpen, ConnectPullQuery, ConnectSessionParams
13
15
  } from './types.js'
14
16
 
15
17
  /**
@@ -140,12 +142,12 @@ export const ConnectOpResultSchema = {
140
142
  additionalProperties: false,
141
143
  } as unknown as JSONSchemaType<ConnectOpResult>
142
144
 
143
- export const ConnectWaitQuerySchema = {
145
+ export const ConnectPullQuerySchema = {
144
146
  type: 'object',
145
147
  properties: { wait: { type: 'integer', minimum: 0, maximum: 45, nullable: true } },
146
148
  required: [],
147
149
  additionalProperties: false,
148
- } as JSONSchemaType<ConnectWaitQuery>
150
+ } as JSONSchemaType<ConnectPullQuery>
149
151
 
150
152
  /** Every project-scoped connector route addresses the project by `:id`. */
151
153
  export const ConnectProjectIdSchema = {
@@ -162,12 +164,12 @@ export const ConnectOpParamsSchema = {
162
164
  additionalProperties: false,
163
165
  } as JSONSchemaType<{ sessionId: string, opId: string }>
164
166
 
165
- export const ConnectJobParamsSchema = {
167
+ export const ConnectStoryParamsSchema = {
166
168
  type: 'object',
167
- properties: { id: idValue, jobId: { type: 'string', minLength: 1, maxLength: 256 } },
168
- required: ['id', 'jobId'],
169
+ properties: { id: idValue, storyId: idValue },
170
+ required: ['id', 'storyId'],
169
171
  additionalProperties: false,
170
- } as JSONSchemaType<ConnectJobParams>
172
+ } as JSONSchemaType<{ id: string, storyId: string }>
171
173
 
172
174
  export const ConnectCreateBodySchema = {
173
175
  type: 'object',
@@ -313,6 +315,33 @@ export const ConnectProjectLlmBodySchema = {
313
315
  additionalProperties: false,
314
316
  } as unknown as JSONSchemaType<ConnectProjectLlmBody>
315
317
 
318
+ /**
319
+ * The branding patch a connector saves.
320
+ *
321
+ * STRUCTURAL only — lengths and types. What makes a value acceptable (a non-empty copyright and
322
+ * organization, a legal link that is `https://` or a same-origin path, a real Google tag id) is the
323
+ * platform's rule, applied by the handler to the MERGED record with the same checks the web form
324
+ * uses; a pattern repeated here would be a second copy of those rules free to drift from the first.
325
+ * No `pattern`, and no `enum` on the tag: a connector and the platform deploy apart, and a tag kind
326
+ * Google adds later must be refused by the rule that knows about it, not by a stale wire schema.
327
+ */
328
+ export const ConnectProjectBrandingSaveSchema = {
329
+ type: 'object',
330
+ properties: {
331
+ copyright: {
332
+ type: 'string', minLength: 1, maxLength: CONNECT_BRANDING_COPYRIGHT_MAX, nullable: true,
333
+ },
334
+ organizationName: {
335
+ type: 'string', minLength: 1, maxLength: CONNECT_BRANDING_ORGANIZATION_MAX, nullable: true,
336
+ },
337
+ termsUrl: { type: 'string', maxLength: CONNECT_BRANDING_URL_MAX, nullable: true },
338
+ privacyUrl: { type: 'string', maxLength: CONNECT_BRANDING_URL_MAX, nullable: true },
339
+ googleTag: { type: 'string', maxLength: CONNECT_BRANDING_GOOGLE_TAG_MAX, nullable: true },
340
+ },
341
+ required: [],
342
+ additionalProperties: false,
343
+ } as unknown as JSONSchemaType<ConnectProjectBrandingSave>
344
+
316
345
  export const ModelTaskResultSchema = {
317
346
  type: 'object',
318
347
  properties: {
@@ -4,8 +4,8 @@ import type {
4
4
  OriginState, StoryEstimateBand
5
5
  } from '../convert/index.js'
6
6
  import type {
7
- ConnectExecutor, ConnectHarness, ConnectJobBlock, ConnectJobKind, ConnectJobStatus, ConnectLlm,
8
- ConnectSessionStatus, ConnectTarget, ConnectTransport, ModelTier
7
+ ConnectExecutor, ConnectHarness, ConnectLlm, ConnectSessionStatus, ConnectTarget,
8
+ ConnectTransport, ConnectWaitReason, ModelTier
9
9
  } from './consts.js'
10
10
  import type { InquiryAnswerPayload, InquiryPayload } from './ops.js'
11
11
 
@@ -82,68 +82,22 @@ export interface ConnectSessionView {
82
82
  expiresAt: string
83
83
  }
84
84
 
85
- /**
86
- * A derived view of "what the platform is doing for this project right now".
87
- *
88
- * Never stored. It is composed per request from the project lock, the slot record, the story
89
- * card, the latest pipeline run row and the operations queued for the project — the same facts
90
- * the manager UI reads, arranged for a caller that has one question ("may I stop waiting?") and
91
- * one follow-up ("what do I call next?").
92
- *
93
- * Its `id` is composed and parsed only through `jobIdOf` / `parseJobId`.
94
- */
95
- export interface ConnectJob {
96
- id: string
97
- kind: ConnectJobKind
98
- status: ConnectJobStatus
99
- /** The project CARD id. */
100
- projectId: string
101
- /**
102
- * The story CARD id — never the story's code.
103
- *
104
- * The name is kept because a parent agent reads it: a wire field name is that agent's
105
- * vocabulary and is never renamed, only re-documented.
106
- */
107
- storyId?: string
108
- runId?: string
109
- /** The pipeline step in flight, when a run row says. */
110
- phase?: string
111
- progress?: ConnectJobProgress
112
- blockedOn?: ConnectJobBlock
113
- /**
114
- * The question a parked run is waiting on — present exactly when it is blocked on one.
115
- *
116
- * Carried on the job rather than left to a second lookup because a parent reads a job and
117
- * nothing else while it polls: a run that stopped for a person, described only as "blocked",
118
- * is a run whose parent waits out the timeout for a question it was never shown. It is also
119
- * the ONLY way back to a question whose operation timed out while nobody was attached — the
120
- * connector's own queue holds nothing at that point.
121
- */
122
- inquiry?: InquiryPayload
123
- /** One sentence a parent agent can show a human. */
124
- message?: string
125
- /** Present on `Failed`, and on `Done` where the run recorded a warning. */
126
- error?: string
127
- /** Kind-specific payload once `Done`. */
128
- result?: Record<string, unknown>
129
- startedAt?: string
130
- updatedAt: string
85
+ export interface ConnectPullQuery {
86
+ /** Seconds to wait before answering; clamped to the pull ceiling. */
87
+ wait?: number
131
88
  }
132
89
 
133
- export interface ConnectJobProgress {
90
+ export interface ConnectRunStatus {
91
+ runId: string
92
+ pipeline: string
93
+ status: string
134
94
  step?: string
135
95
  completed: string[]
136
96
  pending: string[]
137
- }
138
-
139
- export interface ConnectJobParams {
140
- id: string
141
- jobId: string
142
- }
143
-
144
- export interface ConnectWaitQuery {
145
- /** Seconds to wait before answering; clamped to the pull ceiling. */
146
- wait?: number
97
+ warnings?: string[]
98
+ error?: string
99
+ startedAt?: string
100
+ updatedAt?: string
147
101
  }
148
102
 
149
103
  /** What a connector needs to know about a project in one call. */
@@ -181,18 +135,30 @@ export interface ConnectProjectStatus {
181
135
  }
182
136
  production?: { id: string, status: string, host?: string }
183
137
  agent: { locked: boolean, task?: string, lockedAt?: string }
184
- run?: {
185
- runId: string
186
- pipeline: string
187
- status: string
188
- step?: string
189
- completed: string[]
190
- pending: string[]
191
- error?: string
192
- }
138
+ run?: ConnectRunStatus
139
+ waitingFor?: ConnectWaitReason
140
+ pendingInquiry?: InquiryPayload
193
141
  session?: ConnectSessionView
194
142
  /** Set for a local target: the connector should not offer cloud-only operations. */
195
143
  local: boolean
144
+ updatedAt: string
145
+ }
146
+
147
+ /** A story card composed with its deterministic development run. */
148
+ export interface ConnectStoryStatus {
149
+ projectId: string
150
+ story: {
151
+ id: string
152
+ code: string
153
+ title: string
154
+ status: string
155
+ intrinsic: string
156
+ warning?: string
157
+ }
158
+ run?: ConnectRunStatus
159
+ waitingFor?: ConnectWaitReason
160
+ pendingInquiry?: InquiryPayload
161
+ updatedAt: string
196
162
  }
197
163
 
198
164
  /** The record a local project keeps so a later session knows what it is. */
@@ -217,7 +183,7 @@ export interface ConnectProfileSettingsView extends ConnectProfileSettings {
217
183
  * The profile's preference for who performs a CONVERSION's model calls.
218
184
  *
219
185
  * Its own setting rather than a reading of `llmMode`, because the two answer for different
220
- * work: a conversion reads somebody else's whole repository, which is the one job where handing
186
+ * work: a conversion reads somebody else's whole repository, which is the one case where handing
221
187
  * the inference to the parent agent is the cheap default rather than the experimental option.
222
188
  *
223
189
  * OPTIONAL for the same reason {@link ConnectCapabilitiesView.defaults} carries `converterLlm`
@@ -257,6 +223,34 @@ export interface ConnectProjectLlmBody {
257
223
  llmMode: ConnectLlm | null
258
224
  }
259
225
 
226
+ /**
227
+ * A project's branding as a connector reads it — what the generated application says about who
228
+ * made it, and the Google tag it loads.
229
+ *
230
+ * Every field is a string, `''` when unset, in the platform's own branding vocabulary. The
231
+ * platform credit is absent on purpose: hiding it is a paid capability behind its own gated route,
232
+ * and neither reading nor saving this record may reach it.
233
+ */
234
+ export interface ConnectProjectBranding {
235
+ /** The copyright line in the application's footer. Never empty once saved. */
236
+ copyright: string
237
+ /** The organization's display name. Never empty once saved. */
238
+ organizationName: string
239
+ /** `''`, an `https://` URL, or a same-origin path such as `/terms` (the generated page). */
240
+ termsUrl: string
241
+ /** `''`, an `https://` URL, or a same-origin path such as `/privacy` (the generated page). */
242
+ privacyUrl: string
243
+ /** `''`, or a Google tag id: `GTM-…`, `G-…`, `GT-…`, `AW-…`, `DC-…`. */
244
+ googleTag: string
245
+ }
246
+
247
+ /**
248
+ * A PATCH of a project's branding: every field optional, and an absent field keeps its current
249
+ * value. The platform merges it over what is stored, validates the result as a whole with the
250
+ * rules the web form uses, and answers the merged record.
251
+ */
252
+ export interface ConnectProjectBrandingSave extends Partial<ConnectProjectBranding> {}
253
+
260
254
  /** What the platform tells a connector about itself. */
261
255
  export interface ConnectCapabilitiesView {
262
256
  /** Tier → the platform role names that will be asked for at that tier. */
@@ -397,6 +391,7 @@ export interface ConversionStatusView {
397
391
  runId?: string
398
392
  /** Set exactly when `status` is `Waiting`: the question the run stopped on. */
399
393
  pendingInquiry?: InquiryPayload
394
+ waitingFor?: ConnectWaitReason
400
395
  lastError?: string
401
396
  updatedAt: string
402
397
  }
@@ -428,6 +423,8 @@ export interface ConnectPipelineState {
428
423
  failedAt?: string
429
424
  error?: string
430
425
  note?: string
426
+ waitingFor?: ConnectWaitReason
427
+ pendingInquiry?: InquiryPayload
431
428
  attempts: number
432
429
  startedAt: string
433
430
  heartbeatAt: string
package/src/consts.ts CHANGED
@@ -17,6 +17,9 @@ export const metadataConfigs = [
17
17
  'brandingPrivacyUrl',
18
18
  'brandingCredit',
19
19
  'brandingHideCreditIntent',
20
+ // Optional in `SlotConstMetadata`: omitted from a push while unset (an older publisher refuses
21
+ // an undeclared key), so an empty stored row must never be delivered as `''`.
22
+ 'brandingGoogleTag',
20
23
  ] satisfies (keyof NonSecretScalarSlotMetadata)[]
21
24
 
22
25
  export const metadataLists = [
@@ -40,7 +40,7 @@ export const isEphemeralActor = (actor?: StoryActor): boolean =>
40
40
  export interface StoryDesignJob {
41
41
  /** The queue it is enqueued onto. */
42
42
  queue: string
43
- /** The job name, which IS its entrypoint alias — `app.job.<name>`. */
43
+ /** The job name, which becomes the backend-only `job:<name>` protocol alias. */
44
44
  name: string
45
45
  /** The processor module, relative to the worker package's `src`. */
46
46
  path: string
@@ -116,6 +116,12 @@ export interface StoryMeta extends Record<string, unknown> {
116
116
  * that moves section when it is implemented leaves its own dashboard behind.
117
117
  */
118
118
  section?: string
119
+ /**
120
+ * This is the landing gate's story — a guest starts it on the landing page and continues here
121
+ * after signing in. Copied from the card's `fields.landing`; written only when `true`, so every
122
+ * other story's file keeps the shape it always had.
123
+ */
124
+ landing?: boolean
119
125
  entity: string
120
126
  entities: string[]
121
127
  screens: StoryScreenRef[]
@@ -153,6 +159,8 @@ export interface StoryWriteInput {
153
159
  narrative: string
154
160
  status: string
155
161
  primary: boolean
162
+ /** The card's landing flag — see {@link StoryMeta.landing}. Absent reads as `false`. */
163
+ landing?: boolean
156
164
  /** Carried through a develop run so the rewrite does not drop the scaffold's assignment. */
157
165
  section?: string
158
166
  /** Likewise the reserved screen name. */
@@ -35,7 +35,7 @@ export const VIABLE_SPEC_FLOW = 'viable:spec'
35
35
  * The story flow's status keys.
36
36
  *
37
37
  * Byte-identical to the strings a story has always carried — the frontmatter of
38
- * `docs/stories/<code>.md`, the connector's job status mapping, the board's columns, their i18n
38
+ * `docs/stories/<code>.md`, connector status rendering, the board's columns, their i18n
39
39
  * keys and every end-to-end selector read these exact values. A key is a wire contract and is
40
40
  * never renamed.
41
41
  */
@@ -115,19 +115,22 @@ export const projectBriefOf = (project: Workcard, specs: readonly Specification[
115
115
  * What the metadata store writes to `docs/stories/<code>.md`, from the card and a run's content.
116
116
  *
117
117
  * The CODE is the target's only story identifier — a card id never reaches a target file — so a
118
- * story card without one is refused rather than filed under its id.
118
+ * story card without one is refused rather than filed under its id. The landing flag is carried
119
+ * only when it is set, so every other story's frontmatter keeps the shape it always had.
119
120
  */
120
121
  export const storyWriteInputOf = (card: Workcard, content: StoryWriteContent): StoryWriteInput => {
121
122
  if (card.code == null || card.code === '') {
122
123
  throw new ProjectStoryMissconfigured('no-code')
123
124
  }
124
125
  const { status, ...rest } = content
126
+ const fields = storyFieldsOf(card)
125
127
 
126
128
  return {
127
129
  ...rest,
128
130
  code: card.code,
129
131
  narrative: card.title,
130
132
  status: status ?? card.status,
131
- primary: storyFieldsOf(card).primary,
133
+ primary: fields.primary,
134
+ ...(fields.landing === true ? { landing: true } : {}),
132
135
  }
133
136
  }
@@ -3,4 +3,5 @@ export * from './errors.js'
3
3
  export * from './schemas.js'
4
4
  export * from './flows.js'
5
5
  export * from './helpers.js'
6
+ export * from './landing.js'
6
7
  export type * from './types.js'
@@ -0,0 +1,43 @@
1
+ import { TITLE_MAX } from '@owlmeans/planning'
2
+
3
+ /**
4
+ * The sentence a landing story's narrative carries — what a person reading the board sees.
5
+ *
6
+ * The AUTHORITY is the card's `fields.landing` flag, never this text: the design and development
7
+ * stages key on the flag, and a person may reword the narrative at any time. The sentence exists so
8
+ * the board says in plain words why this story is different, and so the analyst and the designer,
9
+ * who read the narrative, write a screen that continues what the guest started.
10
+ *
11
+ * A constant, byte for byte, because {@link hasLandingSentence} is how a resumed decision step
12
+ * knows it already appended it.
13
+ */
14
+ export const LANDING_STORY_SENTENCE = 'A visitor can start this on the landing page without an account;'
15
+ + ' after signing in they continue here with their choices carried over.'
16
+
17
+ const normalized = (text: string): string => text.replace(/\s+/g, ' ')
18
+
19
+ /** Whether a narrative already carries the landing sentence, whatever whitespace surrounds it. */
20
+ export const hasLandingSentence = (title: string): boolean =>
21
+ normalized(title).includes(LANDING_STORY_SENTENCE)
22
+
23
+ /**
24
+ * The narrative with the landing sentence appended once.
25
+ *
26
+ * Idempotent — a narrative that already carries the sentence comes back unchanged, so a decision
27
+ * step that is resumed after it wrote the card never appends a second copy. It never produces a
28
+ * title longer than a card accepts (`TITLE_MAX`): a narrative with no room left is returned as it
29
+ * is rather than cut, because a person's words are worth more than the note, and the flag on the
30
+ * card still carries the fact.
31
+ */
32
+ export const withLandingSentence = (title: string): string => {
33
+ if (hasLandingSentence(title)) {
34
+ return title
35
+ }
36
+ const base = title.trimEnd()
37
+ if (base === '') {
38
+ return LANDING_STORY_SENTENCE
39
+ }
40
+ const joined = `${base} ${LANDING_STORY_SENTENCE}`
41
+
42
+ return joined.length > TITLE_MAX ? title : joined
43
+ }
@@ -28,6 +28,18 @@ export const ViableProjectFieldsSchema = {
28
28
  origin: { ...ProjectOriginSchema, nullable: true },
29
29
  connectLlmMode: { type: 'string', enum: [...Object.values(ConnectLlm), null], nullable: true },
30
30
  converterLlmMode: { type: 'string', enum: [...Object.values(ConnectLlm), null], nullable: true },
31
+ // `story: null` is a DECIDED "no gate" and must stay spellable; an absent `landing` is "never
32
+ // decided". `at` carries no `format`: the planning registry compiles without ajv-formats.
33
+ landing: {
34
+ type: 'object',
35
+ nullable: true,
36
+ properties: {
37
+ story: { type: 'string', minLength: 1, maxLength: CODE_MAX, nullable: true },
38
+ at: { type: 'string', minLength: 1, maxLength: 32 },
39
+ },
40
+ required: ['at'],
41
+ additionalProperties: false,
42
+ },
31
43
  },
32
44
  required: [],
33
45
  additionalProperties: false,
@@ -48,6 +60,7 @@ export const ViableStoryFieldsSchema = {
48
60
  actor: { type: 'string', enum: [...Object.values(StoryActor), null], nullable: true },
49
61
  warning: { type: 'string', maxLength: 1024, nullable: true },
50
62
  kind: { type: 'string', enum: [...Object.values(StoryKind), null], nullable: true },
63
+ landing: { type: 'boolean', nullable: true },
51
64
  },
52
65
  required: ['area', 'primary'],
53
66
  additionalProperties: false,
@@ -32,6 +32,23 @@ export type ViableProjectFields = {
32
32
  connectLlmMode?: ConnectLlm
33
33
  /** Who performs a conversion's model calls on this project; absent inherits. */
34
34
  converterLlmMode?: ConnectLlm
35
+ /**
36
+ * The landing-gate decision: which story a guest can start on the landing page.
37
+ *
38
+ * Three states, and the third is why this is an object rather than a code: ABSENT means the
39
+ * decision was never made (an initialization that has not reached it, or a project older than
40
+ * the gate), `story: null` means it WAS made and the answer is "no gate", and a code names the
41
+ * story. A failed decision is never recorded — writing `null` for it would read as a decided
42
+ * "none" and no later run would ask again. `at` is when it was decided, an ISO timestamp.
43
+ */
44
+ landing?: ViableLandingDecision
45
+ }
46
+
47
+ /** The recorded landing-gate decision — see {@link ViableProjectFields.landing}. */
48
+ export interface ViableLandingDecision {
49
+ /** The story card's CODE, or `null` for a decided "no gate". */
50
+ story: string | null
51
+ at: string
35
52
  }
36
53
 
37
54
  /**
@@ -51,6 +68,15 @@ export type ViableStoryFields = {
51
68
  warning?: string
52
69
  /** Which half of the analysis the story came from. */
53
70
  kind?: StoryKind
71
+ /**
72
+ * The story a guest starts on the landing page — the landing gate's story. At most one per
73
+ * project, and the project card's `fields.landing.story` names the same code.
74
+ *
75
+ * Its development gains a step that replaces the gate's sketch on the guest home with the real
76
+ * component, and its full-scale screen reads the choices the guest carried over. Absent and
77
+ * `false` read the same.
78
+ */
79
+ landing?: boolean
54
80
  }
55
81
 
56
82
  export interface ViableProjectCard extends Project {
@@ -67,9 +93,9 @@ export type ViableSpecification = Specification
67
93
  /**
68
94
  * What a develop run hands the metadata store beside the card.
69
95
  *
70
- * The code, the narrative and the primary flag are the CARD's and are never passed separately — a
71
- * second copy is a second answer. `status` defaults to the card's own.
96
+ * The code, the narrative, the primary flag and the landing flag are the CARD's and are never
97
+ * passed separately — a second copy is a second answer. `status` defaults to the card's own.
72
98
  */
73
99
  export type StoryWriteContent =
74
- & Omit<StoryWriteInput, 'code' | 'narrative' | 'primary' | 'status'>
100
+ & Omit<StoryWriteInput, 'code' | 'narrative' | 'primary' | 'landing' | 'status'>
75
101
  & { status?: string }