@pikku/core 0.12.125 → 0.12.127

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 0.12.127
2
+
3
+ ### Patch Changes
4
+
5
+ - f02585e: `pikku audit` tags every advisory and update with `dependencyType: 'prod' | 'dev'`, walking `bun.lock` from each workspace's runtime dependencies without descending into peers or build tools (vite, esbuild, babel, the TanStack Start plugin, the pikku CLI). The console's security view counts only production advisories and folds dev-only ones into a collapsed section.
6
+ - 5586749: A suspended workflow's pause step now reads as `running` while the run waits, and only becomes `succeeded` when the run resumes past it — previously it was marked succeeded the moment the run paused.
7
+
8
+ ## 0.12.126
9
+
10
+ ### Patch Changes
11
+
12
+ - 44da33f: A scenario run records which version of the suite it ran against — the commit, and which attempt against that commit it is
13
+ - 44da33f: The scenarios screen and the runs screen are one surface: the declared suite is the document and a run is a lens over it. A scenario is filed as `running` the moment it starts, so a console watching a run in progress can tell what is on screen now from what is still waiting, and the run snapshots each scenario's title, description and cast so the record reads as prose.
14
+
1
15
  ## 0.12.125
2
16
 
3
17
  ### Patch Changes
@@ -15,6 +15,7 @@ export const scenarioRunSummary = (record) => ({
15
15
  runId: record.runId,
16
16
  environment: record.environment,
17
17
  surface: record.surface,
18
+ ...(record.version ? { version: record.version } : {}),
18
19
  status: record.status,
19
20
  startedAt: record.startedAt,
20
21
  finishedAt: record.finishedAt,
@@ -82,7 +83,18 @@ export class FileScenarioRunStore {
82
83
  if (!record) {
83
84
  return;
84
85
  }
85
- record.results.push(result);
86
+ const existing = record.results.findIndex((candidate) => candidate.name === result.name);
87
+ if (existing === -1) {
88
+ record.results.push(result);
89
+ }
90
+ else {
91
+ record.results[existing] = {
92
+ ...(record.results[existing].artifacts
93
+ ? { artifacts: record.results[existing].artifacts }
94
+ : {}),
95
+ ...result,
96
+ };
97
+ }
86
98
  await this.write(record);
87
99
  });
88
100
  }
