@linxin666/dsh-client-ui-task-board 0.4.3 → 0.4.5

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 (128) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +56 -18
  3. package/README.zh.md +56 -18
  4. package/lib/client.js +6242 -958
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +3475 -234
  7. package/lib/types/client/PluginSettingsCard.d.ts +7 -0
  8. package/lib/types/client/TaskBoardSettingsCard.d.ts +19 -3
  9. package/lib/types/client/board/ClampedMarkdown.d.ts +3 -0
  10. package/lib/types/client/board/ConfirmDialog.d.ts +4 -1
  11. package/lib/types/client/board/EditTaskModal.d.ts +5 -2
  12. package/lib/types/client/board/LinkSubtaskModal.d.ts +5 -2
  13. package/lib/types/client/board/NewTaskModal.d.ts +4 -1
  14. package/lib/types/client/board/TagManagerModal.d.ts +26 -0
  15. package/lib/types/client/board/TaskBoard.d.ts +10 -1
  16. package/lib/types/client/board/TaskCard.d.ts +14 -1
  17. package/lib/types/client/board/TaskDetail.d.ts +3 -1
  18. package/lib/types/client/board/TaskForm.d.ts +23 -2
  19. package/lib/types/client/board/VerificationReport.d.ts +23 -0
  20. package/lib/types/client/board/card-view.d.ts +113 -0
  21. package/lib/types/client/board/icons.d.ts +32 -0
  22. package/lib/types/client/board/overlay.d.ts +69 -0
  23. package/lib/types/client/board/preset-label.d.ts +22 -0
  24. package/lib/types/client/board/status-key.d.ts +15 -0
  25. package/lib/types/client/board/task-markdown.d.ts +19 -0
  26. package/lib/types/client/board-card-seat.d.ts +34 -0
  27. package/lib/types/client/host-api.d.ts +24 -1
  28. package/lib/types/client/index.d.ts +19 -0
  29. package/lib/types/client/locales.d.ts +141 -3
  30. package/lib/types/client/native-panel.d.ts +6 -20
  31. package/lib/types/client/schedule-zone.d.ts +47 -0
  32. package/lib/types/client/seats.d.ts +18 -0
  33. package/lib/types/client/service.d.ts +32 -0
  34. package/lib/types/client/settings-form.d.ts +16 -0
  35. package/lib/types/core/controller.d.ts +38 -1
  36. package/lib/types/core/degraded-reason.d.ts +46 -0
  37. package/lib/types/core/extension.d.ts +283 -0
  38. package/lib/types/core/handover.d.ts +13 -1
  39. package/lib/types/core/issue-form.d.ts +16 -0
  40. package/lib/types/core/package-name.d.ts +9 -0
  41. package/lib/types/core/schedule.d.ts +95 -20
  42. package/lib/types/core/subtask.d.ts +30 -11
  43. package/lib/types/core/tasks.d.ts +110 -5
  44. package/lib/types/core/use-cases/task-create.d.ts +2 -1
  45. package/lib/types/core/use-cases/task-schedule.d.ts +8 -4
  46. package/lib/types/core/use-cases/task-tag.d.ts +48 -0
  47. package/lib/types/core/use-cases/task-update.d.ts +5 -3
  48. package/lib/types/core/verification.d.ts +386 -0
  49. package/lib/types/core/workspace-target.d.ts +41 -0
  50. package/lib/types/host/agent-tools.d.ts +1 -1
  51. package/lib/types/host/extension-registry.d.ts +111 -0
  52. package/lib/types/host/llm-dispatch.d.ts +63 -0
  53. package/lib/types/host/verification-gate.d.ts +71 -0
  54. package/lib/types/host/verification-runner.d.ts +108 -0
  55. package/lib/types/host/workspace-evidence.d.ts +53 -0
  56. package/lib/types/host-ledger.d.ts +107 -11
  57. package/lib/types/host-runner.d.ts +99 -4
  58. package/lib/types/host-service.d.ts +114 -2
  59. package/lib/types/index.d.ts +80 -26
  60. package/lib/types/protocol.d.ts +53 -3
  61. package/lib/types/tool-surface.d.ts +71 -0
  62. package/package.json +27 -26
  63. package/src/client/PluginSettingsCard.tsx +9 -0
  64. package/src/client/TaskBoardSettingsCard.tsx +304 -65
  65. package/src/client/board/ClampedMarkdown.tsx +69 -0
  66. package/src/client/board/ConfirmDialog.tsx +7 -3
  67. package/src/client/board/EditTaskModal.tsx +5 -2
  68. package/src/client/board/LinkSubtaskModal.tsx +30 -15
  69. package/src/client/board/NewTaskModal.tsx +288 -151
  70. package/src/client/board/TagManagerModal.tsx +235 -0
  71. package/src/client/board/TaskBoard.tsx +259 -103
  72. package/src/client/board/TaskCard.tsx +238 -86
  73. package/src/client/board/TaskDetail.tsx +154 -59
  74. package/src/client/board/TaskForm.tsx +61 -6
  75. package/src/client/board/VerificationReport.tsx +203 -0
  76. package/src/client/board/card-view.ts +220 -0
  77. package/src/client/board/icons.tsx +89 -0
  78. package/src/client/board/overlay.tsx +189 -0
  79. package/src/client/board/preset-label.ts +44 -0
  80. package/src/client/board/status-key.ts +27 -0
  81. package/src/client/board/task-markdown.module.css +137 -0
  82. package/src/client/board/task-markdown.tsx +106 -0
  83. package/src/client/board-card-seat.ts +102 -0
  84. package/src/client/board-settings.module.css +66 -0
  85. package/src/client/board.module.css +602 -68
  86. package/src/client/host-api.ts +109 -6
  87. package/src/client/index.ts +48 -6
  88. package/src/client/locales.ts +290 -12
  89. package/src/client/native-panel.tsx +18 -2
  90. package/src/client/schedule-zone.ts +135 -0
  91. package/src/client/seats.tsx +58 -0
  92. package/src/client/service.ts +94 -0
  93. package/src/client/settings-card.module.css +31 -5
  94. package/src/client/settings-form.ts +27 -1
  95. package/src/core/controller.ts +101 -5
  96. package/src/core/degraded-reason.ts +81 -0
  97. package/src/core/extension.ts +376 -0
  98. package/src/core/freeze-snapshot.ts +2 -2
  99. package/src/core/handover.ts +16 -1
  100. package/src/core/issue-form.ts +19 -0
  101. package/src/core/package-name.ts +9 -0
  102. package/src/core/schedule.ts +211 -55
  103. package/src/core/store.ts +26 -1
  104. package/src/core/subtask.ts +77 -22
  105. package/src/core/tasks.ts +138 -10
  106. package/src/core/use-cases/task-create.ts +14 -2
  107. package/src/core/use-cases/task-parent.ts +3 -2
  108. package/src/core/use-cases/task-schedule.ts +17 -6
  109. package/src/core/use-cases/task-tag.ts +110 -0
  110. package/src/core/use-cases/task-update.ts +13 -4
  111. package/src/core/verification.ts +826 -0
  112. package/src/core/workspace-target.ts +59 -0
  113. package/src/host/agent-tools.ts +58 -24
  114. package/src/host/extension-registry.ts +509 -0
  115. package/src/host/llm-dispatch.ts +87 -0
  116. package/src/host/verification-gate.ts +331 -0
  117. package/src/host/verification-runner.ts +535 -0
  118. package/src/host/workspace-evidence.ts +176 -0
  119. package/src/host-ai.ts +15 -9
  120. package/src/host-ledger.ts +342 -51
  121. package/src/host-routes.ts +15 -2
  122. package/src/host-runner.ts +219 -20
  123. package/src/host-service.ts +346 -26
  124. package/src/index.ts +204 -16
  125. package/src/protocol.ts +122 -9
  126. package/src/tool-surface.ts +95 -0
  127. package/lib/types/host/run-guarded.d.ts +0 -39
  128. package/src/host/run-guarded.ts +0 -76
