@piecemaker-legal/piecemaker 2.0.9 → 2.0.11
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/dist/assets/FindReplaceDialog-KU5TEIBJ-BucOHLdm.js +1 -0
- package/dist/assets/FootnotePropertiesDialog-W3YHM4BV-D5UqbelV.js +1 -0
- package/dist/assets/HyperlinkDialog-ZYH7ZHRF-8yEhLigd.js +144 -0
- package/dist/assets/HyperlinkDialog-ZYH7ZHRF-qIPBOssF.css +1 -0
- package/dist/assets/ImagePositionDialog-HEWYR6Q3-wGIBYxCm.js +1 -0
- package/dist/assets/ImagePropertiesDialog-RAB47C6M-D86PckZ2.js +1 -0
- package/dist/assets/PageSetupDialog-AIGIXO3E-DLETP-7v.js +1 -0
- package/dist/assets/SplitCellDialog-IFBKYCD6-CwdQBXeb.js +1 -0
- package/dist/assets/TablePropertiesDialog-TMLKGOOW-j2nA7KJs.js +1 -0
- package/dist/assets/WatermarkDialog-KRL7WMIS-XFJ9gTkC.js +1 -0
- package/dist/assets/{abnfDiagram-VCTEODGH-WrsSAHOe.js → abnfDiagram-VCTEODGH-DiCrND_Y.js} +1 -1
- package/dist/assets/arc-DOjgbMYz.js +1 -0
- package/dist/assets/architectureDiagram-5GKGNRK7-brzIFVhl.js +36 -0
- package/dist/assets/{blockDiagram-I7D4REHJ-zGMnF7Ox.js → blockDiagram-I7D4REHJ-C8JhTjQQ.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-ClWw3bqt.js → c4Diagram-7LVT6UL2-jfYxccyk.js} +1 -1
- package/dist/assets/channel-Dajzu2W1.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-C-9ICPHv.js → chunk-2Q5K7J3B-CrlEShp9.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-Bawy3teT.js → chunk-5VM5RSS4-DzPlUHGq.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-DQ375RQO.js → chunk-F27PBJKO-Cp9cpeWU.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-CflNF2f6.js → chunk-IMKFNOWR-BifUldEN.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-CIXQv0gc.js → chunk-JWPE2WC7-ggPEIkWu.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-Cza5j6Qw.js → chunk-POPQ4Y6H-3h_nayRX.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-GQ_VvWZR.js → chunk-SVP7TREG-CH29aG6J.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-BEmU16W5.js → chunk-TICWLB2K-PluJUM5k.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-C1KpkLYH.js → chunk-XXDRQBXY-DXU39Vwg.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-dDEP_giv.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-dDEP_giv.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-CZE48TRG.js → cose-bilkent-JH36ORCC-Dz6roYrN.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-L-tx1eC-.js → cynefin-OW5HDTMX-BLzrpSit.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-Coa8oJwR.js → cynefinDiagram-5FMLGOSQ-kfxnERDZ.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-Bu_3Y75K.js → dagre-GXQ25YYZ-DP57bp-N.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-CFiiV4es.js → diagram-S7CK7UJ4-DAlsrQVW.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-CCXheGAA.js → diagram-UQ7AKVKN-By5yrMer.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-B70m4lr_.js → diagram-VSXAHHWV-Dx89kryN.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-CHkiMOVA.js → diagram-VX7I27RA-B9fARitZ.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-_awpc4Bs.js → diagram-Z3DM3KII-DC15CEH1.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-CZzjH86H.js → ebnfDiagram-PWID7BFC-BKQzghGF.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-9DgiHZg9.js → erDiagram-RLTQ6QDP-CPY6RM7G.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-DHY_503b.js → flowDiagram-HODETNUW-4dL4GJcf.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-DPiiYZ_l.js → ganttDiagram-EL5Y4UJY-D4-cVcfb.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-Ddd_evm7.js → gitGraphDiagram-WWUBYQGX-BMeVIEiX.js} +1 -1
- package/dist/assets/{index-tibHq7Qp.js → index-DNtFDOni.js} +140 -140
- package/dist/assets/index-Dc9wNuS4.css +1 -0
- package/dist/assets/{infoDiagram-27XIBGKW-BPRNhfwb.js → infoDiagram-27XIBGKW-D5qMSUEU.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-BXx6aqkq.js → ishikawaDiagram-5VMMS53U-BDnyKRHm.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-BK8TZM29.js → journeyDiagram-3NMN7TZE-dGz5ZGzq.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-CHioRmxz.js → kanban-definition-UXKFOSKX-D7UAz7o_.js} +6 -6
- package/dist/assets/layout-DKrmEGrz.js +1 -0
- package/dist/assets/{linear-CTEhUcKG.js → linear-CrTdMY-p.js} +1 -1
- package/dist/assets/{mermaid.core-DYUb_UUB.js → mermaid.core-CXQOT5G6.js} +7 -7
- package/dist/assets/{mindmap-definition-YA3MSWOX-D7ODZ4oS.js → mindmap-definition-YA3MSWOX-VgEiYfay.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-8J-_2_kw.js → pegDiagram-XKGWAZYB-9IqT8gGx.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-ebg0yfMi.js → pieDiagram-E7YTZNPT-D98pRE-t.js} +1 -1
- package/dist/assets/processTemplate-GPFDLQMX-B1sVV2O0.js +22 -0
- package/dist/assets/{quadrantDiagram-AXDQQJYC-BoWkDiFb.js → quadrantDiagram-AXDQQJYC-b9PwkYzL.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-BRJ77ldz.js → railroadDiagram-O6MQD6OU-Dz87hsPE.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-Z0JJgktA.js → requirementDiagram-BXWQKSXE-CkcV73dK.js} +1 -1
- package/dist/assets/sankeyDiagram-P5KCCOFB-UBN31Yrs.js +40 -0
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-BPAjtXwp.js → sequenceDiagram-WJ2MYXX4-CpQxd5Za.js} +1 -1
- package/dist/assets/{server.browser-BzI1jrZw.js → server.browser-BY3bL-IX.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BGZPCzM4.js → sizeCapture-INFHLROL-mCsFmyzw.js} +1 -1
- package/dist/assets/stateDiagram-D77RDMKH-B0MTBN-3.js +1 -0
- package/dist/assets/stateDiagram-v2-MP3YSRHH-DzBPN39W.js +1 -0
- package/dist/assets/{swimlanes-42K2YHIH-DvuB15qF.js → swimlanes-42K2YHIH-Dzydjm0e.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-BXQpbUMD.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-ZIziYCIF.js → timeline-definition-24CTP7MA-Dz0toOLu.js} +3 -3
- package/dist/assets/{vendor-codemirror-CjW0lHR5.js → vendor-codemirror-CN-sJePf.js} +2 -2
- package/dist/assets/{vendor-react-D809iwXR.js → vendor-react-B22wqN3J.js} +5 -5
- package/dist/assets/{vennDiagram-4TSXK5OY-C5_B9gWa.js → vennDiagram-4TSXK5OY-DOWp7dkf.js} +4 -4
- package/dist/assets/{wardleyDiagram-VM6X3IG4-DMlH9Afw.js → wardleyDiagram-VM6X3IG4-CUxsztUB.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-BldhJt7i.js → xychartDiagram-S5SC5T6Z-DS96vNED.js} +1 -1
- package/dist/index.html +4 -4
- package/dist/sw.js +1 -1
- package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js +4 -53
- package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js +2 -3
- package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js +30 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js.map +1 -0
- package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js +24 -0
- package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js.map +1 -0
- package/dist-server/server/piecemaker/agent-instructions.js +148 -0
- package/dist-server/server/piecemaker/agent-instructions.js.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/lifecycle.js +2 -3
- package/dist-server/server/piecemaker/anonymizer/lifecycle.js.map +1 -1
- package/dist-server/server/piecemaker/docx-document.js +50 -0
- package/dist-server/server/piecemaker/docx-document.js.map +1 -0
- package/dist-server/server/piecemaker/index.js +13 -2
- package/dist-server/server/piecemaker/index.js.map +1 -1
- package/dist-server/server/piecemaker/model-discovery/codex-catalog.js +46 -0
- package/dist-server/server/piecemaker/model-discovery/codex-catalog.js.map +1 -0
- package/dist-server/server/piecemaker/model-discovery/index.js +42 -0
- package/dist-server/server/piecemaker/model-discovery/index.js.map +1 -0
- package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js +19 -0
- package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js.map +1 -0
- package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js +61 -0
- package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js.map +1 -0
- package/dist-server/server/piecemaker/project-registry.js +29 -0
- package/dist-server/server/piecemaker/project-registry.js.map +1 -0
- package/package.json +12 -1
- package/scripts/piecemaker/cli/disable-anonymizer.mjs +19 -0
- package/scripts/piecemaker/cli/lib/config.mjs +0 -1
- package/scripts/piecemaker/cli/lib/plugins.mjs +1 -0
- package/scripts/piecemaker/cli/lib/services.mjs +1 -10
- package/scripts/piecemaker/cli/piecemaker.mjs +0 -3
- package/server/modules/providers/list/mistral/mistral-models.provider.ts +4 -53
- package/server/modules/providers/list/mistral/mistral-runtime.provider.ts +2 -3
- package/server/modules/providers/list/mistral/mistral-vibe-models.ts +43 -0
- package/server/modules/providers/tests/mistral-vibe-models.test.ts +27 -0
- package/server/piecemaker/agent-instructions.ts +148 -0
- package/server/piecemaker/anonymizer/client-config.cjs +92 -92
- package/server/piecemaker/anonymizer/dictionary.cjs +34 -3
- package/server/piecemaker/anonymizer/hudsucker-fixture.cjs +9 -16
- package/server/piecemaker/anonymizer/hudsucker-proxy/Cargo.toml +1 -1
- package/server/piecemaker/anonymizer/hudsucker-proxy/src/main.rs +251 -268
- package/server/piecemaker/anonymizer/hudsucker-smoke.cjs +343 -0
- package/server/piecemaker/anonymizer/lifecycle.ts +2 -3
- package/server/piecemaker/anonymizer/rewriter-bridge.cjs +13 -4
- package/server/piecemaker/anonymizer/rewriter-worker.cjs +85 -0
- package/server/piecemaker/anonymizer/service.cjs +109 -179
- package/server/piecemaker/anonymizer/sqlite-dictionary.cjs +12 -1
- package/server/piecemaker/docx-document.ts +54 -0
- package/server/piecemaker/harness/decisions.cjs +1 -1
- package/server/piecemaker/harness/index.cjs +2 -3
- package/server/piecemaker/harness/verification.cjs +1 -1
- package/server/piecemaker/index.ts +15 -3
- package/server/piecemaker/model-discovery/codex-catalog.ts +67 -0
- package/server/piecemaker/model-discovery/index.ts +69 -0
- package/server/piecemaker/model-discovery/mistral-catalog.ts +36 -0
- package/server/piecemaker/model-discovery/stdio-rpc.ts +79 -0
- package/server/piecemaker/project-registry.ts +34 -0
- package/server/piecemaker/router.cjs +6 -8
- package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +31 -77
- package/server/piecemaker/vendor/installer/lib/codex-skills.mjs +2 -84
- package/server/piecemaker/vendor/installer/lib/service.mjs +4 -24
- package/server/piecemaker/vendor/installer/steps/02-dependances-node.mjs +5 -5
- package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +10 -21
- package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +0 -11
- package/server/piecemaker/vendor/installer/steps/09-codex-plugin.mjs +6 -36
- package/server/piecemaker/vendor/installer/steps/13-garde-secrets.mjs +30 -12
- package/server/piecemaker/vendor/piecemaker-plugin/README.md +2 -9
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +5 -5
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/classify-ai-documents.mjs +8 -8
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +2 -2
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +4 -6
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs +2 -90
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +71 -38
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +8 -38
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +82 -61
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +189 -41
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +4 -55
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +24 -117
- package/server/piecemaker/vendor/piecemaker-plugin/skills/ajout-de-fonctionnalites/SKILL.md +4 -18
- package/server/piecemaker/vendor/piecemaker-plugin/skills/tamponnage/SKILL.md +2 -2
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +14 -148
- package/server/piecemaker/vendor/websocket-server/case-registry.cjs +16 -42
- package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +0 -73
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +0 -7
- package/server/piecemaker/vendor/websocket-server/stamping-routes.cjs +3 -12
- package/server/piecemaker/vendor/websocket-server/workspace-paths.cjs +6 -6
- package/dist/assets/arc-DAA6wH-C.js +0 -1
- package/dist/assets/architectureDiagram-5GKGNRK7-BGNHr7ef.js +0 -36
- package/dist/assets/channel-BAQyfMll.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-BNGCuvrR.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-BNGCuvrR.js +0 -1
- package/dist/assets/index-WwknP0l4.css +0 -1
- package/dist/assets/layout-DEnkyfTY.js +0 -1
- package/dist/assets/sankeyDiagram-P5KCCOFB-4PW5HTOP.js +0 -40
- package/dist/assets/stateDiagram-D77RDMKH-o-vEcKwz.js +0 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-BsuDaKkN.js +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-DcCAyKlT.js +0 -8
- package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +0 -78
- package/scripts/piecemaker/hooks/proxy-guard.mjs +0 -251
- package/server/piecemaker/anonymizer/providers.cjs +0 -120
- package/server/piecemaker/vendor/installer/steps/08-telegram.mjs +0 -482
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
- package/server/piecemaker/vendor/websocket-server/telegram-admin.cjs +0 -602
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
import type { ProviderModelOption, ProviderModelsDefinition } from '@/shared/types.js';
|
|
4
|
+
|
|
5
|
+
import { withStdioRpcServer, type RpcCall, type StdioRpcServer } from './stdio-rpc.js';
|
|
6
|
+
|
|
7
|
+
type CodexListedModel = {
|
|
8
|
+
model: string;
|
|
9
|
+
displayName?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
hidden?: boolean;
|
|
12
|
+
isDefault?: boolean;
|
|
13
|
+
defaultReasoningEffort?: string;
|
|
14
|
+
supportedReasoningEfforts?: { reasoningEffort: string; description?: string }[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type CodexModelListPage = {
|
|
18
|
+
data?: CodexListedModel[];
|
|
19
|
+
nextCursor?: string | null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const MAX_PAGES = 10;
|
|
23
|
+
|
|
24
|
+
function bundledCodexAppServer(): StdioRpcServer {
|
|
25
|
+
const launcher = createRequire(import.meta.url).resolve('@openai/codex/bin/codex.js');
|
|
26
|
+
return { command: process.execPath, args: [launcher, 'app-server'] };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function toModelOption(listed: CodexListedModel): ProviderModelOption {
|
|
30
|
+
const efforts = listed.supportedReasoningEfforts ?? [];
|
|
31
|
+
return {
|
|
32
|
+
value: listed.model,
|
|
33
|
+
label: listed.displayName || listed.model,
|
|
34
|
+
...(listed.description ? { description: listed.description } : {}),
|
|
35
|
+
...(efforts.length > 0 ? {
|
|
36
|
+
effort: {
|
|
37
|
+
...(listed.defaultReasoningEffort ? { default: listed.defaultReasoningEffort } : {}),
|
|
38
|
+
values: efforts.map(({ reasoningEffort, description }) => ({
|
|
39
|
+
value: reasoningEffort,
|
|
40
|
+
...(description ? { description } : {}),
|
|
41
|
+
})),
|
|
42
|
+
},
|
|
43
|
+
} : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function listCodexModels(call: RpcCall): Promise<ProviderModelsDefinition> {
|
|
48
|
+
const listed: CodexListedModel[] = [];
|
|
49
|
+
let cursor: string | null = null;
|
|
50
|
+
for (let page = 0; page < MAX_PAGES; page += 1) {
|
|
51
|
+
const result = await call('model/list', { cursor, includeHidden: false }) as CodexModelListPage;
|
|
52
|
+
listed.push(...(result.data ?? []));
|
|
53
|
+
cursor = result.nextCursor ?? null;
|
|
54
|
+
if (!cursor) break;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const visible = listed.filter((model) => model.model && !model.hidden);
|
|
58
|
+
if (visible.length === 0) throw new Error('codex app-server listed no models');
|
|
59
|
+
return {
|
|
60
|
+
OPTIONS: visible.map(toModelOption),
|
|
61
|
+
DEFAULT: (visible.find((model) => model.isDefault) ?? visible[0]).model,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function discoverCodexModels(timeoutMs: number): Promise<ProviderModelsDefinition> {
|
|
66
|
+
return withStdioRpcServer(bundledCodexAppServer(), listCodexModels, timeoutMs);
|
|
67
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { IProvider } from '@/shared/interfaces.js';
|
|
2
|
+
import type { ProviderModelsDefinition } from '@/shared/types.js';
|
|
3
|
+
|
|
4
|
+
import { discoverCodexModels } from './codex-catalog.js';
|
|
5
|
+
import { discoverMistralModels } from './mistral-catalog.js';
|
|
6
|
+
|
|
7
|
+
type Discover = (timeoutMs: number) => Promise<ProviderModelsDefinition>;
|
|
8
|
+
|
|
9
|
+
type ProviderLookup = {
|
|
10
|
+
resolveProvider(provider: string): Pick<IProvider, 'models'>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ModelDiscoveryOptions = {
|
|
14
|
+
discoverers?: Record<string, Discover>;
|
|
15
|
+
refreshAfterMs?: number;
|
|
16
|
+
retryAfterMs?: number;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
now?: () => number;
|
|
19
|
+
warn?: (message: string) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const DEFAULT_DISCOVERERS: Record<string, Discover> = {
|
|
23
|
+
codex: discoverCodexModels,
|
|
24
|
+
mistral: discoverMistralModels,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function installModelDiscovery(registry: ProviderLookup, options: ModelDiscoveryOptions = {}) {
|
|
28
|
+
const {
|
|
29
|
+
discoverers = DEFAULT_DISCOVERERS,
|
|
30
|
+
refreshAfterMs = 10 * 60_000,
|
|
31
|
+
retryAfterMs = 60_000,
|
|
32
|
+
timeoutMs = 20_000,
|
|
33
|
+
now = Date.now,
|
|
34
|
+
warn = (message) => console.warn(message),
|
|
35
|
+
} = options;
|
|
36
|
+
|
|
37
|
+
for (const [provider, discover] of Object.entries(discoverers)) {
|
|
38
|
+
const models = registry.resolveProvider(provider).models;
|
|
39
|
+
const curated = models.getSupportedModels.bind(models);
|
|
40
|
+
let lastDiscovered: ProviderModelsDefinition | null = null;
|
|
41
|
+
let served: ProviderModelsDefinition | null = null;
|
|
42
|
+
let expiresAt = 0;
|
|
43
|
+
let refreshing: Promise<ProviderModelsDefinition> | null = null;
|
|
44
|
+
|
|
45
|
+
const refresh = () => {
|
|
46
|
+
refreshing ??= (async () => {
|
|
47
|
+
try {
|
|
48
|
+
lastDiscovered = await discover(timeoutMs);
|
|
49
|
+
served = lastDiscovered;
|
|
50
|
+
expiresAt = now() + refreshAfterMs;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
warn(`[PieceMaker] ${provider} model discovery failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
53
|
+
served = lastDiscovered ?? await curated();
|
|
54
|
+
expiresAt = now() + retryAfterMs;
|
|
55
|
+
}
|
|
56
|
+
return served;
|
|
57
|
+
})().finally(() => { refreshing = null; });
|
|
58
|
+
return refreshing;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
models.getSupportedModels = async () => {
|
|
62
|
+
if (!served) return refresh();
|
|
63
|
+
if (now() >= expiresAt) void refresh();
|
|
64
|
+
return served;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
void models.getSupportedModels();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { buildVibeModelsEnvironment, vibeModelOption } from '@/modules/providers/list/mistral/mistral-vibe-models.js';
|
|
2
|
+
import type { ProviderModelsDefinition } from '@/shared/types.js';
|
|
3
|
+
|
|
4
|
+
import { withStdioRpcServer, type RpcCall } from './stdio-rpc.js';
|
|
5
|
+
|
|
6
|
+
type VibeModelView = {
|
|
7
|
+
name: string;
|
|
8
|
+
alias: string;
|
|
9
|
+
displayName?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type VibeConfigRead = {
|
|
13
|
+
config?: {
|
|
14
|
+
models?: VibeModelView[];
|
|
15
|
+
activeModel?: { alias?: string } | null;
|
|
16
|
+
defaultModelAlias?: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export async function listVibeModels(call: RpcCall): Promise<ProviderModelsDefinition> {
|
|
21
|
+
const { config } = await call('config/read', {}) as VibeConfigRead;
|
|
22
|
+
const models = (config?.models ?? []).filter((model) => model.alias);
|
|
23
|
+
if (models.length === 0) throw new Error('vibe-app-server listed no models');
|
|
24
|
+
|
|
25
|
+
const aliases = new Set(models.map((model) => model.alias));
|
|
26
|
+
const preferred = [config?.activeModel?.alias, config?.defaultModelAlias].find((alias) => alias && aliases.has(alias));
|
|
27
|
+
return {
|
|
28
|
+
OPTIONS: models.map((model) => vibeModelOption(model.alias, model.displayName || model.alias, model.name)),
|
|
29
|
+
DEFAULT: preferred ?? models[0].alias,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function discoverMistralModels(timeoutMs: number): Promise<ProviderModelsDefinition> {
|
|
34
|
+
const env = { ...process.env, VIBE_MODELS: buildVibeModelsEnvironment() };
|
|
35
|
+
return withStdioRpcServer({ command: 'vibe-app-server', args: [], env }, listVibeModels, timeoutMs);
|
|
36
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import readline from 'node:readline';
|
|
2
|
+
|
|
3
|
+
import crossSpawn from 'cross-spawn';
|
|
4
|
+
|
|
5
|
+
type RpcReply = {
|
|
6
|
+
id?: number;
|
|
7
|
+
result?: unknown;
|
|
8
|
+
error?: { message?: string };
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type RpcCall = (method: string, params: unknown) => Promise<unknown>;
|
|
12
|
+
|
|
13
|
+
export type StdioRpcServer = {
|
|
14
|
+
command: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
env?: NodeJS.ProcessEnv;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const CLIENT_INFO = { name: 'piecemaker', title: 'PieceMaker', version: '1' };
|
|
20
|
+
|
|
21
|
+
export async function withStdioRpcServer<T>(
|
|
22
|
+
server: StdioRpcServer,
|
|
23
|
+
exchange: (call: RpcCall) => Promise<T>,
|
|
24
|
+
timeoutMs: number,
|
|
25
|
+
): Promise<T> {
|
|
26
|
+
const child = crossSpawn(server.command, server.args, { env: server.env ?? process.env, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
27
|
+
const pending = new Map<number, (reply: RpcReply) => void>();
|
|
28
|
+
let nextId = 1;
|
|
29
|
+
let stderr = '';
|
|
30
|
+
|
|
31
|
+
const failAll = (reason: string) => {
|
|
32
|
+
for (const settle of pending.values()) settle({ error: { message: reason } });
|
|
33
|
+
pending.clear();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
child.stderr?.on('data', (chunk) => { stderr = (stderr + String(chunk)).slice(-1000); });
|
|
37
|
+
child.on('error', (error) => failAll(error.message));
|
|
38
|
+
child.on('exit', (code) => failAll(`${server.command} exited (code ${code ?? 'null'}) ${stderr.trim().split('\n').pop() ?? ''}`.trim()));
|
|
39
|
+
child.stdin?.on('error', (error) => failAll(error.message));
|
|
40
|
+
child.stdout?.on('error', (error) => failAll(error.message));
|
|
41
|
+
child.stderr?.on('error', () => {});
|
|
42
|
+
|
|
43
|
+
const reader = readline.createInterface({ input: child.stdout! });
|
|
44
|
+
reader.on('line', (line) => {
|
|
45
|
+
let reply: RpcReply;
|
|
46
|
+
try { reply = JSON.parse(line) as RpcReply; } catch { return; }
|
|
47
|
+
if (typeof reply.id !== 'number') return;
|
|
48
|
+
pending.get(reply.id)?.(reply);
|
|
49
|
+
pending.delete(reply.id);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const call: RpcCall = (method, params) => new Promise((resolve, reject) => {
|
|
53
|
+
const id = nextId++;
|
|
54
|
+
pending.set(id, (reply) => (reply.error
|
|
55
|
+
? reject(new Error(reply.error.message || `${server.command} rejected ${method}`))
|
|
56
|
+
: resolve(reply.result)));
|
|
57
|
+
child.stdin?.write(`${JSON.stringify({ jsonrpc: '2.0', id, method, params })}\n`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
let timer: NodeJS.Timeout | undefined;
|
|
61
|
+
const deadline = new Promise<never>((_, reject) => {
|
|
62
|
+
timer = setTimeout(() => reject(new Error(`${server.command} did not answer within ${timeoutMs} ms`)), timeoutMs);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
return await Promise.race([
|
|
67
|
+
(async () => {
|
|
68
|
+
await call('initialize', { clientInfo: CLIENT_INFO, capabilities: {} });
|
|
69
|
+
child.stdin?.write(`${JSON.stringify({ jsonrpc: '2.0', method: 'initialized', params: {} })}\n`);
|
|
70
|
+
return exchange(call);
|
|
71
|
+
})(),
|
|
72
|
+
deadline,
|
|
73
|
+
]);
|
|
74
|
+
} finally {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
reader.close();
|
|
77
|
+
child.kill();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
import { projectsDb } from '@/modules/database/index.js';
|
|
4
|
+
|
|
5
|
+
const PUBLISH_INTERVAL_MS = 5000;
|
|
6
|
+
|
|
7
|
+
type PublishProjectSource = (sourceId: string, folders: string[] | null) => void;
|
|
8
|
+
|
|
9
|
+
export function startProjectRegistry(publishProjectSource: PublishProjectSource): () => void {
|
|
10
|
+
const sourceId = `database:${path.resolve(process.env.DATABASE_PATH || 'auth.db')}`;
|
|
11
|
+
let publishedSignature: string | null = null;
|
|
12
|
+
|
|
13
|
+
const publishProjects = () => {
|
|
14
|
+
const folders = [...projectsDb.getProjectPaths(), ...projectsDb.getArchivedProjectPaths()]
|
|
15
|
+
.map((row) => row.project_path)
|
|
16
|
+
.sort();
|
|
17
|
+
const signature = folders.join('\n');
|
|
18
|
+
if (signature === publishedSignature) return;
|
|
19
|
+
publishProjectSource(sourceId, folders);
|
|
20
|
+
publishedSignature = signature;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const publishProjectsSafely = () => {
|
|
24
|
+
try {
|
|
25
|
+
publishProjects();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('[PieceMaker] Publication des projets impossible :', error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
publishProjectsSafely();
|
|
32
|
+
setInterval(publishProjectsSafely, PUBLISH_INTERVAL_MS).unref();
|
|
33
|
+
return publishProjectsSafely;
|
|
34
|
+
}
|
|
@@ -13,10 +13,10 @@ const path = require('path');
|
|
|
13
13
|
const VENDOR_ROOT = path.join(__dirname, 'vendor');
|
|
14
14
|
|
|
15
15
|
const { createAnonymizerRouter } = require('./anonymizer/routes.cjs');
|
|
16
|
-
const { createAnonymizerService } = require('./anonymizer/service.cjs');
|
|
17
16
|
const { createAdminRouter, registerLegalCase } = require('./vendor/websocket-server/admin-routes.cjs');
|
|
18
17
|
const { stopOriginalsJobs } = require('./vendor/websocket-server/originals-pipeline.cjs');
|
|
19
|
-
const {
|
|
18
|
+
const { resolveCaseReference } = require('./vendor/websocket-server/case-registry.cjs');
|
|
19
|
+
const { publishProjectSource } = require('./vendor/piecemaker-plugin/scripts/lib/case-folders.cjs');
|
|
20
20
|
const protectionLibrary = require('./vendor/piecemaker-plugin/scripts/lib/protection.cjs');
|
|
21
21
|
const { createProtectionBypassRouter } = require('./protection/routes.cjs');
|
|
22
22
|
const { createActivationRouter } = require('./activation/index.cjs');
|
|
@@ -53,7 +53,7 @@ function piecemakerHome() {
|
|
|
53
53
|
* @param {() => object} [options.getRuntimeStatus] Ce que la carte des composants
|
|
54
54
|
* affiche du serveur hôte (port, hôte, dépendances système).
|
|
55
55
|
*/
|
|
56
|
-
function createPieceMakerRouter({ getRuntimeStatus = defaultRuntimeStatus, anonymizer
|
|
56
|
+
function createPieceMakerRouter({ getRuntimeStatus = defaultRuntimeStatus, anonymizer, publishProjects = () => {} } = {}) {
|
|
57
57
|
const express = require('express');
|
|
58
58
|
const router = express.Router();
|
|
59
59
|
|
|
@@ -64,9 +64,9 @@ function createPieceMakerRouter({ getRuntimeStatus = defaultRuntimeStatus, anony
|
|
|
64
64
|
// l'app de bureau (origine `file://`) comme l'accès depuis le réseau local.
|
|
65
65
|
router.post('/repository/cases/selected', async (request, response) => {
|
|
66
66
|
try {
|
|
67
|
+
publishProjects();
|
|
67
68
|
const result = await registerLegalCase({
|
|
68
69
|
folder: request.body?.folder,
|
|
69
|
-
configFile: path.join(homeDir, 'config.json'),
|
|
70
70
|
homeDir,
|
|
71
71
|
});
|
|
72
72
|
response.status(201).json({ ok: true, ...result });
|
|
@@ -78,7 +78,7 @@ function createPieceMakerRouter({ getRuntimeStatus = defaultRuntimeStatus, anony
|
|
|
78
78
|
// Levée de protection à l'échelle du dossier : ajout PieceMaker monté avant
|
|
79
79
|
// le vendor, qui n'expose que le classement pièce par pièce.
|
|
80
80
|
router.use(createProtectionBypassRouter({
|
|
81
|
-
resolveCase: (reference) => resolveCaseReference(
|
|
81
|
+
resolveCase: (reference) => resolveCaseReference(reference),
|
|
82
82
|
protection: protectionLibrary,
|
|
83
83
|
}));
|
|
84
84
|
|
|
@@ -98,11 +98,9 @@ function createPieceMakerRouter({ getRuntimeStatus = defaultRuntimeStatus, anony
|
|
|
98
98
|
|
|
99
99
|
router.use(createStampingRouter({ homeDir }));
|
|
100
100
|
|
|
101
|
-
const anonymizer = applicationAnonymizer || createAnonymizerService({ homeDir });
|
|
102
|
-
if (!applicationAnonymizer) void anonymizer.start();
|
|
103
101
|
router.use(createAnonymizerRouter({ service: anonymizer }));
|
|
104
102
|
|
|
105
103
|
return router;
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
module.exports = { createPieceMakerRouter, piecemakerHome, stopOriginalsJobs, VENDOR_ROOT };
|
|
106
|
+
module.exports = { createPieceMakerRouter, piecemakerHome, publishProjectSource, stopOriginalsJobs, VENDOR_ROOT };
|
|
@@ -37,14 +37,12 @@ import { COMMANDS, CHRONOLOGY_ACTIONS } from '../lib/commandes.mjs';
|
|
|
37
37
|
import { loadConfig, readEnv, markStep, loadState, CONFIG_FILE } from '../lib/state.mjs';
|
|
38
38
|
import { scheduleStepResume, selectStepsToResume } from '../lib/resume-steps.mjs';
|
|
39
39
|
import { appServerPort, readLocalScanJob, startLocalScan } from '../lib/conversion-client.mjs';
|
|
40
|
-
import {
|
|
40
|
+
import { checkForUpdate, updateRepository } from '../lib/service.mjs';
|
|
41
41
|
|
|
42
42
|
const require = createRequire(import.meta.url);
|
|
43
43
|
const CLAUDE_ASSETS_MODULE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../websocket-server/claude-assets.cjs');
|
|
44
44
|
const CLAUDE_HOOKS_MODULE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../websocket-server/claude-hooks.cjs');
|
|
45
|
-
const CENTRAL_MAPPING_MODULE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../piecemaker-plugin/scripts/lib/central-mapping.cjs');
|
|
46
45
|
const DOCUMENT_INDEX_MODULE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../websocket-server/document-index.cjs');
|
|
47
|
-
const CASE_INSTRUCTIONS_MODULE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../websocket-server/case-instructions.cjs');
|
|
48
46
|
const ORIGINALS_PIPELINE_MODULE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../websocket-server/originals-pipeline.cjs');
|
|
49
47
|
const APP_CLI_LIB = path.join(GIT_REPO_ROOT, 'scripts', 'piecemaker', 'cli', 'lib');
|
|
50
48
|
|
|
@@ -62,18 +60,7 @@ function loadClaudeIntegrations() {
|
|
|
62
60
|
: null;
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
function loadCentralMappingIntegration() {
|
|
67
|
-
if (!fs.existsSync(CENTRAL_MAPPING_MODULE)) return null;
|
|
68
|
-
try {
|
|
69
|
-
const integration = require(CENTRAL_MAPPING_MODULE);
|
|
70
|
-
return typeof integration.syncCentralMapping === 'function' ? integration : null;
|
|
71
|
-
} catch {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function reconcileCentralMapping() {
|
|
63
|
+
function removeDeprecatedClaudeHooks() {
|
|
77
64
|
let hooksRemoved = false;
|
|
78
65
|
const claude = loadClaudeIntegrations();
|
|
79
66
|
if (typeof claude?.removeDeprecatedHooks === 'function') {
|
|
@@ -82,31 +69,9 @@ function reconcileCentralMapping() {
|
|
|
82
69
|
if (!cleanup.ok) log.warn(`Hooks hérités non nettoyés (${cleanup.reason}).`);
|
|
83
70
|
else if (cleanup.changed) log.ok('Hooks hérités Claude Code retirés.');
|
|
84
71
|
}
|
|
85
|
-
|
|
86
|
-
const integration = loadCentralMappingIntegration();
|
|
87
|
-
const central = integration?.syncCentralMapping(loadConfig());
|
|
88
|
-
if (central) log.ok(`Mapping central du proxy reconstruit (${central.entities || 0} entité(s)).`);
|
|
89
|
-
else log.warn('Mapping central du proxy non reconstruit ; relancez « piecemaker ».');
|
|
90
72
|
return hooksRemoved;
|
|
91
73
|
}
|
|
92
74
|
|
|
93
|
-
function reconcileCaseInstructions() {
|
|
94
|
-
if (!fs.existsSync(CASE_INSTRUCTIONS_MODULE)) return false;
|
|
95
|
-
try {
|
|
96
|
-
const { refreshRegisteredCaseRules } = require(CASE_INSTRUCTIONS_MODULE);
|
|
97
|
-
if (typeof refreshRegisteredCaseRules !== 'function') return false;
|
|
98
|
-
const result = refreshRegisteredCaseRules(REPO_ROOT, loadConfig());
|
|
99
|
-
if (result.failed.length) {
|
|
100
|
-
log.warn(`${result.failed.length} règle(s) de dossier n’ont pas pu être actualisées.`);
|
|
101
|
-
}
|
|
102
|
-
if (result.refreshed) log.ok(`${result.refreshed} règle(s) de dossier PieceMaker actualisée(s).`);
|
|
103
|
-
return result.failed.length === 0;
|
|
104
|
-
} catch (error) {
|
|
105
|
-
log.warn(`Règles de dossier non actualisées (${error.message}).`);
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
75
|
/**
|
|
111
76
|
* Reprend en tâche de fond les étapes d'installation restées incomplètes.
|
|
112
77
|
*
|
|
@@ -427,8 +392,8 @@ function formatChronologyText(chronology) {
|
|
|
427
392
|
}
|
|
428
393
|
|
|
429
394
|
function locateChronologyCase(flags) {
|
|
430
|
-
const {
|
|
431
|
-
const located =
|
|
395
|
+
const { locateProjectCase } = require('../../piecemaker-plugin/scripts/lib/case-folders.cjs');
|
|
396
|
+
const located = locateProjectCase(flags.caseTarget || process.cwd());
|
|
432
397
|
if (!located) {
|
|
433
398
|
throw new Error('Lancez la commande depuis un dossier juridique enregistré ou passez --case <chemin>.');
|
|
434
399
|
}
|
|
@@ -625,8 +590,8 @@ async function runConversionCommand(flags) {
|
|
|
625
590
|
if (!fs.existsSync(ORIGINALS_PIPELINE_MODULE)) {
|
|
626
591
|
throw new Error('Le module de conversion PieceMaker est introuvable.');
|
|
627
592
|
}
|
|
628
|
-
const {
|
|
629
|
-
const located =
|
|
593
|
+
const { locateProjectCase } = require('../../piecemaker-plugin/scripts/lib/case-folders.cjs');
|
|
594
|
+
const located = locateProjectCase(flags.caseTarget || process.cwd());
|
|
630
595
|
if (!located) {
|
|
631
596
|
throw new Error('Lancez la commande depuis un dossier juridique enregistré ou passez --case <chemin>.');
|
|
632
597
|
}
|
|
@@ -666,8 +631,7 @@ async function runOperationalCommand(command, knownUpdate = null, flags = {}) {
|
|
|
666
631
|
const pending = knownUpdate ?? checkForUpdate();
|
|
667
632
|
if (!pending.available) {
|
|
668
633
|
log.ok(`PieceMaker est déjà à jour (${pending.ref}, ${pending.current.slice(0, 7)}).`);
|
|
669
|
-
|
|
670
|
-
if (reconcileCentralMapping()) {
|
|
634
|
+
if (removeDeprecatedClaudeHooks()) {
|
|
671
635
|
log.info('Rouvrez les sessions Claude Code actives pour oublier les hooks hérités.');
|
|
672
636
|
}
|
|
673
637
|
// « update » reste le geste de remise à niveau : même sans nouveau commit,
|
|
@@ -681,44 +645,34 @@ async function runOperationalCommand(command, knownUpdate = null, flags = {}) {
|
|
|
681
645
|
log.info(`Restauration de l’installation depuis le dépôt distant (${pending.localChanges} fichier(s) localement modifié(s)).`);
|
|
682
646
|
}
|
|
683
647
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
log.ok(`PieceMaker mis à jour (${result.ref}, ${result.target.slice(0, 7)}).`);
|
|
687
|
-
|
|
688
|
-
reconcileCaseInstructions();
|
|
648
|
+
const result = updateRepository(pending);
|
|
649
|
+
log.ok(`PieceMaker mis à jour (${result.ref}, ${result.target.slice(0, 7)}).`);
|
|
689
650
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
// Les composants PieceMaker sont découverts directement dans
|
|
695
|
-
// ~/.claude/{skills,agents}. Les liens symboliques suivent déjà le dépôt ;
|
|
696
|
-
// cet appel rafraîchit aussi le repli par copie sur les plateformes qui ne
|
|
697
|
-
// peuvent pas créer de liens.
|
|
698
|
-
const claudeIntegrations = loadClaudeIntegrations();
|
|
699
|
-
if (commandExists('claude', ['--version']) && claudeIntegrations) {
|
|
700
|
-
const claudeAssets = claudeIntegrations.syncClaudeAssets(REPO_ROOT, os.homedir());
|
|
701
|
-
if (claudeAssets.conflicts.length) {
|
|
702
|
-
log.warn(`${claudeAssets.conflicts.length} skill(s)/agent(s) Claude personnel(s) homonyme(s) conservé(s).`);
|
|
703
|
-
} else {
|
|
704
|
-
log.ok(`${claudeAssets.registered} skill(s)/agent(s) PieceMaker synchronisé(s) pour Claude Code.`);
|
|
705
|
-
}
|
|
706
|
-
const claudeHooks = claudeIntegrations.installClaudeHooks(REPO_ROOT, os.homedir());
|
|
707
|
-
if (!claudeHooks.ok) log.warn(`Hooks Claude Code non synchronisés (${claudeHooks.reason}).`);
|
|
708
|
-
else if (claudeHooks.changed) log.ok(`${claudeHooks.registered} hook(s) PieceMaker synchronisé(s) pour Claude Code.`);
|
|
709
|
-
}
|
|
651
|
+
if (result.pythonChanged) {
|
|
652
|
+
log.warn('Une dépendance Python a changé : relancez « piecemaker install » (étape 03 si elle est installée).');
|
|
653
|
+
}
|
|
710
654
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
655
|
+
// Les composants PieceMaker sont découverts directement dans
|
|
656
|
+
// ~/.claude/{skills,agents}. Les liens symboliques suivent déjà le dépôt ;
|
|
657
|
+
// cet appel rafraîchit aussi le repli par copie sur les plateformes qui ne
|
|
658
|
+
// peuvent pas créer de liens.
|
|
659
|
+
const claudeIntegrations = loadClaudeIntegrations();
|
|
660
|
+
if (commandExists('claude', ['--version']) && claudeIntegrations) {
|
|
661
|
+
const claudeAssets = claudeIntegrations.syncClaudeAssets(REPO_ROOT, os.homedir());
|
|
662
|
+
if (claudeAssets.conflicts.length) {
|
|
663
|
+
log.warn(`${claudeAssets.conflicts.length} skill(s)/agent(s) Claude personnel(s) homonyme(s) conservé(s).`);
|
|
664
|
+
} else {
|
|
665
|
+
log.ok(`${claudeAssets.registered} skill(s)/agent(s) PieceMaker synchronisé(s) pour Claude Code.`);
|
|
718
666
|
}
|
|
667
|
+
const claudeHooks = claudeIntegrations.installClaudeHooks(REPO_ROOT, os.homedir());
|
|
668
|
+
if (!claudeHooks.ok) log.warn(`Hooks Claude Code non synchronisés (${claudeHooks.reason}).`);
|
|
669
|
+
else if (claudeHooks.changed) log.ok(`${claudeHooks.registered} hook(s) PieceMaker synchronisé(s) pour Claude Code.`);
|
|
719
670
|
}
|
|
720
|
-
|
|
721
|
-
|
|
671
|
+
|
|
672
|
+
removeDeprecatedClaudeHooks();
|
|
673
|
+
log.info('Rouvrez les sessions Claude Code/Codex actives pour charger les hooks et le MCP mis à jour.');
|
|
674
|
+
// Une mise à jour qui a échoué ne doit pas enchaîner sur une
|
|
675
|
+
// réinstallation en fond : l'exception traverse d'abord.
|
|
722
676
|
await resumePendingStepsAfterUpdate();
|
|
723
677
|
return 0;
|
|
724
678
|
}
|
|
@@ -11,8 +11,6 @@ import fs from 'node:fs';
|
|
|
11
11
|
import os from 'node:os';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
|
|
14
|
-
import { GIT_REPO_ROOT } from './platform.mjs';
|
|
15
|
-
|
|
16
14
|
const PLUGIN_DIRECTORY = 'piecemaker-plugin';
|
|
17
15
|
const PLUGIN_SKILL_PATH = /(^|[\\/])piecemaker-plugin[\\/]skills[\\/][^\\/]+$/;
|
|
18
16
|
|
|
@@ -32,32 +30,6 @@ export function codexHooksFile(userHome = os.homedir()) {
|
|
|
32
30
|
return path.join(userHome, '.codex', 'hooks.json');
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
/** Script unifié Claude/Codex, à la racine du dépôt — pas une copie vendorisée. */
|
|
36
|
-
function codexProxyGuardScript() {
|
|
37
|
-
return path.join(GIT_REPO_ROOT, 'scripts', 'piecemaker', 'hooks', 'proxy-guard.mjs');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function isPieceMakerProxyGuard(handler) {
|
|
41
|
-
const command = typeof handler?.command === 'string' ? handler.command : '';
|
|
42
|
-
const commandWindows = typeof handler?.commandWindows === 'string' ? handler.commandWindows : '';
|
|
43
|
-
return (command.includes('proxy-guard.mjs') || commandWindows.includes('proxy-guard.mjs'))
|
|
44
|
-
&& (command.includes('PIECEMAKER_HOOK_CLIENT=codex') || commandWindows.includes('PIECEMAKER_HOOK_CLIENT=codex'));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function codexProxyGuardGroup() {
|
|
48
|
-
const script = codexProxyGuardScript();
|
|
49
|
-
return {
|
|
50
|
-
matcher: 'startup|resume|clear',
|
|
51
|
-
hooks: [{
|
|
52
|
-
type: 'command',
|
|
53
|
-
command: `PIECEMAKER_HOOK_CLIENT=codex node ${JSON.stringify(script)}`,
|
|
54
|
-
commandWindows: `set "PIECEMAKER_HOOK_CLIENT=codex" && node ${JSON.stringify(script)}`,
|
|
55
|
-
timeout: 45,
|
|
56
|
-
statusMessage: 'Vérification de l’anonymisation PieceMaker',
|
|
57
|
-
}],
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
33
|
function readCodexHooks(userHome) {
|
|
62
34
|
const file = codexHooksFile(userHome);
|
|
63
35
|
if (!fs.existsSync(file)) return { file, document: { hooks: {} } };
|
|
@@ -68,7 +40,7 @@ function readCodexHooks(userHome) {
|
|
|
68
40
|
}
|
|
69
41
|
if (document.hooks === undefined) document.hooks = {};
|
|
70
42
|
if (!document.hooks || typeof document.hooks !== 'object' || Array.isArray(document.hooks)
|
|
71
|
-
|| (document.hooks.
|
|
43
|
+
|| (document.hooks.PreToolUse !== undefined && !Array.isArray(document.hooks.PreToolUse))) {
|
|
72
44
|
return { file, error: 'hooks-invalides' };
|
|
73
45
|
}
|
|
74
46
|
return { file, document };
|
|
@@ -77,60 +49,6 @@ function readCodexHooks(userHome) {
|
|
|
77
49
|
}
|
|
78
50
|
}
|
|
79
51
|
|
|
80
|
-
export function codexSessionHookStatus(repoRoot, userHome = os.homedir()) {
|
|
81
|
-
const loaded = readCodexHooks(userHome);
|
|
82
|
-
if (loaded.error) return { ok: false, changed: false, file: loaded.file, reason: loaded.error };
|
|
83
|
-
const expected = codexProxyGuardGroup(repoRoot);
|
|
84
|
-
const groups = Array.isArray(loaded.document.hooks.SessionStart)
|
|
85
|
-
? loaded.document.hooks.SessionStart
|
|
86
|
-
: [];
|
|
87
|
-
const managed = groups.flatMap((group) => Array.isArray(group?.hooks) ? group.hooks : [])
|
|
88
|
-
.filter(isPieceMakerProxyGuard);
|
|
89
|
-
const exact = groups.some((group) => group?.matcher === expected.matcher
|
|
90
|
-
&& Array.isArray(group.hooks)
|
|
91
|
-
&& group.hooks.some((handler) => JSON.stringify(handler) === JSON.stringify(expected.hooks[0])));
|
|
92
|
-
return {
|
|
93
|
-
ok: exact && managed.length === 1,
|
|
94
|
-
changed: false,
|
|
95
|
-
file: loaded.file,
|
|
96
|
-
reason: exact && managed.length === 1 ? null : 'hook-absent-ou-perime',
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Fusionne uniquement la sentinelle SessionStart ; tous les hooks personnels sont conservés. */
|
|
101
|
-
export function installCodexSessionHook(repoRoot, userHome = os.homedir()) {
|
|
102
|
-
const loaded = readCodexHooks(userHome);
|
|
103
|
-
if (loaded.error) return { ok: false, changed: false, file: loaded.file, reason: loaded.error };
|
|
104
|
-
const document = loaded.document;
|
|
105
|
-
const groups = Array.isArray(document.hooks.SessionStart)
|
|
106
|
-
? document.hooks.SessionStart
|
|
107
|
-
: [];
|
|
108
|
-
const preserved = [];
|
|
109
|
-
for (const group of groups) {
|
|
110
|
-
if (!group || typeof group !== 'object' || Array.isArray(group)) {
|
|
111
|
-
preserved.push(group);
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const hooks = Array.isArray(group.hooks) ? group.hooks.filter((handler) => !isPieceMakerProxyGuard(handler)) : [];
|
|
115
|
-
if (hooks.length || !Array.isArray(group.hooks)) preserved.push({ ...group, hooks });
|
|
116
|
-
}
|
|
117
|
-
document.description ||= 'Hooks locaux Codex, dont la sentinelle d’anonymisation PieceMaker.';
|
|
118
|
-
document.hooks.SessionStart = [...preserved, codexProxyGuardGroup(repoRoot)];
|
|
119
|
-
const output = `${JSON.stringify(document, null, 2)}\n`;
|
|
120
|
-
let current = null;
|
|
121
|
-
try { current = fs.readFileSync(loaded.file, 'utf8'); } catch { /* fichier absent */ }
|
|
122
|
-
if (current === output) return { ok: true, changed: false, file: loaded.file, registered: 1 };
|
|
123
|
-
try {
|
|
124
|
-
fs.mkdirSync(path.dirname(loaded.file), { recursive: true });
|
|
125
|
-
const temporary = `${loaded.file}.tmp-${process.pid}`;
|
|
126
|
-
fs.writeFileSync(temporary, output, 'utf8');
|
|
127
|
-
fs.renameSync(temporary, loaded.file);
|
|
128
|
-
return { ok: true, changed: true, file: loaded.file, registered: 1 };
|
|
129
|
-
} catch (error) {
|
|
130
|
-
return { ok: false, changed: false, file: loaded.file, reason: error?.message || 'ecriture-impossible' };
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
52
|
/** Même script que la protection Claude Code : contrat PreToolUse deny identique. */
|
|
135
53
|
function codexProtectionScript(repoRoot) {
|
|
136
54
|
return path.join(pluginRoot(repoRoot), 'scripts', 'protect-originals.mjs');
|
|
@@ -194,7 +112,7 @@ export function installCodexProtectionHook(repoRoot, userHome = os.homedir()) {
|
|
|
194
112
|
const hooks = Array.isArray(group.hooks) ? group.hooks.filter((handler) => !isPieceMakerProtection(handler)) : [];
|
|
195
113
|
if (hooks.length || !Array.isArray(group.hooks)) preserved.push({ ...group, hooks });
|
|
196
114
|
}
|
|
197
|
-
document.description ||= 'Hooks locaux Codex, dont la
|
|
115
|
+
document.description ||= 'Hooks locaux Codex, dont la protection des pièces PieceMaker.';
|
|
198
116
|
document.hooks.PreToolUse = [...preserved, codexProtectionGroup(repoRoot)];
|
|
199
117
|
const output = `${JSON.stringify(document, null, 2)}\n`;
|
|
200
118
|
let current = null;
|