dsh-archify-projects 0.0.0-stage → 0.1.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.
Files changed (148) hide show
  1. package/README.md +204 -2
  2. package/cordis.patch.yml +99 -0
  3. package/dist/client.js +2261 -0
  4. package/dist/client.js.map +1 -0
  5. package/docs/CONTAINER.md +197 -0
  6. package/docs/DESIGN.md +905 -0
  7. package/docs/HANDOVER.md +391 -0
  8. package/docs/PUBLISH.md +107 -0
  9. package/icon.svg +12 -0
  10. package/lib/host/archify-skill.js +116 -0
  11. package/lib/host/archify-skill.js.map +1 -0
  12. package/lib/host/config.js +95 -0
  13. package/lib/host/config.js.map +1 -0
  14. package/lib/host/context.js +28 -0
  15. package/lib/host/context.js.map +1 -0
  16. package/lib/host/git.js +185 -0
  17. package/lib/host/git.js.map +1 -0
  18. package/lib/host/http.js +184 -0
  19. package/lib/host/http.js.map +1 -0
  20. package/lib/host/index.js +90 -0
  21. package/lib/host/index.js.map +1 -0
  22. package/lib/host/policy.js +124 -0
  23. package/lib/host/policy.js.map +1 -0
  24. package/lib/host/routes.js +667 -0
  25. package/lib/host/routes.js.map +1 -0
  26. package/lib/host/runner.js +913 -0
  27. package/lib/host/runner.js.map +1 -0
  28. package/lib/host/store.js +370 -0
  29. package/lib/host/store.js.map +1 -0
  30. package/lib/host/workspace.js +65 -0
  31. package/lib/host/workspace.js.map +1 -0
  32. package/lib/shared/format.js +138 -0
  33. package/lib/shared/format.js.map +1 -0
  34. package/lib/shared/prompt.js +257 -0
  35. package/lib/shared/prompt.js.map +1 -0
  36. package/lib/shared/protocol.js +31 -0
  37. package/lib/shared/protocol.js.map +1 -0
  38. package/lib/shared/types.js +173 -0
  39. package/lib/shared/types.js.map +1 -0
  40. package/locale/en.json +6 -0
  41. package/locale/zh.json +6 -0
  42. package/package.json +98 -4
  43. package/skills/archify/LICENSE +22 -0
  44. package/skills/archify/SKILL.md +109 -0
  45. package/skills/archify/THIRD_PARTY_NOTICES.md +69 -0
  46. package/skills/archify/assets/JetBrainsMono-OFL.txt +93 -0
  47. package/skills/archify/assets/template.html +13709 -0
  48. package/skills/archify/bin/archify.mjs +6936 -0
  49. package/skills/archify/bin/delivery-update.mjs +91 -0
  50. package/skills/archify/bin/finalize.mjs +895 -0
  51. package/skills/archify/bin/open-artifact.mjs +146 -0
  52. package/skills/archify/bin/preview.mjs +969 -0
  53. package/skills/archify/bin/recover-output.mjs +41 -0
  54. package/skills/archify/bin/visual-check.mjs +2667 -0
  55. package/skills/archify/brand-marks/README.md +31 -0
  56. package/skills/archify/brand-marks/catalog.json +131 -0
  57. package/skills/archify/delta/architecture-delta.mjs +1313 -0
  58. package/skills/archify/examples/agent-run.lifecycle.json +55 -0
  59. package/skills/archify/examples/agent-tool-call.workflow.json +74 -0
  60. package/skills/archify/examples/async-job-roundtrip.sequence.json +56 -0
  61. package/skills/archify/examples/brand-aware-delivery.architecture.json +34 -0
  62. package/skills/archify/examples/cache-miss-request.sequence.json +77 -0
  63. package/skills/archify/examples/checkout-platform.base.architecture.json +32 -0
  64. package/skills/archify/examples/checkout-platform.head.architecture.json +32 -0
  65. package/skills/archify/examples/dataflow-product-analytics.html +13820 -0
  66. package/skills/archify/examples/deployment-release.lifecycle.json +48 -0
  67. package/skills/archify/examples/event-stream.dataflow.json +52 -0
  68. package/skills/archify/examples/holiday-planning.workflow.json +143 -0
  69. package/skills/archify/examples/incident-response.workflow.json +59 -0
  70. package/skills/archify/examples/lifecycle-agent-run.html +13765 -0
  71. package/skills/archify/examples/locales/de.json +425 -0
  72. package/skills/archify/examples/locales/es.json +440 -0
  73. package/skills/archify/examples/locales/fr.json +425 -0
  74. package/skills/archify/examples/locales/fr.partial.json +22 -0
  75. package/skills/archify/examples/locales/it.json +425 -0
  76. package/skills/archify/examples/locales/ja.json +425 -0
  77. package/skills/archify/examples/locales/ko.json +440 -0
  78. package/skills/archify/examples/locales/pt.json +425 -0
  79. package/skills/archify/examples/locales/ru.json +425 -0
  80. package/skills/archify/examples/product-analytics.dataflow.json +71 -0
  81. package/skills/archify/examples/production-deployment.architecture.json +51 -0
  82. package/skills/archify/examples/release-delivery.workflow.json +57 -0
  83. package/skills/archify/examples/sequence-cache-miss-request.html +13835 -0
  84. package/skills/archify/examples/web-app-rendered.html +13808 -0
  85. package/skills/archify/examples/web-app.architecture.json +41 -0
  86. package/skills/archify/examples/workflow-agent-tool-call-rendered.html +13826 -0
  87. package/skills/archify/migrations/workflow-v2.mjs +280 -0
  88. package/skills/archify/package.json +17 -0
  89. package/skills/archify/recipes/scenarios.mjs +430 -0
  90. package/skills/archify/references/architecture-layout-repair.md +18 -0
  91. package/skills/archify/references/authoring-contract.md +419 -0
  92. package/skills/archify/references/authoring-defaults.md +41 -0
  93. package/skills/archify/references/brand-marks.md +82 -0
  94. package/skills/archify/references/delivery-contract.md +588 -0
  95. package/skills/archify/references/repository-authoring.md +105 -0
  96. package/skills/archify/references/update-awareness.md +12 -0
  97. package/skills/archify/references/viewer-runtime.md +35 -0
  98. package/skills/archify/renderers/architecture/grid.mjs +62 -0
  99. package/skills/archify/renderers/architecture/labels.mjs +215 -0
  100. package/skills/archify/renderers/architecture/render-architecture.mjs +1001 -0
  101. package/skills/archify/renderers/architecture/routing.mjs +1157 -0
  102. package/skills/archify/renderers/dataflow/README.md +105 -0
  103. package/skills/archify/renderers/dataflow/render-dataflow.mjs +544 -0
  104. package/skills/archify/renderers/lifecycle/README.md +171 -0
  105. package/skills/archify/renderers/lifecycle/grid-routing.mjs +429 -0
  106. package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +938 -0
  107. package/skills/archify/renderers/sequence/README.md +129 -0
  108. package/skills/archify/renderers/sequence/render-sequence.mjs +526 -0
  109. package/skills/archify/renderers/shared/atomic-output.mjs +1982 -0
  110. package/skills/archify/renderers/shared/brand-marks.mjs +670 -0
  111. package/skills/archify/renderers/shared/cli.mjs +451 -0
  112. package/skills/archify/renderers/shared/desktop-readability.mjs +132 -0
  113. package/skills/archify/renderers/shared/diagnostics.mjs +173 -0
  114. package/skills/archify/renderers/shared/engineering-profiles.mjs +157 -0
  115. package/skills/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  116. package/skills/archify/renderers/shared/generated-validators.mjs +134 -0
  117. package/skills/archify/renderers/shared/geometry.mjs +1941 -0
  118. package/skills/archify/renderers/shared/i18n.mjs +603 -0
  119. package/skills/archify/renderers/shared/layout-report.mjs +42 -0
  120. package/skills/archify/renderers/shared/legend.mjs +217 -0
  121. package/skills/archify/renderers/shared/output-path.mjs +440 -0
  122. package/skills/archify/renderers/shared/path-semantics.mjs +1017 -0
  123. package/skills/archify/renderers/shared/portable-path.mjs +408 -0
  124. package/skills/archify/renderers/shared/repository-evidence.mjs +352 -0
  125. package/skills/archify/renderers/shared/repository-location.mjs +59 -0
  126. package/skills/archify/renderers/shared/route-quality.mjs +614 -0
  127. package/skills/archify/renderers/shared/sidecar-path.mjs +38 -0
  128. package/skills/archify/renderers/shared/spatial-grid.mjs +66 -0
  129. package/skills/archify/renderers/shared/text-fit.mjs +105 -0
  130. package/skills/archify/renderers/shared/utils.mjs +254 -0
  131. package/skills/archify/renderers/shared/validator.mjs +86 -0
  132. package/skills/archify/renderers/workflow/README.md +301 -0
  133. package/skills/archify/renderers/workflow/render-workflow.mjs +37 -0
  134. package/skills/archify/renderers/workflow/workflow-compiler.mjs +4913 -0
  135. package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  136. package/skills/archify/schemas/README.md +256 -0
  137. package/skills/archify/schemas/architecture.schema.json +152 -0
  138. package/skills/archify/schemas/common.schema.json +181 -0
  139. package/skills/archify/schemas/dataflow.schema.json +254 -0
  140. package/skills/archify/schemas/lifecycle.schema.json +280 -0
  141. package/skills/archify/schemas/sequence.schema.json +234 -0
  142. package/skills/archify/schemas/workflow.schema.json +439 -0
  143. package/skills/archify/scripts/check-render-output.mjs +1388 -0
  144. package/skills/archify/scripts/check-update.mjs +1710 -0
  145. package/skills/archify/scripts/delivery-update-child.mjs +23 -0
  146. package/skills/archify/scripts/render-examples.mjs +26 -0
  147. package/skills/archify/scripts/update-contract.mjs +182 -0
  148. package/skills/archify/skill-release.json +10 -0