@@ -5,7 +5,9 @@
5
5
  * unit-testable in isolation.
6
6
  */
7
7
  import type { FreezeSnapshot } from './freeze-snapshot.ts';
8
+ import type { ExecutionVerification } from './verification.ts';
8
9
  import type { TaskHandover, TaskHandoverInput } from './handover.ts';
10
+ import { type TaskBoardExtensionPayload } from './extension.ts';
9
11
  /** Task lifecycle status, one per kanban column. */
10
12
  export type TaskStatus = 'backlog' | 'todo' | 'running' | 'done' | 'failed';
11
13
  /** Settled outcome of one execution attempt. */
@@ -52,6 +54,14 @@ export interface ExecutionRecord {
52
54
  ownResult?: ExecutionOutcome;
53
55
  /** Human failure text that arrived with {@link ownResult}. */
54
56
  ownError?: string;
57
+ /**
58
+ * Goal acceptance state of this execution (task-board goal verification).
59
+ * Fixed when the execution starts and never rewritten from later settings:
60
+ * the contract is frozen here, the attempts accrue here, and the settlement
61
+ * rule reads the pass record here. Absent on an execution that started
62
+ * before the feature existed, which keeps it on the historical verdict.
63
+ */
64
+ verification?: ExecutionVerification;
55
65
  }