@@ -318,6 +318,8 @@ export type CommonWireMeta = {
318
318
  */
319
319
  export type SecuritySeverity = 'critical' | 'high' | 'moderate' | 'low' | 'info';
320
320
  export type SecurityUpdateLevel = 'major' | 'minor' | 'patch' | 'unknown';
321
+ /** `dev` = only reachable through devDependencies or build tooling, so never shipped. */
322
+ export type SecurityDependencyType = 'prod' | 'dev';
321
323
  export interface SecurityAuditIssue {
322
324
  package: string;
323
325
  severity: SecuritySeverity;
@@ -328,12 +330,14 @@ export interface SecurityAuditIssue {
328
330
  cwe: string[];
329
331
  cvssScore: number | null;
330
332
  recommendedVersion: string | null;
333
+ dependencyType?: SecurityDependencyType;
331
334
  }
332
335
  export interface SecurityAuditUpdate {
333
336
  package: string;
334
337
  current: string;
335
338
  latest: string;
336
339
  level: SecurityUpdateLevel;
340
+ dependencyType?: SecurityDependencyType;
337
341
  }
338
342
  export interface SecurityAuditSummary {
339
343
  totalIssues: number;
@@ -1,2 +1,2 @@
1
- export type { AuthInstance, CommonWireMeta, CoreConfig, CoreServices, CoreSingletonServices, CoreUserSession, CreateConfig, CreateSingletonServices, CreateWireServices, GetCredential, PikkuWire, PikkuWiringTypes, PostgresConfig, SecretlessServices, SecurityAuditIssue, SecurityAuditReport, SecurityAuditSummary, SecurityAuditUpdate, SecuritySeverity, SecurityUpdateLevel, ServerLifecycle, WireServices, } from './core.types.js';
1
+ export type { AuthInstance, CommonWireMeta, CoreConfig, CoreServices, CoreSingletonServices, CoreUserSession, CreateConfig, CreateSingletonServices, CreateWireServices, GetCredential, PikkuWire, PikkuWiringTypes, PostgresConfig, SecretlessServices, SecurityAuditIssue, SecurityAuditReport, SecurityAuditSummary, SecurityAuditUpdate, SecuritySeverity, SecurityUpdateLevel, SecurityDependencyType, ServerLifecycle, WireServices, } from './core.types.js';
2
2
  export type * from './state.types.js';
@@ -8,7 +8,7 @@ import type { ScenarioBrowserProvider, ScenarioEnvironment, ScenarioSurface } fr
8
8
  import type { PikkuWorkflowWire, WorkflowQueueOptions } from './workflow.types.js';
9
9
  export { addFeature, resolveFeatureScenarios } from './feature.js';
10
10
  export type { CoreFeature, CoreFeatureScenario, FeatureMeta, FeaturesMeta, PikkuBrowserWire, PikkuScenarioWire, ScenarioBrowserFailure, ScenarioBrowserProvider, ScenarioEnvironment, ScenarioStepKind, ScenarioStepMeta, ScenarioStepOptions, ScenarioScreenshotOptions, ScenarioStepPhase, ScenarioSurface, TestIdSelector, } from './scenario.types.js';
11
- export type { ScenarioArtifact, ScenarioFailureDetail, ScenarioResult, ScenarioRunRecord, ScenarioRunReport, ScenarioRunSelection, ScenarioRunStatus, ScenarioRunStore, ScenarioRunSummary, ScenarioStepRow, ScenarioStepVideoOffset, } from './scenario-run.types.js';
11
+ export type { ScenarioArtifact, ScenarioFailureDetail, ScenarioResult, ScenarioRunRecord, ScenarioRunReport, ScenarioRunSelection, ScenarioRunStatus, ScenarioRunStore, ScenarioRunSummary, ScenarioRunVersion, ScenarioStepRow, ScenarioStepVideoOffset, } from './scenario-run.types.js';
12
12
  export { SCENARIO_SURFACES } from './scenario-step.types.js';
13
13
  export { resolveScenarioSurfaces } from './scenario-surface.js';
14
14
  export { pollUntil, type PollOptions } from './scenario-poll.js';
@@ -95,7 +95,12 @@ export interface ScenarioFailureDetail {
95
95
  }
96
96
  export interface ScenarioResult {
97
97
  name: string;
98
- status: 'passed' | 'failed';
98
+ /**
99
+ * `running` is filed the moment the scenario starts and replaced when it
100
+ * ends, so a console watching a run in progress can tell the scenario on
101
+ * screen right now from the ones still waiting their turn.
102
+ */
103
+ status: 'passed' | 'failed' | 'running';
99
104
  durationMs: number;
100
105
  output?: unknown;
101
106
  error?: string;
@@ -117,6 +122,11 @@ export interface ScenarioResult {
117
122
  * feature under, and it is what survives the title being rewritten.
118
123
  */
119
124
  featureId?: string;
125
+ /** The scenario's declared title, snapshotted so the record reads as prose. */
126
+ title?: string;
127
+ description?: string;
128
+ /** Who the scenario cast, in declaration order. */
129
+ actors?: string[];
120
130
  tags?: string[];
121
131
  /** Images and footage this scenario produced, filed under the run. */
122
132
  artifacts?: ScenarioArtifact[];
@@ -155,6 +165,32 @@ export interface ScenarioRunSelection {
155
165
  tags?: string[];
156
166
  excludeTags?: string[];
157
167
  }
168
+ /**
169
+ * Which version of the suite a run ran against.
170
+ *
171
+ * A run is only comparable to another run of the same thing, and "the same
172
+ * thing" is the commit — two runs a day apart are not a flake and a fix if the
173
+ * suite moved between them. `attempt` counts the runs already filed against
174
+ * that commit, so a suite re-run until it passes reads as one version with
175
+ * several attempts rather than several unrelated runs.
176
+ *
177
+ * Absent when the project is not in a git repository, or has no commits yet:
178
+ * an unversioned run is still a run, and saying nothing is better than
179
+ * inventing a version for it.
180
+ */
181
+ export interface ScenarioRunVersion {
182
+ /** The commit the working tree was at, in full. */
183
+ commit: string;
184
+ /**
185
+ * The tree had uncommitted changes, so the commit does not describe what
186
+ * actually ran. Recorded rather than refused — running against a dirty tree
187
+ * is the normal way to work — but a reader comparing two attempts of the
188
+ * same commit needs to know one of them was not really that commit.
189
+ */
190
+ dirty?: boolean;
191
+ /** Which run this is against that commit, counting from one. */
192
+ attempt: number;
193
+ }
158
194
  /**
159
195
  * A whole run, as it is stored and read back.
160
196
  *
@@ -170,6 +206,8 @@ export interface ScenarioRunRecord extends ScenarioRunReport {
170
206
  surface: string;
171
207
  /** Absent on a run of the whole suite; see {@link ScenarioRunSelection}. */
172
208
  selection?: ScenarioRunSelection;
209
+ /** The suite version this ran against, when the project has one. */
210
+ version?: ScenarioRunVersion;
173
211
  startedAt: string;
174
212
  finishedAt?: string;
175
213
  }
@@ -178,6 +216,7 @@ export interface ScenarioRunSummary {
178
216
  runId: string;
179
217
  environment: string;
180
218
  surface: string;
219
+ version?: ScenarioRunVersion;
181
220
  status: ScenarioRunStatus;
182
221
  startedAt: string;
183
222
  finishedAt?: string;
@@ -202,7 +241,11 @@ export interface ScenarioRunSummary {
202
241
  export interface ScenarioRunStore {
203
242
  /** Open a run. Called before the first scenario, with `status: 'running'`. */
204
243
  start(record: ScenarioRunRecord): Promise<void>;
205
- /** Append one finished scenario to an open run. */
244
+ /**
245
+ * File one scenario's state against an open run, replacing whatever was
246
+ * filed for that name before — a scenario is recorded twice, once as
247
+ * `running` and once with its outcome.
248
+ */
206
249
  recordScenario(runId: string, result: ScenarioResult): Promise<void>;
207
250
  /**
208
251
  * File the run's artifacts against the scenarios that produced them.
@@ -180,6 +180,9 @@ export interface ScenarioScreenshotOptions {
180
180
  /**
181
181
  * One actor's browser session, handed to a step as `wire.browser`.
182
182
  *
183
+ * Every actor gets their own, so a two-actor scenario drives two sessions and
184
+ * `screenshot` files each shot under the actor it belongs to.
185
+ *
183
186
  * Only what every driver can honour is declared here. A driver package adds
184
187
  * the rest by declaration-merging onto this interface — `@pikku/playwright`
185
188
  * contributes `page`, `context` and `locate` — so a step written against the
@@ -6,7 +6,7 @@ export type SuspendStore = Pick<ApprovalStore, 'getStepState' | 'insertStepState
6
6
  /**
7
7
  * Record a suspension point and unwind the run.
8
8
  *
9
- * A suspension that has already succeeded returns instead of throwing, so a
10
- * replay walks past a gate the run has already passed through.
9
+ * The gate stays `running` while the run waits, so it reads as in progress; the
10
+ * replay that follows a resume settles it and walks past.
11
11
  */
12
12
  export declare const recordSuspension: (store: SuspendStore, runId: string, reason: string, stepName: string, fromStepName: string | undefined) => Promise<void>;
@@ -4,8 +4,8 @@ export const suspendStepNameFor = (reason) => `__workflow_suspend:${reason}`;
4
4
  /**
5
5
  * Record a suspension point and unwind the run.
6
6
  *
7
- * A suspension that has already succeeded returns instead of throwing, so a
8
- * replay walks past a gate the run has already passed through.
7
+ * The gate stays `running` while the run waits, so it reads as in progress; the
8
+ * replay that follows a resume settles it and walks past.
9
9
  */
10
10
  export const recordSuspension = async (store, runId, reason, stepName, fromStepName) => {
11
11
  const insert = () => store.insertStepState(runId, stepName, 'pikkuWorkflowSuspend', { reason }, undefined, fromStepName);
@@ -22,12 +22,10 @@ export const recordSuspension = async (store, runId, reason, stepName, fromStepN
22
22
  if (stepState.status === 'succeeded') {
23
23
  return;
24
24
  }
25
- if (stepState.status === 'pending') {
26
- await store.setStepRunning(stepState.stepId);
25
+ if (stepState.status === 'running') {
26
+ await store.setStepResult(stepState.stepId, { reason });
27
+ return;
27
28
  }
28
- await store.setStepResult(stepState.stepId, {
29
- reason,
30
- suspendedAt: new Date().toISOString(),
31
- });
29
+ await store.setStepRunning(stepState.stepId);
32
30
  throw new WorkflowSuspendedException(runId, reason);
33
31
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.12.125",
3
+ "version": "0.12.127",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",