@specship/specship-win32-arm64 0.25.0 → 0.28.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/bin/specship.cmd +31 -1
- package/lib/dist/activation/cheatsheet.d.ts +17 -1
- package/lib/dist/activation/cheatsheet.d.ts.map +1 -1
- package/lib/dist/activation/cheatsheet.js +47 -3
- package/lib/dist/activation/cheatsheet.js.map +1 -1
- package/lib/dist/activation/hook-output.d.ts +80 -0
- package/lib/dist/activation/hook-output.d.ts.map +1 -0
- package/lib/dist/activation/hook-output.js +103 -0
- package/lib/dist/activation/hook-output.js.map +1 -0
- package/lib/dist/activation/search-intercept.d.ts +60 -29
- package/lib/dist/activation/search-intercept.d.ts.map +1 -1
- package/lib/dist/activation/search-intercept.js +159 -55
- package/lib/dist/activation/search-intercept.js.map +1 -1
- package/lib/dist/activation/steering.d.ts +8 -10
- package/lib/dist/activation/steering.d.ts.map +1 -1
- package/lib/dist/activation/steering.js +21 -6
- package/lib/dist/activation/steering.js.map +1 -1
- package/lib/dist/behaviour/behaviour-surface.d.ts +47 -0
- package/lib/dist/behaviour/behaviour-surface.d.ts.map +1 -1
- package/lib/dist/behaviour/behaviour-surface.js +108 -2
- package/lib/dist/behaviour/behaviour-surface.js.map +1 -1
- package/lib/dist/bin/node-version-check.d.ts +22 -7
- package/lib/dist/bin/node-version-check.d.ts.map +1 -1
- package/lib/dist/bin/node-version-check.js +39 -9
- package/lib/dist/bin/node-version-check.js.map +1 -1
- package/lib/dist/bin/specship.js +762 -81
- package/lib/dist/bin/specship.js.map +1 -1
- package/lib/dist/commands/specship/learn.md +22 -0
- package/lib/dist/commands/specship/spec.md +12 -0
- package/lib/dist/db/sqlite-adapter.d.ts +7 -5
- package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/lib/dist/db/sqlite-adapter.js +11 -9
- package/lib/dist/db/sqlite-adapter.js.map +1 -1
- package/lib/dist/enforce/changed-files.d.ts +11 -0
- package/lib/dist/enforce/changed-files.d.ts.map +1 -1
- package/lib/dist/enforce/changed-files.js +42 -0
- package/lib/dist/enforce/changed-files.js.map +1 -1
- package/lib/dist/enforce/enforce.d.ts +25 -1
- package/lib/dist/enforce/enforce.d.ts.map +1 -1
- package/lib/dist/enforce/enforce.js +58 -3
- package/lib/dist/enforce/enforce.js.map +1 -1
- package/lib/dist/enforce/mutation.d.ts +46 -0
- package/lib/dist/enforce/mutation.d.ts.map +1 -0
- package/lib/dist/enforce/mutation.js +104 -0
- package/lib/dist/enforce/mutation.js.map +1 -0
- package/lib/dist/enforce/suppressions.d.ts +33 -0
- package/lib/dist/enforce/suppressions.d.ts.map +1 -0
- package/lib/dist/enforce/suppressions.js +159 -0
- package/lib/dist/enforce/suppressions.js.map +1 -0
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.js +16 -2
- package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
- package/lib/dist/graph/spec-coverage.d.ts +57 -1
- package/lib/dist/graph/spec-coverage.d.ts.map +1 -1
- package/lib/dist/graph/spec-coverage.js +129 -5
- package/lib/dist/graph/spec-coverage.js.map +1 -1
- package/lib/dist/health/smoke-check.js +2 -2
- package/lib/dist/health/smoke-check.js.map +1 -1
- package/lib/dist/index.d.ts +8 -3
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +65 -9
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/gemini-commands.d.ts +107 -0
- package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
- package/lib/dist/installer/gemini-commands.js +264 -0
- package/lib/dist/installer/gemini-commands.js.map +1 -0
- package/lib/dist/installer/index.d.ts +23 -1
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +22 -3
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/install-defaults.d.ts +19 -0
- package/lib/dist/installer/install-defaults.d.ts.map +1 -1
- package/lib/dist/installer/install-defaults.js +28 -0
- package/lib/dist/installer/install-defaults.js.map +1 -1
- package/lib/dist/installer/instructions-template.d.ts +22 -0
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +37 -1
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/installer/targets/claude.d.ts +4 -0
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +8 -25
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/gemini.d.ts +85 -12
- package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
- package/lib/dist/installer/targets/gemini.js +527 -30
- package/lib/dist/installer/targets/gemini.js.map +1 -1
- package/lib/dist/installer/targets/shared.d.ts +13 -0
- package/lib/dist/installer/targets/shared.d.ts.map +1 -1
- package/lib/dist/installer/targets/shared.js +18 -0
- package/lib/dist/installer/targets/shared.js.map +1 -1
- package/lib/dist/installer/targets/types.d.ts +12 -0
- package/lib/dist/installer/targets/types.d.ts.map +1 -1
- package/lib/dist/jira/auto-publish.d.ts +71 -4
- package/lib/dist/jira/auto-publish.d.ts.map +1 -1
- package/lib/dist/jira/auto-publish.js +186 -17
- package/lib/dist/jira/auto-publish.js.map +1 -1
- package/lib/dist/jira/reconcile.d.ts +24 -1
- package/lib/dist/jira/reconcile.d.ts.map +1 -1
- package/lib/dist/jira/reconcile.js +46 -2
- package/lib/dist/jira/reconcile.js.map +1 -1
- package/lib/dist/jira/repo-config.d.ts +9 -0
- package/lib/dist/jira/repo-config.d.ts.map +1 -1
- package/lib/dist/jira/repo-config.js +11 -0
- package/lib/dist/jira/repo-config.js.map +1 -1
- package/lib/dist/jira/types.d.ts +7 -0
- package/lib/dist/jira/types.d.ts.map +1 -1
- package/lib/dist/jira/types.js.map +1 -1
- package/lib/dist/knowledge/enforce.d.ts +75 -0
- package/lib/dist/knowledge/enforce.d.ts.map +1 -0
- package/lib/dist/knowledge/enforce.js +250 -0
- package/lib/dist/knowledge/enforce.js.map +1 -0
- package/lib/dist/knowledge/facts.d.ts +33 -0
- package/lib/dist/knowledge/facts.d.ts.map +1 -0
- package/lib/dist/knowledge/facts.js +117 -0
- package/lib/dist/knowledge/facts.js.map +1 -0
- package/lib/dist/knowledge/proposals.d.ts +88 -0
- package/lib/dist/knowledge/proposals.d.ts.map +1 -0
- package/lib/dist/knowledge/proposals.js +360 -0
- package/lib/dist/knowledge/proposals.js.map +1 -0
- package/lib/dist/knowledge/stale.d.ts +64 -0
- package/lib/dist/knowledge/stale.d.ts.map +1 -0
- package/lib/dist/knowledge/stale.js +174 -0
- package/lib/dist/knowledge/stale.js.map +1 -0
- package/lib/dist/mcp/gemini-session.d.ts +50 -0
- package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
- package/lib/dist/mcp/gemini-session.js +159 -0
- package/lib/dist/mcp/gemini-session.js.map +1 -0
- package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
- package/lib/dist/mcp/jira-tools.js +25 -0
- package/lib/dist/mcp/jira-tools.js.map +1 -1
- package/lib/dist/mcp/model-context.d.ts +22 -9
- package/lib/dist/mcp/model-context.d.ts.map +1 -1
- package/lib/dist/mcp/model-context.js +35 -13
- package/lib/dist/mcp/model-context.js.map +1 -1
- package/lib/dist/mcp/proxy.js +1 -1
- package/lib/dist/mcp/proxy.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +16 -15
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +67 -1
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/session.js +1 -1
- package/lib/dist/mcp/session.js.map +1 -1
- package/lib/dist/mcp/spec-tools.d.ts +9 -1
- package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
- package/lib/dist/mcp/spec-tools.js +69 -21
- package/lib/dist/mcp/spec-tools.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts +37 -1
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +120 -9
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/pulse/pulse.d.ts +93 -0
- package/lib/dist/pulse/pulse.d.ts.map +1 -0
- package/lib/dist/pulse/pulse.js +401 -0
- package/lib/dist/pulse/pulse.js.map +1 -0
- package/lib/dist/reflect/apply.d.ts.map +1 -1
- package/lib/dist/reflect/apply.js +38 -3
- package/lib/dist/reflect/apply.js.map +1 -1
- package/lib/dist/reflect/auto-sweep.d.ts +26 -0
- package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
- package/lib/dist/reflect/auto-sweep.js +90 -0
- package/lib/dist/reflect/auto-sweep.js.map +1 -0
- package/lib/dist/reflect/cli.d.ts +62 -0
- package/lib/dist/reflect/cli.d.ts.map +1 -0
- package/lib/dist/reflect/cli.js +163 -0
- package/lib/dist/reflect/cli.js.map +1 -0
- package/lib/dist/reflect/miner.d.ts.map +1 -1
- package/lib/dist/reflect/miner.js +119 -0
- package/lib/dist/reflect/miner.js.map +1 -1
- package/lib/dist/reflect/sweep.d.ts +1 -0
- package/lib/dist/reflect/sweep.d.ts.map +1 -1
- package/lib/dist/reflect/sweep.js +62 -13
- package/lib/dist/reflect/sweep.js.map +1 -1
- package/lib/dist/reflect/targets.d.ts +2 -0
- package/lib/dist/reflect/targets.d.ts.map +1 -1
- package/lib/dist/reflect/targets.js +33 -0
- package/lib/dist/reflect/targets.js.map +1 -1
- package/lib/dist/reflect/types.d.ts +19 -2
- package/lib/dist/reflect/types.d.ts.map +1 -1
- package/lib/dist/resolution/test-title-links.d.ts.map +1 -1
- package/lib/dist/resolution/test-title-links.js +3 -14
- package/lib/dist/resolution/test-title-links.js.map +1 -1
- package/lib/dist/server/routes/claude.js +15 -7
- package/lib/dist/server/routes/knowledge.js +118 -0
- package/lib/dist/server/server.js +2 -0
- package/lib/dist/spec-lint/lint.d.ts +1 -1
- package/lib/dist/spec-lint/lint.d.ts.map +1 -1
- package/lib/dist/spec-lint/lint.js +63 -2
- package/lib/dist/spec-lint/lint.js.map +1 -1
- package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
- package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
- package/lib/dist/spec-quality/criterion-ids.js +38 -0
- package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
- package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
- package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
- package/lib/dist/spec-quality/evidence-kind.js +183 -0
- package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
- package/lib/dist/spec-quality/link-persist.d.ts +65 -0
- package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
- package/lib/dist/spec-quality/link-persist.js +249 -0
- package/lib/dist/spec-quality/link-persist.js.map +1 -0
- package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
- package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
- package/lib/dist/spec-quality/plan-scope.js +129 -0
- package/lib/dist/spec-quality/plan-scope.js.map +1 -0
- package/lib/dist/spec-quality/postcheck.d.ts +85 -0
- package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
- package/lib/dist/spec-quality/postcheck.js +390 -0
- package/lib/dist/spec-quality/postcheck.js.map +1 -0
- package/lib/dist/spec-quality/readiness.d.ts +72 -0
- package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
- package/lib/dist/spec-quality/readiness.js +226 -0
- package/lib/dist/spec-quality/readiness.js.map +1 -0
- package/lib/dist/workflows/agents/claude.d.ts +16 -0
- package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
- package/lib/dist/workflows/agents/claude.js +82 -0
- package/lib/dist/workflows/agents/claude.js.map +1 -0
- package/lib/dist/workflows/agents/gemini.d.ts +21 -0
- package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
- package/lib/dist/workflows/agents/gemini.js +124 -0
- package/lib/dist/workflows/agents/gemini.js.map +1 -0
- package/lib/dist/workflows/agents/index.d.ts +28 -0
- package/lib/dist/workflows/agents/index.d.ts.map +1 -0
- package/lib/dist/workflows/agents/index.js +104 -0
- package/lib/dist/workflows/agents/index.js.map +1 -0
- package/lib/dist/workflows/agents/types.d.ts +55 -0
- package/lib/dist/workflows/agents/types.d.ts.map +1 -0
- package/lib/dist/workflows/agents/types.js +46 -0
- package/lib/dist/workflows/agents/types.js.map +1 -0
- package/lib/dist/workflows/batch.d.ts +63 -0
- package/lib/dist/workflows/batch.d.ts.map +1 -0
- package/lib/dist/workflows/batch.js +151 -0
- package/lib/dist/workflows/batch.js.map +1 -0
- package/lib/dist/workflows/defaults/claude-design-implement.yaml +3 -4
- package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
- package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -436
- package/lib/dist/workflows/defaults/spec-implement.yaml +465 -46
- package/lib/dist/workflows/discovery.d.ts +13 -0
- package/lib/dist/workflows/discovery.d.ts.map +1 -1
- package/lib/dist/workflows/discovery.js +79 -17
- package/lib/dist/workflows/discovery.js.map +1 -1
- package/lib/dist/workflows/executor.d.ts +18 -0
- package/lib/dist/workflows/executor.d.ts.map +1 -1
- package/lib/dist/workflows/executor.js +130 -33
- package/lib/dist/workflows/executor.js.map +1 -1
- package/lib/dist/workflows/gc.d.ts +50 -0
- package/lib/dist/workflows/gc.d.ts.map +1 -0
- package/lib/dist/workflows/gc.js +120 -0
- package/lib/dist/workflows/gc.js.map +1 -0
- package/lib/dist/workflows/merge-queue.d.ts +64 -0
- package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
- package/lib/dist/workflows/merge-queue.js +162 -0
- package/lib/dist/workflows/merge-queue.js.map +1 -0
- package/lib/dist/workflows/runners/approval.d.ts +1 -1
- package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
- package/lib/dist/workflows/runners/approval.js +11 -2
- package/lib/dist/workflows/runners/approval.js.map +1 -1
- package/lib/dist/workflows/runners/bash.d.ts +15 -0
- package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
- package/lib/dist/workflows/runners/bash.js +50 -1
- package/lib/dist/workflows/runners/bash.js.map +1 -1
- package/lib/dist/workflows/runners/prompt.d.ts +16 -41
- package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
- package/lib/dist/workflows/runners/prompt.js +55 -120
- package/lib/dist/workflows/runners/prompt.js.map +1 -1
- package/lib/dist/workflows/runners/types.d.ts +12 -0
- package/lib/dist/workflows/runners/types.d.ts.map +1 -1
- package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
- package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
- package/lib/dist/workflows/schemas/workflow.js +27 -0
- package/lib/dist/workflows/schemas/workflow.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +2 -2
- package/package.json +5 -3
- package/node.exe +0 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline pulse (PIPETRUST-DOC, REQ-PIPETRUST-007) — surface pipeline
|
|
3
|
+
* failures instead of waiting for someone to discover them.
|
|
4
|
+
*
|
|
5
|
+
* Four checks:
|
|
6
|
+
* - release — conclusion of the latest release workflow run (`gh`)
|
|
7
|
+
* - npm — published npm version vs latest GitHub release / package.json
|
|
8
|
+
* - jira — failures recorded by the last JIRA auto-publish
|
|
9
|
+
* - worktrees — workflow-run worktrees whose branch is already merged
|
|
10
|
+
*
|
|
11
|
+
* Every external command goes through an injectable {@link CommandRunner}
|
|
12
|
+
* with a per-command timeout and a total time budget. A missing tool, a
|
|
13
|
+
* timeout or a network failure turns that check into `skipped` — pulse never
|
|
14
|
+
* throws and never stalls its caller. Results are cached to
|
|
15
|
+
* `.specship/pulse.json` so a session-start summary can read them without
|
|
16
|
+
* touching the network.
|
|
17
|
+
*/
|
|
18
|
+
export type PulseStatus = 'ok' | 'fail' | 'skipped';
|
|
19
|
+
export type PulseCheckId = 'release' | 'npm' | 'jira' | 'worktrees';
|
|
20
|
+
export interface PulseItem {
|
|
21
|
+
id: PulseCheckId;
|
|
22
|
+
status: PulseStatus;
|
|
23
|
+
message: string;
|
|
24
|
+
hint?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface PulseResult {
|
|
27
|
+
/** Epoch ms when the checks ran. */
|
|
28
|
+
checkedAt: number;
|
|
29
|
+
items: PulseItem[];
|
|
30
|
+
/** True when the result was served from `.specship/pulse.json`. */
|
|
31
|
+
fromCache: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface CommandResult {
|
|
34
|
+
/** Exit code 0. */
|
|
35
|
+
ok: boolean;
|
|
36
|
+
stdout: string;
|
|
37
|
+
stderr?: string;
|
|
38
|
+
/** The command was killed by its timeout. */
|
|
39
|
+
timedOut?: boolean;
|
|
40
|
+
/** The executable was not found. */
|
|
41
|
+
missing?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export type CommandRunner = (cmd: string, args: string[], opts: {
|
|
44
|
+
cwd: string;
|
|
45
|
+
timeoutMs: number;
|
|
46
|
+
}) => Promise<CommandResult>;
|
|
47
|
+
export interface PulseOptions {
|
|
48
|
+
projectRoot: string;
|
|
49
|
+
/** Command runner seam (tests inject a fake; default spawns the real tool). */
|
|
50
|
+
runner?: CommandRunner;
|
|
51
|
+
/** Clock seam (epoch ms). */
|
|
52
|
+
now?: () => number;
|
|
53
|
+
/** Serve the cache when it is younger than this. Default: always recompute. */
|
|
54
|
+
maxAgeMs?: number;
|
|
55
|
+
/** Ignore the cache and recompute. */
|
|
56
|
+
refresh?: boolean;
|
|
57
|
+
/** Hard per-command timeout (ms). Default 3000. */
|
|
58
|
+
commandTimeoutMs?: number;
|
|
59
|
+
/** Total time budget for all commands (ms). Default 5000. */
|
|
60
|
+
totalBudgetMs?: number;
|
|
61
|
+
/** Persist the computed result to `.specship/pulse.json`. Default true. */
|
|
62
|
+
writeCache?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a run worktree's path to its full workflow run id (for the purge
|
|
65
|
+
* hint). Default: the short run id parsed from the branch/dir name.
|
|
66
|
+
*/
|
|
67
|
+
runIdForWorktree?: (workingPath: string, branch: string) => string | undefined;
|
|
68
|
+
}
|
|
69
|
+
export declare function pulseCachePath(projectRoot: string): string;
|
|
70
|
+
/** Read the cached pulse without running anything. Null when absent/corrupt. */
|
|
71
|
+
export declare function readCachedPulse(projectRoot: string): PulseResult | null;
|
|
72
|
+
/** Default runner: execFile with a hard timeout; never rejects. */
|
|
73
|
+
export declare const defaultCommandRunner: CommandRunner;
|
|
74
|
+
/** Compare dotted versions numerically (pre-release suffixes ignored). */
|
|
75
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
76
|
+
interface WorktreeEntry {
|
|
77
|
+
path: string;
|
|
78
|
+
branch?: string;
|
|
79
|
+
prunable?: boolean;
|
|
80
|
+
}
|
|
81
|
+
export declare function parseWorktreePorcelain(out: string): WorktreeEntry[];
|
|
82
|
+
/**
|
|
83
|
+
* Compute (or serve from cache) the pipeline pulse. Never throws: every
|
|
84
|
+
* check that cannot run cleanly degrades to `skipped`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function computePulse(opts: PulseOptions): Promise<PulseResult>;
|
|
87
|
+
/**
|
|
88
|
+
* One human line per failing item; an empty array when everything is
|
|
89
|
+
* healthy or skipped (so a session-start summary stays silent).
|
|
90
|
+
*/
|
|
91
|
+
export declare function formatPulseLines(items: PulseItem[]): string[];
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=pulse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulse.d.ts","sourceRoot":"","sources":["../../src/pulse/pulse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;AACpD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,YAAY,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACrC,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,6BAA6B;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAChF;AAMD,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAIvE;AAED,mEAAmE;AACnE,eAAO,MAAM,oBAAoB,EAAE,aAiC/B,CAAC;AAiDL,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAU5D;AAuHD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAenE;AA6DD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAyC3E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAI7D"}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pipeline pulse (PIPETRUST-DOC, REQ-PIPETRUST-007) — surface pipeline
|
|
4
|
+
* failures instead of waiting for someone to discover them.
|
|
5
|
+
*
|
|
6
|
+
* Four checks:
|
|
7
|
+
* - release — conclusion of the latest release workflow run (`gh`)
|
|
8
|
+
* - npm — published npm version vs latest GitHub release / package.json
|
|
9
|
+
* - jira — failures recorded by the last JIRA auto-publish
|
|
10
|
+
* - worktrees — workflow-run worktrees whose branch is already merged
|
|
11
|
+
*
|
|
12
|
+
* Every external command goes through an injectable {@link CommandRunner}
|
|
13
|
+
* with a per-command timeout and a total time budget. A missing tool, a
|
|
14
|
+
* timeout or a network failure turns that check into `skipped` — pulse never
|
|
15
|
+
* throws and never stalls its caller. Results are cached to
|
|
16
|
+
* `.specship/pulse.json` so a session-start summary can read them without
|
|
17
|
+
* touching the network.
|
|
18
|
+
*/
|
|
19
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
26
|
+
}) : (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
o[k2] = m[k];
|
|
29
|
+
}));
|
|
30
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
+
}) : function(o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
+
var ownKeys = function(o) {
|
|
37
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
+
var ar = [];
|
|
39
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
+
return ar;
|
|
41
|
+
};
|
|
42
|
+
return ownKeys(o);
|
|
43
|
+
};
|
|
44
|
+
return function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.defaultCommandRunner = void 0;
|
|
54
|
+
exports.pulseCachePath = pulseCachePath;
|
|
55
|
+
exports.readCachedPulse = readCachedPulse;
|
|
56
|
+
exports.compareVersions = compareVersions;
|
|
57
|
+
exports.parseWorktreePorcelain = parseWorktreePorcelain;
|
|
58
|
+
exports.computePulse = computePulse;
|
|
59
|
+
exports.formatPulseLines = formatPulseLines;
|
|
60
|
+
const fs = __importStar(require("fs"));
|
|
61
|
+
const path = __importStar(require("path"));
|
|
62
|
+
const child_process_1 = require("child_process");
|
|
63
|
+
const directory_1 = require("../directory");
|
|
64
|
+
const paths_1 = require("../statusline/paths");
|
|
65
|
+
const auto_publish_1 = require("../jira/auto-publish");
|
|
66
|
+
const DEFAULT_COMMAND_TIMEOUT_MS = 3000;
|
|
67
|
+
const DEFAULT_TOTAL_BUDGET_MS = 5000;
|
|
68
|
+
const FAILED_CONCLUSIONS = new Set(['failure', 'timed_out', 'startup_failure', 'cancelled']);
|
|
69
|
+
function pulseCachePath(projectRoot) {
|
|
70
|
+
return path.join((0, directory_1.getSpecShipDir)(projectRoot), 'pulse.json');
|
|
71
|
+
}
|
|
72
|
+
/** Read the cached pulse without running anything. Null when absent/corrupt. */
|
|
73
|
+
function readCachedPulse(projectRoot) {
|
|
74
|
+
const raw = (0, paths_1.readJsonSafe)(pulseCachePath(projectRoot));
|
|
75
|
+
if (!raw || typeof raw.checkedAt !== 'number' || !Array.isArray(raw.items))
|
|
76
|
+
return null;
|
|
77
|
+
return { checkedAt: raw.checkedAt, items: raw.items, fromCache: true };
|
|
78
|
+
}
|
|
79
|
+
/** Default runner: execFile with a hard timeout; never rejects. */
|
|
80
|
+
const defaultCommandRunner = (cmd, args, opts) => new Promise((resolve) => {
|
|
81
|
+
try {
|
|
82
|
+
(0, child_process_1.execFile)(cmd, args, {
|
|
83
|
+
cwd: opts.cwd,
|
|
84
|
+
timeout: Math.max(1, opts.timeoutMs),
|
|
85
|
+
windowsHide: true,
|
|
86
|
+
encoding: 'utf-8',
|
|
87
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
88
|
+
// npm / gh ship as .cmd shims on Windows.
|
|
89
|
+
shell: process.platform === 'win32',
|
|
90
|
+
}, (err, stdout, stderr) => {
|
|
91
|
+
if (!err) {
|
|
92
|
+
resolve({ ok: true, stdout: String(stdout), stderr: String(stderr) });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const e = err;
|
|
96
|
+
resolve({
|
|
97
|
+
ok: false,
|
|
98
|
+
stdout: String(stdout ?? ''),
|
|
99
|
+
stderr: String(stderr ?? ''),
|
|
100
|
+
missing: e.code === 'ENOENT',
|
|
101
|
+
timedOut: e.killed === true || e.signal === 'SIGTERM',
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
resolve({ ok: false, stdout: '', missing: true });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
exports.defaultCommandRunner = defaultCommandRunner;
|
|
110
|
+
/** Budget-aware wrapper around the runner. Never rejects. */
|
|
111
|
+
function makeExec(runner, cwd, commandTimeoutMs, totalBudgetMs) {
|
|
112
|
+
const deadline = Date.now() + totalBudgetMs;
|
|
113
|
+
return async (cmd, args) => {
|
|
114
|
+
const remaining = deadline - Date.now();
|
|
115
|
+
if (remaining <= 0)
|
|
116
|
+
return { ok: false, stdout: '', timedOut: true };
|
|
117
|
+
const timeoutMs = Math.min(commandTimeoutMs, remaining);
|
|
118
|
+
try {
|
|
119
|
+
let timer;
|
|
120
|
+
const guard = new Promise((resolve) => {
|
|
121
|
+
timer = setTimeout(() => resolve({ ok: false, stdout: '', timedOut: true }), timeoutMs + 250);
|
|
122
|
+
});
|
|
123
|
+
const result = await Promise.race([runner(cmd, args, { cwd, timeoutMs }), guard]);
|
|
124
|
+
if (timer)
|
|
125
|
+
clearTimeout(timer);
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return { ok: false, stdout: '', missing: true };
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function skipReason(tool, r) {
|
|
134
|
+
if (r.missing)
|
|
135
|
+
return `${tool} not available`;
|
|
136
|
+
if (r.timedOut)
|
|
137
|
+
return `${tool} check timed out`;
|
|
138
|
+
return `${tool} check unavailable (offline or not authenticated)`;
|
|
139
|
+
}
|
|
140
|
+
function parseJson(s) {
|
|
141
|
+
try {
|
|
142
|
+
return JSON.parse(s);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function dateOnly(iso) {
|
|
149
|
+
if (!iso)
|
|
150
|
+
return 'unknown date';
|
|
151
|
+
return iso.slice(0, 10);
|
|
152
|
+
}
|
|
153
|
+
/** Compare dotted versions numerically (pre-release suffixes ignored). */
|
|
154
|
+
function compareVersions(a, b) {
|
|
155
|
+
const norm = (v) => (v.trim().replace(/^v/i, '').split(/[-+]/)[0] ?? '').split('.').map((n) => parseInt(n, 10) || 0);
|
|
156
|
+
const pa = norm(a);
|
|
157
|
+
const pb = norm(b);
|
|
158
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
159
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
160
|
+
if (d !== 0)
|
|
161
|
+
return d > 0 ? 1 : -1;
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
// Checks
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
async function checkRelease(projectRoot, exec) {
|
|
169
|
+
const wf = path.join(projectRoot, '.github', 'workflows', 'release.yml');
|
|
170
|
+
if (!fs.existsSync(wf)) {
|
|
171
|
+
return { id: 'release', status: 'skipped', message: 'Release: no .github/workflows/release.yml' };
|
|
172
|
+
}
|
|
173
|
+
const r = await exec('gh', [
|
|
174
|
+
'run', 'list', '--workflow=release.yml', '--limit', '1',
|
|
175
|
+
'--json', 'conclusion,createdAt,displayTitle,databaseId',
|
|
176
|
+
]);
|
|
177
|
+
if (!r.ok) {
|
|
178
|
+
return { id: 'release', status: 'skipped', message: `Release: ${skipReason('gh', r)}` };
|
|
179
|
+
}
|
|
180
|
+
const runs = parseJson(r.stdout);
|
|
181
|
+
if (!runs)
|
|
182
|
+
return { id: 'release', status: 'skipped', message: 'Release: unreadable gh output' };
|
|
183
|
+
const run = runs[0];
|
|
184
|
+
if (!run)
|
|
185
|
+
return { id: 'release', status: 'ok', message: 'Release: no runs yet' };
|
|
186
|
+
const title = run.displayTitle ? ` (${run.displayTitle})` : '';
|
|
187
|
+
const when = dateOnly(run.createdAt);
|
|
188
|
+
if (!run.conclusion) {
|
|
189
|
+
return { id: 'release', status: 'ok', message: `Release: run in progress${title}, started ${when}` };
|
|
190
|
+
}
|
|
191
|
+
if (!FAILED_CONCLUSIONS.has(run.conclusion)) {
|
|
192
|
+
return { id: 'release', status: 'ok', message: `Release: last run ${run.conclusion}${title} on ${when}` };
|
|
193
|
+
}
|
|
194
|
+
// Failing step — one extra cheap call; omitted when unavailable.
|
|
195
|
+
let step = '';
|
|
196
|
+
if (typeof run.databaseId === 'number') {
|
|
197
|
+
const v = await exec('gh', ['run', 'view', String(run.databaseId), '--json', 'jobs']);
|
|
198
|
+
if (v.ok) {
|
|
199
|
+
const data = parseJson(v.stdout);
|
|
200
|
+
for (const job of data?.jobs ?? []) {
|
|
201
|
+
const s = (job.steps ?? []).find((x) => x.conclusion && FAILED_CONCLUSIONS.has(x.conclusion));
|
|
202
|
+
if (s?.name) {
|
|
203
|
+
step = ` at step "${s.name}"${job.name ? ` (job ${job.name})` : ''}`;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
id: 'release',
|
|
211
|
+
status: 'fail',
|
|
212
|
+
message: `Release workflow ${run.conclusion} on ${when}${title}${step}`,
|
|
213
|
+
hint: 'gh run list --workflow=release.yml',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async function checkNpm(projectRoot, exec) {
|
|
217
|
+
const pkg = (0, paths_1.readJsonSafe)(path.join(projectRoot, 'package.json'));
|
|
218
|
+
if (!pkg?.name || pkg.private) {
|
|
219
|
+
return { id: 'npm', status: 'skipped', message: 'npm: no published package.json' };
|
|
220
|
+
}
|
|
221
|
+
const [npmRes, ghRes] = await Promise.all([
|
|
222
|
+
exec('npm', ['view', pkg.name, 'version']),
|
|
223
|
+
exec('gh', ['release', 'list', '--limit', '1', '--json', 'tagName']),
|
|
224
|
+
]);
|
|
225
|
+
if (!npmRes.ok) {
|
|
226
|
+
return { id: 'npm', status: 'skipped', message: `npm: ${skipReason('npm', npmRes)}` };
|
|
227
|
+
}
|
|
228
|
+
const published = npmRes.stdout.trim().split(/\s+/).pop() ?? '';
|
|
229
|
+
if (!published)
|
|
230
|
+
return { id: 'npm', status: 'skipped', message: 'npm: no published version' };
|
|
231
|
+
let releaseTag;
|
|
232
|
+
if (ghRes.ok) {
|
|
233
|
+
const rel = parseJson(ghRes.stdout);
|
|
234
|
+
releaseTag = rel?.[0]?.tagName;
|
|
235
|
+
}
|
|
236
|
+
const lags = [];
|
|
237
|
+
if (releaseTag && compareVersions(releaseTag, published) > 0) {
|
|
238
|
+
lags.push(`latest GitHub release is ${releaseTag}`);
|
|
239
|
+
}
|
|
240
|
+
if (pkg.version && compareVersions(pkg.version, published) > 0) {
|
|
241
|
+
lags.push(`package.json is ${pkg.version}`);
|
|
242
|
+
}
|
|
243
|
+
if (lags.length > 0) {
|
|
244
|
+
return {
|
|
245
|
+
id: 'npm',
|
|
246
|
+
status: 'fail',
|
|
247
|
+
message: `npm ${pkg.name} is at ${published} but ${lags.join(' and ')}`,
|
|
248
|
+
hint: 'check the release workflow\'s publish step',
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const relNote = releaseTag ? `, matches release ${releaseTag}` : ghRes.ok ? '' : ' (GitHub release not checked)';
|
|
252
|
+
return { id: 'npm', status: 'ok', message: `npm ${pkg.name} at ${published}${relNote}` };
|
|
253
|
+
}
|
|
254
|
+
function checkJira(projectRoot) {
|
|
255
|
+
const last = (0, auto_publish_1.readLastAutoPublishReport)(projectRoot);
|
|
256
|
+
if (!last)
|
|
257
|
+
return { id: 'jira', status: 'skipped', message: 'JIRA auto-publish: no report yet' };
|
|
258
|
+
const when = dateOnly(new Date(last.at).toISOString());
|
|
259
|
+
if (last.skipped) {
|
|
260
|
+
return { id: 'jira', status: 'skipped', message: `JIRA auto-publish skipped on ${when}: ${last.note ?? last.skipped}` };
|
|
261
|
+
}
|
|
262
|
+
if (last.counts.failed > 0) {
|
|
263
|
+
const sample = last.failures.slice(0, 3).map((f) => f.specId).join(', ');
|
|
264
|
+
const more = last.failures.length > 3 ? ', …' : '';
|
|
265
|
+
return {
|
|
266
|
+
id: 'jira',
|
|
267
|
+
status: 'fail',
|
|
268
|
+
message: `JIRA auto-publish: ${last.counts.failed} failed on ${when}${sample ? ` (${sample}${more})` : ''}`,
|
|
269
|
+
hint: 'details in .specship/jira-publish-last.json',
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
id: 'jira',
|
|
274
|
+
status: 'ok',
|
|
275
|
+
message: `JIRA auto-publish: ${last.counts.published} published, ${last.counts.unchanged} unchanged on ${when}`,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function parseWorktreePorcelain(out) {
|
|
279
|
+
const entries = [];
|
|
280
|
+
let cur = null;
|
|
281
|
+
for (const line of out.split(/\r?\n/)) {
|
|
282
|
+
if (line.startsWith('worktree ')) {
|
|
283
|
+
if (cur)
|
|
284
|
+
entries.push(cur);
|
|
285
|
+
cur = { path: line.slice('worktree '.length) };
|
|
286
|
+
}
|
|
287
|
+
else if (cur && line.startsWith('branch ')) {
|
|
288
|
+
cur.branch = line.slice('branch '.length).replace(/^refs\/heads\//, '');
|
|
289
|
+
}
|
|
290
|
+
else if (cur && line.startsWith('prunable')) {
|
|
291
|
+
cur.prunable = true;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (cur)
|
|
295
|
+
entries.push(cur);
|
|
296
|
+
return entries;
|
|
297
|
+
}
|
|
298
|
+
function isRunWorktree(e) {
|
|
299
|
+
if (e.branch?.startsWith('specship/wf-'))
|
|
300
|
+
return true;
|
|
301
|
+
return /[\\/]\.specship[\\/]worktrees[\\/]/.test(e.path);
|
|
302
|
+
}
|
|
303
|
+
function shortRunId(e) {
|
|
304
|
+
const src = e.branch ?? path.basename(e.path);
|
|
305
|
+
const m = /([0-9a-f]{8})$/i.exec(src) ?? /([0-9a-f]{8})$/i.exec(path.basename(e.path));
|
|
306
|
+
return m?.[1] ?? path.basename(e.path);
|
|
307
|
+
}
|
|
308
|
+
async function defaultBranch(exec) {
|
|
309
|
+
const sym = await exec('git', ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD']);
|
|
310
|
+
if (sym.ok && sym.stdout.trim())
|
|
311
|
+
return sym.stdout.trim().replace(/^origin\//, '');
|
|
312
|
+
for (const name of ['main', 'master']) {
|
|
313
|
+
const r = await exec('git', ['rev-parse', '--verify', '--quiet', `refs/heads/${name}`]);
|
|
314
|
+
if (r.ok)
|
|
315
|
+
return name;
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
async function checkWorktrees(exec, runIdFor) {
|
|
320
|
+
const list = await exec('git', ['worktree', 'list', '--porcelain']);
|
|
321
|
+
if (!list.ok) {
|
|
322
|
+
return { id: 'worktrees', status: 'skipped', message: `Worktrees: ${skipReason('git', list)}` };
|
|
323
|
+
}
|
|
324
|
+
const runTrees = parseWorktreePorcelain(list.stdout)
|
|
325
|
+
.slice(1) // the main worktree is never a run worktree
|
|
326
|
+
.filter((e) => !e.prunable && e.branch && isRunWorktree(e));
|
|
327
|
+
if (runTrees.length === 0) {
|
|
328
|
+
return { id: 'worktrees', status: 'ok', message: 'Worktrees: no workflow-run worktrees on disk' };
|
|
329
|
+
}
|
|
330
|
+
const base = await defaultBranch(exec);
|
|
331
|
+
if (!base)
|
|
332
|
+
return { id: 'worktrees', status: 'skipped', message: 'Worktrees: default branch unknown' };
|
|
333
|
+
const merged = await exec('git', ['branch', '--merged', base, '--format=%(refname:short)']);
|
|
334
|
+
if (!merged.ok) {
|
|
335
|
+
return { id: 'worktrees', status: 'skipped', message: `Worktrees: ${skipReason('git', merged)}` };
|
|
336
|
+
}
|
|
337
|
+
const mergedSet = new Set(merged.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean));
|
|
338
|
+
const stale = runTrees.filter((e) => mergedSet.has(e.branch));
|
|
339
|
+
if (stale.length === 0) {
|
|
340
|
+
return { id: 'worktrees', status: 'ok', message: `Worktrees: ${runTrees.length} run worktree(s), none merged` };
|
|
341
|
+
}
|
|
342
|
+
const ids = stale.map((e) => runIdFor?.(e.path, e.branch) ?? shortRunId(e));
|
|
343
|
+
return {
|
|
344
|
+
id: 'worktrees',
|
|
345
|
+
status: 'fail',
|
|
346
|
+
message: `${stale.length} merged workflow-run worktree(s) still on disk: ${stale.map((e) => path.basename(e.path)).join(', ')}`,
|
|
347
|
+
hint: ids.map((id) => `specship workflow purge ${id}`).join('; '),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
351
|
+
// Public API
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
/**
|
|
354
|
+
* Compute (or serve from cache) the pipeline pulse. Never throws: every
|
|
355
|
+
* check that cannot run cleanly degrades to `skipped`.
|
|
356
|
+
*/
|
|
357
|
+
async function computePulse(opts) {
|
|
358
|
+
const now = opts.now ?? Date.now;
|
|
359
|
+
const root = opts.projectRoot;
|
|
360
|
+
if (!opts.refresh && typeof opts.maxAgeMs === 'number') {
|
|
361
|
+
const cached = readCachedPulse(root);
|
|
362
|
+
if (cached && now() - cached.checkedAt <= opts.maxAgeMs)
|
|
363
|
+
return cached;
|
|
364
|
+
}
|
|
365
|
+
const exec = makeExec(opts.runner ?? exports.defaultCommandRunner, root, opts.commandTimeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS, opts.totalBudgetMs ?? DEFAULT_TOTAL_BUDGET_MS);
|
|
366
|
+
const safe = async (id, label, fn) => {
|
|
367
|
+
try {
|
|
368
|
+
return await fn();
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
return { id, status: 'skipped', message: `${label}: ${err instanceof Error ? err.message : String(err)}` };
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
// Network checks run concurrently so the total stays within budget.
|
|
375
|
+
const items = await Promise.all([
|
|
376
|
+
safe('release', 'Release', () => checkRelease(root, exec)),
|
|
377
|
+
safe('npm', 'npm', () => checkNpm(root, exec)),
|
|
378
|
+
safe('jira', 'JIRA auto-publish', () => checkJira(root)),
|
|
379
|
+
safe('worktrees', 'Worktrees', () => checkWorktrees(exec, opts.runIdForWorktree)),
|
|
380
|
+
]);
|
|
381
|
+
const result = { checkedAt: now(), items, fromCache: false };
|
|
382
|
+
if (opts.writeCache !== false) {
|
|
383
|
+
try {
|
|
384
|
+
(0, paths_1.writeJsonAtomic)(pulseCachePath(root), { checkedAt: result.checkedAt, items });
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
/* the cache is best-effort */
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* One human line per failing item; an empty array when everything is
|
|
394
|
+
* healthy or skipped (so a session-start summary stays silent).
|
|
395
|
+
*/
|
|
396
|
+
function formatPulseLines(items) {
|
|
397
|
+
return items
|
|
398
|
+
.filter((i) => i.status === 'fail')
|
|
399
|
+
.map((i) => `⚠ ${i.message}${i.hint ? ` — ${i.hint}` : ''}`);
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=pulse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pulse.js","sourceRoot":"","sources":["../../src/pulse/pulse.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/reflect/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAU7E,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmB9D;AAsBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/reflect/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAU7E,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmB9D;AAsBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,CA4D1D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAwCxE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAuCtE"}
|
|
@@ -113,11 +113,26 @@ const MEMORY_INDEX = (homeDir) => path.join(homeDir, '.claude', 'memory', 'MEMOR
|
|
|
113
113
|
function previewProposal(p) {
|
|
114
114
|
const { payload, targetPath, targetKind } = p;
|
|
115
115
|
const cur = readFileSafe(targetPath);
|
|
116
|
-
if (payload.kind === 'claude_md') {
|
|
116
|
+
if (payload.kind === 'claude_md' || payload.kind === 'conventions') {
|
|
117
117
|
const { start, end } = (0, targets_1.learningMarkers)(payload.markerId);
|
|
118
118
|
const after = previewMarkedUpsert(cur.content, start, end, payload.block);
|
|
119
119
|
return { targetPath, targetKind, exists: cur.exists, before: cur.content, after, diff: lineDiff(cur.content, after) };
|
|
120
120
|
}
|
|
121
|
+
if (payload.kind === 'domain_fact') {
|
|
122
|
+
// REQ-ALEARN-003.A2: an engine-written draft is recognizable by its
|
|
123
|
+
// frontmatter marker; anything else at the path is a human's file — refuse.
|
|
124
|
+
const conflict = cur.exists && !cur.content.includes((0, targets_1.domainFactMarker)(payload.slug));
|
|
125
|
+
const after = conflict ? cur.content : payload.content;
|
|
126
|
+
return {
|
|
127
|
+
targetPath,
|
|
128
|
+
targetKind,
|
|
129
|
+
exists: cur.exists,
|
|
130
|
+
before: cur.content,
|
|
131
|
+
after,
|
|
132
|
+
diff: conflict ? '(conflict: a non-SpecShip domain fact already exists here)' : lineDiff(cur.content, after),
|
|
133
|
+
conflict,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
121
136
|
if (payload.kind === 'memory_note') {
|
|
122
137
|
const conflict = cur.exists && !cur.content.includes((0, targets_1.memoryNoteMarker)(payload.slug));
|
|
123
138
|
const after = conflict ? cur.content : payload.note;
|
|
@@ -156,11 +171,20 @@ function previewProposal(p) {
|
|
|
156
171
|
*/
|
|
157
172
|
function applyProposal(p, homeDir) {
|
|
158
173
|
const { payload, targetPath } = p;
|
|
159
|
-
if (payload.kind === 'claude_md') {
|
|
174
|
+
if (payload.kind === 'claude_md' || payload.kind === 'conventions') {
|
|
160
175
|
const { start, end } = (0, targets_1.learningMarkers)(payload.markerId);
|
|
161
176
|
const res = (0, shared_1.upsertMarkedSection)(targetPath, start, end, payload.block);
|
|
162
177
|
return res === 'unchanged' ? 'unchanged' : 'applied';
|
|
163
178
|
}
|
|
179
|
+
if (payload.kind === 'domain_fact') {
|
|
180
|
+
const cur = readFileSafe(targetPath);
|
|
181
|
+
if (cur.exists && !cur.content.includes((0, targets_1.domainFactMarker)(payload.slug)))
|
|
182
|
+
return 'conflict';
|
|
183
|
+
if (cur.exists && cur.content === payload.content)
|
|
184
|
+
return 'unchanged';
|
|
185
|
+
(0, shared_1.atomicWriteFileSync)(targetPath, payload.content);
|
|
186
|
+
return 'applied';
|
|
187
|
+
}
|
|
164
188
|
if (payload.kind === 'memory_note') {
|
|
165
189
|
const cur = readFileSafe(targetPath);
|
|
166
190
|
if (cur.exists && !cur.content.includes((0, targets_1.memoryNoteMarker)(payload.slug)))
|
|
@@ -193,10 +217,21 @@ function applyProposal(p, homeDir) {
|
|
|
193
217
|
*/
|
|
194
218
|
function undoProposal(p, homeDir) {
|
|
195
219
|
const { payload, targetPath } = p;
|
|
196
|
-
if (payload.kind === 'claude_md') {
|
|
220
|
+
if (payload.kind === 'claude_md' || payload.kind === 'conventions') {
|
|
197
221
|
const { start, end } = (0, targets_1.learningMarkers)(payload.markerId);
|
|
198
222
|
return (0, shared_1.removeMarkedSection)(targetPath, start, end) === 'removed' ? 'undone' : 'noop';
|
|
199
223
|
}
|
|
224
|
+
if (payload.kind === 'domain_fact') {
|
|
225
|
+
const cur = readFileSafe(targetPath);
|
|
226
|
+
if (cur.exists && cur.content.includes((0, targets_1.domainFactMarker)(payload.slug))) {
|
|
227
|
+
try {
|
|
228
|
+
fs.unlinkSync(targetPath);
|
|
229
|
+
return 'undone';
|
|
230
|
+
}
|
|
231
|
+
catch { /* ignore */ }
|
|
232
|
+
}
|
|
233
|
+
return 'noop';
|
|
234
|
+
}
|
|
200
235
|
if (payload.kind === 'memory_note') {
|
|
201
236
|
const cur = readFileSafe(targetPath);
|
|
202
237
|
let touched = false;
|