56
66
  /**
57
67
  * Maximum number of execution records retained per task. Older settled runs
@@ -75,6 +85,13 @@ export interface ScheduleRule {
75
85
  enabled: boolean;
76
86
  /** 5-field cron expression: `分 时 日 月 周`. */
77
87
  cron: string;
88
+ /**
89
+ * IANA zone the cron wall clock is read in (issue #1722). Absent means the
90
+ * Host process zone, which is what a rule written before zones were
91
+ * persisted keeps using; the Host stamps its own zone at ledger migration so
92
+ * a later `TZ` change cannot silently move an existing rule.
93
+ */
94
+ timeZone?: string;
78
95
  /** Next due instant (ms epoch); maintained by the scheduler/controller. */
79
96
  nextRunAt: number | undefined;
80
97
  /** Instant of the latest scheduled trigger (ms epoch). */
@@ -214,6 +231,30 @@ export interface TaskRecord {
214
231
  * and a subtask's own permission pin cannot be honored in this mode.
215
232
  */
216
233
  teamRun?: boolean;
234
+ /**
235
+ * Start every execution of this task with dsh's built-in `/goal` command,
236
+ * armed with the composed execution prompt as its objective. The session then
237
+ * keeps working automatic continuation rounds until the agent marks the goal
238
+ * complete, and this board settles the execution on the goal's own end
239
+ * instead of at the first turn end. Absent means ON — the option is checked
240
+ * by default, so only an explicit `false` runs the task as a single plain
241
+ * turn. A session whose `/goal` command is refused still runs the prompt.
242
+ */
243
+ goalRun?: boolean;
244
+ /**
245
+ * Run this task's goal executions WITHOUT the board's acceptance gate.
246
+ *
247
+ * Absent means INHERIT: the execution's applicability is decided by the
248
+ * board-wide `goalVerification` switch frozen at start, exactly as a card
249
+ * that never touched this option behaves. Only an explicit `true` opts the
250
+ * card out, and the execution records `applicability: 'disabled'` so the
251
+ * report says plainly that nothing certified this run.
252
+ *
253
+ * The opt-out is per execution, not per run: flipping it never rewrites the
254
+ * verdict rule of an execution already open, and a rerun or a scheduled
255
+ * occurrence reads the card's current value when it freezes its contract.
256
+ */
257
+ skipVerification?: boolean;
217
258
  /**
218
259
  * Frozen context snapshot for a continuation card; absent on plain tasks.
219
260
  * Sanitized before it enters the ledger (redaction, slash-command taint,
@@ -245,6 +286,20 @@ export interface TaskRecord {
245
286
  * absent means on-board.
246
287
  */
247
288
  archivedAt?: number;
289
+ /**
290
+ * Opaque external-provider metadata, keyed by extension id; optional and
291
+ * additive so existing tasks require no ledger migration. The board stores
292
+ * and forwards it without interpreting the keys — each provider owns the
293
+ * shape and validation of its own entry.
294
+ */
295
+ integrations?: Record<string, TaskBoardExtensionPayload>;
296
+ /**
297
+ * Whether the card is held off the board: it exists in the ledger (and its
298
+ * execution history is intact) but no column ever renders it. Providers
299
+ * create hidden cards for work they materialize but do not want displayed;
300
+ * absent means on-board.
301
+ */
302
+ hidden?: boolean;
248
303
  }