@@ -0,0 +1,42 @@
1
+ /** Serialize computed layout for dry-run / inspect (#9). */
2
+
3
+ export function componentBox(c) {
4
+ return {
5
+ id: c.id,
6
+ type: c.type,
7
+ label: c.label,
8
+ x: Math.round(c.x),
9
+ y: Math.round(c.y),
10
+ width: c.width,
11
+ height: c.height,
12
+ ...(Number.isInteger(c.row) ? { row: c.row } : {}),
13
+ ...(Number.isInteger(c.col) ? { col: c.col } : {}),
14
+ ...(Array.isArray(c.pos) ? { pos: c.pos.map(Math.round) } : {}),
15
+ };
16
+ }
17
+
18
+ export function boundaryBox(b) {
19
+ return {
20
+ kind: b.kind,
21
+ label: b.label,
22
+ x: Math.round(b.x),
23
+ y: Math.round(b.y),
24
+ width: Math.round(b.width),
25
+ height: Math.round(b.height),
26
+ wraps: b.wraps,
27
+ };
28
+ }
29
+
30
+ export function connectionPath(conn, routed, labelAt) {
31
+ return {
32
+ from: conn.from,
33
+ to: conn.to,
34
+ label: conn.label ?? null,
35
+ variant: conn.variant ?? 'default',
36
+ route: conn.route ?? 'auto',
37
+ // These points are repair inputs: rounding a fractional port makes a
38
+ // reused waypoint diagonal relative to the actual endpoint.
39
+ points: routed.points.map(([x, y]) => [x, y]),
40
+ ...(labelAt ? { labelAt: labelAt.map(Math.round) } : {}),
41
+ };
42
+ }
@@ -0,0 +1,217 @@
1
+ import { throwDiagnosticError } from './diagnostics.mjs';
2
+ import { rectsOverlap, segmentIntersectsRect } from './geometry.mjs';
3
+ import { esc, textUnits } from './utils.mjs';
4
+ import { translateMessage } from './i18n.mjs';
5
+
6
+ const DEFAULT_FONT_SIZE = 8;
7
+ const DEFAULT_ITEM_GAP = 22;
8
+ const DEFAULT_LINE_GAP = 22;
9
+ const DEFAULT_SWATCH_GAP = 8;
10
+ const TEXT_ADVANCE_EM = 0.62;
11
+ const INTERACTIVE_BADGE_ALLOWANCE = 21;
12
+
13
+ export function relationshipLegendObstacles(relations, { pointsFor, labelRectFor } = {}) {
14
+ const obstacles = [];
15
+ for (const [index, relation] of (Array.isArray(relations) ? relations : []).entries()) {
16
+ const points = typeof pointsFor === 'function' ? pointsFor(relation, index) : [];
17
+ const finitePoints = (Array.isArray(points) ? points : []).filter((point) => (
18
+ Array.isArray(point) && point.length === 2 && point.every(Number.isFinite)
19
+ ));
20
+ for (let pointIndex = 0; pointIndex < finitePoints.length - 1; pointIndex += 1) {
21
+ obstacles.push({
22
+ kind: 'relationship-segment',
23
+ start: finitePoints[pointIndex],
24
+ end: finitePoints[pointIndex + 1],
25
+ });
26
+ }
27
+ const labelRect = typeof labelRectFor === 'function' ? labelRectFor(relation, index) : null;
28
+ if (labelRect && [labelRect.x, labelRect.y, labelRect.width, labelRect.height].every(Number.isFinite)) {
29
+ obstacles.push({ kind: 'relationship-label', ...labelRect });
30
+ }
31
+ }
32
+ return obstacles;
33
+ }
34
+
35
+ export function resolveLegend(config, catalog, presentKinds) {
36
+ const mode = config?.mode || 'auto';
37
+ if (mode === 'hidden') return [];
38
+ const present = presentKinds instanceof Set ? presentKinds : new Set(presentKinds || []);
39
+ const overrides = config?.entries || {};
40
+
41
+ return catalog.flatMap((catalogEntry) => {
42
+ const override = overrides[catalogEntry.kind] || {};
43
+ const selectedByMode = mode === 'all' || present.has(catalogEntry.kind);
44
+ const visible = override.visible === true || (selectedByMode && override.visible !== false);
45
+ if (!visible) return [];
46
+ return [{
47
+ ...catalogEntry,
48
+ label: override.label || catalogEntry.label,
49
+ present: present.has(catalogEntry.kind),
50
+ interactive: catalogEntry.interactive !== false && present.has(catalogEntry.kind),
51
+ }];
52
+ });
53
+ }
54
+
55
+ function measuredEntryWidth(entry, fontSize, swatchGap) {
56
+ const swatchWidth = entry.swatchWidth ?? 14;
57
+ return Math.ceil(
58
+ swatchWidth
59
+ + swatchGap
60
+ + textUnits(entry.label) * fontSize * TEXT_ADVANCE_EM
61
+ + (entry.interactive ? INTERACTIVE_BADGE_ALLOWANCE : 0),
62
+ );
63
+ }
64
+
65
+ // One pure footprint calculation owns both auto-viewBox sizing and final SVG
66
+ // placement. Callers must not maintain a second approximation of legend width
67
+ // or row count; that would make generated geometry disagree with validation.
68
+ export function legendFootprint(entries, {
69
+ width,
70
+ fontSize = DEFAULT_FONT_SIZE,
71
+ itemGap = DEFAULT_ITEM_GAP,
72
+ lineGap = DEFAULT_LINE_GAP,
73
+ swatchGap = DEFAULT_SWATCH_GAP,
74
+ } = {}) {
75
+ if (!entries.length) {
76
+ return { measured: [], rows: [], rowCount: 0, minWidth: 0, extraHeight: 0 };
77
+ }
78
+ const measured = entries.map((entry) => ({
79
+ ...entry,
80
+ width: measuredEntryWidth(entry, fontSize, entry.swatchGap ?? swatchGap),
81
+ }));
82
+ const rows = [[]];
83
+ let cursor = 0;
84
+ for (const entry of measured) {
85
+ const row = rows.at(-1);
86
+ const required = (row.length ? itemGap : 0) + entry.width;
87
+ if (row.length && cursor + required > width) {
88
+ rows.push([entry]);
89
+ cursor = entry.width;
90
+ } else {
91
+ row.push(entry);
92
+ cursor += required;
93
+ }
94
+ }
95
+ return {
96
+ measured,
97
+ rows,
98
+ rowCount: rows.length,
99
+ minWidth: measured.reduce((width, entry) => Math.max(width, entry.width), 0),
100
+ extraHeight: (rows.length - 1) * lineGap,
101
+ };
102
+ }
103
+
104
+ export function measureLegend(entries, {
105
+ x,
106
+ baselineY,
107
+ width,
108
+ fontSize = DEFAULT_FONT_SIZE,
109
+ itemGap = DEFAULT_ITEM_GAP,
110
+ lineGap = DEFAULT_LINE_GAP,
111
+ swatchGap = DEFAULT_SWATCH_GAP,
112
+ minTitleY = 0,
113
+ obstacles = [],
114
+ unfit = 'error',
115
+ diagramType = 'diagram',
116
+ } = {}) {
117
+ if (!entries.length) return { entries: [], rowCount: 0, titleY: null };
118
+ const footprint = legendFootprint(entries, { width, fontSize, itemGap, lineGap, swatchGap });
119
+ const tooWide = footprint.measured.find((entry) => entry.width > width);
120
+ if (tooWide) {
121
+ if (unfit === 'hide') return null;
122
+ const message = `[legend/label-too-wide] ${diagramType} legend label for "${tooWide.kind}" needs ${tooWide.width}px but only ${width}px is available.`;
123
+ throwDiagnosticError(message, [{
124
+ code: 'legend/label-too-wide',
125
+ severity: 'error',
126
+ message,
127
+ subject: { diagramType, path: `/meta/legend/entries/${tooWide.kind}/label` },
128
+ evidence: { kind: tooWide.kind, measuredWidthPx: tooWide.width, availableWidthPx: width },
129
+ supportedFixes: ['shorten the legend label or use a wider viewBox'],
130
+ }]);
131
+ }
132
+
133
+ const titleY = baselineY - footprint.extraHeight - 20;
134
+ const legendTopY = titleY - 10;
135
+ if (legendTopY < minTitleY) {
136
+ if (unfit === 'hide') return null;
137
+ const message = `[legend/vertical-overflow] ${diagramType} legend needs ${footprint.rowCount} rows, which would start at y=${legendTopY} above the available legend band at y=${minTitleY}.`;
138
+ throwDiagnosticError(message, [{
139
+ code: 'legend/vertical-overflow',
140
+ severity: 'error',
141
+ message,
142
+ subject: { diagramType, path: '/meta/legend' },
143
+ evidence: { rowCount: footprint.rowCount, requiredTopY: legendTopY, availableTopY: minTitleY },
144
+ supportedFixes: ['shorten legend labels, hide nonessential entries, or use a wider viewBox'],
145
+ }]);
146
+ }
147
+
148
+ const positioned = [];
149
+ footprint.rows.forEach((row, rowIndex) => {
150
+ let entryX = x;
151
+ const baseline = baselineY - (footprint.rowCount - rowIndex - 1) * lineGap;
152
+ for (const entry of row) {
153
+ positioned.push({ ...entry, x: entryX, baseline, row: rowIndex });
154
+ entryX += entry.width + itemGap;
155
+ }
156
+ });
157
+
158
+ const legendRects = [
159
+ { kind: 'title', x, y: legendTopY, width: 48, height: 14 },
160
+ ...positioned.map((entry) => ({
161
+ kind: entry.kind,
162
+ x: entry.x,
163
+ y: entry.baseline - 10,
164
+ width: entry.width,
165
+ height: 14,
166
+ })),
167
+ ];
168
+ const collision = legendRects.find((legendRect) => obstacles.some((obstacle) => (
169
+ Array.isArray(obstacle.start) && Array.isArray(obstacle.end)
170
+ ? segmentIntersectsRect({ start: obstacle.start, end: obstacle.end }, legendRect)
171
+ : rectsOverlap(obstacle, legendRect)
172
+ )));
173
+ if (collision) {
174
+ if (unfit === 'hide') return null;
175
+ const message = `[legend/content-overlap] ${diagramType} legend entry "${collision.kind}" overlaps authored relationship geometry.`;
176
+ throwDiagnosticError(message, [{
177
+ code: 'legend/content-overlap',
178
+ severity: 'error',
179
+ message,
180
+ subject: { diagramType, path: '/meta/legend' },
181
+ evidence: { legendKind: collision.kind, legendRect: collision },
182
+ supportedFixes: ['shorten or hide legend entries, use a wider viewBox, or move the authored relationship route/label out of the legend band'],
183
+ }]);
184
+ }
185
+
186
+ return {
187
+ entries: positioned,
188
+ rowCount: footprint.rowCount,
189
+ titleY,
190
+ fontSize,
191
+ };
192
+ }
193
+
194
+ export function renderLegend({ entries, layout, renderSwatch, locale }) {
195
+ if (!entries.length) return '';
196
+ const measured = measureLegend(entries, layout);
197
+ if (!measured) return '';
198
+ const hasInteractiveEntries = measured.entries.some((entry) => entry.interactive);
199
+ const renderedFontSize = measured.fontSize < 8 ? measured.fontSize + 0.5 : measured.fontSize + 2;
200
+ const rootAttributes = hasInteractiveEntries ? ' data-legend="" data-legend-bridge=""' : ' data-legend=""';
201
+ const parts = [
202
+ ` <g${rootAttributes}>`,
203
+ ` <text x="${layout.x}" y="${measured.titleY}" class="t-primary" font-size="12" font-weight="650">${esc(translateMessage(locale, 'legend.title'))}</text>`,
204
+ ];
205
+
206
+ for (const entry of measured.entries) {
207
+ const interactive = entry.interactive
208
+ ? ` data-legend-kind="${esc(entry.kind)}" data-legend-label="${esc(entry.label)}"`
209
+ : '';
210
+ parts.push(` <g data-legend-semantic-kind="${esc(entry.kind)}"${interactive} data-legend-x="${entry.x}" data-legend-baseline="${entry.baseline}" data-legend-width="${entry.width}">`);
211
+ parts.push(` ${renderSwatch(entry)}`);
212
+ parts.push(` <text x="${entry.x + (entry.swatchWidth ?? 14) + (entry.swatchGap ?? DEFAULT_SWATCH_GAP)}" y="${entry.baseline}" class="t-muted" font-size="${renderedFontSize}" font-weight="500">${esc(entry.label)}</text>`);
213
+ parts.push(' </g>');
214
+ }
215
+ parts.push(' </g>');
216
+ return parts.join('\n');
217
+ }