249
304
  /**
250
305
  * Statuses a task may be archived from: every status but `running`, whose
@@ -270,7 +325,7 @@ export interface NewTaskInput {
270
325
  * inherits the parent's unset execution targets.
271
326
  */
272
327
  parentId?: string;
273
- /** Workspace the execution must run in; empty/absent = the recent workspace. */
328
+ /** Workspace the execution must run in; empty/absent = the creating session's workspace for a root task, else the recent workspace at execution time. */
274
329
  workspaceId?: string;
275
330
  /** Agent preset the execution session must be composed from; empty/absent = deployment default. */
276
331
  mode?: string;
@@ -282,14 +337,26 @@ export interface NewTaskInput {
282
337
  reuseSession?: boolean;
283
338
  /** Run the subtree as an Agent Team (Team Lead session plus one teammate per direct subtask). */
284
339
  teamRun?: boolean;
340
+ /**
341
+ * Start the execution with dsh's built-in `/goal`. Absent/true keeps the
342
+ * default (goal run); an explicit false requests a single plain turn.
343
+ */
344
+ goalRun?: boolean;
345
+ /**
346
+ * Run this task's goal executions without the acceptance gate; absent
347
+ * inherits the board-wide `goalVerification` switch.
348
+ */
349
+ skipVerification?: boolean;
285
350
  /**
286
351
  * Optional scheduled-run rule requested at creation time (the new-task
287
- * dialog): an enable flag plus a 5-field cron expression. The create use
288
- * case arms it only when enabled and the expression is valid.
352
+ * dialog): an enable flag, a 5-field cron expression, and the IANA zone its
353
+ * wall clock is read in (absent means the Host zone). The create use case
354
+ * arms it only when enabled and the expression is valid.
289
355
  */
290
356
  schedule?: {
291
357
  enabled: boolean;
292
358
  cron: string;
359
+ timeZone?: string;
293
360
  };
294
361
  /**
295
362
  * Optional frozen context snapshot (goal/progress/next, sanitized by the
@@ -309,13 +376,31 @@ export interface NewTaskInput {
309
376
  * ahead of the execution prompt; a bare name changes nothing at run time.
310
377
  */
311
378
  tags?: TaskTag[];
379
+ /** Opaque external-provider metadata keyed by extension id. */
380
+ integrations?: Record<string, TaskBoardExtensionPayload>;
381
+ /** Column the created card opens in; absent means the board default (todo). */
382
+ status?: TaskStatus;
383
+ /** Create the card off-board (held in the ledger, never rendered). */
384
+ hidden?: boolean;
312
385
  }
313
386
  /** The five kanban columns, in display order. */
314
387
  export declare const COLUMNS: readonly {
315
388
  status: TaskStatus;
316
389
  label: string;
317
390
  }[];
318
- /** Statuses a user may move a card to manually (execution states are owned by the runner). */
391
+ /**
392
+ * Statuses a card may be moved to by hand: every column. The board UI and the
393
+ * agent tool surface share this one list, so no column can be manual on one
394
+ * surface and locked on the other.
395
+ *
396
+ * The column is a board statement, not a claim about a run. A hand-written
397
+ * `done`/`failed` declares that the work finished (or failed) outside a
398
+ * Host-run execution — human hands, an external system — and a hand-written
399
+ * `running` says the work is under way without a tracked session. None of them
400
+ * creates an {@link ExecutionRecord}, which is what keeps a declaration
401
+ * distinguishable from a recorded outcome in the card's execution history; the
402
+ * next settled run overwrites the column with the real one.
403
+ */
319
404
  export declare const MANUAL_STATUSES: readonly TaskStatus[];
320
405
  /** Statuses the runner may move a card to from 'running'. */
321
406
  export declare const RUNNER_SETTLE_STATUSES: readonly TaskStatus[];
@@ -323,8 +408,28 @@ export declare const RUNNER_SETTLE_STATUSES: readonly TaskStatus[];
323
408
  export declare const ALL_STATUSES: readonly TaskStatus[];
324
409
  /** Brand an unknown string as a status; undefined when it is not one. */
325
410
  export declare function isTaskStatus(value: unknown): value is TaskStatus;
326
- /** Whether a manual move target is allowed from the given status. */
411
+ /**
412
+ * Whether the manual move `from` -> `to` is a legal *column* change: any
413
+ * column, and never the one the card already shows.
414
+ *
415
+ * Whether the card may be moved at all is a separate question. The lock an
416
+ * executing card carries belongs to its open execution, never to the column
417
+ * text, so it is {@link canMoveTask} — not this predicate — that expresses it.
418
+ */
327
419
  export declare function canMoveManually(from: TaskStatus, to: TaskStatus): boolean;
420
+ /**
421
+ * Whether the board may move `task` to `to` by hand: the card is on-board,
422
+ * holds no open execution, and the target is a legal column change. The ledger,
423
+ * the detail view's status buttons and the board's drop handler all decide
424
+ * through this one predicate, so no two surfaces can disagree about a card.
425
+ */
426
+ export declare function canMoveTask(task: TaskRecord, to: TaskStatus): boolean;
427
+ /**
428
+ * Whether the task still has an execution the runner has not settled. This —
429
+ * not the `running` column — is what "the runner owns this card" means: a card
430
+ * parked in `running` by hand has no session and stays fully movable.
431
+ */
432
+ export declare function hasOpenExecution(task: TaskRecord): boolean;
328
433
  /** Normalize one optional execution-target string: trim; blank collapses to undefined. */
329
434
  export declare function normalizeTargetId(value: string | undefined): string | undefined;
330
435
  /**
@@ -22,5 +22,6 @@ export interface CreateTaskResult {
22
22
  * @param now - clock instant (ms epoch).
23
23
  * @param id - minted task id.
24
24
  * @param maxSubtaskDepth - deployment subtask depth limit.
25
+ * @param hostTimeZone - zone a rule that stores no zone of its own follows.
25
26
  */
26
- export declare function applyCreateTask(tasks: readonly TaskRecord[], input: NewTaskInput, now: number, id: string, maxSubtaskDepth?: number): CreateTaskResult;
27
+ export declare function applyCreateTask(tasks: readonly TaskRecord[], input: NewTaskInput, now: number, id: string, maxSubtaskDepth?: number, hostTimeZone?: string): CreateTaskResult;
@@ -3,6 +3,8 @@ import { type TaskRecord } from '../tasks.ts';
3
3
  export interface SetSchedulePatch {
4
4
  enabled?: boolean;
5
5
  cron?: string;
6
+ /** IANA zone for the cron wall clock; `null` clears it back to the Host zone. */
7
+ timeZone?: string | null;
6
8
  }
7
9
  /** Result of arming/disarming a rule. */
8
10
  export interface SetScheduleResult {
@@ -12,15 +14,17 @@ export interface SetScheduleResult {
12
14
  applied: boolean;
13
15
  }
14
16
  /**
15
- * Set an on-board task's schedule rule. A blank or invalid cron, or an
16
- * archived task, is rejected (state untouched); an enabled rule computes the
17
- * next run instant immediately, a disabled one carries no next-run instant.
17
+ * Set an on-board task's schedule rule. A blank or invalid cron, an unknown or
18
+ * archived task, or an unusable zone is rejected (state untouched); an enabled
19
+ * rule computes the next run instant immediately in the rule's own zone, a
20
+ * disabled one carries no next-run instant.
18
21
  * @param tasks - current ledger.
19
22
  * @param id - the task to schedule.
20
23
  * @param patch - rule fields to change (absent fields keep their current value).
21
24
  * @param now - clock instant (ms epoch).
25
+ * @param hostTimeZone - zone a rule with no stored zone follows.
22
26
  */
23
- export declare function applySetSchedule(tasks: readonly TaskRecord[], id: string, patch: SetSchedulePatch, now: number): SetScheduleResult;
27
+ export declare function applySetSchedule(tasks: readonly TaskRecord[], id: string, patch: SetSchedulePatch, now: number, hostTimeZone: string): SetScheduleResult;
24
28
  /**
25
29
  * Roll a task's schedule rule forward (scheduler callback): persist the next
26
30
  * due instant and the trigger instant. No-op for tasks without a rule (deleted
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Label-management use cases (issue: labels could not be cleaned up).
3
+ *
4
+ * A label lives on every task that carries it, so renaming or removing one is a
5
+ * ledger-wide edit, not a task edit: the board's label row is the union of the
6
+ * labels in use, and without these two transitions a label created by an
7
+ * afternoon experiment stayed on the board forever.
8
+ *
9
+ * Both transitions are pure ledger rewrites (no persistence, no notify — the
10
+ * controller and the Host ledger orchestrate those), and both are idempotent:
11
+ * a label that no task carries changes nothing and reports no error for the
12
+ * delete path (the desired end state already holds), while a rename from an
13
+ * unknown label is refused so a stale tab cannot silently do nothing.
14
+ *
15
+ * Renaming onto a name that is already in use MERGES the two: a task carrying
16
+ * both keeps the row it already had (with its execution hint) and loses the
17
+ * duplicate, which is the only reading that cannot lose a hint the user typed.
18
+ */
19
+ import { type TaskRecord } from '../tasks.ts';
20
+ /** Outcome of one ledger-wide label edit. */
21
+ export interface TagEditResult {
22
+ /** The ledger after the edit, or the input unchanged when nothing applied. */
23
+ tasks: readonly TaskRecord[];
24
+ /** Whether any task actually changed (drives whether the caller persists). */
25
+ changed: boolean;
26
+ /** Refusal reason; the ledger is unchanged when set. */
27
+ error?: string;
28
+ }
29
+ /**
30
+ * Rename one label everywhere, merging into an existing label of the target
31
+ * name. Every touched task gets a fresh updatedAt; untouched tasks keep theirs.
32
+ * @param tasks - current ledger.
33
+ * @param from - the label to rename.
34
+ * @param to - the new name (an existing name merges the two labels).
35
+ * @param now - clock instant (ms epoch).
36
+ * @returns the rewritten ledger, or a refusal.
37
+ */
38
+ export declare function applyRenameTag(tasks: readonly TaskRecord[], from: string, to: string, now: number): TagEditResult;
39
+ /**
40
+ * Remove one label from every task that carries it. Archived cards are included:
41
+ * the board's label row draws from the whole ledger, so a label left on an
42
+ * archived card would come straight back into the filter.
43
+ * @param tasks - current ledger.
44
+ * @param name - the label to remove.
45
+ * @param now - clock instant (ms epoch).
46
+ * @returns the rewritten ledger.
47
+ */
48
+ export declare function applyDeleteTag(tasks: readonly TaskRecord[], name: string, now: number): TagEditResult;
@@ -15,7 +15,7 @@ import type { TaskHandoverInput } from '../handover.ts';
15
15
  * Editable fields on a task (the update patch surface). `freeze` replaces the
16
16
  * continuation-card snapshot (restamping frozenAt); an explicit null clears it.
17
17
  */
18
- export type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession' | 'teamRun'>> & {
18
+ export type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession' | 'teamRun' | 'goalRun' | 'skipVerification'>> & {
19
19
  freeze?: FreezeSnapshot & {
20
20
  redacted?: boolean;
21
21
  } | null;
@@ -39,8 +39,10 @@ export declare const TASK_CONTENT_FIELDS: readonly ["title", "description", "pro
39
39
  export declare function hasContentPatch(patch: TaskUpdatePatch): boolean;
40
40
  /**
41
41
  * Whether a task's content may still be edited: the task must be on-board
42
- * (not archived) and must never have started executing. Fail-closed: a
43
- * running, settled, or cancelled-before-launch task keeps its content fixed.
42
+ * (not archived) and must never have started executing. Fail-closed: a task
43
+ * with any execution record — running, settled, or cancelled before launch —
44
+ * keeps its content fixed. The run, not the column, is the trigger: a card
45
+ * parked in 'running' by hand has nothing recorded yet and stays editable.
44
46
  */
45
47
  export declare function canEditTaskContent(task: TaskRecord): boolean;
46
48
  /**